xref: /AOO41X/main/vcl/unx/generic/dtrans/X11_selection.cxx (revision 024fb564ad8d4d8ae344f6355df7cd6e03f59e9a)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include "unx/saldisp.hxx"
28 #include "unx/saldata.hxx"
29 
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/time.h>
34 
35 #include "tools/prex.h"
36 #include <X11/Xatom.h>
37 #include <X11/keysym.h>
38 #include <X11/Xutil.h>
39 #include "tools/postx.h"
40 #if defined(LINUX) || defined(NETBSD) || defined (FREEBSD)
41 #include <sys/poll.h>
42 #else
43 #include <poll.h>
44 #endif
45 #include <sal/alloca.h>
46 
47 #include <X11_selection.hxx>
48 #include <X11_clipboard.hxx>
49 #include <X11_transferable.hxx>
50 #include <X11_dndcontext.hxx>
51 #include <bmp.hxx>
52 
53 #include "vcl/svapp.hxx"
54 
55 // pointer bitmaps
56 #include <copydata_curs.h>
57 #include <copydata_mask.h>
58 #include <movedata_curs.h>
59 #include <movedata_mask.h>
60 #include <linkdata_curs.h>
61 #include <linkdata_mask.h>
62 #include <nodrop_curs.h>
63 #include <nodrop_mask.h>
64 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
65 #include <com/sun/star/awt/MouseEvent.hpp>
66 #include <com/sun/star/awt/MouseButton.hpp>
67 #include <rtl/tencinfo.h>
68 #include <osl/process.h>
69 
70 #include <comphelper/processfactory.hxx>
71 #include <vos/mutex.hxx>
72 
73 #define DRAG_EVENT_MASK ButtonPressMask         |\
74                             ButtonReleaseMask       |\
75                             PointerMotionMask       |\
76                             EnterWindowMask         |\
77                             LeaveWindowMask
78 
79 namespace {
80 
81 namespace css = com::sun::star;
82 
83 }
84 
85 using namespace com::sun::star::datatransfer;
86 using namespace com::sun::star::datatransfer::dnd;
87 using namespace com::sun::star::lang;
88 using namespace com::sun::star::awt;
89 using namespace com::sun::star::uno;
90 using namespace com::sun::star::frame;
91 using namespace cppu;
92 using namespace osl;
93 using namespace rtl;
94 
95 using namespace x11;
96 
97 // stubs to satisfy solaris compiler's rather rigid linking warning
98 extern "C"
99 {
call_SelectionManager_run(void * pMgr)100     static void call_SelectionManager_run( void * pMgr )
101     {
102         SelectionManager::run( pMgr );
103     }
104 
call_SelectionManager_runDragExecute(void * pMgr)105     static void call_SelectionManager_runDragExecute( void * pMgr )
106     {
107         SelectionManager::runDragExecute( pMgr );
108     }
109 }
110 
111 
112 static const long nXdndProtocolRevision = 5;
113 
114 // mapping between mime types (or what the office thinks of mime types)
115 // and X convention types
116 struct NativeTypeEntry
117 {
118     Atom            nAtom;
119     const char*     pType;              // Mime encoding on our side
120     const char*     pNativeType;        // string corresponding to nAtom for the case of nAtom being uninitialized
121     int             nFormat;            // the corresponding format
122 };
123 
124 // the convention for Xdnd is mime types as specified by the corresponding
125 // RFC's with the addition that text/plain without charset tag contains iso8859-1
126 // sadly some applications (e.g. gtk) do not honor the mimetype only rule,
127 // so for compatibility add UTF8_STRING
128 static NativeTypeEntry aXdndConversionTab[] =
129 {
130     { 0, "text/plain;charset=iso8859-1", "text/plain", 8 },
131     { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 }
132 };
133 
134 // for clipboard and primary selections there is only a convention for text
135 // that the encoding name of the text is taken as type in all capitalized letters
136 static NativeTypeEntry aNativeConversionTab[] =
137 {
138     { 0, "text/plain;charset=utf-16", "ISO10646-1", 16 },
139     { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 },
140     { 0, "text/plain;charset=utf-8", "UTF-8", 8 },
141     { 0, "text/plain;charset=utf-8", "text/plain;charset=UTF-8", 8 },
142     // ISO encodings
143     { 0, "text/plain;charset=iso8859-2", "ISO8859-2", 8 },
144     { 0, "text/plain;charset=iso8859-3", "ISO8859-3", 8 },
145     { 0, "text/plain;charset=iso8859-4", "ISO8859-4", 8 },
146     { 0, "text/plain;charset=iso8859-5", "ISO8859-5", 8 },
147     { 0, "text/plain;charset=iso8859-6", "ISO8859-6", 8 },
148     { 0, "text/plain;charset=iso8859-7", "ISO8859-7", 8 },
149     { 0, "text/plain;charset=iso8859-8", "ISO8859-8", 8 },
150     { 0, "text/plain;charset=iso8859-9", "ISO8859-9", 8 },
151     { 0, "text/plain;charset=iso8859-10", "ISO8859-10", 8 },
152     { 0, "text/plain;charset=iso8859-13", "ISO8859-13", 8 },
153     { 0, "text/plain;charset=iso8859-14", "ISO8859-14", 8 },
154     { 0, "text/plain;charset=iso8859-15", "ISO8859-15", 8 },
155     // asian encodings
156     { 0, "text/plain;charset=jisx0201.1976-0", "JISX0201.1976-0", 8 },
157     { 0, "text/plain;charset=jisx0208.1983-0", "JISX0208.1983-0", 8 },
158     { 0, "text/plain;charset=jisx0208.1990-0", "JISX0208.1990-0", 8 },
159     { 0, "text/plain;charset=jisx0212.1990-0", "JISX0212.1990-0", 8 },
160     { 0, "text/plain;charset=gb2312.1980-0", "GB2312.1980-0", 8 },
161     { 0, "text/plain;charset=ksc5601.1992-0", "KSC5601.1992-0", 8 },
162     // eastern european encodings
163     { 0, "text/plain;charset=koi8-r", "KOI8-R", 8 },
164     { 0, "text/plain;charset=koi8-u", "KOI8-U", 8 },
165     // String (== iso8859-1)
166     { XA_STRING, "text/plain;charset=iso8859-1", "STRING", 8 },
167     // special for compound text
168     { 0, "text/plain;charset=compound_text", "COMPOUND_TEXT", 8 },
169 
170     // PIXMAP
171     { XA_PIXMAP, "image/bmp", "PIXMAP", 32 }
172 };
173 
getTextPlainEncoding(const OUString & rMimeType)174 rtl_TextEncoding x11::getTextPlainEncoding( const OUString& rMimeType )
175 {
176     rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
177     OUString aMimeType( rMimeType.toAsciiLowerCase() );
178     sal_Int32 nIndex = 0;
179     if( aMimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain" , 10 ) )
180     {
181         if( aMimeType.getLength() == 10 ) // only "text/plain"
182             aEncoding = RTL_TEXTENCODING_ISO_8859_1;
183         else
184         {
185             while( nIndex != -1 )
186             {
187                 OUString aToken = aMimeType.getToken( 0, ';', nIndex );
188                 sal_Int32 nPos = 0;
189                 if( aToken.getToken( 0, '=', nPos ).equalsAsciiL( "charset", 7 ) )
190                 {
191                     OString aEncToken = OUStringToOString( aToken.getToken( 0, '=', nPos ), RTL_TEXTENCODING_ISO_8859_1 );
192                     aEncoding = rtl_getTextEncodingFromUnixCharset( aEncToken.getStr() );
193                     if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
194                     {
195                         if( aEncToken.equalsIgnoreAsciiCase( "utf-8" ) )
196                             aEncoding = RTL_TEXTENCODING_UTF8;
197                     }
198                     if( aEncoding != RTL_TEXTENCODING_DONTKNOW )
199                         break;
200                 }
201             }
202         }
203     }
204 #if OSL_DEBUG_LEVEL > 1
205     if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
206         fprintf( stderr, "getTextPlainEncoding( %s ) failed\n", OUStringToOString( rMimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
207 #endif
208     return aEncoding;
209 }
210 
211 // ------------------------------------------------------------------------
212 
getInstances()213 ::std::hash_map< OUString, SelectionManager*, OUStringHash >& SelectionManager::getInstances()
214 {
215     static ::std::hash_map< OUString, SelectionManager*, OUStringHash > aInstances;
216     return aInstances;
217 }
218 
219 // ------------------------------------------------------------------------
220 
SelectionManager()221 SelectionManager::SelectionManager() :
222         m_nIncrementalThreshold( 15*1024 ),
223         m_pDisplay( NULL ),
224         m_aThread( NULL ),
225         m_aDragExecuteThread( NULL ),
226         m_aWindow( None ),
227         m_nSelectionTimeout( 0 ),
228         m_nSelectionTimestamp( CurrentTime ),
229         m_bDropEnterSent( true ),
230         m_aCurrentDropWindow( None ),
231         m_nDropTime( None ),
232         m_nLastDropAction( 0 ),
233         m_nLastX( 0 ),
234         m_nLastY( 0 ),
235         m_nDropTimestamp( 0 ),
236         m_bDropWaitingForCompletion( false ),
237         m_aDropWindow( None ),
238         m_aDropProxy( None ),
239         m_aDragSourceWindow( None ),
240         m_nLastDragX( 0 ),
241         m_nLastDragY( 0 ),
242         m_nNoPosX( 0 ),
243         m_nNoPosY( 0 ),
244         m_nNoPosWidth( 0 ),
245         m_nNoPosHeight( 0 ),
246         m_nDragButton( 0 ),
247         m_nUserDragAction( 0 ),
248         m_nTargetAcceptAction( 0 ),
249         m_nSourceActions( 0 ),
250         m_bLastDropAccepted( false ),
251         m_bDropSuccess( false ),
252         m_bDropSent( false ),
253         m_bWaitingForPrimaryConversion( false ),
254         m_nDragTimestamp( None ),
255         m_aMoveCursor( None ),
256         m_aCopyCursor( None ),
257         m_aLinkCursor( None ),
258         m_aNoneCursor( None ),
259         m_aCurrentCursor( None ),
260         m_nCurrentProtocolVersion( nXdndProtocolRevision ),
261         m_nCLIPBOARDAtom( None ),
262         m_nTARGETSAtom( None ),
263         m_nTIMESTAMPAtom( None ),
264         m_nTEXTAtom( None ),
265         m_nINCRAtom( None ),
266         m_nCOMPOUNDAtom( None ),
267         m_nMULTIPLEAtom( None ),
268         m_nUTF16Atom( None ),
269         m_nImageBmpAtom( None ),
270         m_nXdndAware( None ),
271         m_nXdndEnter( None ),
272         m_nXdndLeave( None ),
273         m_nXdndPosition( None ),
274         m_nXdndStatus( None ),
275         m_nXdndDrop( None ),
276         m_nXdndFinished( None ),
277         m_nXdndSelection( None ),
278         m_nXdndTypeList( None ),
279         m_nXdndProxy( None ),
280         m_nXdndActionCopy( None ),
281         m_nXdndActionMove( None ),
282         m_nXdndActionLink( None ),
283         m_nXdndActionAsk( None ),
284         m_nXdndActionPrivate( None ),
285         m_bShutDown( false )
286 {
287     m_aDropEnterEvent.data.l[0] = None;
288     m_aDragRunning.reset();
289 }
290 
createCursor(const char * pPointerData,const char * pMaskData,int width,int height,int hotX,int hotY)291 XLIB_Cursor SelectionManager::createCursor( const char* pPointerData, const char* pMaskData, int width, int height, int hotX, int hotY )
292 {
293     Pixmap aPointer;
294     Pixmap aMask;
295     XColor aBlack, aWhite;
296 
297     aBlack.pixel = BlackPixel( m_pDisplay, 0 );
298     aBlack.red = aBlack.green = aBlack.blue = 0;
299     aBlack.flags = DoRed | DoGreen | DoBlue;
300 
301     aWhite.pixel = WhitePixel( m_pDisplay, 0 );
302     aWhite.red = aWhite.green = aWhite.blue = 0xffff;
303     aWhite.flags = DoRed | DoGreen | DoBlue;
304 
305     aPointer =
306         XCreateBitmapFromData( m_pDisplay,
307                                m_aWindow,
308                                pPointerData,
309                                width,
310                                height );
311     aMask
312         = XCreateBitmapFromData( m_pDisplay,
313                                  m_aWindow,
314                                  pMaskData,
315                                  width,
316                                  height );
317     XLIB_Cursor aCursor =
318         XCreatePixmapCursor( m_pDisplay, aPointer, aMask,
319                              &aBlack, &aWhite,
320                              hotX,
321                              hotY );
322     XFreePixmap( m_pDisplay, aPointer );
323     XFreePixmap( m_pDisplay, aMask );
324 
325     return aCursor;
326 }
327 
initialize(const Sequence<Any> & arguments)328 void SelectionManager::initialize( const Sequence< Any >& arguments ) throw (::com::sun::star::uno::Exception)
329 {
330     MutexGuard aGuard(m_aMutex);
331 
332     if( ! m_xDisplayConnection.is() )
333     {
334         /*
335          *  first argument must be a ::com::sun::star::awt::XDisplayConnection
336          *  from this we will get the XEvents of the vcl event loop by
337          *  registering us as XEventHandler on it.
338          *
339          *  implementor's note:
340          *  FIXME:
341          *  finally the clipboard and XDND service is back in the module it belongs
342          *  now cleanup and sharing of resources with the normal vcl event loop
343          *  needs to be added. The display used whould be that of the normal event loop
344          *  and synchronization should be done via the SolarMutex.
345          */
346         if( arguments.getLength() > 0 )
347             arguments.getConstArray()[0] >>= m_xDisplayConnection;
348         if( ! m_xDisplayConnection.is() )
349         {
350 #if 0
351             // for the time being try to live without XDisplayConnection
352             // for the sake of clipboard service
353             // clipboard service should be initialized with a XDisplayConnection
354             // in the future
355             Exception aExc;
356             aExc.Message = OUString::createFromAscii( "initialize me with a valid XDisplayConnection" );
357             aExc.Context = static_cast< OWeakObject* >(this);
358             throw aExc;
359 #endif
360         }
361         else
362             m_xDisplayConnection->addEventHandler( Any(), this, ~0 );
363     }
364 
365     if( !m_xBitmapConverter.is() )
366     {
367         if( arguments.getLength() > 2 )
368             arguments.getConstArray()[2] >>= m_xBitmapConverter;
369     }
370 
371     OUString aParam;
372     if( ! m_pDisplay )
373     {
374         OUString aUDisplay;
375         if( m_xDisplayConnection.is() )
376         {
377             Any aIdentifier;
378             aIdentifier = m_xDisplayConnection->getIdentifier();
379             aIdentifier >>= aUDisplay;
380         }
381 
382         OString aDisplayName( OUStringToOString( aUDisplay, RTL_TEXTENCODING_ISO_8859_1 ) );
383 
384         m_pDisplay = XOpenDisplay( aDisplayName.getLength() ? aDisplayName.getStr() : NULL );
385 
386         if( m_pDisplay )
387         {
388 #ifdef SYNCHRONIZE
389             XSynchronize( m_pDisplay, True );
390 #endif
391             // clipboard selection
392             m_nCLIPBOARDAtom    = getAtom( OUString::createFromAscii( "CLIPBOARD" ) );
393 
394             // special targets
395             m_nTARGETSAtom      = getAtom( OUString::createFromAscii( "TARGETS" ) );
396             m_nTIMESTAMPAtom    = getAtom( OUString::createFromAscii( "TIMESTAMP" ) );
397             m_nTEXTAtom         = getAtom( OUString::createFromAscii( "TEXT" ) );
398             m_nINCRAtom         = getAtom( OUString::createFromAscii( "INCR" ) );
399             m_nCOMPOUNDAtom     = getAtom( OUString::createFromAscii( "COMPOUND_TEXT" ) );
400             m_nMULTIPLEAtom     = getAtom( OUString::createFromAscii( "MULTIPLE" ) );
401             m_nUTF16Atom        = getAtom( OUString::createFromAscii( "ISO10646-1" ) );
402 //            m_nUTF16Atom      = getAtom( OUString::createFromAscii( "text/plain;charset=ISO-10646-UCS-2" ) );
403             m_nImageBmpAtom     = getAtom( OUString::createFromAscii( "image/bmp" ) );
404 
405             // Atoms for Xdnd protocol
406             m_nXdndAware        = getAtom( OUString::createFromAscii( "XdndAware" ) );
407             m_nXdndEnter        = getAtom( OUString::createFromAscii( "XdndEnter" ) );
408             m_nXdndLeave        = getAtom( OUString::createFromAscii( "XdndLeave" ) );
409             m_nXdndPosition     = getAtom( OUString::createFromAscii( "XdndPosition" ) );
410             m_nXdndStatus       = getAtom( OUString::createFromAscii( "XdndStatus" ) );
411             m_nXdndDrop         = getAtom( OUString::createFromAscii( "XdndDrop" ) );
412             m_nXdndFinished     = getAtom( OUString::createFromAscii( "XdndFinished" ) );
413             m_nXdndSelection    = getAtom( OUString::createFromAscii( "XdndSelection" ) );
414             m_nXdndTypeList     = getAtom( OUString::createFromAscii( "XdndTypeList" ) );
415             m_nXdndProxy        = getAtom( OUString::createFromAscii( "XdndProxy" ) );
416             m_nXdndActionCopy   = getAtom( OUString::createFromAscii( "XdndActionCopy" ) );
417             m_nXdndActionMove   = getAtom( OUString::createFromAscii( "XdndActionMove" ) );
418             m_nXdndActionLink   = getAtom( OUString::createFromAscii( "XdndActionLink" ) );
419             m_nXdndActionAsk    = getAtom( OUString::createFromAscii( "XdndActionAsk" ) );
420             m_nXdndActionPrivate= getAtom( OUString::createFromAscii( "XdndActionPrivate" ) );
421 
422             // initialize map with member none
423             m_aAtomToString[ 0 ]= OUString::createFromAscii( "None" );
424             m_aAtomToString[ XA_PRIMARY ] = OUString::createFromAscii( "PRIMARY" );
425 
426             // create a (invisible) message window
427             m_aWindow = XCreateSimpleWindow( m_pDisplay, DefaultRootWindow( m_pDisplay ),
428                                              10, 10, 10, 10, 0, 0, 1 );
429 
430             // initialize threshold for incremetal transfers
431             // ICCCM says it should be smaller that the max request size
432             // which in turn is guaranteed to be at least 16k bytes
433             m_nIncrementalThreshold = XMaxRequestSize( m_pDisplay ) - 1024;
434 
435             if( m_aWindow )
436             {
437 #define createCursorFromXPM(name) createCursor((const char*)name##curs##_bits, (const char*)name##mask##_bits, name##curs_width, name##curs_height, name##curs_x_hot, name##curs_y_hot );
438                 // initialize default cursors
439                 m_aMoveCursor = createCursorFromXPM( movedata_);
440                 m_aCopyCursor = createCursorFromXPM( copydata_);
441                 m_aLinkCursor = createCursorFromXPM( linkdata_);
442                 m_aNoneCursor = createCursorFromXPM( nodrop_);
443 
444                 // just interested in SelectionClear/Notify/Request and PropertyChange
445                 XSelectInput( m_pDisplay, m_aWindow, PropertyChangeMask );
446                 // create the transferable for Drag operations
447                 m_xDropTransferable = new X11Transferable( *this, static_cast< OWeakObject* >(this), m_nXdndSelection );
448                 registerHandler( m_nXdndSelection, *this );
449 
450                 m_aThread = osl_createSuspendedThread( call_SelectionManager_run, this );
451                 if( m_aThread )
452                     osl_resumeThread( m_aThread );
453 #if OSL_DEBUG_LEVEL > 1
454                 else
455                     fprintf( stderr, "SelectionManager::initialize: creation of dispatch thread failed !\n" );
456 #endif
457             }
458         }
459     }
460 }
461 
462 // ------------------------------------------------------------------------
463 
~SelectionManager()464 SelectionManager::~SelectionManager()
465 {
466 #if OSL_DEBUG_LEVEL > 1
467     fprintf( stderr, "SelectionManager::~SelectionManager (%s)\n", m_pDisplay ? DisplayString(m_pDisplay) : "no display" );
468 #endif
469     {
470         MutexGuard aGuard( *Mutex::getGlobalMutex() );
471 
472         ::std::hash_map< OUString, SelectionManager*, OUStringHash >::iterator it;
473         for( it = getInstances().begin(); it != getInstances().end(); ++it )
474             if( it->second == this )
475             {
476                 getInstances().erase( it );
477                 break;
478             }
479     }
480 
481     if( m_aThread )
482     {
483         osl_terminateThread( m_aThread );
484         osl_joinWithThread( m_aThread );
485         osl_destroyThread( m_aThread );
486     }
487 
488     if( m_aDragExecuteThread )
489     {
490         osl_terminateThread( m_aDragExecuteThread );
491         osl_joinWithThread( m_aDragExecuteThread );
492         m_aDragExecuteThread = NULL;
493         // thread handle is freed in dragDoDispatch()
494     }
495 
496     MutexGuard aGuard(m_aMutex);
497 
498 #if OSL_DEBUG_LEVEL > 1
499     fprintf( stderr, "shutting down SelectionManager\n" );
500 #endif
501 
502     if( m_xDisplayConnection.is() )
503     {
504         m_xDisplayConnection->removeEventHandler( Any(), this );
505         m_xDisplayConnection.clear();
506     }
507 
508     if( m_pDisplay )
509     {
510         deregisterHandler( m_nXdndSelection );
511         // destroy message window
512         if( m_aWindow )
513             XDestroyWindow( m_pDisplay, m_aWindow );
514         // release cursors
515         if (m_aMoveCursor != None)
516             XFreeCursor(m_pDisplay, m_aMoveCursor);
517         if (m_aCopyCursor != None)
518             XFreeCursor(m_pDisplay, m_aCopyCursor);
519         if (m_aLinkCursor != None)
520             XFreeCursor(m_pDisplay, m_aLinkCursor);
521         if (m_aNoneCursor != None)
522             XFreeCursor(m_pDisplay, m_aNoneCursor);
523 
524         // paranoia setting, the drag thread should have
525         // done that already
526         XUngrabPointer( m_pDisplay, CurrentTime );
527         XUngrabKeyboard( m_pDisplay, CurrentTime );
528 
529         XCloseDisplay( m_pDisplay );
530     }
531 }
532 
533 // ------------------------------------------------------------------------
534 
getAdaptor(Atom selection)535 SelectionAdaptor* SelectionManager::getAdaptor( Atom selection )
536 {
537     ::std::hash_map< Atom, Selection* >::iterator it =
538           m_aSelections.find( selection );
539     return it != m_aSelections.end() ? it->second->m_pAdaptor : NULL;
540 }
541 
542 // ------------------------------------------------------------------------
543 
convertFromCompound(const char * pText,int nLen)544 OUString SelectionManager::convertFromCompound( const char* pText, int nLen )
545 {
546     MutexGuard aGuard( m_aMutex );
547     OUString aRet;
548     if( nLen < 0 )
549         nLen = strlen( pText );
550 
551     char** pTextList = NULL;
552     int nTexts = 0;
553 
554     XTextProperty aProp;
555     aProp.value     = (unsigned char*)pText;
556     aProp.encoding  = m_nCOMPOUNDAtom;
557     aProp.format    = 8;
558     aProp.nitems    = nLen;
559     XmbTextPropertyToTextList( m_pDisplay,
560                                &aProp,
561                                &pTextList,
562                                &nTexts );
563     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
564     for( int i = 0; i < nTexts; i++ )
565         aRet += OStringToOUString( pTextList[i], aEncoding );
566 
567     if( pTextList )
568         XFreeStringList( pTextList );
569 
570     return aRet;
571 }
572 
573 // ------------------------------------------------------------------------
574 
convertToCompound(const OUString & rText)575 OString SelectionManager::convertToCompound( const OUString& rText )
576 {
577     MutexGuard aGuard( m_aMutex );
578     XTextProperty aProp;
579     aProp.value = NULL;
580     aProp.encoding = XA_STRING;
581     aProp.format = 8;
582     aProp.nitems = 0;
583 
584     OString aRet( rText.getStr(), rText.getLength(), osl_getThreadTextEncoding() );
585     char* pT = const_cast<char*>(aRet.getStr());
586 
587     XmbTextListToTextProperty( m_pDisplay,
588                                &pT,
589                                1,
590                                XCompoundTextStyle,
591                                &aProp );
592     if( aProp.value )
593     {
594         aRet = (char*)aProp.value;
595         XFree( aProp.value );
596 #ifdef SOLARIS
597         /*  #97070#
598          *  for currently unknown reasons XmbTextListToTextProperty on Solaris returns
599          *  no data in ISO8859-n encodings (at least for n = 1, 15)
600          *  in these encodings the directly converted text does the
601          *  trick, also.
602          */
603         if( ! aRet.getLength() && rText.getLength() )
604             aRet = OUStringToOString( rText, osl_getThreadTextEncoding() );
605 #endif
606     }
607     else
608         aRet = OString();
609 
610     return aRet;
611 }
612 
613 // ------------------------------------------------------------------------
614 
convertData(const css::uno::Reference<XTransferable> & xTransferable,Atom nType,Atom nSelection,int & rFormat,Sequence<sal_Int8> & rData)615 bool SelectionManager::convertData(
616                                    const css::uno::Reference< XTransferable >& xTransferable,
617                                    Atom nType,
618                                    Atom nSelection,
619                                    int& rFormat,
620                                    Sequence< sal_Int8 >& rData )
621 {
622     bool bSuccess = false;
623 
624     if( ! xTransferable.is() )
625         return bSuccess;
626 
627     try
628     {
629 
630         DataFlavor aFlavor;
631         aFlavor.MimeType = convertTypeFromNative( nType, nSelection, rFormat );
632 
633         sal_Int32 nIndex = 0;
634         if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "text/plain" ) == 0 )
635         {
636             if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "charset=utf-16" ) == 0 )
637                 aFlavor.DataType = getCppuType( (OUString *) 0 );
638             else
639                 aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
640         }
641         else
642             aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
643 
644         if( xTransferable->isDataFlavorSupported( aFlavor ) )
645         {
646             Any aValue( xTransferable->getTransferData( aFlavor ) );
647             if( aValue.getValueTypeClass() == TypeClass_STRING )
648             {
649                 OUString aString;
650                 aValue >>= aString;
651                 rData = Sequence< sal_Int8 >( (sal_Int8*)aString.getStr(), aString.getLength() * sizeof( sal_Unicode ) );
652                 bSuccess = true;
653             }
654             else if( aValue.getValueType() == getCppuType( (Sequence< sal_Int8 >*)0 ) )
655             {
656                 aValue >>= rData;
657                 bSuccess = true;
658             }
659         }
660         else if( aFlavor.MimeType.compareToAscii( "text/plain", 10 ) == 0 )
661         {
662             rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
663             bool bCompoundText = false;
664             if( nType == m_nCOMPOUNDAtom )
665                 bCompoundText = true;
666             else
667                 aEncoding = getTextPlainEncoding( aFlavor.MimeType );
668             if( aEncoding != RTL_TEXTENCODING_DONTKNOW || bCompoundText )
669             {
670                 aFlavor.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
671                 aFlavor.DataType = getCppuType( (OUString *) 0 );
672                 if( xTransferable->isDataFlavorSupported( aFlavor ) )
673                 {
674                     Any aValue( xTransferable->getTransferData( aFlavor ) );
675                     OUString aString;
676                     aValue >>= aString;
677                     OString aByteString( bCompoundText ? convertToCompound( aString ) : OUStringToOString( aString, aEncoding ) );
678                     rData = Sequence< sal_Int8 >( (sal_Int8*)aByteString.getStr(), aByteString.getLength() * sizeof( sal_Char ) );
679                     bSuccess = true;
680                 }
681             }
682         }
683     }
684     // various exceptions possible ... which all lead to a failed conversion
685     // so simplify here to a catch all
686     catch(...)
687     {
688     }
689 
690     return bSuccess;
691 }
692 
693 // ------------------------------------------------------------------------
694 
get(const OUString & rDisplayName)695 SelectionManager& SelectionManager::get( const OUString& rDisplayName )
696 {
697     MutexGuard aGuard( *Mutex::getGlobalMutex() );
698 
699     OUString aDisplayName( rDisplayName );
700     if( ! aDisplayName.getLength() )
701         aDisplayName = OStringToOUString( getenv( "DISPLAY" ), RTL_TEXTENCODING_ISO_8859_1 );
702     SelectionManager* pInstance = NULL;
703 
704     ::std::hash_map< OUString, SelectionManager*, OUStringHash >::iterator it = getInstances().find( aDisplayName );
705     if( it != getInstances().end() )
706         pInstance = it->second;
707     else pInstance = getInstances()[ aDisplayName ] = new SelectionManager();
708 
709     return *pInstance;
710 }
711 
712 // ------------------------------------------------------------------------
713 
getString(Atom aAtom)714 const OUString& SelectionManager::getString( Atom aAtom )
715 {
716     MutexGuard aGuard(m_aMutex);
717 
718     ::std::hash_map< Atom, OUString >::const_iterator it;
719     if( ( it = m_aAtomToString.find( aAtom ) ) == m_aAtomToString.end() )
720     {
721         static OUString aEmpty;
722         char* pAtom = m_pDisplay ? XGetAtomName( m_pDisplay, aAtom ) : NULL;
723         if( ! pAtom )
724             return aEmpty;
725         OUString aString( OStringToOUString( pAtom, RTL_TEXTENCODING_ISO_8859_1 ) );
726         XFree( pAtom );
727         m_aStringToAtom[ aString ] = aAtom;
728         m_aAtomToString[ aAtom ] = aString;
729     }
730     return m_aAtomToString[ aAtom ];
731 }
732 
733 // ------------------------------------------------------------------------
734 
getAtom(const OUString & rString)735 Atom SelectionManager::getAtom( const OUString& rString )
736 {
737     MutexGuard aGuard(m_aMutex);
738 
739     ::std::hash_map< OUString, Atom, OUStringHash >::const_iterator it;
740     if( ( it = m_aStringToAtom.find( rString ) ) == m_aStringToAtom.end() )
741     {
742         static Atom nNoDisplayAtoms = 1;
743         Atom aAtom = m_pDisplay ? XInternAtom( m_pDisplay, OUStringToOString( rString, RTL_TEXTENCODING_ISO_8859_1).getStr(), False ) : nNoDisplayAtoms++;
744         m_aStringToAtom[ rString ] = aAtom;
745         m_aAtomToString[ aAtom ] = rString;
746     }
747     return m_aStringToAtom[ rString ];
748 }
749 
750 // ------------------------------------------------------------------------
751 
requestOwnership(Atom selection)752 bool SelectionManager::requestOwnership( Atom selection )
753 {
754     bool bSuccess = false;
755     if( m_pDisplay && m_aWindow )
756     {
757         MutexGuard aGuard(m_aMutex);
758 
759         SelectionAdaptor* pAdaptor = getAdaptor( selection );
760         if( pAdaptor )
761         {
762             XSetSelectionOwner( m_pDisplay, selection, m_aWindow, CurrentTime );
763             if( XGetSelectionOwner( m_pDisplay, selection ) == m_aWindow )
764                 bSuccess = true;
765 #if OSL_DEBUG_LEVEL > 1
766             fprintf( stderr, "%s ownership for selection %s\n",
767                      bSuccess ? "acquired" : "failed to acquire",
768                      OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
769 #endif
770             Selection* pSel = m_aSelections[ selection ];
771             pSel->m_bOwner = bSuccess;
772             delete pSel->m_pPixmap;
773             pSel->m_pPixmap = NULL;
774             pSel->m_nOrigTimestamp = m_nSelectionTimestamp;
775         }
776 #if OSL_DEBUG_LEVEL > 1
777         else
778             fprintf( stderr, "no adaptor for selection %s\n",
779                      OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
780 
781         if( pAdaptor->getTransferable().is() )
782         {
783             Sequence< DataFlavor > aTypes = pAdaptor->getTransferable()->getTransferDataFlavors();
784             for( int i = 0; i < aTypes.getLength(); i++ )
785             {
786                 fprintf( stderr, "   %s\n", OUStringToOString( aTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
787             }
788         }
789 #endif
790     }
791     return bSuccess;
792 }
793 
794 // ------------------------------------------------------------------------
795 
convertTypeToNative(const OUString & rType,Atom selection,int & rFormat,::std::list<Atom> & rConversions,bool bPushFront)796 void SelectionManager::convertTypeToNative( const OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront )
797 {
798     NativeTypeEntry* pTab = selection == m_nXdndSelection ? aXdndConversionTab : aNativeConversionTab;
799     int nTabEntries = selection == m_nXdndSelection
800         ? sizeof(aXdndConversionTab)/sizeof(aXdndConversionTab[0]) :
801         sizeof(aNativeConversionTab)/sizeof(aNativeConversionTab[0]);
802 
803     OString aType( OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ) );
804     rFormat = 0;
805     for( int i = 0; i < nTabEntries; i++ )
806     {
807         if( aType.equalsIgnoreAsciiCase( pTab[i].pType ) )
808         {
809             if( ! pTab[i].nAtom )
810                 pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
811             rFormat = pTab[i].nFormat;
812             if( bPushFront )
813                 rConversions.push_front( pTab[i].nAtom );
814             else
815                 rConversions.push_back( pTab[i].nAtom );
816             if( pTab[i].nFormat == XA_PIXMAP )
817             {
818                 if( bPushFront )
819                 {
820                     rConversions.push_front( XA_VISUALID );
821                     rConversions.push_front( XA_COLORMAP );
822                 }
823                 else
824                 {
825                     rConversions.push_back( XA_VISUALID );
826                     rConversions.push_back( XA_COLORMAP );
827                 }
828             }
829         }
830     }
831     if( ! rFormat )
832         rFormat = 8; // byte buffer
833     if( bPushFront )
834         rConversions.push_front( getAtom( rType ) );
835     else
836         rConversions.push_back( getAtom( rType ) );
837 };
838 
839 // ------------------------------------------------------------------------
840 
getNativeTypeList(const Sequence<DataFlavor> & rTypes,std::list<Atom> & rOutTypeList,Atom targetselection)841 void SelectionManager::getNativeTypeList( const Sequence< DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection )
842 {
843     rOutTypeList.clear();
844 
845     int nFormat;
846     int nFlavors = rTypes.getLength();
847     const DataFlavor* pFlavors = rTypes.getConstArray();
848     bool bHaveText = false;
849     for( int i = 0; i < nFlavors; i++ )
850     {
851         if( pFlavors[i].MimeType.compareToAscii( "text/plain", 10 ) == 0)
852             bHaveText = true;
853         else
854             convertTypeToNative( pFlavors[i].MimeType, targetselection, nFormat, rOutTypeList );
855     }
856     if( bHaveText )
857     {
858         if( targetselection != m_nXdndSelection )
859         {
860             // only mimetypes should go into Xdnd type list
861             rOutTypeList.push_front( XA_STRING );
862             rOutTypeList.push_front( m_nCOMPOUNDAtom );
863         }
864         convertTypeToNative( OUString::createFromAscii( "text/plain;charset=utf-8" ), targetselection, nFormat, rOutTypeList, true );
865     }
866     if( targetselection != m_nXdndSelection )
867         rOutTypeList.push_back( m_nMULTIPLEAtom );
868 }
869 
870 // ------------------------------------------------------------------------
871 
convertTypeFromNative(Atom nType,Atom selection,int & rFormat)872 OUString SelectionManager::convertTypeFromNative( Atom nType, Atom selection, int& rFormat )
873 {
874     NativeTypeEntry* pTab = selection == m_nXdndSelection ? aXdndConversionTab : aNativeConversionTab;
875     int nTabEntries = selection == m_nXdndSelection
876         ? sizeof(aXdndConversionTab)/sizeof(aXdndConversionTab[0]) :
877         sizeof(aNativeConversionTab)/sizeof(aNativeConversionTab[0]);
878 
879     for( int i = 0; i < nTabEntries; i++ )
880     {
881         if( ! pTab[i].nAtom )
882             pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
883         if( nType == pTab[i].nAtom )
884         {
885             rFormat = pTab[i].nFormat;
886             return OStringToOUString( pTab[i].pType, RTL_TEXTENCODING_ISO_8859_1 );
887         }
888     }
889     rFormat = 8;
890     return getString( nType );
891 }
892 
893 // ------------------------------------------------------------------------
894 
getPasteData(Atom selection,Atom type,Sequence<sal_Int8> & rData)895 bool SelectionManager::getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData )
896 {
897     ResettableMutexGuard aGuard(m_aMutex);
898     ::std::hash_map< Atom, Selection* >::iterator it;
899     bool bSuccess = false;
900 
901 #if OSL_DEBUG_LEVEL > 1
902     OUString aSelection( getString( selection ) );
903     OUString aType( getString( type ) );
904     fprintf( stderr, "getPasteData( %s, native: %s )\n",
905              OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
906              OUStringToOString( aType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
907              );
908 #endif
909 
910     if( ! m_pDisplay )
911         return false;
912 
913     it = m_aSelections.find( selection );
914     if( it == m_aSelections.end() )
915         return false;
916 
917     XLIB_Window aSelectionOwner = XGetSelectionOwner( m_pDisplay, selection );
918     if( aSelectionOwner == None )
919         return false;
920     if( aSelectionOwner == m_aWindow )
921     {
922         // probably bad timing led us here
923 #if OSL_DEBUG_LEVEL > 1
924         fprintf( stderr, "Innere Nabelschau\n" );
925 #endif
926         return false;
927     }
928 
929     // ICCCM recommends to destroy property before convert request unless
930     // parameters are transported; we do only in case of MULTIPLE,
931     // so destroy property unless target is MULTIPLE
932     if( type != m_nMULTIPLEAtom )
933         XDeleteProperty( m_pDisplay, m_aWindow, selection );
934 
935     XConvertSelection( m_pDisplay, selection, type, selection, m_aWindow, selection == m_nXdndSelection ? m_nDropTime : CurrentTime );
936     it->second->m_eState            = Selection::WaitingForResponse;
937     it->second->m_aRequestedType    = type;
938     it->second->m_aData             = Sequence< sal_Int8 >();
939     it->second->m_aDataArrived.reset();
940     // really start the request; if we don't flush the
941     // queue the request won't leave it because there are no more
942     // X calls after this until the data arrived or timeout
943     XFlush( m_pDisplay );
944 
945     // do a reschedule
946     struct timeval tv_last, tv_current;
947     gettimeofday( &tv_last, NULL );
948     tv_current = tv_last;
949 
950     XEvent aEvent;
951     do
952     {
953         bool bAdjustTime = false;
954         {
955             bool bHandle = false;
956 
957             if( XCheckTypedEvent( m_pDisplay,
958                                   PropertyNotify,
959                                   &aEvent
960                                   ) )
961             {
962                 bHandle = true;
963                 if( aEvent.xproperty.window == m_aWindow
964                     && aEvent.xproperty.atom == selection )
965                     bAdjustTime = true;
966             }
967             else
968             if( XCheckTypedEvent( m_pDisplay,
969                                   SelectionClear,
970                                   &aEvent
971                                   ) )
972             {
973                 bHandle = true;
974             }
975             else
976             if( XCheckTypedEvent( m_pDisplay,
977                                   SelectionRequest,
978                                   &aEvent
979                                   ) )
980                 bHandle = true;
981             else
982             if( XCheckTypedEvent( m_pDisplay,
983                                   SelectionNotify,
984                                   &aEvent
985                                   ) )
986             {
987                 bHandle = true;
988                 if( aEvent.xselection.selection == selection
989                     && ( aEvent.xselection.requestor == m_aWindow ||
990                          aEvent.xselection.requestor == m_aCurrentDropWindow )
991                     )
992                     bAdjustTime = true;
993             }
994             else
995             {
996                 TimeValue aTVal;
997                 aTVal.Seconds = 0;
998                 aTVal.Nanosec = 100000000;
999                 aGuard.clear();
1000                 osl_waitThread( &aTVal );
1001                 aGuard.reset();
1002             }
1003             if( bHandle )
1004             {
1005                 aGuard.clear();
1006                 handleXEvent( aEvent );
1007                 aGuard.reset();
1008             }
1009         }
1010         gettimeofday( &tv_current, NULL );
1011         if( bAdjustTime )
1012             tv_last = tv_current;
1013     } while( ! it->second->m_aDataArrived.check() && (tv_current.tv_sec - tv_last.tv_sec) < getSelectionTimeout() );
1014 
1015 #if OSL_DEBUG_LEVEL > 1
1016     if( (tv_current.tv_sec - tv_last.tv_sec) > getSelectionTimeout() )
1017         fprintf( stderr, "timed out\n" );
1018 #endif
1019     if( it->second->m_aDataArrived.check() &&
1020         it->second->m_aData.getLength() )
1021     {
1022         rData = it->second->m_aData;
1023         bSuccess = true;
1024     }
1025 #if OSL_DEBUG_LEVEL > 1
1026     else
1027         fprintf( stderr, "conversion unsuccessfull\n" );
1028 #endif
1029     return bSuccess;
1030 }
1031 
1032 // ------------------------------------------------------------------------
1033 
getPasteData(Atom selection,const::rtl::OUString & rType,Sequence<sal_Int8> & rData)1034 bool SelectionManager::getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData )
1035 {
1036     int nFormat;
1037     bool bSuccess = false;
1038 
1039     ::std::hash_map< Atom, Selection* >::iterator it;
1040     {
1041         MutexGuard aGuard(m_aMutex);
1042 
1043         it = m_aSelections.find( selection );
1044         if( it == m_aSelections.end() )
1045             return false;
1046     }
1047 
1048     if( it->second->m_aTypes.getLength() == 0 )
1049     {
1050         Sequence< DataFlavor > aFlavors;
1051         getPasteDataTypes( selection, aFlavors );
1052         if( it->second->m_aTypes.getLength() == 0 )
1053             return false;
1054     }
1055 
1056     const Sequence< DataFlavor >& rTypes( it->second->m_aTypes );
1057     const std::vector< Atom >& rNativeTypes( it->second->m_aNativeTypes );
1058 #if OSL_DEBUG_LEVEL > 1
1059     fprintf( stderr, "getPasteData( \"%s\", \"%s\" )\n",
1060              OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1061              OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1062 #endif
1063 
1064     if( rType.equalsAsciiL( "text/plain;charset=utf-16", 25 ) )
1065     {
1066         // lets see if we have UTF16 else try to find something convertible
1067         if( it->second->m_aTypes.getLength() && ! it->second->m_bHaveUTF16 )
1068         {
1069             Sequence< sal_Int8 > aData;
1070             if( it->second->m_aUTF8Type != None &&
1071                 getPasteData( selection,
1072                               it->second->m_aUTF8Type,
1073                               aData )
1074                 )
1075             {
1076               OUString aRet( (const sal_Char*)aData.getConstArray(), aData.getLength(), RTL_TEXTENCODING_UTF8 );
1077               rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
1078               bSuccess = true;
1079             }
1080             else if( it->second->m_bHaveCompound &&
1081                 getPasteData( selection,
1082                               m_nCOMPOUNDAtom,
1083                               aData )
1084                 )
1085             {
1086                 OUString aRet( convertFromCompound( (const char*)aData.getConstArray(), aData.getLength() ) );
1087                 rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
1088                 bSuccess = true;
1089             }
1090             else
1091             {
1092                 for( int i = 0; i < rTypes.getLength(); i++ )
1093                 {
1094                     rtl_TextEncoding aEncoding = getTextPlainEncoding( rTypes.getConstArray()[i].MimeType );
1095                     if( aEncoding != RTL_TEXTENCODING_DONTKNOW  &&
1096                         aEncoding != RTL_TEXTENCODING_UNICODE   &&
1097                         getPasteData( selection,
1098                                       rNativeTypes[i],
1099                                       aData )
1100                         )
1101                     {
1102 #if OSL_DEBUG_LEVEL > 1
1103                         fprintf( stderr, "using \"%s\" instead of \"%s\"\n",
1104                                  OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1105                                  OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
1106                                  );
1107 #endif
1108                         OString aConvert( (sal_Char*)aData.getConstArray(), aData.getLength() );
1109                         OUString aUTF( OStringToOUString( aConvert, aEncoding ) );
1110                         rData = Sequence< sal_Int8 >( (sal_Int8*)aUTF.getStr(), (aUTF.getLength()+1)*sizeof( sal_Unicode ) );
1111                         bSuccess = true;
1112                         break;
1113                     }
1114                 }
1115             }
1116         }
1117     }
1118     else if( rType.equalsAsciiL( "image/bmp", 9 ) )
1119     {
1120         // #i83376# try if someone has the data in image/bmp already before
1121         // doing the PIXMAP stuff (e.g. the gimp has this)
1122         bSuccess = getPasteData( selection, m_nImageBmpAtom, rData );
1123         #if OSL_DEBUG_LEVEL > 1
1124         if( bSuccess )
1125             fprintf( stderr, "got %d bytes of image/bmp\n", (int)rData.getLength() );
1126         #endif
1127         if( ! bSuccess )
1128         {
1129             Pixmap aPixmap = None;
1130             Colormap aColormap = None;
1131 
1132             // prepare property for MULTIPLE request
1133             Sequence< sal_Int8 > aData;
1134             Atom pTypes[4] = { XA_PIXMAP, XA_PIXMAP,
1135             XA_COLORMAP, XA_COLORMAP };
1136             {
1137                 MutexGuard aGuard(m_aMutex);
1138 
1139                 XChangeProperty( m_pDisplay,
1140                     m_aWindow,
1141                     selection,
1142                     XA_ATOM,
1143                     32,
1144                     PropModeReplace,
1145                     (unsigned char*)pTypes,
1146                     4 );
1147             }
1148 
1149             // try MULTIPLE request
1150             if( getPasteData( selection, m_nMULTIPLEAtom, aData ) )
1151             {
1152                 Atom* pReturnedTypes = (Atom*)aData.getArray();
1153                 if( pReturnedTypes[0] == XA_PIXMAP && pReturnedTypes[1] == XA_PIXMAP )
1154                 {
1155                     MutexGuard aGuard(m_aMutex);
1156 
1157                     Atom type = None;
1158                     int format = 0;
1159                     unsigned long nItems = 0;
1160                     unsigned long nBytes = 0;
1161                     unsigned char* pReturn = NULL;
1162                     XGetWindowProperty( m_pDisplay, m_aWindow, XA_PIXMAP, 0, 1, True, XA_PIXMAP, &type, &format, &nItems, &nBytes, &pReturn );
1163                     if( pReturn )
1164                     {
1165                         if( type == XA_PIXMAP )
1166                             aPixmap = *(Pixmap*)pReturn;
1167                         XFree( pReturn );
1168                         pReturn = NULL;
1169                         if( pReturnedTypes[2] == XA_COLORMAP && pReturnedTypes[3] == XA_COLORMAP )
1170                         {
1171                             XGetWindowProperty( m_pDisplay, m_aWindow, XA_COLORMAP, 0, 1, True, XA_COLORMAP, &type, &format, &nItems, &nBytes, &pReturn );
1172                             if( pReturn )
1173                             {
1174                                 if( type == XA_COLORMAP )
1175                                     aColormap = *(Colormap*)pReturn;
1176                                 XFree( pReturn );
1177                             }
1178                         }
1179                     }
1180                     #if OSL_DEBUG_LEVEL > 1
1181                     else
1182                     {
1183                         fprintf( stderr, "could not get PIXMAP property: type=%s, format=%d, items=%ld, bytes=%ld, ret=0x%p\n", OUStringToOString( getString( type ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), format, nItems, nBytes, pReturn );
1184                     }
1185                     #endif
1186                 }
1187             }
1188 
1189             if( aPixmap == None )
1190             {
1191                 // perhaps two normal requests will work
1192                 if( getPasteData( selection, XA_PIXMAP, aData ) )
1193                 {
1194                     aPixmap = *(Pixmap*)aData.getArray();
1195                     if( aColormap == None && getPasteData( selection, XA_COLORMAP, aData ) )
1196                         aColormap = *(Colormap*)aData.getArray();
1197                 }
1198             }
1199 
1200             // convert data if possible
1201             if( aPixmap != None )
1202             {
1203                 MutexGuard aGuard(m_aMutex);
1204 
1205                 sal_Int32 nOutSize = 0;
1206                 sal_uInt8* pBytes = X11_getBmpFromPixmap( m_pDisplay, aPixmap, aColormap, nOutSize );
1207                 if( pBytes && nOutSize )
1208                 {
1209                     rData = Sequence< sal_Int8 >( nOutSize );
1210                     memcpy( rData.getArray(), pBytes, nOutSize );
1211                     X11_freeBmp( pBytes );
1212                     bSuccess = true;
1213                 }
1214             }
1215         }
1216     }
1217 
1218     if( ! bSuccess )
1219     {
1220         ::std::list< Atom > aTypes;
1221         convertTypeToNative( rType, selection, nFormat, aTypes );
1222         ::std::list< Atom >::const_iterator type_it;
1223         Atom nSelectedType = None;
1224         for( type_it = aTypes.begin(); type_it != aTypes.end() && nSelectedType == None; ++type_it )
1225         {
1226             for( unsigned int i = 0; i < rNativeTypes.size() && nSelectedType == None; i++ )
1227                 if( rNativeTypes[i] == *type_it )
1228                     nSelectedType = *type_it;
1229         }
1230         if( nSelectedType != None )
1231             bSuccess = getPasteData( selection, nSelectedType, rData );
1232     }
1233 #if OSL_DEBUG_LEVEL > 1
1234     fprintf( stderr, "getPasteData for selection %s and data type %s returns %s, returned sequence has length %ld\n",
1235              OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1236              OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1237              bSuccess ? "true" : "false",
1238              rData.getLength()
1239              );
1240 #endif
1241     return bSuccess;
1242 }
1243 
1244 // ------------------------------------------------------------------------
1245 
getPasteDataTypes(Atom selection,Sequence<DataFlavor> & rTypes)1246 bool SelectionManager::getPasteDataTypes( Atom selection, Sequence< DataFlavor >& rTypes )
1247 {
1248     ::std::hash_map< Atom, Selection* >::iterator it;
1249     {
1250         MutexGuard aGuard(m_aMutex);
1251 
1252         it = m_aSelections.find( selection );
1253         if( it != m_aSelections.end()                           &&
1254             it->second->m_aTypes.getLength()                    &&
1255             abs( it->second->m_nLastTimestamp - time( NULL ) ) < 2
1256             )
1257         {
1258             rTypes = it->second->m_aTypes;
1259             return true;
1260         }
1261     }
1262 
1263     bool bSuccess = false;
1264     bool bHaveUTF16 = false;
1265     Atom aUTF8Type = None;
1266     bool bHaveCompound = false;
1267     bool bHaveText = false;
1268     Sequence< sal_Int8 > aAtoms;
1269 
1270     if( selection == m_nXdndSelection )
1271     {
1272         // xdnd sends first three types with XdndEnter
1273         // if more than three types are supported then the XDndTypeList
1274         // property on the source window is used
1275         if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
1276         {
1277             if( m_aDropEnterEvent.data.l[1] & 1 )
1278             {
1279                 const unsigned int atomcount = 256;
1280                 // more than three types; look in property
1281                 MutexGuard aGuard(m_aMutex);
1282 
1283                 Atom nType;
1284                 int nFormat;
1285                 unsigned long nItems, nBytes;
1286                 unsigned char* pBytes = NULL;
1287 
1288                 XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
1289                                     m_nXdndTypeList, 0, atomcount, False,
1290                                     XA_ATOM,
1291                                     &nType, &nFormat, &nItems, &nBytes, &pBytes );
1292 #if OSL_DEBUG_LEVEL > 1
1293                 fprintf( stderr, "have %ld data types in XdndTypeList\n", nItems );
1294 #endif
1295                 if( nItems == atomcount && nBytes > 0 )
1296                 {
1297                     // wow ... more than 256 types !
1298                     aAtoms.realloc( sizeof( Atom )*atomcount+nBytes );
1299                     memcpy( aAtoms.getArray(), pBytes, sizeof( Atom )*atomcount );
1300                     XFree( pBytes );
1301                     pBytes = NULL;
1302                     XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
1303                                         m_nXdndTypeList, atomcount, nBytes/sizeof(Atom),
1304                                         False, XA_ATOM,
1305                                         &nType, &nFormat, &nItems, &nBytes, &pBytes );
1306                     {
1307                         memcpy( aAtoms.getArray()+atomcount*sizeof(Atom), pBytes, nItems*sizeof(Atom) );
1308                         XFree( pBytes );
1309                     }
1310                 }
1311                 else
1312                 {
1313                     aAtoms.realloc( sizeof(Atom)*nItems );
1314                     memcpy( aAtoms.getArray(), pBytes, nItems*sizeof(Atom) );
1315                     XFree( pBytes );
1316                 }
1317             }
1318             else
1319             {
1320                 // one to three types
1321                 int n = 0, i;
1322                 for( i = 0; i < 3; i++ )
1323                     if( m_aDropEnterEvent.data.l[2+i] )
1324                         n++;
1325 #if OSL_DEBUG_LEVEL > 1
1326                 fprintf( stderr, "have %d data types in XdndEnter\n", n );
1327 #endif
1328                 aAtoms.realloc( sizeof(Atom)*n );
1329                 for( i = 0, n = 0; i < 3; i++ )
1330                     if( m_aDropEnterEvent.data.l[2+i] )
1331                         ((Atom*)aAtoms.getArray())[n++] = m_aDropEnterEvent.data.l[2+i];
1332             }
1333         }
1334     }
1335     // get data of type TARGETS
1336     else if( ! getPasteData( selection, m_nTARGETSAtom, aAtoms ) )
1337         aAtoms = Sequence< sal_Int8 >();
1338 
1339     std::vector< Atom > aNativeTypes;
1340     if( aAtoms.getLength() )
1341     {
1342         sal_Int32 nAtoms = aAtoms.getLength() / sizeof(Atom);
1343         Atom* pAtoms = (Atom*)aAtoms.getArray();
1344         rTypes.realloc( nAtoms );
1345         aNativeTypes.resize( nAtoms );
1346         DataFlavor* pFlavors = rTypes.getArray();
1347         sal_Int32 nNativeTypesIndex = 0;
1348         while( nAtoms-- )
1349         {
1350 #if OSL_DEBUG_LEVEL > 1
1351             if( *pAtoms && *pAtoms < 0x01000000 )
1352                 fprintf( stderr, "native type: %s\n", OUStringToOString( getString( *pAtoms ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1353 #endif
1354             if( *pAtoms == m_nCOMPOUNDAtom )
1355                 bHaveText = bHaveCompound = true;
1356             else if( *pAtoms && *pAtoms < 0x01000000 )
1357             {
1358                 int nFormat;
1359                 pFlavors->MimeType = convertTypeFromNative( *pAtoms, selection, nFormat );
1360                 pFlavors->DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
1361                 sal_Int32 nIndex = 0;
1362                 if( pFlavors->MimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain", 10 ) )
1363                 {
1364                     OUString aToken(pFlavors->MimeType.getToken( 0, ';', nIndex ));
1365                     // omit text/plain;charset=unicode since it is not well defined
1366                     if( aToken.compareToAscii( "charset=unicode" ) == 0 )
1367                     {
1368                         pAtoms++;
1369                         continue;
1370                     }
1371                     bHaveText = true;
1372                     if( aToken.compareToAscii( "charset=utf-16" ) == 0 )
1373                     {
1374                         bHaveUTF16 = true;
1375                         pFlavors->DataType = getCppuType( (OUString*)0 );
1376                     }
1377                     else if( aToken.compareToAscii( "charset=utf-8" ) == 0 )
1378                     {
1379                         aUTF8Type = *pAtoms;
1380                     }
1381                 }
1382                 pFlavors++;
1383                 aNativeTypes[ nNativeTypesIndex ] = *pAtoms;
1384                 nNativeTypesIndex++;
1385             }
1386             pAtoms++;
1387         }
1388         if( (pFlavors - rTypes.getArray()) < rTypes.getLength() )
1389             rTypes.realloc(pFlavors - rTypes.getArray());
1390         bSuccess = rTypes.getLength() ? true : false;
1391         if( bHaveText && ! bHaveUTF16 )
1392         {
1393                int i = 0;
1394 
1395             int nNewFlavors = rTypes.getLength()+1;
1396             Sequence< DataFlavor > aTemp( nNewFlavors );
1397             for( i = 0; i < nNewFlavors-1; i++ )
1398                 aTemp.getArray()[i+1] = rTypes.getConstArray()[i];
1399             aTemp.getArray()[0].MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
1400             aTemp.getArray()[0].DataType = getCppuType( (OUString*)0 );
1401             rTypes = aTemp;
1402 
1403             std::vector< Atom > aNativeTemp( nNewFlavors );
1404             for( i = 0; i < nNewFlavors-1; i++ )
1405                 aNativeTemp[ i + 1 ] = aNativeTypes[ i ];
1406             aNativeTemp[0] = None;
1407             aNativeTypes = aNativeTemp;
1408         }
1409     }
1410 
1411     {
1412         MutexGuard aGuard(m_aMutex);
1413 
1414         it = m_aSelections.find( selection );
1415         if( it != m_aSelections.end() )
1416         {
1417             if( bSuccess )
1418             {
1419                 it->second->m_aTypes            = rTypes;
1420                 it->second->m_aNativeTypes      = aNativeTypes;
1421                 it->second->m_nLastTimestamp    = time( NULL );
1422                 it->second->m_bHaveUTF16        = bHaveUTF16;
1423                 it->second->m_aUTF8Type         = aUTF8Type;
1424                 it->second->m_bHaveCompound     = bHaveCompound;
1425             }
1426             else
1427             {
1428                 it->second->m_aTypes            = Sequence< DataFlavor >();
1429                 it->second->m_aNativeTypes      = std::vector< Atom >();
1430                 it->second->m_nLastTimestamp    = 0;
1431                 it->second->m_bHaveUTF16        = false;
1432                 it->second->m_aUTF8Type         = None;
1433                 it->second->m_bHaveCompound     = false;
1434             }
1435         }
1436     }
1437 
1438 #if OSL_DEBUG_LEVEL > 1
1439 //    if( selection != m_nCLIPBOARDAtom )
1440     {
1441         fprintf( stderr, "SelectionManager::getPasteDataTypes( %s ) = %s\n", OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), bSuccess ? "true" : "false" );
1442         for( int i = 0; i < rTypes.getLength(); i++ )
1443             fprintf( stderr, "type: %s\n", OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1444     }
1445 #endif
1446 
1447     return bSuccess;
1448 }
1449 
1450 // ------------------------------------------------------------------------
1451 
getPixmapHolder(Atom selection)1452 PixmapHolder* SelectionManager::getPixmapHolder( Atom selection )
1453 {
1454     std::hash_map< Atom, Selection* >::const_iterator it = m_aSelections.find( selection );
1455     if( it == m_aSelections.end() )
1456         return NULL;
1457     if( ! it->second->m_pPixmap )
1458         it->second->m_pPixmap = new PixmapHolder( m_pDisplay );
1459     return it->second->m_pPixmap;
1460 }
1461 
GetTrueFormatSize(int nFormat)1462 static sal_Size GetTrueFormatSize(int nFormat)
1463 {
1464     // http://mail.gnome.org/archives/wm-spec-list/2003-March/msg00067.html
1465     return nFormat == 32 ? sizeof(long) : nFormat/8;
1466 }
1467 
sendData(SelectionAdaptor * pAdaptor,XLIB_Window requestor,Atom target,Atom property,Atom selection)1468 bool SelectionManager::sendData( SelectionAdaptor* pAdaptor,
1469                                  XLIB_Window requestor,
1470                                  Atom target,
1471                                  Atom property,
1472                                  Atom selection )
1473 {
1474     ResettableMutexGuard aGuard( m_aMutex );
1475 
1476     // handle targets related to image/bmp
1477     if( target == XA_COLORMAP || target == XA_PIXMAP || target == XA_BITMAP || target == XA_VISUALID )
1478     {
1479         PixmapHolder* pPixmap = getPixmapHolder( selection );
1480         if( ! pPixmap ) return false;
1481         XID nValue = None;
1482 
1483         // handle colormap request
1484         if( target == XA_COLORMAP )
1485             nValue = (XID)pPixmap->getColormap();
1486         else if( target == XA_VISUALID )
1487             nValue = (XID)pPixmap->getVisualID();
1488         else if( target == XA_PIXMAP || target == XA_BITMAP )
1489         {
1490             nValue = (XID)pPixmap->getPixmap();
1491             if( nValue == None )
1492             {
1493                 // first conversion
1494                 Sequence< sal_Int8 > aData;
1495                 int nFormat;
1496                 aGuard.clear();
1497                 bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
1498                 aGuard.reset();
1499                 if( bConverted )
1500                 {
1501                     // get pixmap again since clearing the guard could have invalidated
1502                     // the pixmap in another thread
1503                     pPixmap = getPixmapHolder( selection );
1504                     // conversion succeeded, so aData contains image/bmp now
1505                     if( pPixmap->needsConversion( (const sal_uInt8*)aData.getConstArray() )
1506                         && m_xBitmapConverter.is() )
1507                     {
1508 #if OSL_DEBUG_LEVEL > 1
1509                         fprintf( stderr, "trying bitmap conversion\n" );
1510 #endif
1511                         css::uno::Reference<XBitmap> xBM( new BmpTransporter( aData ) );
1512                         Sequence<Any> aArgs(2), aOutArgs;
1513                         Sequence<sal_Int16> aOutIndex;
1514                         aArgs.getArray()[0] = makeAny( xBM );
1515                         aArgs.getArray()[1] = makeAny( (sal_uInt16)pPixmap->getDepth() );
1516                         aGuard.clear();
1517                         try
1518                         {
1519                             Any aResult =
1520                                 m_xBitmapConverter->invoke( OUString::createFromAscii( "convert-bitmap-depth" ),
1521                                                             aArgs, aOutIndex, aOutArgs );
1522                             if( aResult >>= xBM )
1523                                 aData = xBM->getDIB();
1524                         }
1525                         catch(...)
1526                         {
1527 #if OSL_DEBUG_LEVEL > 1
1528                             fprintf( stderr, "exception in bitmap converter\n" );
1529 #endif
1530                         }
1531                         aGuard.reset();
1532                     }
1533                     // get pixmap again since clearing the guard could have invalidated
1534                     // the pixmap in another thread
1535                     pPixmap = getPixmapHolder( selection );
1536                     nValue = (XID)pPixmap->setBitmapData( (const sal_uInt8*)aData.getConstArray() );
1537                 }
1538                 if( nValue == None )
1539                     return false;
1540             }
1541             if( target == XA_BITMAP )
1542                 nValue = (XID)pPixmap->getBitmap();
1543         }
1544 
1545         XChangeProperty( m_pDisplay,
1546                          requestor,
1547                          property,
1548                          target,
1549                          32,
1550                          PropModeReplace,
1551                          (const unsigned char*)&nValue,
1552                          1);
1553         return true;
1554     }
1555 
1556     /*
1557      *  special target TEXT allows us to transfer
1558      *  the data in an encoding of our choice
1559      *  COMPOUND_TEXT will work with most applications
1560      */
1561     if( target == m_nTEXTAtom )
1562         target = m_nCOMPOUNDAtom;
1563 
1564     Sequence< sal_Int8 > aData;
1565     int nFormat;
1566     aGuard.clear();
1567     bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
1568     aGuard.reset();
1569     if( bConverted )
1570     {
1571         // conversion succeeded
1572         if( aData.getLength() > m_nIncrementalThreshold )
1573         {
1574 #if OSL_DEBUG_LEVEL > 1
1575             fprintf( stderr, "using INCR protocol\n" );
1576             std::hash_map< XLIB_Window, std::hash_map< Atom, IncrementalTransfer > >::const_iterator win_it = m_aIncrementals.find( requestor );
1577             if( win_it != m_aIncrementals.end() )
1578             {
1579                 std::hash_map< Atom, IncrementalTransfer >::const_iterator inc_it = win_it->second.find( property );
1580                 if( inc_it != win_it->second.end() )
1581                 {
1582                     const IncrementalTransfer& rInc = inc_it->second;
1583                     fprintf( stderr, "premature end and new start for INCR transfer for window 0x%lx, property %s, type %s\n",
1584                              rInc.m_aRequestor,
1585                              OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1586                              OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
1587                              );
1588                 }
1589             }
1590 #endif
1591 
1592             // insert IncrementalTransfer
1593             IncrementalTransfer& rInc   = m_aIncrementals[ requestor ][ property ];
1594             rInc.m_aData                = aData;
1595             rInc.m_nBufferPos           = 0;
1596             rInc.m_aRequestor           = requestor;
1597             rInc.m_aProperty            = property;
1598             rInc.m_aTarget              = target;
1599             rInc.m_nFormat              = nFormat;
1600             rInc.m_nTransferStartTime   = time( NULL );
1601 
1602             // use incr protocol, signal start to requestor
1603             long nMinSize = m_nIncrementalThreshold;
1604             XSelectInput( m_pDisplay, requestor, PropertyChangeMask );
1605             XChangeProperty( m_pDisplay, requestor, property,
1606                              m_nINCRAtom, 32,  PropModeReplace, (unsigned char*)&nMinSize, 1 );
1607             XFlush( m_pDisplay );
1608         }
1609         else
1610         {
1611             sal_Size nUnitSize = GetTrueFormatSize(nFormat);
1612             XChangeProperty( m_pDisplay,
1613                              requestor,
1614                              property,
1615                              target,
1616                              nFormat,
1617                              PropModeReplace,
1618                              (const unsigned char*)aData.getConstArray(),
1619                              aData.getLength()/nUnitSize );
1620             }
1621     }
1622 #if OSL_DEBUG_LEVEL > 1
1623     else
1624         fprintf( stderr, "convertData failed for type: %s \n",
1625                  OUStringToOString( convertTypeFromNative( target, selection, nFormat ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1626 #endif
1627     return bConverted;
1628 }
1629 
1630 // ------------------------------------------------------------------------
1631 
handleSelectionRequest(XSelectionRequestEvent & rRequest)1632 bool SelectionManager::handleSelectionRequest( XSelectionRequestEvent& rRequest )
1633 {
1634     ResettableMutexGuard aGuard( m_aMutex );
1635 #if OSL_DEBUG_LEVEL > 1
1636     fprintf( stderr, "handleSelectionRequest for selection %s and target %s\n",
1637              OUStringToOString( getString( rRequest.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1638              OUStringToOString( getString( rRequest.target ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
1639              );
1640 #endif
1641 
1642     XEvent aNotify;
1643 
1644     aNotify.type                  = SelectionNotify;
1645     aNotify.xselection.display    = rRequest.display;
1646     aNotify.xselection.send_event = True;
1647     aNotify.xselection.requestor  = rRequest.requestor;
1648     aNotify.xselection.selection  = rRequest.selection;
1649     aNotify.xselection.time       = rRequest.time;
1650     aNotify.xselection.target     = rRequest.target;
1651     aNotify.xselection.property   = None;
1652 
1653     SelectionAdaptor* pAdaptor = getAdaptor( rRequest.selection );
1654     // ensure that we still own that selection
1655     if( pAdaptor &&
1656         XGetSelectionOwner( m_pDisplay, rRequest.selection ) == m_aWindow )
1657     {
1658         css::uno::Reference< XTransferable > xTrans( pAdaptor->getTransferable() );
1659         if( rRequest.target == m_nTARGETSAtom )
1660         {
1661             // someone requests our types
1662             if( xTrans.is() )
1663             {
1664                 aGuard.clear();
1665                 Sequence< DataFlavor > aFlavors = xTrans->getTransferDataFlavors();
1666                 aGuard.reset();
1667 
1668                 ::std::list< Atom > aConversions;
1669                 getNativeTypeList( aFlavors, aConversions, rRequest.selection );
1670 
1671                 int i, nTypes = aConversions.size();
1672                 Atom* pTypes = (Atom*)alloca( nTypes * sizeof( Atom ) );
1673                 std::list< Atom >::const_iterator it;
1674                 for( i = 0, it = aConversions.begin(); i < nTypes; i++, ++it )
1675                     pTypes[i] = *it;
1676                 XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
1677                                  XA_ATOM, 32, PropModeReplace, (const unsigned char*)pTypes, nTypes );
1678                 aNotify.xselection.property = rRequest.property;
1679 #if OSL_DEBUG_LEVEL > 1
1680                 fprintf( stderr, "sending type list:\n" );
1681                 for( int k = 0; k < nTypes; k++ )
1682                     fprintf( stderr, "   %s\n", pTypes[k] ? XGetAtomName( m_pDisplay, pTypes[k] ) : "<None>" );
1683 #endif
1684             }
1685         }
1686         else if( rRequest.target == m_nTIMESTAMPAtom )
1687         {
1688             long nTimeStamp = (long)m_aSelections[rRequest.selection]->m_nOrigTimestamp;
1689             XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
1690                              XA_INTEGER, 32, PropModeReplace, (const unsigned char*)&nTimeStamp, 1 );
1691             aNotify.xselection.property = rRequest.property;
1692 #if OSL_DEBUG_LEVEL > 1
1693                 fprintf( stderr, "sending timestamp: %d\n", (int)nTimeStamp );
1694 #endif
1695         }
1696         else
1697         {
1698             bool bEventSuccess = false;
1699             if( rRequest.target == m_nMULTIPLEAtom )
1700             {
1701                 // get all targets
1702                 Atom nType = None;
1703                 int nFormat = 0;
1704                 unsigned long nItems = 0, nBytes = 0;
1705                 unsigned char* pData = NULL;
1706 
1707                 // get number of atoms
1708                 XGetWindowProperty( m_pDisplay,
1709                                     rRequest.requestor,
1710                                     rRequest.property,
1711                                     0, 0,
1712                                     False,
1713                                     AnyPropertyType,
1714                                     &nType, &nFormat,
1715                                     &nItems, &nBytes,
1716                                     &pData );
1717                 if( nFormat == 32 && nBytes/4 )
1718                 {
1719                     if( pData ) // ?? should not happen
1720                     {
1721                         XFree( pData );
1722                         pData = NULL;
1723                     }
1724                     XGetWindowProperty( m_pDisplay,
1725                                         rRequest.requestor,
1726                                         rRequest.property,
1727                                         0, nBytes/4,
1728                                         False,
1729                                         nType,
1730                                         &nType, &nFormat,
1731                                         &nItems, &nBytes,
1732                                         &pData );
1733                     if( pData && nItems )
1734                     {
1735 #if OSL_DEBUG_LEVEL > 1
1736                         fprintf( stderr, "found %ld atoms in MULTIPLE request\n", nItems );
1737 #endif
1738                         bEventSuccess = true;
1739                         bool bResetAtoms = false;
1740                         Atom* pAtoms = (Atom*)pData;
1741                         aGuard.clear();
1742                         for( unsigned int i = 0; i < nItems; i += 2 )
1743                         {
1744 #if OSL_DEBUG_LEVEL > 1
1745                             fprintf( stderr, "   %s => %s: ",
1746                                      OUStringToOString( getString( pAtoms[i] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1747                                      OUStringToOString( getString( pAtoms[i+1] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1748 #endif
1749                             bool bSuccess = sendData( pAdaptor, rRequest.requestor, pAtoms[i], pAtoms[i+1], rRequest.selection );
1750 #if OSL_DEBUG_LEVEL > 1
1751                             fprintf( stderr, "%s\n", bSuccess ? "succeeded" : "failed" );
1752 #endif
1753                             if( ! bSuccess )
1754                             {
1755                                 pAtoms[i] = None;
1756                                 bResetAtoms = true;
1757                             }
1758                         }
1759                         aGuard.reset();
1760                         if( bResetAtoms )
1761                             XChangeProperty( m_pDisplay,
1762                                              rRequest.requestor,
1763                                              rRequest.property,
1764                                              XA_ATOM,
1765                                              32,
1766                                              PropModeReplace,
1767                                              pData,
1768                                              nBytes/4 );
1769                     }
1770                     if( pData )
1771                         XFree( pData );
1772                 }
1773 #if OSL_DEBUG_LEVEL > 1
1774                 else
1775                 {
1776                     fprintf( stderr, "could not get type list from \"%s\" of type \"%s\" on requestor 0x%lx, requestor has properties:",
1777                              OUStringToOString( getString( rRequest.property ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1778                              OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1779                              rRequest.requestor );
1780                     int nProps = 0;
1781                     Atom* pProps = XListProperties( m_pDisplay, rRequest.requestor, &nProps );
1782                     if( pProps )
1783                     {
1784                         for( int i = 0; i < nProps; i++ )
1785                             fprintf( stderr, " \"%s\"", OUStringToOString( getString( pProps[i]), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1786                         XFree( pProps );
1787                     }
1788                 }
1789 #endif
1790             }
1791             else
1792             {
1793                 aGuard.clear();
1794                 bEventSuccess = sendData( pAdaptor, rRequest.requestor, rRequest.target, rRequest.property, rRequest.selection );
1795                 aGuard.reset();
1796             }
1797             if( bEventSuccess )
1798             {
1799                 aNotify.xselection.target = rRequest.target;
1800                 aNotify.xselection.property = rRequest.property;
1801             }
1802         }
1803         aGuard.clear();
1804         xTrans.clear();
1805         aGuard.reset();
1806     }
1807     XSendEvent( m_pDisplay, rRequest.requestor, False, 0, &aNotify );
1808 
1809     if( rRequest.selection == XA_PRIMARY    &&
1810         m_bWaitingForPrimaryConversion      &&
1811         m_xDragSourceListener.is() )
1812     {
1813         DragSourceDropEvent dsde;
1814         dsde.Source                 = static_cast< OWeakObject* >(this);
1815         dsde.DragSourceContext      = new DragSourceContext( m_aDropWindow, rRequest.time, *this );
1816         dsde.DragSource             = static_cast< XDragSource* >(this);
1817         if( aNotify.xselection.property != None )
1818         {
1819             dsde.DropAction         = DNDConstants::ACTION_COPY;
1820             dsde.DropSuccess        = sal_True;
1821         }
1822         else
1823         {
1824             dsde.DropAction         = DNDConstants::ACTION_NONE;
1825             dsde.DropSuccess        = sal_False;
1826         }
1827         css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
1828         m_xDragSourceListener.clear();
1829         aGuard.clear();
1830         if( xListener.is() )
1831             xListener->dragDropEnd( dsde );
1832     }
1833 
1834     // we handled the event in any case by answering
1835     return true;
1836 }
1837 
1838 // ------------------------------------------------------------------------
1839 
handleReceivePropertyNotify(XPropertyEvent & rNotify)1840 bool SelectionManager::handleReceivePropertyNotify( XPropertyEvent& rNotify )
1841 {
1842     MutexGuard aGuard( m_aMutex );
1843     // data we requested arrived
1844 #if OSL_DEBUG_LEVEL > 1
1845     fprintf( stderr, "handleReceivePropertyNotify for property %s\n",
1846              OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1847 #endif
1848     bool bHandled = false;
1849 
1850     ::std::hash_map< Atom, Selection* >::iterator it =
1851           m_aSelections.find( rNotify.atom );
1852     if( it != m_aSelections.end() &&
1853         rNotify.state == PropertyNewValue &&
1854         ( it->second->m_eState == Selection::WaitingForResponse     ||
1855           it->second->m_eState == Selection::WaitingForData         ||
1856           it->second->m_eState == Selection::IncrementalTransfer
1857           )
1858         )
1859     {
1860         // MULTIPLE requests are only complete after selection notify
1861         if( it->second->m_aRequestedType == m_nMULTIPLEAtom &&
1862             ( it->second->m_eState == Selection::WaitingForResponse ||
1863               it->second->m_eState == Selection::WaitingForData ) )
1864             return false;
1865 
1866         bHandled = true;
1867 
1868         Atom nType = None;
1869         int nFormat = 0;
1870         unsigned long nItems = 0, nBytes = 0;
1871         unsigned char* pData = NULL;
1872 
1873         // get type and length
1874         XGetWindowProperty( m_pDisplay,
1875                             rNotify.window,
1876                             rNotify.atom,
1877                             0, 0,
1878                             False,
1879                             AnyPropertyType,
1880                             &nType, &nFormat,
1881                             &nItems, &nBytes,
1882                             &pData );
1883 #if OSL_DEBUG_LEVEL > 1
1884         fprintf( stderr, "found %ld bytes data of type %s and format %d, items = %ld\n",
1885                  nBytes,
1886                  OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1887                  nFormat, nItems );
1888 #endif
1889         if( pData )
1890         {
1891             XFree( pData );
1892             pData = NULL;
1893         }
1894 
1895         if( nType == m_nINCRAtom )
1896         {
1897             // start data transfer
1898             XDeleteProperty( m_pDisplay, rNotify.window, rNotify.atom );
1899             it->second->m_eState = Selection::IncrementalTransfer;
1900         }
1901         else if( nType != None )
1902         {
1903             XGetWindowProperty( m_pDisplay,
1904                                 rNotify.window,
1905                                 rNotify.atom,
1906                                 0, nBytes/4 +1,
1907                                 True,
1908                                 nType,
1909                                 &nType, &nFormat,
1910                                 &nItems, &nBytes,
1911                                 &pData );
1912 #if OSL_DEBUG_LEVEL > 1
1913             fprintf( stderr, "read %ld items data of type %s and format %d, %ld bytes left in property\n",
1914                      nItems,
1915                      OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1916                      nFormat, nBytes );
1917 #endif
1918 
1919             sal_Size nUnitSize = GetTrueFormatSize(nFormat);
1920 
1921             if( it->second->m_eState == Selection::WaitingForData ||
1922                 it->second->m_eState == Selection::WaitingForResponse )
1923             {
1924                 // copy data
1925                 it->second->m_aData = Sequence< sal_Int8 >( (sal_Int8*)pData, nItems*nUnitSize );
1926                 it->second->m_eState = Selection::Inactive;
1927                 it->second->m_aDataArrived.set();
1928             }
1929             else if( it->second->m_eState == Selection::IncrementalTransfer )
1930             {
1931                 if( nItems )
1932                 {
1933                     // append data
1934                     Sequence< sal_Int8 > aData( it->second->m_aData.getLength() + nItems*nUnitSize );
1935                     memcpy( aData.getArray(), it->second->m_aData.getArray(), it->second->m_aData.getLength() );
1936                     memcpy( aData.getArray() + it->second->m_aData.getLength(), pData, nItems*nUnitSize );
1937                     it->second->m_aData = aData;
1938                 }
1939                 else
1940                 {
1941                     it->second->m_eState = Selection::Inactive;
1942                     it->second->m_aDataArrived.set();
1943                 }
1944             }
1945             if( pData )
1946                 XFree( pData );
1947         }
1948         else if( it->second->m_eState == Selection::IncrementalTransfer )
1949         {
1950             it->second->m_eState = Selection::Inactive;
1951             it->second->m_aDataArrived.set();
1952         }
1953     }
1954     return bHandled;
1955 }
1956 
1957 // ------------------------------------------------------------------------
1958 
handleSendPropertyNotify(XPropertyEvent & rNotify)1959 bool SelectionManager::handleSendPropertyNotify( XPropertyEvent& rNotify )
1960 {
1961     MutexGuard aGuard( m_aMutex );
1962 
1963     // ready for next part of a IncrementalTransfer
1964 #if OSL_DEBUG_LEVEL > 1
1965     fprintf( stderr, "handleSendPropertyNotify for property %s (%s)\n",
1966              OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1967              rNotify.state == PropertyNewValue ? "new value" : ( rNotify.state == PropertyDelete ? "deleted" : "unknown")
1968              );
1969 #endif
1970 
1971     bool bHandled = false;
1972     // feed incrementals
1973     if( rNotify.state == PropertyDelete )
1974     {
1975         std::hash_map< XLIB_Window, std::hash_map< Atom, IncrementalTransfer > >::iterator it;
1976         it = m_aIncrementals.find( rNotify.window );
1977         if( it != m_aIncrementals.end() )
1978         {
1979             bHandled = true;
1980             int nCurrentTime = time( NULL );
1981             std::hash_map< Atom, IncrementalTransfer >::iterator inc_it;
1982             // throw out aborted transfers
1983             std::list< Atom > aTimeouts;
1984             for( inc_it = it->second.begin(); inc_it != it->second.end(); ++inc_it )
1985             {
1986                 if( (nCurrentTime - inc_it->second.m_nTransferStartTime) > (getSelectionTimeout()+2) )
1987                 {
1988                     aTimeouts.push_back( inc_it->first );
1989 #if OSL_DEBUG_LEVEL > 1
1990                     const IncrementalTransfer& rInc = inc_it->second;
1991                     fprintf( stderr, "timeout on INCR transfer for window 0x%lx, property %s, type %s\n",
1992                              rInc.m_aRequestor,
1993                              OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1994                              OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
1995                              );
1996 #endif
1997                 }
1998             }
1999 
2000             while( aTimeouts.begin() != aTimeouts.end() )
2001             {
2002                 // transfer broken, might even be a new client with the
2003                 // same window id
2004                 it->second.erase( aTimeouts.front() );
2005                 aTimeouts.pop_front();
2006             }
2007 
2008             inc_it = it->second.find( rNotify.atom );
2009             if( inc_it != it->second.end() )
2010             {
2011                 IncrementalTransfer& rInc = inc_it->second;
2012 
2013                 int nBytes = rInc.m_aData.getLength() - rInc.m_nBufferPos;
2014                 nBytes = (nBytes > m_nIncrementalThreshold) ? m_nIncrementalThreshold : nBytes;
2015                 if( nBytes < 0 )  // sanity check
2016                     nBytes = 0;
2017 #if OSL_DEBUG_LEVEL > 1
2018                 fprintf( stderr, "pushing %d bytes: \"%.*s\"...\n",
2019                          nBytes, nBytes > 32 ? 32 : nBytes,
2020                          (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos );
2021 #endif
2022 
2023                 sal_Size nUnitSize = GetTrueFormatSize(rInc.m_nFormat);
2024 
2025                 XChangeProperty( m_pDisplay,
2026                                  rInc.m_aRequestor,
2027                                  rInc.m_aProperty,
2028                                  rInc.m_aTarget,
2029                                  rInc.m_nFormat,
2030                                  PropModeReplace,
2031                                  (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos,
2032                                  nBytes/nUnitSize );
2033                 rInc.m_nBufferPos += nBytes;
2034                 rInc.m_nTransferStartTime = nCurrentTime;
2035 
2036                 if( nBytes == 0 ) // transfer finished
2037                 {
2038 #if OSL_DEBUG_LEVEL > 1
2039                     fprintf( stderr, "finished INCR transfer for window 0x%lx, property %s, type %s\n",
2040                              rInc.m_aRequestor,
2041                              OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
2042                              OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
2043                              );
2044 #endif
2045                     it->second.erase( inc_it );
2046                 }
2047 
2048             }
2049             // eventually clean up the hash map
2050             if( it->second.begin() == it->second.end() )
2051                 m_aIncrementals.erase( it );
2052         }
2053     }
2054     return bHandled;
2055 }
2056 
2057 // ------------------------------------------------------------------------
2058 
handleSelectionNotify(XSelectionEvent & rNotify)2059 bool SelectionManager::handleSelectionNotify( XSelectionEvent& rNotify )
2060 {
2061     MutexGuard aGuard( m_aMutex );
2062 
2063     bool bHandled = false;
2064 
2065     // notification about success/failure of one of our conversion requests
2066 #if OSL_DEBUG_LEVEL > 1
2067     OUString aSelection( getString( rNotify.selection ) );
2068     OUString aProperty( OUString::createFromAscii( "None" ) );
2069     if( rNotify.property )
2070         aProperty = getString( rNotify.property );
2071     fprintf( stderr, "handleSelectionNotify for selection %s and property %s (0x%lx)\n",
2072              OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
2073              OUStringToOString( aProperty, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
2074              rNotify.property
2075              );
2076     if( rNotify.requestor != m_aWindow && rNotify.requestor != m_aCurrentDropWindow )
2077         fprintf( stderr, "Warning: selection notify for unknown window 0x%lx\n", rNotify.requestor );
2078 #endif
2079     ::std::hash_map< Atom, Selection* >::iterator it =
2080           m_aSelections.find( rNotify.selection );
2081     if (
2082         (rNotify.requestor == m_aWindow || rNotify.requestor == m_aCurrentDropWindow) &&
2083         it != m_aSelections.end() &&
2084         (
2085          (it->second->m_eState == Selection::WaitingForResponse) ||
2086          (it->second->m_eState == Selection::WaitingForData)
2087         )
2088        )
2089     {
2090         bHandled = true;
2091         if( it->second->m_aRequestedType == m_nMULTIPLEAtom )
2092         {
2093             Atom nType = None;
2094             int nFormat = 0;
2095             unsigned long nItems = 0, nBytes = 0;
2096             unsigned char* pData = NULL;
2097 
2098             // get type and length
2099             XGetWindowProperty( m_pDisplay,
2100                                 rNotify.requestor,
2101                                 rNotify.property,
2102                                 0, 256,
2103                                 False,
2104                                 AnyPropertyType,
2105                                 &nType, &nFormat,
2106                                 &nItems, &nBytes,
2107                                 &pData );
2108             if( nBytes ) // HUGE request !!!
2109             {
2110                 if( pData )
2111                     XFree( pData );
2112                 XGetWindowProperty( m_pDisplay,
2113                                     rNotify.requestor,
2114                                     rNotify.property,
2115                                     0, 256+(nBytes+3)/4,
2116                                     False,
2117                                     AnyPropertyType,
2118                                     &nType, &nFormat,
2119                                     &nItems, &nBytes,
2120                                     &pData );
2121             }
2122             it->second->m_eState        = Selection::Inactive;
2123             sal_Size nUnitSize = GetTrueFormatSize(nFormat);
2124             it->second->m_aData         = Sequence< sal_Int8 >((sal_Int8*)pData, nItems * nUnitSize);
2125             it->second->m_aDataArrived.set();
2126             if( pData )
2127                 XFree( pData );
2128         }
2129         // WaitingForData can actually happen; some
2130         // applications (e.g. cmdtool on Solaris) first send
2131         // a success and then cancel it. Weird !
2132         else if( rNotify.property == None )
2133         {
2134             // conversion failed, stop transfer
2135             it->second->m_eState        = Selection::Inactive;
2136             it->second->m_aData         = Sequence< sal_Int8 >();
2137             it->second->m_aDataArrived.set();
2138         }
2139         // get the bytes, by INCR if necessary
2140         else
2141             it->second->m_eState = Selection::WaitingForData;
2142     }
2143 #if OSL_DEBUG_LEVEL > 1
2144     else if( it != m_aSelections.end() )
2145         fprintf( stderr, "Warning: selection in state %d\n", it->second->m_eState );
2146 #endif
2147     return bHandled;
2148 }
2149 
2150 // ------------------------------------------------------------------------
2151 
handleDropEvent(XClientMessageEvent & rMessage)2152 bool SelectionManager::handleDropEvent( XClientMessageEvent& rMessage )
2153 {
2154     ResettableMutexGuard aGuard(m_aMutex);
2155 
2156     // handle drop related events
2157     XLIB_Window aSource = rMessage.data.l[0];
2158     XLIB_Window aTarget = rMessage.window;
2159 
2160     bool bHandled = false;
2161 
2162     ::std::hash_map< XLIB_Window, DropTargetEntry >::iterator it =
2163           m_aDropTargets.find( aTarget );
2164 
2165 #if OSL_DEBUG_LEVEL > 1
2166     if( rMessage.message_type == m_nXdndEnter     ||
2167         rMessage.message_type == m_nXdndLeave     ||
2168         rMessage.message_type == m_nXdndDrop      ||
2169         rMessage.message_type == m_nXdndPosition  )
2170     {
2171         fprintf( stderr, "got drop event %s, ", OUStringToOString( getString( rMessage.message_type ), RTL_TEXTENCODING_ASCII_US).getStr() );
2172         if( it == m_aDropTargets.end() )
2173             fprintf( stderr, "but no target found\n" );
2174         else if( ! it->second.m_pTarget->m_bActive )
2175             fprintf( stderr, "but target is inactive\n" );
2176         else if( m_aDropEnterEvent.data.l[0] != None && (XLIB_Window)m_aDropEnterEvent.data.l[0] != aSource )
2177             fprintf( stderr, "but source 0x%lx is unknown (expected 0x%lx or 0)\n", aSource, m_aDropEnterEvent.data.l[0] );
2178         else
2179             fprintf( stderr, "processing.\n" );
2180     }
2181 #endif
2182 
2183     if( it != m_aDropTargets.end() && it->second.m_pTarget->m_bActive &&
2184         m_bDropWaitingForCompletion && m_aDropEnterEvent.data.l[0] )
2185     {
2186         bHandled = true;
2187         OSL_ENSURE( 0, "someone forgot to call dropComplete ?" );
2188         // some listener forgot to call dropComplete in the last operation
2189         // let us end it now and accept the new enter event
2190         aGuard.clear();
2191         dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
2192         aGuard.reset();
2193     }
2194 
2195     if( it != m_aDropTargets.end() &&
2196         it->second.m_pTarget->m_bActive &&
2197        ( m_aDropEnterEvent.data.l[0] == None || XLIB_Window(m_aDropEnterEvent.data.l[0]) == aSource )
2198         )
2199     {
2200         if( rMessage.message_type == m_nXdndEnter )
2201         {
2202             bHandled = true;
2203             m_aDropEnterEvent           = rMessage;
2204             m_bDropEnterSent            = false;
2205             m_aCurrentDropWindow        = aTarget;
2206             m_nCurrentProtocolVersion   = m_aDropEnterEvent.data.l[1] >> 24;
2207 #if OSL_DEBUG_LEVEL > 1
2208             fprintf( stderr, "received XdndEnter on 0x%lx\n", aTarget );
2209 #endif
2210         }
2211         else if(
2212                 rMessage.message_type == m_nXdndPosition &&
2213                 aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
2214                 )
2215         {
2216             bHandled = true;
2217             m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[3] : CurrentTime;
2218             if( ! m_bDropEnterSent )
2219                 m_nDropTimestamp = m_nDropTime;
2220 
2221             XLIB_Window aChild;
2222             XTranslateCoordinates( m_pDisplay,
2223                                    it->second.m_aRootWindow,
2224                                    it->first,
2225                                    rMessage.data.l[2] >> 16,
2226                                    rMessage.data.l[2] & 0xffff,
2227                                    &m_nLastX, &m_nLastY,
2228                                    &aChild );
2229 
2230 #if OSL_DEBUG_LEVEL > 1
2231             fprintf( stderr, "received XdndPosition on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
2232 #endif
2233             DropTargetDragEnterEvent aEvent;
2234             aEvent.Source       = static_cast< XDropTarget* >(it->second.m_pTarget);
2235             aEvent.Context      = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
2236             aEvent.LocationX    = m_nLastX;
2237             aEvent.LocationY    = m_nLastY;
2238             aEvent.SourceActions = m_nSourceActions;
2239             if( m_nCurrentProtocolVersion < 2 )
2240                 aEvent.DropAction = DNDConstants::ACTION_COPY;
2241             else if( Atom(rMessage.data.l[4]) == m_nXdndActionCopy )
2242                 aEvent.DropAction = DNDConstants::ACTION_COPY;
2243             else if( Atom(rMessage.data.l[4]) == m_nXdndActionMove )
2244                 aEvent.DropAction = DNDConstants::ACTION_MOVE;
2245             else if( Atom(rMessage.data.l[4]) == m_nXdndActionLink )
2246                 aEvent.DropAction = DNDConstants::ACTION_LINK;
2247             else if( Atom(rMessage.data.l[4]) == m_nXdndActionAsk )
2248                 // currently no interface to implement ask
2249                 aEvent.DropAction = ~0;
2250             else
2251                 aEvent.DropAction = DNDConstants::ACTION_NONE;
2252 
2253             m_nLastDropAction   = aEvent.DropAction;
2254             if( ! m_bDropEnterSent )
2255             {
2256                 m_bDropEnterSent = true;
2257                 aEvent.SupportedDataFlavors = m_xDropTransferable->getTransferDataFlavors();
2258                 aGuard.clear();
2259                 it->second->dragEnter( aEvent );
2260             }
2261             else
2262             {
2263                 aGuard.clear();
2264                 it->second->dragOver( aEvent );
2265             }
2266         }
2267         else if(
2268                 rMessage.message_type == m_nXdndLeave  &&
2269                 aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
2270                 )
2271         {
2272             bHandled = true;
2273 #if OSL_DEBUG_LEVEL > 1
2274             fprintf( stderr, "received XdndLeave on 0x%lx\n", aTarget );
2275 #endif
2276             DropTargetEvent aEvent;
2277             aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
2278             m_aDropEnterEvent.data.l[0] = None;
2279             if( m_aCurrentDropWindow == aTarget )
2280                 m_aCurrentDropWindow = None;
2281             m_nCurrentProtocolVersion = nXdndProtocolRevision;
2282             aGuard.clear();
2283             it->second->dragExit( aEvent );
2284         }
2285         else if(
2286                 rMessage.message_type == m_nXdndDrop &&
2287                 aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
2288                 )
2289         {
2290             bHandled = true;
2291             m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[2] : CurrentTime;
2292 
2293 #if OSL_DEBUG_LEVEL > 1
2294             fprintf( stderr, "received XdndDrop on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
2295 #endif
2296             if( m_bLastDropAccepted )
2297             {
2298                 DropTargetDropEvent aEvent;
2299                 aEvent.Source       = static_cast< XDropTarget* >(it->second.m_pTarget);
2300                 aEvent.Context      = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
2301                 aEvent.LocationX    = m_nLastX;
2302                 aEvent.LocationY    = m_nLastY;
2303                 aEvent.DropAction   = m_nLastDropAction;
2304                 // there is nothing corresponding to source supported actions
2305                 // every source can do link, copy and move
2306                 aEvent.SourceActions= m_nLastDropAction;
2307                 aEvent.Transferable = m_xDropTransferable;
2308 
2309                 m_bDropWaitingForCompletion = true;
2310                 aGuard.clear();
2311                 it->second->drop( aEvent );
2312             }
2313             else
2314             {
2315 #if OSL_DEBUG_LEVEL > 1
2316                 fprintf( stderr, "XdndDrop canceled due to m_bLastDropAccepted = fale\n" );
2317 #endif
2318                 DropTargetEvent aEvent;
2319                 aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
2320                 aGuard.clear();
2321                 it->second->dragExit( aEvent );
2322                 // reset the drop status, notify source
2323                 dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
2324             }
2325         }
2326     }
2327     return bHandled;
2328 }
2329 
2330 /*
2331  *  methods for XDropTargetDropContext
2332  */
2333 
dropComplete(sal_Bool bSuccess,XLIB_Window aDropWindow,XLIB_Time)2334 void SelectionManager::dropComplete( sal_Bool bSuccess, XLIB_Window aDropWindow, XLIB_Time )
2335 {
2336     ClearableMutexGuard aGuard(m_aMutex);
2337 
2338     if( aDropWindow == m_aCurrentDropWindow )
2339     {
2340         if( m_xDragSourceListener.is() )
2341         {
2342             DragSourceDropEvent dsde;
2343             dsde.Source             = static_cast< OWeakObject* >(this);
2344             dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2345             dsde.DragSource         = static_cast< XDragSource* >(this);
2346             dsde.DropAction         = getUserDragAction();
2347             dsde.DropSuccess        = bSuccess;
2348             css::uno::Reference< XDragSourceListener > xListener = m_xDragSourceListener;
2349             m_xDragSourceListener.clear();
2350 
2351             aGuard.clear();
2352             xListener->dragDropEnd( dsde );
2353         }
2354         else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
2355         {
2356             XEvent aEvent;
2357             aEvent.xclient.type         = ClientMessage;
2358             aEvent.xclient.display      = m_pDisplay;
2359             aEvent.xclient.window       = m_aDropEnterEvent.data.l[0];
2360             aEvent.xclient.message_type = m_nXdndFinished;
2361             aEvent.xclient.format       = 32;
2362             aEvent.xclient.data.l[0]    = m_aCurrentDropWindow;
2363             aEvent.xclient.data.l[1]    = bSuccess ? 1 : 0;
2364             aEvent.xclient.data.l[2]    = 0;
2365             aEvent.xclient.data.l[3]    = 0;
2366             aEvent.xclient.data.l[4]    = 0;
2367             if( bSuccess )
2368             {
2369                 if( m_nLastDropAction & DNDConstants::ACTION_MOVE )
2370                     aEvent.xclient.data.l[2] = m_nXdndActionMove;
2371                 else if( m_nLastDropAction & DNDConstants::ACTION_COPY )
2372                     aEvent.xclient.data.l[2] = m_nXdndActionCopy;
2373                 else if( m_nLastDropAction & DNDConstants::ACTION_LINK )
2374                     aEvent.xclient.data.l[2] = m_nXdndActionLink;
2375             }
2376 
2377 #if OSL_DEBUG_LEVEL > 1
2378             fprintf( stderr, "Sending XdndFinished to 0x%lx\n",
2379                      m_aDropEnterEvent.data.l[0]
2380                      );
2381 #endif
2382 
2383             XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
2384                         False, NoEventMask, & aEvent );
2385 
2386             m_aDropEnterEvent.data.l[0] = None;
2387             m_aCurrentDropWindow        = None;
2388             m_nCurrentProtocolVersion   = nXdndProtocolRevision;
2389         }
2390         m_bDropWaitingForCompletion = false;
2391     }
2392     else
2393         OSL_ASSERT( "dropComplete from invalid DropTargetDropContext" );
2394 }
2395 
2396 /*
2397  *  methods for XDropTargetDragContext
2398  */
2399 
2400 // ------------------------------------------------------------------------
2401 
sendDragStatus(Atom nDropAction)2402 void SelectionManager::sendDragStatus( Atom nDropAction )
2403 {
2404     ClearableMutexGuard aGuard(m_aMutex);
2405 
2406     if( m_xDragSourceListener.is() )
2407     {
2408         sal_Int8 nNewDragAction;
2409         if( nDropAction == m_nXdndActionMove )
2410             nNewDragAction = DNDConstants::ACTION_MOVE;
2411         else if( nDropAction == m_nXdndActionCopy )
2412             nNewDragAction = DNDConstants::ACTION_COPY;
2413         else if( nDropAction == m_nXdndActionLink )
2414             nNewDragAction = DNDConstants::ACTION_LINK;
2415         else
2416             nNewDragAction = DNDConstants::ACTION_NONE;
2417         nNewDragAction &= m_nSourceActions;
2418 
2419         if( nNewDragAction != m_nTargetAcceptAction )
2420         {
2421             setCursor( getDefaultCursor( nNewDragAction ), m_aDropWindow, m_nDragTimestamp );
2422             m_nTargetAcceptAction = nNewDragAction;
2423         }
2424 
2425         DragSourceDragEvent dsde;
2426         dsde.Source             = static_cast< OWeakObject* >(this);
2427         dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2428         dsde.DragSource         = static_cast< XDragSource* >(this);
2429         dsde.DropAction         = m_nSourceActions;
2430         dsde.UserAction         = getUserDragAction();
2431 
2432         css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
2433         // caution: do not change anything after this
2434         aGuard.clear();
2435         if( xListener.is() )
2436             xListener->dragOver( dsde );
2437     }
2438     else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
2439     {
2440         XEvent aEvent;
2441         aEvent.xclient.type         = ClientMessage;
2442         aEvent.xclient.display      = m_pDisplay;
2443         aEvent.xclient.window       = m_aDropEnterEvent.data.l[0];
2444         aEvent.xclient.message_type = m_nXdndStatus;
2445         aEvent.xclient.format       = 32;
2446         aEvent.xclient.data.l[0]    = m_aCurrentDropWindow;
2447         aEvent.xclient.data.l[1]    = 2;
2448         if( nDropAction == m_nXdndActionMove    ||
2449             nDropAction == m_nXdndActionLink    ||
2450             nDropAction == m_nXdndActionCopy )
2451             aEvent.xclient.data.l[1] |= 1;
2452         aEvent.xclient.data.l[2] = 0;
2453         aEvent.xclient.data.l[3] = 0;
2454         aEvent.xclient.data.l[4] = m_nCurrentProtocolVersion > 1 ? nDropAction : 0;
2455 
2456 #if OSL_DEBUG_LEVEL > 1
2457         fprintf( stderr, "Sending XdndStatus to 0x%lx with action %s\n",
2458                  m_aDropEnterEvent.data.l[0],
2459                  OUStringToOString( getString( nDropAction ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
2460                  );
2461 #endif
2462 
2463         XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
2464                     False, NoEventMask, & aEvent );
2465         XFlush( m_pDisplay );
2466     }
2467 }
2468 
2469 // ------------------------------------------------------------------------
2470 
getUserDragAction() const2471 sal_Int8 SelectionManager::getUserDragAction() const
2472 {
2473     return (m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT) ? m_nTargetAcceptAction : m_nUserDragAction;
2474 }
2475 
2476 // ------------------------------------------------------------------------
2477 
updateDragAction(int modifierState)2478 bool SelectionManager::updateDragAction( int modifierState )
2479 {
2480     bool bRet = false;
2481 
2482     sal_Int8 nNewDropAction = DNDConstants::ACTION_MOVE;
2483     if( ( modifierState & ShiftMask ) && ! ( modifierState & ControlMask ) )
2484         nNewDropAction = DNDConstants::ACTION_MOVE;
2485     else if( ( modifierState & ControlMask ) && ! ( modifierState & ShiftMask ) )
2486         nNewDropAction = DNDConstants::ACTION_COPY;
2487     else if( ( modifierState & ShiftMask ) && ( modifierState & ControlMask ) )
2488         nNewDropAction = DNDConstants::ACTION_LINK;
2489     if( m_nCurrentProtocolVersion < 0 && m_aDropWindow != None )
2490         nNewDropAction = DNDConstants::ACTION_COPY;
2491     nNewDropAction &= m_nSourceActions;
2492 
2493     if( ! ( modifierState & ( ControlMask | ShiftMask ) ) )
2494     {
2495         if( ! nNewDropAction )
2496         {
2497             // default to an action so the user does not have to press
2498             // keys explicitly
2499             if( m_nSourceActions & DNDConstants::ACTION_MOVE )
2500                 nNewDropAction = DNDConstants::ACTION_MOVE;
2501             else if( m_nSourceActions & DNDConstants::ACTION_COPY )
2502                 nNewDropAction = DNDConstants::ACTION_COPY;
2503             else if( m_nSourceActions & DNDConstants::ACTION_LINK )
2504                 nNewDropAction = DNDConstants::ACTION_LINK;
2505         }
2506         nNewDropAction |= DNDConstants::ACTION_DEFAULT;
2507     }
2508 
2509     if( nNewDropAction != m_nUserDragAction || m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT )
2510     {
2511 #if OSL_DEBUG_LEVEL > 1
2512         fprintf( stderr, "updateDragAction: %x -> %x\n", (int)m_nUserDragAction, (int)nNewDropAction );
2513 #endif
2514         bRet = true;
2515         m_nUserDragAction = nNewDropAction;
2516 
2517         DragSourceDragEvent dsde;
2518         dsde.Source             = static_cast< OWeakObject* >(this);
2519         dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2520         dsde.DragSource         = static_cast< XDragSource* >(this);
2521         dsde.DropAction         = m_nUserDragAction;
2522         dsde.UserAction         = m_nUserDragAction;
2523         m_nTargetAcceptAction   = DNDConstants::ACTION_DEFAULT; // invalidate last accept
2524         m_xDragSourceListener->dropActionChanged( dsde );
2525     }
2526     return bRet;
2527 }
2528 
2529 // ------------------------------------------------------------------------
2530 
sendDropPosition(bool bForce,XLIB_Time eventTime)2531 void SelectionManager::sendDropPosition( bool bForce, XLIB_Time eventTime )
2532 {
2533     ClearableMutexGuard aGuard(m_aMutex);
2534 
2535     if( m_bDropSent )
2536         return;
2537 
2538     ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
2539           m_aDropTargets.find( m_aDropWindow );
2540     if( it != m_aDropTargets.end() )
2541     {
2542         if( it->second.m_pTarget->m_bActive )
2543         {
2544             int x, y;
2545             XLIB_Window aChild;
2546             XTranslateCoordinates( m_pDisplay, it->second.m_aRootWindow, m_aDropWindow, m_nLastDragX, m_nLastDragY, &x, &y, &aChild );
2547             DropTargetDragEvent dtde;
2548             dtde.Source         = static_cast< OWeakObject* >(it->second.m_pTarget );
2549             dtde.Context        = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
2550             dtde.LocationX      = x;
2551             dtde.LocationY      = y;
2552             dtde.DropAction     = getUserDragAction();
2553             dtde.SourceActions  = m_nSourceActions;
2554             aGuard.clear();
2555             it->second->dragOver( dtde );
2556         }
2557     }
2558     else if( bForce ||
2559 
2560              m_nLastDragX < m_nNoPosX || m_nLastDragX >= m_nNoPosX+m_nNoPosWidth ||
2561              m_nLastDragY < m_nNoPosY || m_nLastDragY >= m_nNoPosY+m_nNoPosHeight
2562              )
2563     {
2564         // send XdndPosition
2565         XEvent aEvent;
2566         aEvent.type = ClientMessage;
2567         aEvent.xclient.display      = m_pDisplay;
2568         aEvent.xclient.format       = 32;
2569         aEvent.xclient.message_type = m_nXdndPosition;
2570         aEvent.xclient.window       = m_aDropWindow;
2571         aEvent.xclient.data.l[0]    = m_aWindow;
2572         aEvent.xclient.data.l[1]    = 0;
2573         aEvent.xclient.data.l[2]    = m_nLastDragX << 16 | (m_nLastDragY&0xffff);
2574         aEvent.xclient.data.l[3]    = eventTime;
2575 
2576         if( m_nUserDragAction & DNDConstants::ACTION_COPY )
2577             aEvent.xclient.data.l[4]=m_nXdndActionCopy;
2578         else if( m_nUserDragAction & DNDConstants::ACTION_MOVE )
2579             aEvent.xclient.data.l[4]=m_nXdndActionMove;
2580         else if( m_nUserDragAction & DNDConstants::ACTION_LINK )
2581             aEvent.xclient.data.l[4]=m_nXdndActionLink;
2582         else
2583             aEvent.xclient.data.l[4]=m_nXdndActionCopy;
2584         XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
2585         m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
2586     }
2587 }
2588 
2589 // ------------------------------------------------------------------------
2590 
handleDragEvent(XEvent & rMessage)2591 bool SelectionManager::handleDragEvent( XEvent& rMessage )
2592 {
2593     if( ! m_xDragSourceListener.is() )
2594         return false;
2595 
2596     ResettableMutexGuard aGuard(m_aMutex);
2597 
2598     bool bHandled = false;
2599 
2600     // for shortcut
2601     ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
2602           m_aDropTargets.find( m_aDropWindow );
2603 #if OSL_DEBUG_LEVEL > 1
2604     switch( rMessage.type )
2605     {
2606         case ClientMessage:
2607             fprintf( stderr, "handleDragEvent: %s\n", OUStringToOString( getString( rMessage.xclient.message_type ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
2608             break;
2609         case MotionNotify:
2610 //          fprintf( stderr, "handleDragEvent: MotionNotify\n" );
2611             break;
2612         case EnterNotify:
2613             fprintf( stderr, "handleDragEvent: EnterNotify\n" );
2614             break;
2615         case LeaveNotify:
2616             fprintf( stderr, "handleDragEvent: LeaveNotify\n" );
2617             break;
2618         case ButtonPress:
2619             fprintf( stderr, "handleDragEvent: ButtonPress %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
2620             break;
2621         case ButtonRelease:
2622             fprintf( stderr, "handleDragEvent: ButtonRelease %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
2623             break;
2624         case XLIB_KeyPress:
2625             fprintf( stderr, "handleDragEvent: KeyPress\n" );
2626             break;
2627         case KeyRelease:
2628             fprintf( stderr, "handleDragEvent: KeyRelease\n" );
2629             break;
2630         default:
2631             fprintf( stderr, "handleDragEvent: <unknown type %d>\n", rMessage.type );
2632             break;
2633     }
2634 #endif
2635 
2636     // handle drag related events
2637     if( rMessage.type == ClientMessage )
2638     {
2639         if( Atom(rMessage.xclient.message_type) == m_nXdndStatus && Atom(rMessage.xclient.data.l[0]) == m_aDropWindow )
2640         {
2641             bHandled = true;
2642             DragSourceDragEvent dsde;
2643             dsde.Source                 = static_cast< OWeakObject* >(this);
2644             dsde.DragSourceContext      = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2645             dsde.DragSource             = static_cast< XDragSource* >( this );
2646             dsde.UserAction = getUserDragAction();
2647             dsde.DropAction = DNDConstants::ACTION_NONE;
2648             m_bDropSuccess = rMessage.xclient.data.l[1] & 1 ? true : false;
2649 #if OSL_DEBUG_LEVEL > 1
2650             fprintf( stderr, "status drop action: accept = %s, %s\n",
2651                      m_bDropSuccess ? "true" : "false",
2652                      OUStringToOString( getString( rMessage.xclient.data.l[4] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
2653 #endif
2654             if( rMessage.xclient.data.l[1] & 1 )
2655             {
2656                 if( m_nCurrentProtocolVersion > 1 )
2657                 {
2658                     if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionCopy )
2659                         dsde.DropAction = DNDConstants::ACTION_COPY;
2660                     else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionMove )
2661                         dsde.DropAction = DNDConstants::ACTION_MOVE;
2662                     else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionLink )
2663                         dsde.DropAction = DNDConstants::ACTION_LINK;
2664                 }
2665                 else
2666                     dsde.DropAction = DNDConstants::ACTION_COPY;
2667             }
2668             m_nTargetAcceptAction = dsde.DropAction;
2669 
2670             if( ! ( rMessage.xclient.data.l[1] & 2 ) )
2671             {
2672                 m_nNoPosX       = rMessage.xclient.data.l[2] >> 16;
2673                 m_nNoPosY       = rMessage.xclient.data.l[2] & 0xffff;
2674                 m_nNoPosWidth   = rMessage.xclient.data.l[3] >> 16;
2675                 m_nNoPosHeight  = rMessage.xclient.data.l[3] & 0xffff;
2676             }
2677             else
2678                 m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
2679 
2680             setCursor( getDefaultCursor( dsde.DropAction ), m_aDropWindow, m_nDragTimestamp );
2681             aGuard.clear();
2682             m_xDragSourceListener->dragOver( dsde );
2683         }
2684         else if( Atom(rMessage.xclient.message_type) == m_nXdndFinished && m_aDropWindow == Atom(rMessage.xclient.data.l[0]) )
2685         {
2686             bHandled = true;
2687             // notify the listener
2688             DragSourceDropEvent dsde;
2689             dsde.Source             = static_cast< OWeakObject* >(this);
2690             dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2691             dsde.DragSource         = static_cast< XDragSource* >(this);
2692             dsde.DropAction         = m_nTargetAcceptAction;
2693             dsde.DropSuccess        = m_bDropSuccess;
2694             css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
2695             m_xDragSourceListener.clear();
2696             aGuard.clear();
2697             xListener->dragDropEnd( dsde );
2698         }
2699     }
2700     else if( rMessage.type == MotionNotify ||
2701              rMessage.type == EnterNotify || rMessage.type == LeaveNotify
2702              )
2703     {
2704         bHandled = true;
2705         bool bForce = false;
2706         int root_x  = rMessage.type == MotionNotify ? rMessage.xmotion.x_root : rMessage.xcrossing.x_root;
2707         int root_y  = rMessage.type == MotionNotify ? rMessage.xmotion.y_root : rMessage.xcrossing.y_root;
2708         XLIB_Window root = rMessage.type == MotionNotify ? rMessage.xmotion.root : rMessage.xcrossing.root;
2709         m_nDragTimestamp = rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time;
2710 
2711         aGuard.clear();
2712         if( rMessage.type == MotionNotify )
2713         {
2714             bForce = updateDragAction( rMessage.xmotion.state );
2715         }
2716         updateDragWindow( root_x, root_y, root );
2717         aGuard.reset();
2718 
2719         if( m_nCurrentProtocolVersion >= 0 && m_aDropProxy != None )
2720         {
2721             aGuard.clear();
2722             sendDropPosition( bForce, rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time );
2723         }
2724     }
2725     else if( rMessage.type == XLIB_KeyPress || rMessage.type == KeyRelease )
2726     {
2727         bHandled = true;
2728         const KeySym aKey = XkbKeycodeToKeysym( m_pDisplay, rMessage.xkey.keycode, 0, 0 );
2729         if( aKey == XK_Escape )
2730         {
2731             // abort drag
2732             if( it != m_aDropTargets.end() )
2733             {
2734                 DropTargetEvent dte;
2735                 dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
2736                 aGuard.clear();
2737                 it->second.m_pTarget->dragExit( dte );
2738             }
2739             else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
2740             {
2741                 // send XdndLeave
2742                 XEvent aEvent;
2743                 aEvent.type = ClientMessage;
2744                 aEvent.xclient.display      = m_pDisplay;
2745                 aEvent.xclient.format       = 32;
2746                 aEvent.xclient.message_type = m_nXdndLeave;
2747                 aEvent.xclient.window       = m_aDropWindow;
2748                 aEvent.xclient.data.l[0]    = m_aWindow;
2749                 memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
2750                 m_aDropWindow = m_aDropProxy = None;
2751                 XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
2752             }
2753             // notify the listener
2754             DragSourceDropEvent dsde;
2755             dsde.Source             = static_cast< OWeakObject* >(this);
2756             dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2757             dsde.DragSource         = static_cast< XDragSource* >(this);
2758             dsde.DropAction         = DNDConstants::ACTION_NONE;
2759             dsde.DropSuccess        = sal_False;
2760             css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
2761             m_xDragSourceListener.clear();
2762             aGuard.clear();
2763             xListener->dragDropEnd( dsde );
2764         }
2765         else
2766         {
2767             /*
2768              *  man page says: state is state immediate PRIOR to the
2769              *  event. It would seem that this is a somewhat arguable
2770              *  design decision.
2771              */
2772             int nState = rMessage.xkey.state;
2773             int nNewState = 0;
2774             switch( aKey )
2775             {
2776                 case XK_Shift_R:
2777                 case XK_Shift_L: nNewState = ShiftMask;break;
2778                 case XK_Control_R:
2779                 case XK_Control_L: nNewState = ControlMask;break;
2780                     // just interested in shift and ctrl for dnd
2781             }
2782             if( rMessage.type == XLIB_KeyPress )
2783                 nState |= nNewState;
2784             else
2785                 nState &= ~nNewState;
2786             aGuard.clear();
2787             if( updateDragAction( nState ) )
2788                 sendDropPosition( true, rMessage.xkey.time );
2789         }
2790     }
2791     else if(
2792             ( rMessage.type == ButtonPress || rMessage.type == ButtonRelease ) &&
2793             rMessage.xbutton.button == m_nDragButton )
2794     {
2795         bool bCancel = true;
2796         if( m_aDropWindow != None )
2797         {
2798             if( it != m_aDropTargets.end() )
2799             {
2800                 if( it->second.m_pTarget->m_bActive && m_nUserDragAction != DNDConstants::ACTION_NONE && m_bLastDropAccepted )
2801                 {
2802                     bHandled = true;
2803                     int x, y;
2804                     XLIB_Window aChild;
2805                     XTranslateCoordinates( m_pDisplay, rMessage.xbutton.root, m_aDropWindow, rMessage.xbutton.x_root, rMessage.xbutton.y_root, &x, &y, &aChild );
2806                     DropTargetDropEvent dtde;
2807                     dtde.Source         = static_cast< OWeakObject* >(it->second.m_pTarget );
2808                     dtde.Context        = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
2809                     dtde.LocationX      = x;
2810                     dtde.LocationY      = y;
2811                     dtde.DropAction     = m_nUserDragAction;
2812                     dtde.SourceActions  = m_nSourceActions;
2813                     dtde.Transferable   = m_xDragSourceTransferable;
2814                     m_bDropSent                 = true;
2815                     m_nDropTimeout              = time( NULL );
2816                     m_bDropWaitingForCompletion = true;
2817                     aGuard.clear();
2818                     it->second->drop( dtde );
2819                     bCancel = false;
2820                 }
2821                 else bCancel = true;
2822             }
2823             else if( m_nCurrentProtocolVersion >= 0 )
2824             {
2825                 bHandled = true;
2826 
2827                 XEvent aEvent;
2828                 aEvent.type = ClientMessage;
2829                 aEvent.xclient.display      = m_pDisplay;
2830                 aEvent.xclient.format       = 32;
2831                 aEvent.xclient.message_type = m_nXdndDrop;
2832                 aEvent.xclient.window       = m_aDropWindow;
2833                 aEvent.xclient.data.l[0]    = m_aWindow;
2834                 aEvent.xclient.data.l[1]    = 0;
2835                 aEvent.xclient.data.l[2]    = rMessage.xbutton.time;
2836                 aEvent.xclient.data.l[3]    = 0;
2837                 aEvent.xclient.data.l[4]    = 0;
2838 
2839                 m_bDropSent                 = true;
2840                 m_nDropTimeout              = time( NULL );
2841                 XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
2842                 bCancel = false;
2843             }
2844             else
2845             {
2846                 // dropping on non XdndWindows: acquire ownership of
2847                 // PRIMARY and send a middle mouse button click down/up to
2848                 // target window
2849                 SelectionAdaptor* pAdaptor = getAdaptor( XA_PRIMARY );
2850                 if( pAdaptor )
2851                 {
2852                     bHandled = true;
2853 
2854                     XLIB_Window aDummy;
2855                     XEvent aEvent;
2856                     aEvent.type = ButtonPress;
2857                     aEvent.xbutton.display      = m_pDisplay;
2858                     aEvent.xbutton.window       = m_aDropWindow;
2859                     aEvent.xbutton.root         = rMessage.xbutton.root;
2860                     aEvent.xbutton.subwindow    = m_aDropWindow;
2861                     aEvent.xbutton.time         = rMessage.xbutton.time+1;
2862                     aEvent.xbutton.x_root       = rMessage.xbutton.x_root;
2863                     aEvent.xbutton.y_root       = rMessage.xbutton.y_root;
2864                     aEvent.xbutton.state        = rMessage.xbutton.state;
2865                     aEvent.xbutton.button       = Button2;
2866                     aEvent.xbutton.same_screen  = True;
2867                     XTranslateCoordinates( m_pDisplay,
2868                                            rMessage.xbutton.root, m_aDropWindow,
2869                                            rMessage.xbutton.x_root, rMessage.xbutton.y_root,
2870                                            &aEvent.xbutton.x, &aEvent.xbutton.y,
2871                                            &aDummy );
2872                     XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonPressMask, &aEvent );
2873                     aEvent.xbutton.type   = ButtonRelease;
2874                     aEvent.xbutton.time++;
2875                     aEvent.xbutton.state |= Button2Mask;
2876                     XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonReleaseMask, &aEvent );
2877 
2878                     m_bDropSent                 = true;
2879                     m_nDropTimeout              = time( NULL );
2880                     XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
2881                     m_bWaitingForPrimaryConversion  = true;
2882                     m_bDropSent                     = true;
2883                     m_nDropTimeout                  = time( NULL );
2884                     // HACK :-)
2885                     aGuard.clear();
2886                     static_cast< X11Clipboard* >( pAdaptor )->setContents( m_xDragSourceTransferable, css::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >() );
2887                     aGuard.reset();
2888                     bCancel = false;
2889                 }
2890             }
2891         }
2892         if( bCancel )
2893         {
2894             // cancel drag
2895             DragSourceDropEvent dsde;
2896             dsde.Source             = static_cast< OWeakObject* >(this);
2897             dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2898             dsde.DragSource         = static_cast< XDragSource* >(this);
2899             dsde.DropAction         = DNDConstants::ACTION_NONE;
2900             dsde.DropSuccess        = sal_False;
2901             css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
2902             m_xDragSourceListener.clear();
2903             aGuard.clear();
2904             xListener->dragDropEnd( dsde );
2905             bHandled = true;
2906         }
2907     }
2908     return bHandled;
2909 }
2910 
2911 // ------------------------------------------------------------------------
2912 
accept(sal_Int8 dragOperation,XLIB_Window aDropWindow,XLIB_Time)2913 void SelectionManager::accept( sal_Int8 dragOperation, XLIB_Window aDropWindow, XLIB_Time )
2914 {
2915     if( aDropWindow == m_aCurrentDropWindow )
2916     {
2917 #if OSL_DEBUG_LEVEL > 1
2918         fprintf( stderr, "accept: %x\n", dragOperation );
2919 #endif
2920         Atom nAction = None;
2921         dragOperation &= (DNDConstants::ACTION_MOVE | DNDConstants::ACTION_COPY | DNDConstants::ACTION_LINK);
2922         if( dragOperation & DNDConstants::ACTION_MOVE )
2923             nAction = m_nXdndActionMove;
2924         else if( dragOperation & DNDConstants::ACTION_COPY )
2925             nAction = m_nXdndActionCopy;
2926         else if( dragOperation & DNDConstants::ACTION_LINK )
2927             nAction = m_nXdndActionLink;
2928         m_bLastDropAccepted = true;
2929         sendDragStatus( nAction );
2930     }
2931 }
2932 
2933 // ------------------------------------------------------------------------
2934 
reject(XLIB_Window aDropWindow,XLIB_Time)2935 void SelectionManager::reject( XLIB_Window aDropWindow, XLIB_Time )
2936 {
2937     if( aDropWindow == m_aCurrentDropWindow )
2938     {
2939 #if OSL_DEBUG_LEVEL > 1
2940         fprintf( stderr, "reject\n" );
2941 #endif
2942         m_bLastDropAccepted = false;
2943         sendDragStatus( None );
2944         if( m_bDropSent && m_xDragSourceListener.is() )
2945         {
2946             DragSourceDropEvent dsde;
2947             dsde.Source             = static_cast< OWeakObject* >(this);
2948             dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
2949             dsde.DragSource         = static_cast< XDragSource* >(this);
2950             dsde.DropAction         = DNDConstants::ACTION_NONE;
2951             dsde.DropSuccess        = sal_False;
2952             m_xDragSourceListener->dragDropEnd( dsde );
2953             m_xDragSourceListener.clear();
2954         }
2955     }
2956 }
2957 
2958 /*
2959  *  XDragSource
2960  */
2961 
isDragImageSupported()2962 sal_Bool SelectionManager::isDragImageSupported() throw()
2963 {
2964     return sal_False;
2965 }
2966 
2967 // ------------------------------------------------------------------------
2968 
getDefaultCursor(sal_Int8 dragAction)2969 sal_Int32 SelectionManager::getDefaultCursor( sal_Int8 dragAction ) throw()
2970 {
2971     XLIB_Cursor aCursor = m_aNoneCursor;
2972     if( dragAction & DNDConstants::ACTION_MOVE )
2973         aCursor = m_aMoveCursor;
2974     else if( dragAction & DNDConstants::ACTION_COPY )
2975         aCursor = m_aCopyCursor;
2976     else if( dragAction & DNDConstants::ACTION_LINK )
2977         aCursor = m_aLinkCursor;
2978     return aCursor;
2979 }
2980 
2981 // ------------------------------------------------------------------------
2982 
getXdndVersion(XLIB_Window aWindow,XLIB_Window & rProxy)2983 int SelectionManager::getXdndVersion( XLIB_Window aWindow, XLIB_Window& rProxy )
2984 {
2985     Atom* pProperties = NULL;
2986     int nProperties = 0;
2987     Atom nType;
2988     int nFormat;
2989     unsigned long nItems, nBytes;
2990     unsigned char* pBytes = NULL;
2991 
2992     int nVersion = -1;
2993     rProxy = None;
2994 
2995     /*
2996      *  XListProperties is used here to avoid unnecessary XGetWindowProperty calls
2997      *  and therefore reducing latency penalty
2998      */
2999     pProperties = XListProperties( m_pDisplay, aWindow, &nProperties );
3000     // first look for proxy
3001     int i;
3002     for( i = 0; i < nProperties; i++ )
3003     {
3004         if( pProperties[i] == m_nXdndProxy )
3005         {
3006             XGetWindowProperty( m_pDisplay, aWindow, m_nXdndProxy, 0, 1, False, XA_WINDOW,
3007                                 &nType, &nFormat, &nItems, &nBytes, &pBytes );
3008             if( pBytes )
3009             {
3010                 if( nType == XA_WINDOW )
3011                     rProxy = *(XLIB_Window*)pBytes;
3012                 XFree( pBytes );
3013                 pBytes = NULL;
3014                 if( rProxy != None )
3015                 {
3016                     // now check proxy wether it points to itself
3017                     XGetWindowProperty( m_pDisplay, rProxy, m_nXdndProxy, 0, 1, False, XA_WINDOW,
3018                                         &nType, &nFormat, &nItems, &nBytes, &pBytes );
3019                     if( pBytes )
3020                     {
3021                         if( nType == XA_WINDOW && *(XLIB_Window*)pBytes != rProxy )
3022                             rProxy = None;
3023                         XFree( pBytes );
3024                         pBytes = NULL;
3025                     }
3026                     else
3027                         rProxy = None;
3028                 }
3029             }
3030             break;
3031         }
3032     }
3033     XLIB_Window aAwareWindow = rProxy != None ? rProxy : aWindow;
3034 
3035     XGetWindowProperty( m_pDisplay, aAwareWindow, m_nXdndAware, 0, 1, False, XA_ATOM,
3036                         &nType, &nFormat, &nItems, &nBytes, &pBytes );
3037     if( pBytes )
3038     {
3039         if( nType == XA_ATOM )
3040             nVersion = *(Atom*)pBytes;
3041         XFree( pBytes );
3042     }
3043 
3044     nVersion = nVersion > nXdndProtocolRevision ? nXdndProtocolRevision : nVersion;
3045 
3046     return nVersion;
3047 }
3048 
3049 // ------------------------------------------------------------------------
3050 
updateDragWindow(int nX,int nY,XLIB_Window aRoot)3051 void SelectionManager::updateDragWindow( int nX, int nY, XLIB_Window aRoot )
3052 {
3053     ResettableMutexGuard aGuard( m_aMutex );
3054 
3055     css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
3056 
3057     m_nLastDragX = nX;
3058     m_nLastDragY = nY;
3059 
3060     XLIB_Window aParent = aRoot;
3061     XLIB_Window aChild;
3062     XLIB_Window aNewProxy = None, aNewCurrentWindow = None;
3063     int nNewProtocolVersion = -1;
3064     int nWinX, nWinY;
3065 
3066     // find the first XdndAware window or check if root window is
3067     // XdndAware or has XdndProxy
3068     do
3069     {
3070         XTranslateCoordinates( m_pDisplay, aRoot, aParent, nX, nY, &nWinX, &nWinY, &aChild );
3071         if( aChild != None )
3072         {
3073             if( aChild == m_aCurrentDropWindow && aChild != aRoot && m_nCurrentProtocolVersion >= 0 )
3074             {
3075                 aParent = aChild;
3076                 break;
3077             }
3078             nNewProtocolVersion = getXdndVersion( aChild, aNewProxy );
3079             aParent = aChild;
3080         }
3081     } while( aChild != None && nNewProtocolVersion < 0 );
3082 
3083     aNewCurrentWindow = aParent;
3084     if( aNewCurrentWindow == aRoot )
3085     {
3086         // no children, try root drop
3087         nNewProtocolVersion = getXdndVersion( aNewCurrentWindow, aNewProxy );
3088         if( nNewProtocolVersion < 3 )
3089         {
3090             aNewCurrentWindow = aNewProxy = None;
3091             nNewProtocolVersion = nXdndProtocolRevision;
3092         }
3093     }
3094 
3095 
3096     DragSourceDragEvent dsde;
3097     dsde.Source             = static_cast< OWeakObject* >(this);
3098     dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
3099     dsde.DragSource         = static_cast< XDragSource* >(this);
3100     dsde.DropAction         = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
3101     dsde.UserAction         = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
3102 
3103     ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it;
3104     if( aNewCurrentWindow != m_aDropWindow )
3105     {
3106 #if OSL_DEBUG_LEVEL > 1
3107         fprintf( stderr, "drag left window 0x%lx (rev. %d), entered window 0x%lx (rev %d)\n", m_aDropWindow, m_nCurrentProtocolVersion, aNewCurrentWindow, nNewProtocolVersion );
3108 #endif
3109 
3110         if( m_aDropWindow != None )
3111         {
3112             it = m_aDropTargets.find( m_aDropWindow );
3113             if( it != m_aDropTargets.end() )
3114                 // shortcut for own drop targets
3115             {
3116                 DropTargetEvent dte;
3117                 dte.Source  = static_cast< OWeakObject* >( it->second.m_pTarget );
3118                 aGuard.clear();
3119                 it->second.m_pTarget->dragExit( dte );
3120                 aGuard.reset();
3121             }
3122             else
3123             {
3124                 // send old drop target a XdndLeave
3125                 XEvent aEvent;
3126                 aEvent.type = ClientMessage;
3127                 aEvent.xclient.display          = m_pDisplay;
3128                 aEvent.xclient.format           = 32;
3129                 aEvent.xclient.message_type     = m_nXdndLeave;
3130                 aEvent.xclient.window           = m_aDropWindow;
3131                 aEvent.xclient.data.l[0]        = m_aWindow;
3132                 aEvent.xclient.data.l[1]        = 0;
3133                 XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
3134             }
3135             if( xListener.is() )
3136             {
3137                 aGuard.clear();
3138                 xListener->dragExit( dsde );
3139                 aGuard.reset();
3140             }
3141         }
3142 
3143         m_nCurrentProtocolVersion   = nNewProtocolVersion;
3144         m_aDropWindow               = aNewCurrentWindow;
3145         m_aDropProxy                = aNewProxy != None ? aNewProxy : m_aDropWindow;
3146 
3147         it = m_aDropTargets.find( m_aDropWindow );
3148         if( it != m_aDropTargets.end() && ! it->second.m_pTarget->m_bActive )
3149             m_aDropProxy = None;
3150 
3151         if( m_aDropProxy != None && xListener.is() )
3152         {
3153             aGuard.clear();
3154             xListener->dragEnter( dsde );
3155             aGuard.reset();
3156         }
3157         // send XdndEnter
3158         if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
3159         {
3160             it = m_aDropTargets.find( m_aDropWindow );
3161             if( it != m_aDropTargets.end() )
3162             {
3163                 XTranslateCoordinates( m_pDisplay, aRoot, m_aDropWindow, nX, nY, &nWinX, &nWinY, &aChild );
3164                 DropTargetDragEnterEvent dtde;
3165                 dtde.Source                 = static_cast< OWeakObject* >( it->second.m_pTarget );
3166                 dtde.Context                = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
3167                 dtde.LocationX              = nWinX;
3168                 dtde.LocationY              = nWinY;
3169                 dtde.DropAction             = m_nUserDragAction;
3170                 dtde.SourceActions          = m_nSourceActions;
3171                 dtde.SupportedDataFlavors   = m_xDragSourceTransferable->getTransferDataFlavors();
3172                 aGuard.clear();
3173                 it->second.m_pTarget->dragEnter( dtde );
3174                 aGuard.reset();
3175             }
3176             else
3177             {
3178                 XEvent aEvent;
3179                 aEvent.type = ClientMessage;
3180                 aEvent.xclient.display          = m_pDisplay;
3181                 aEvent.xclient.format           = 32;
3182                 aEvent.xclient.message_type = m_nXdndEnter;
3183                 aEvent.xclient.window       = m_aDropWindow;
3184                 aEvent.xclient.data.l[0]    = m_aWindow;
3185                 aEvent.xclient.data.l[1]    = m_nCurrentProtocolVersion << 24;
3186                 memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
3187                 // fill in data types
3188                 ::std::list< Atom > aConversions;
3189                 getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
3190                 if( aConversions.size() > 3 )
3191                     aEvent.xclient.data.l[1] |= 1;
3192                 ::std::list< Atom >::const_iterator type_it = aConversions.begin();
3193                 for( int i = 0; type_it != aConversions.end() && i < 3; i++, ++type_it )
3194                     aEvent.xclient.data.l[i+2] = *type_it;
3195                 XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
3196             }
3197         }
3198         m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
3199     }
3200     else if( m_aDropProxy != None && xListener.is() )
3201     {
3202         aGuard.clear();
3203         // drag over for XdndAware windows comes when receiving XdndStatus
3204         xListener->dragOver( dsde );
3205     }
3206 }
3207 
3208 // ------------------------------------------------------------------------
3209 
startDrag(const DragGestureEvent & trigger,sal_Int8 sourceActions,sal_Int32,sal_Int32,const css::uno::Reference<XTransferable> & transferable,const css::uno::Reference<XDragSourceListener> & listener)3210 void SelectionManager::startDrag(
3211                                  const DragGestureEvent& trigger,
3212                                  sal_Int8 sourceActions,
3213                                  sal_Int32,
3214                                  sal_Int32,
3215                                  const css::uno::Reference< XTransferable >& transferable,
3216                                  const css::uno::Reference< XDragSourceListener >& listener
3217                                  ) throw()
3218 {
3219 #if OSL_DEBUG_LEVEL > 1
3220     fprintf( stderr, "startDrag( sourceActions = %x )\n", (int)sourceActions );
3221 #endif
3222 
3223     DragSourceDropEvent aDragFailedEvent;
3224     aDragFailedEvent.Source             = static_cast< OWeakObject* >(this);
3225     aDragFailedEvent.DragSource         = static_cast< XDragSource* >(this);
3226     aDragFailedEvent.DragSourceContext  = new DragSourceContext( None, CurrentTime, *this );
3227     aDragFailedEvent.DropAction         = DNDConstants::ACTION_NONE;
3228     aDragFailedEvent.DropSuccess        = sal_False;
3229 
3230     if( m_aDragRunning.check() )
3231     {
3232         if( listener.is() )
3233             listener->dragDropEnd( aDragFailedEvent );
3234 
3235 #if OSL_DEBUG_LEVEL > 1
3236         fprintf( stderr, "*** ERROR *** second drag and drop started.\n" );
3237         if( m_xDragSourceListener.is() )
3238             fprintf( stderr, "*** ERROR *** drag source listener already set.\n" );
3239         else
3240             fprintf( stderr, "*** ERROR *** drag thread already running.\n" );
3241 #endif
3242         return;
3243     }
3244 
3245     SalFrame* pCaptureFrame = NULL;
3246 
3247     {
3248         ClearableMutexGuard aGuard(m_aMutex);
3249 
3250         // first get the current pointer position and the window that
3251         // the pointer is located in. since said window should be one
3252         // of our DropTargets at the time of executeDrag we can use
3253         // them for a start
3254         XLIB_Window aRoot, aParent, aChild;
3255         int root_x(0), root_y(0), win_x, win_y;
3256         unsigned int mask(0);
3257 
3258         ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it;
3259         it = m_aDropTargets.begin();
3260         while( it != m_aDropTargets.end() )
3261         {
3262             if( XQueryPointer( m_pDisplay, it->second.m_aRootWindow,
3263                                &aRoot, &aParent,
3264                                &root_x, &root_y,
3265                                &win_x, &win_y,
3266                                &mask ) )
3267             {
3268                 aParent = it->second.m_aRootWindow;
3269                 break;
3270             }
3271             ++it;
3272         }
3273 
3274         // don't start DnD if there is none of our windows on the same screen as
3275         // the pointer or if no mouse button is pressed
3276         if( it == m_aDropTargets.end() || (mask & (Button1Mask|Button2Mask|Button3Mask)) == 0 )
3277         {
3278             aGuard.clear();
3279             if( listener.is() )
3280                 listener->dragDropEnd( aDragFailedEvent );
3281             return;
3282         }
3283 
3284         // try to find which of our drop targets is the drag source
3285         // if that drop target is deregistered we should stop executing
3286         // the drag (actually this is a poor substitute for an "endDrag"
3287         // method ).
3288         m_aDragSourceWindow = None;
3289         aParent = aRoot = it->second.m_aRootWindow;
3290         do
3291         {
3292             XTranslateCoordinates( m_pDisplay, aRoot, aParent, root_x, root_y, &win_x, &win_y, &aChild );
3293             if( aChild != None && m_aDropTargets.find( aChild ) != m_aDropTargets.end() )
3294             {
3295                 m_aDragSourceWindow = aChild;
3296 #if OSL_DEBUG_LEVEL > 1
3297                 fprintf( stderr, "found drag source window 0x%lx\n", m_aDragSourceWindow );
3298 #endif
3299                 break;
3300             }
3301             aParent = aChild;
3302         } while( aChild != None );
3303 
3304 
3305 #if OSL_DEBUG_LEVEL > 1
3306         fprintf( stderr, "try to grab pointer ... " );
3307 #endif
3308         int nPointerGrabSuccess =
3309             XGrabPointer( m_pDisplay, it->second.m_aRootWindow, True,
3310                           DRAG_EVENT_MASK,
3311                           GrabModeAsync, GrabModeAsync,
3312                           None,
3313                           None,
3314                           CurrentTime );
3315         /* if we could not grab the pointer here, there is a chance
3316            that the pointer is grabbed by the other vcl display (the main loop)
3317            so let's break that grab an reset it later
3318 
3319            remark: this whole code should really be molten into normal vcl so only
3320            one display is used ....
3321         */
3322         if( nPointerGrabSuccess != GrabSuccess )
3323         {
3324             vos::IMutex& rSolarMutex( Application::GetSolarMutex() );
3325             if( rSolarMutex.tryToAcquire() )
3326             {
3327                 pCaptureFrame = GetX11SalData()->GetDisplay()->GetCaptureFrame();
3328                 if( pCaptureFrame )
3329                 {
3330                     GetX11SalData()->GetDisplay()->CaptureMouse( NULL );
3331                     nPointerGrabSuccess =
3332                                 XGrabPointer( m_pDisplay, it->second.m_aRootWindow, True,
3333                                               DRAG_EVENT_MASK,
3334                                               GrabModeAsync, GrabModeAsync,
3335                                               None,
3336                                               None,
3337                                               CurrentTime );
3338                 }
3339             }
3340         }
3341 #if OSL_DEBUG_LEVEL > 1
3342         fprintf( stderr, "%d\n", nPointerGrabSuccess );
3343 #endif
3344 #if OSL_DEBUG_LEVEL > 1
3345         fprintf( stderr, "try to grab keyboard ... " );
3346 #endif
3347         int nKeyboardGrabSuccess =
3348             XGrabKeyboard( m_pDisplay, it->second.m_aRootWindow, True,
3349                            GrabModeAsync, GrabModeAsync, CurrentTime );
3350 #if OSL_DEBUG_LEVEL > 1
3351         fprintf( stderr, "%d\n", nKeyboardGrabSuccess );
3352 #endif
3353         if( nPointerGrabSuccess != GrabSuccess || nKeyboardGrabSuccess != GrabSuccess )
3354         {
3355             if( nPointerGrabSuccess == GrabSuccess )
3356                 XUngrabPointer( m_pDisplay, CurrentTime );
3357             if( nKeyboardGrabSuccess == GrabSuccess )
3358                 XUngrabKeyboard( m_pDisplay, CurrentTime );
3359             XFlush( m_pDisplay );
3360             aGuard.clear();
3361             if( listener.is() )
3362                 listener->dragDropEnd( aDragFailedEvent );
3363             if( pCaptureFrame )
3364             {
3365                 vos::IMutex& rSolarMutex( Application::GetSolarMutex() );
3366                 if( rSolarMutex.tryToAcquire() )
3367                     GetX11SalData()->GetDisplay()->CaptureMouse( pCaptureFrame );
3368 #if OSL_DEBUG_LEVEL > 0
3369                 else
3370                     OSL_ENSURE( 0, "failed to acquire SolarMutex to reset capture frame" );
3371 #endif
3372             }
3373             return;
3374         }
3375 
3376         m_xDragSourceTransferable   = transferable;
3377         m_xDragSourceListener       = listener;
3378         m_aDragFlavors              = transferable->getTransferDataFlavors();
3379         m_aCurrentCursor            = None;
3380 
3381         requestOwnership( m_nXdndSelection );
3382 
3383         ::std::list< Atom > aConversions;
3384         ::std::list< Atom >::const_iterator type_it;
3385         getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
3386 
3387         int nTypes = aConversions.size();
3388         Atom* pTypes = (Atom*)alloca( sizeof(Atom)*nTypes );
3389         type_it = aConversions.begin();
3390         for( int n = 0; n < nTypes; n++, ++type_it )
3391             pTypes[n] = *type_it;
3392 
3393         XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
3394 
3395         m_nSourceActions                = sourceActions | DNDConstants::ACTION_DEFAULT;
3396         m_nUserDragAction               = DNDConstants::ACTION_MOVE & m_nSourceActions;
3397         if( ! m_nUserDragAction )
3398             m_nUserDragAction           = DNDConstants::ACTION_COPY & m_nSourceActions;
3399         if( ! m_nUserDragAction )
3400             m_nUserDragAction           = DNDConstants::ACTION_LINK & m_nSourceActions;
3401         m_nTargetAcceptAction           = DNDConstants::ACTION_DEFAULT;
3402         m_bDropSent                     = false;
3403         m_bDropSuccess                  = false;
3404         m_bWaitingForPrimaryConversion  = false;
3405         m_nDragButton                   = Button1; // default to left button
3406         com::sun::star::awt::MouseEvent aEvent;
3407         if( trigger.Event >>= aEvent )
3408         {
3409             if( aEvent.Buttons & MouseButton::LEFT )
3410                 m_nDragButton = Button1;
3411             else if( aEvent.Buttons & MouseButton::RIGHT )
3412                 m_nDragButton = Button3;
3413             else if( aEvent.Buttons & MouseButton::MIDDLE )
3414                 m_nDragButton = Button2;
3415         }
3416 #if OSL_DEBUG_LEVEL > 1
3417         fprintf( stderr, "m_nUserDragAction = %x\n", (int)m_nUserDragAction );
3418 #endif
3419         updateDragWindow( root_x, root_y, aRoot );
3420         m_nUserDragAction = ~0;
3421         updateDragAction( mask );
3422     }
3423 
3424     m_aDragRunning.set();
3425     m_aDragExecuteThread = osl_createSuspendedThread( call_SelectionManager_runDragExecute, this );
3426     if( m_aDragExecuteThread )
3427         osl_resumeThread( m_aDragExecuteThread );
3428     else
3429     {
3430 #if OSL_DEBUG_LEVEL > 1
3431         fprintf( stderr, "osl_createSuspendedThread failed for drag execute\n" );
3432 #endif
3433         m_xDragSourceListener.clear();
3434         m_xDragSourceTransferable.clear();
3435 
3436         m_bDropSent                         = false;
3437         m_bDropSuccess                      = false;
3438         m_bWaitingForPrimaryConversion      = false;
3439         m_aDropWindow                       = None;
3440         m_aDropProxy                        = None;
3441         m_nCurrentProtocolVersion           = nXdndProtocolRevision;
3442         m_nNoPosX                           = 0;
3443         m_nNoPosY                           = 0;
3444         m_nNoPosWidth                       = 0;
3445         m_nNoPosHeight                      = 0;
3446         m_aCurrentCursor                    = None;
3447 
3448         XUngrabPointer( m_pDisplay, CurrentTime );
3449         XUngrabKeyboard( m_pDisplay, CurrentTime );
3450         XFlush( m_pDisplay );
3451 
3452         if( pCaptureFrame )
3453         {
3454             vos::IMutex& rSolarMutex( Application::GetSolarMutex() );
3455             if( rSolarMutex.tryToAcquire() )
3456                 GetX11SalData()->GetDisplay()->CaptureMouse( pCaptureFrame );
3457 #if OSL_DEBUG_LEVEL > 0
3458             else
3459                 OSL_ENSURE( 0, "failed to acquire SolarMutex to reset capture frame" );
3460 #endif
3461         }
3462 
3463         m_aDragRunning.reset();
3464 
3465         if( listener.is() )
3466             listener->dragDropEnd( aDragFailedEvent );
3467     }
3468 }
3469 
runDragExecute(void * pThis)3470 void SelectionManager::runDragExecute( void* pThis )
3471 {
3472     SelectionManager* This = (SelectionManager*)pThis;
3473     This->dragDoDispatch();
3474 }
3475 
dragDoDispatch()3476 void SelectionManager::dragDoDispatch()
3477 {
3478 
3479     // do drag
3480     // m_xDragSourceListener will be cleared on finished drop
3481 #if OSL_DEBUG_LEVEL > 1
3482     fprintf( stderr, "begin executeDrag dispatching\n" );
3483 #endif
3484     TimeValue aTVal;
3485     aTVal.Seconds = 0;
3486     aTVal.Nanosec = 200000000;
3487     oslThread aThread = m_aDragExecuteThread;
3488     while( m_xDragSourceListener.is() && ( ! m_bDropSent || time(NULL)-m_nDropTimeout < 5 ) && osl_scheduleThread( aThread ) )
3489     {
3490         // let the thread in the run method do the dispatching
3491         // just look occasionally here whether drop timed out or is completed
3492         osl_waitThread( &aTVal );
3493     }
3494 #if OSL_DEBUG_LEVEL > 1
3495     fprintf( stderr, "end executeDrag dispatching\n" );
3496 #endif
3497     {
3498         ClearableMutexGuard aGuard(m_aMutex);
3499 
3500         css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
3501         css::uno::Reference< XTransferable > xTransferable( m_xDragSourceTransferable );
3502         m_xDragSourceListener.clear();
3503         m_xDragSourceTransferable.clear();
3504 
3505         DragSourceDropEvent dsde;
3506         dsde.Source             = static_cast< OWeakObject* >(this);
3507         dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
3508         dsde.DragSource         = static_cast< XDragSource* >(this);
3509         dsde.DropAction         = DNDConstants::ACTION_NONE;
3510         dsde.DropSuccess        = sal_False;
3511 
3512         // cleanup after drag
3513         if( m_bWaitingForPrimaryConversion )
3514             getAdaptor( XA_PRIMARY )->clearTransferable();
3515 
3516         m_bDropSent                         = false;
3517         m_bDropSuccess                      = false;
3518         m_bWaitingForPrimaryConversion      = false;
3519         m_aDropWindow                       = None;
3520         m_aDropProxy                        = None;
3521         m_nCurrentProtocolVersion           = nXdndProtocolRevision;
3522         m_nNoPosX                           = 0;
3523         m_nNoPosY                           = 0;
3524         m_nNoPosWidth                       = 0;
3525         m_nNoPosHeight                      = 0;
3526         m_aCurrentCursor                    = None;
3527 
3528         XUngrabPointer( m_pDisplay, CurrentTime );
3529         XUngrabKeyboard( m_pDisplay, CurrentTime );
3530         XFlush( m_pDisplay );
3531 
3532         m_aDragExecuteThread = NULL;
3533         m_aDragRunning.reset();
3534 
3535         aGuard.clear();
3536         if( xListener.is() )
3537         {
3538             xTransferable.clear();
3539             xListener->dragDropEnd( dsde );
3540         }
3541     }
3542     osl_destroyThread( aThread );
3543 }
3544 
3545 /*
3546  *  XDragSourceContext
3547  */
3548 
getCurrentCursor()3549 sal_Int32 SelectionManager::getCurrentCursor()
3550 {
3551     return m_aCurrentCursor;
3552 }
3553 
3554 // ------------------------------------------------------------------------
3555 
setCursor(sal_Int32 cursor,XLIB_Window aDropWindow,XLIB_Time)3556 void SelectionManager::setCursor( sal_Int32 cursor, XLIB_Window aDropWindow, XLIB_Time )
3557 {
3558     MutexGuard aGuard( m_aMutex );
3559     if( aDropWindow == m_aDropWindow && XLIB_Cursor(cursor) != m_aCurrentCursor )
3560     {
3561         if( m_xDragSourceListener.is() && ! m_bDropSent )
3562         {
3563             m_aCurrentCursor = cursor;
3564             XChangeActivePointerGrab( m_pDisplay, DRAG_EVENT_MASK, cursor, CurrentTime );
3565             XFlush( m_pDisplay );
3566         }
3567     }
3568 }
3569 
3570 // ------------------------------------------------------------------------
3571 
setImage(sal_Int32,XLIB_Window,XLIB_Time)3572 void SelectionManager::setImage( sal_Int32, XLIB_Window, XLIB_Time )
3573 {
3574 }
3575 
3576 // ------------------------------------------------------------------------
3577 
transferablesFlavorsChanged()3578 void SelectionManager::transferablesFlavorsChanged()
3579 {
3580     MutexGuard aGuard(m_aMutex);
3581 
3582     m_aDragFlavors = m_xDragSourceTransferable->getTransferDataFlavors();
3583     int i;
3584 
3585     std::list< Atom > aConversions;
3586     std::list< Atom >::const_iterator type_it;
3587 
3588     getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
3589 
3590     int nTypes = aConversions.size();
3591     Atom* pTypes = (Atom*)alloca( sizeof(Atom)*aConversions.size() );
3592     for( i = 0, type_it = aConversions.begin(); type_it != aConversions.end(); ++type_it, i++ )
3593         pTypes[i] = *type_it;
3594     XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
3595 
3596     if( m_aCurrentDropWindow != None && m_nCurrentProtocolVersion >= 0 )
3597     {
3598         // send synthetic leave and enter events
3599 
3600         XEvent aEvent;
3601 
3602         aEvent.type = ClientMessage;
3603         aEvent.xclient.display          = m_pDisplay;
3604         aEvent.xclient.format           = 32;
3605         aEvent.xclient.window           = m_aDropWindow;
3606         aEvent.xclient.data.l[0]        = m_aWindow;
3607 
3608         aEvent.xclient.message_type     = m_nXdndLeave;
3609         aEvent.xclient.data.l[1]        = 0;
3610         XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
3611 
3612         aEvent.xclient.message_type = m_nXdndEnter;
3613         aEvent.xclient.data.l[1]    = m_nCurrentProtocolVersion << 24;
3614         memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
3615         // fill in data types
3616         if( nTypes > 3 )
3617             aEvent.xclient.data.l[1] |= 1;
3618         for( int j = 0; j < nTypes && j < 3; j++ )
3619             aEvent.xclient.data.l[j+2] = pTypes[j];
3620 
3621         XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
3622     }
3623 }
3624 
3625 /*
3626  *  dispatch loop
3627  */
3628 
3629 // ------------------------------------------------------------------------
3630 
handleXEvent(XEvent & rEvent)3631 bool SelectionManager::handleXEvent( XEvent& rEvent )
3632 {
3633     /*
3634      *  since we are XConnectionListener to a second X display
3635      *  to get client messages it is essential not to dispatch
3636      *  events twice that we get on both connections
3637      *
3638      *  #95201# between dispatching ButtonPress and startDrag
3639      *  the user can already have released the mouse. The ButtonRelease
3640      *  will then be dispatched in VCLs queue and never turn up here.
3641      *  Which is not so good, since startDrag will XGrabPointer and
3642      *  XGrabKeyboard -> solid lock.
3643      */
3644     if( rEvent.xany.display != m_pDisplay
3645         && rEvent.type != ClientMessage
3646         && rEvent.type != ButtonPress
3647         && rEvent.type != ButtonRelease
3648         )
3649         return false;
3650 
3651     bool bHandled = false;
3652     switch (rEvent.type)
3653     {
3654         case SelectionClear:
3655         {
3656             ClearableMutexGuard aGuard(m_aMutex);
3657 #if OSL_DEBUG_LEVEL > 1
3658             fprintf( stderr, "SelectionClear for selection %s\n",
3659                      OUStringToOString( getString( rEvent.xselectionclear.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
3660                      );
3661 #endif
3662             SelectionAdaptor* pAdaptor = getAdaptor( rEvent.xselectionclear.selection );
3663             std::hash_map< Atom, Selection* >::iterator it( m_aSelections.find( rEvent.xselectionclear.selection ) );
3664             if( it != m_aSelections.end() )
3665                 it->second->m_bOwner = false;
3666             aGuard.clear();
3667             if ( pAdaptor )
3668                 pAdaptor->clearTransferable();
3669         }
3670         break;
3671 
3672         case SelectionRequest:
3673             bHandled = handleSelectionRequest( rEvent.xselectionrequest );
3674             break;
3675         case PropertyNotify:
3676             if( rEvent.xproperty.window == m_aWindow ||
3677                 rEvent.xproperty.window == m_aCurrentDropWindow
3678                 )
3679                 bHandled = handleReceivePropertyNotify( rEvent.xproperty );
3680             else
3681                 bHandled = handleSendPropertyNotify( rEvent.xproperty );
3682             break;
3683         case SelectionNotify:
3684             bHandled = handleSelectionNotify( rEvent.xselection );
3685             break;
3686         case ClientMessage:
3687             // messages from drag target
3688             if( rEvent.xclient.message_type == m_nXdndStatus ||
3689                 rEvent.xclient.message_type == m_nXdndFinished )
3690                 bHandled = handleDragEvent( rEvent );
3691             // messages from drag source
3692             else if(
3693                     rEvent.xclient.message_type == m_nXdndEnter     ||
3694                     rEvent.xclient.message_type == m_nXdndLeave     ||
3695                     rEvent.xclient.message_type == m_nXdndPosition  ||
3696                     rEvent.xclient.message_type == m_nXdndDrop
3697                     )
3698                 bHandled = handleDropEvent( rEvent.xclient );
3699             break;
3700         case EnterNotify:
3701         case LeaveNotify:
3702         case MotionNotify:
3703         case ButtonPress:
3704         case ButtonRelease:
3705         case XLIB_KeyPress:
3706         case KeyRelease:
3707             bHandled = handleDragEvent( rEvent );
3708             break;
3709         default:
3710             ;
3711     }
3712     return bHandled;
3713 }
3714 
3715 // ------------------------------------------------------------------------
3716 
dispatchEvent(int millisec)3717 void SelectionManager::dispatchEvent( int millisec )
3718 {
3719     pollfd aPollFD;
3720     XEvent event;
3721 
3722     // query socket handle to poll on
3723     aPollFD.fd      = ConnectionNumber( m_pDisplay );
3724     aPollFD.events  = POLLIN;
3725     aPollFD.revents = 0;
3726 
3727     // wait for activity (outside the xlib)
3728     if( poll( &aPollFD, 1, millisec ) > 0 )
3729     {
3730         // now acquire the mutex to prevent other threads
3731         // from using the same X connection
3732         ResettableMutexGuard aGuard(m_aMutex);
3733 
3734         // prevent that another thread already ate the input
3735         // this can happen if e.g. another thread does
3736         // an X request getting a response. the response
3737         // would be removed from the queue and we would end up
3738         // with an empty socket here
3739         if( poll( &aPollFD, 1, 0 ) > 0 )
3740         {
3741             int nPending = 1;
3742             while( nPending )
3743             {
3744                 nPending = XPending( m_pDisplay );
3745                 if( nPending )
3746                 {
3747                     XNextEvent( m_pDisplay, &event );
3748                     aGuard.clear();
3749                     handleXEvent( event );
3750                     aGuard.reset();
3751                 }
3752             }
3753         }
3754     }
3755 }
3756 
3757 // ------------------------------------------------------------------------
3758 
run(void * pThis)3759 void SelectionManager::run( void* pThis )
3760 {
3761 #if OSL_DEBUG_LEVEL > 1
3762     fprintf(stderr, "SelectionManager::run\n" );
3763 #endif
3764     // dispatch until the cows come home
3765 
3766     SelectionManager* This = (SelectionManager*)pThis;
3767 
3768     timeval aLast;
3769     gettimeofday( &aLast, 0 );
3770 
3771     css::uno::Reference< XMultiServiceFactory > xFact( ::comphelper::getProcessServiceFactory() );
3772     if( xFact.is() )
3773     {
3774         css::uno::Reference< XDesktop > xDesktop( xFact->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ), UNO_QUERY );
3775         if( xDesktop.is() )
3776             xDesktop->addTerminateListener(This);
3777     }
3778 
3779     while( osl_scheduleThread(This->m_aThread) )
3780     {
3781         This->dispatchEvent( 1000 );
3782 
3783         timeval aNow;
3784         gettimeofday( &aNow, 0 );
3785 
3786         if( (aNow.tv_sec - aLast.tv_sec) > 0 )
3787         {
3788             ClearableMutexGuard aGuard(This->m_aMutex);
3789             std::list< std::pair< SelectionAdaptor*, css::uno::Reference< XInterface > > > aChangeList;
3790 
3791             for( std::hash_map< Atom, Selection* >::iterator it = This->m_aSelections.begin(); it != This->m_aSelections.end(); ++it )
3792             {
3793                 if( it->first != This->m_nXdndSelection && ! it->second->m_bOwner )
3794                 {
3795                     XLIB_Window aOwner = XGetSelectionOwner( This->m_pDisplay, it->first );
3796                     if( aOwner != it->second->m_aLastOwner )
3797                     {
3798                         it->second->m_aLastOwner = aOwner;
3799                         std::pair< SelectionAdaptor*, css::uno::Reference< XInterface > >
3800                             aKeep( it->second->m_pAdaptor, it->second->m_pAdaptor->getReference() );
3801                         aChangeList.push_back( aKeep );
3802                     }
3803                 }
3804             }
3805             aGuard.clear();
3806             while( aChangeList.begin() != aChangeList.end() )
3807             {
3808                 aChangeList.front().first->fireContentsChanged();
3809                 aChangeList.pop_front();
3810             }
3811             aLast = aNow;
3812         }
3813     }
3814 #if OSL_DEBUG_LEVEL > 1
3815     fprintf(stderr, "SelectionManager::run end\n" );
3816 #endif
3817 }
3818 
shutdown()3819 void SelectionManager::shutdown() throw()
3820 {
3821     ResettableMutexGuard aGuard(m_aMutex);
3822     if( m_bShutDown )
3823     {
3824         return;
3825     }
3826     m_bShutDown = true;
3827     // stop dispatching
3828     if( m_aThread )
3829     {
3830         osl_terminateThread( m_aThread );
3831         /*
3832          * Allow thread to finish before app exits to avoid pulling the carpet
3833          * out from under it if pasting is occuring during shutdown
3834          *
3835          * a) allow it to have the Mutex and
3836          * b) reschedule to allow it to complete callbacks to any
3837          * Application::GetSolarMutex protected regions, etc. e.g.
3838          * TransferableHelper::getTransferDataFlavors (via
3839          * SelectionManager::handleSelectionRequest) which it might
3840          * currently be trying to enter.
3841          *
3842          * Otherwise the thread may be left still waiting on a GlobalMutex
3843          * when that gets destroyed, letting the thread blow up and die
3844          * when enters the section in a now dead OOo instance.
3845          */
3846         aGuard.clear();
3847         while (osl_isThreadRunning(m_aThread))
3848         {
3849             vos::OGuard guard2(Application::GetSolarMutex());
3850             Application::Reschedule();
3851         }
3852         osl_joinWithThread( m_aThread );
3853         osl_destroyThread( m_aThread );
3854         m_aThread = NULL;
3855         aGuard.reset();
3856     }
3857     m_xDisplayConnection->removeEventHandler( Any(), this );
3858     m_xDisplayConnection.clear();
3859 }
3860 
3861 // ------------------------------------------------------------------------
3862 
handleEvent(const Any & event)3863 sal_Bool SelectionManager::handleEvent( const Any& event ) throw()
3864 {
3865     Sequence< sal_Int8 > aSeq;
3866     if( (event >>= aSeq) )
3867     {
3868         XEvent* pEvent = (XEvent*)aSeq.getArray();
3869         XLIB_Time nTimestamp = CurrentTime;
3870         if( pEvent->type == ButtonPress || pEvent->type == ButtonRelease )
3871             nTimestamp = pEvent->xbutton.time;
3872         else if( pEvent->type == XLIB_KeyPress || pEvent->type == KeyRelease )
3873             nTimestamp = pEvent->xkey.time;
3874         else if( pEvent->type == MotionNotify )
3875             nTimestamp = pEvent->xmotion.time;
3876         else if( pEvent->type == PropertyNotify )
3877             nTimestamp = pEvent->xproperty.time;
3878 
3879         if( nTimestamp != CurrentTime )
3880         {
3881             MutexGuard aGuard(m_aMutex);
3882 
3883             m_nSelectionTimestamp = nTimestamp;
3884         }
3885 
3886         return sal_Bool( handleXEvent( *pEvent ) );
3887     }
3888     else
3889     {
3890         #if OSL_DEBUG_LEVEL > 1
3891         fprintf( stderr, "SelectionManager got downing event\n" );
3892         #endif
3893         shutdown();
3894     }
3895     return sal_True;
3896 }
3897 
disposing(const::com::sun::star::lang::EventObject &)3898 void SAL_CALL SelectionManager::disposing( const ::com::sun::star::lang::EventObject& )
3899     throw( ::com::sun::star::uno::RuntimeException )
3900 {
3901 }
3902 
queryTermination(const::com::sun::star::lang::EventObject &)3903 void SAL_CALL SelectionManager::queryTermination( const ::com::sun::star::lang::EventObject& )
3904     throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException )
3905 {
3906 }
3907 
3908 /*
3909  * To be safe, shutdown needs to be called before the ~SfxApplication is called, waiting until
3910  * the downing event can be too late if paste are requested during shutdown and ~SfxApplication
3911  * has been called before vcl is shutdown
3912  */
notifyTermination(const::com::sun::star::lang::EventObject & rEvent)3913 void SAL_CALL SelectionManager::notifyTermination( const ::com::sun::star::lang::EventObject& rEvent )
3914     throw( ::com::sun::star::uno::RuntimeException )
3915 {
3916     css::uno::Reference< XDesktop > xDesktop( rEvent.Source, UNO_QUERY );
3917     if( xDesktop.is() == sal_True )
3918         xDesktop->removeTerminateListener( this );
3919     #if OSL_DEBUG_LEVEL > 1
3920     fprintf( stderr, "SelectionManager got app termination event\n" );
3921     #endif
3922     shutdown();
3923 }
3924 
3925 // ------------------------------------------------------------------------
3926 
registerHandler(Atom selection,SelectionAdaptor & rAdaptor)3927 void SelectionManager::registerHandler( Atom selection, SelectionAdaptor& rAdaptor )
3928 {
3929     MutexGuard aGuard(m_aMutex);
3930 
3931     Selection* pNewSelection    = new Selection();
3932     pNewSelection->m_pAdaptor   = &rAdaptor;
3933     pNewSelection->m_aAtom      = selection;
3934     m_aSelections[ selection ]  = pNewSelection;
3935 }
3936 
3937 // ------------------------------------------------------------------------
3938 
deregisterHandler(Atom selection)3939 void SelectionManager::deregisterHandler( Atom selection )
3940 {
3941     MutexGuard aGuard(m_aMutex);
3942 
3943     ::std::hash_map< Atom, Selection* >::iterator it =
3944           m_aSelections.find( selection );
3945     if( it != m_aSelections.end() )
3946     {
3947         delete it->second->m_pPixmap;
3948         delete it->second;
3949         m_aSelections.erase( it );
3950     }
3951 }
3952 
3953 // ------------------------------------------------------------------------
3954 
3955 static bool bWasError = false;
3956 
3957 extern "C"
3958 {
local_xerror_handler(Display *,XErrorEvent *)3959     int local_xerror_handler(Display* , XErrorEvent*)
3960     {
3961         bWasError = true;
3962         return 0;
3963     }
3964     typedef int(*xerror_hdl_t)(Display*,XErrorEvent*);
3965 }
3966 
registerDropTarget(XLIB_Window aWindow,DropTarget * pTarget)3967 void SelectionManager::registerDropTarget( XLIB_Window aWindow, DropTarget* pTarget )
3968 {
3969     MutexGuard aGuard(m_aMutex);
3970 
3971     // sanity check
3972     ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
3973           m_aDropTargets.find( aWindow );
3974     if( it != m_aDropTargets.end() )
3975         OSL_ASSERT( "attempt to register window as drop target twice" );
3976     else if( aWindow && m_pDisplay )
3977     {
3978         DropTargetEntry aEntry( pTarget );
3979         bWasError=false;
3980         /* #i100000# ugly workaround: gtk sets its own XErrorHandler which is not suitable for us
3981            unfortunately XErrorHandler is not per display, so this is just and ugly hack
3982            Need to remove separate display and integrate clipboard/dnd into vcl's unx code ASAP
3983         */
3984         xerror_hdl_t pOldHandler = XSetErrorHandler( local_xerror_handler );
3985         XSelectInput( m_pDisplay, aWindow, PropertyChangeMask );
3986         if( ! bWasError )
3987         {
3988             // set XdndAware
3989             XChangeProperty( m_pDisplay, aWindow, m_nXdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&nXdndProtocolRevision, 1 );
3990             if( ! bWasError )
3991             {
3992                 // get root window of window (in 99.999% of all cases this will be
3993                 // DefaultRootWindow( m_pDisplay )
3994                 int x, y;
3995                 unsigned int w, h, bw, d;
3996                 XGetGeometry( m_pDisplay, aWindow, &aEntry.m_aRootWindow,
3997                               &x, &y, &w, &h, &bw, &d );
3998             }
3999         }
4000         XSetErrorHandler( pOldHandler );
4001         if(bWasError)
4002             return;
4003         m_aDropTargets[ aWindow ] = aEntry;
4004     }
4005     else
4006         OSL_ASSERT( "attempt to register None as drop target" );
4007 }
4008 
4009 // ------------------------------------------------------------------------
4010 
deregisterDropTarget(XLIB_Window aWindow)4011 void SelectionManager::deregisterDropTarget( XLIB_Window aWindow )
4012 {
4013     ClearableMutexGuard aGuard(m_aMutex);
4014 
4015     m_aDropTargets.erase( aWindow );
4016     if( aWindow == m_aDragSourceWindow && m_aDragRunning.check() )
4017     {
4018         // abort drag
4019         std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
4020             m_aDropTargets.find( m_aDropWindow );
4021         if( it != m_aDropTargets.end() )
4022         {
4023             DropTargetEvent dte;
4024             dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
4025             aGuard.clear();
4026             it->second.m_pTarget->dragExit( dte );
4027         }
4028         else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
4029         {
4030             // send XdndLeave
4031             XEvent aEvent;
4032             aEvent.type = ClientMessage;
4033             aEvent.xclient.display      = m_pDisplay;
4034             aEvent.xclient.format       = 32;
4035             aEvent.xclient.message_type = m_nXdndLeave;
4036             aEvent.xclient.window       = m_aDropWindow;
4037             aEvent.xclient.data.l[0]    = m_aWindow;
4038             memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
4039             m_aDropWindow = m_aDropProxy = None;
4040             XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
4041         }
4042         // notify the listener
4043         DragSourceDropEvent dsde;
4044         dsde.Source             = static_cast< OWeakObject* >(this);
4045         dsde.DragSourceContext  = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
4046         dsde.DragSource         = static_cast< XDragSource* >(this);
4047         dsde.DropAction         = DNDConstants::ACTION_NONE;
4048         dsde.DropSuccess        = sal_False;
4049         css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
4050         m_xDragSourceListener.clear();
4051         aGuard.clear();
4052         xListener->dragDropEnd( dsde );
4053     }
4054 }
4055 
4056 /*
4057  *  SelectionAdaptor
4058  */
4059 
getTransferable()4060 css::uno::Reference< XTransferable > SelectionManager::getTransferable() throw()
4061 {
4062     return m_xDragSourceTransferable;
4063 }
4064 
4065 // ------------------------------------------------------------------------
4066 
clearTransferable()4067 void SelectionManager::clearTransferable() throw()
4068 {
4069     m_xDragSourceTransferable.clear();
4070 }
4071 
4072 // ------------------------------------------------------------------------
4073 
fireContentsChanged()4074 void SelectionManager::fireContentsChanged() throw()
4075 {
4076 }
4077 
4078 // ------------------------------------------------------------------------
4079 
getReference()4080 css::uno::Reference< XInterface > SelectionManager::getReference() throw()
4081 {
4082     return css::uno::Reference< XInterface >( static_cast<OWeakObject*>(this) );
4083 }
4084 
4085 // ------------------------------------------------------------------------
4086 
4087 /*
4088  *  SelectionManagerHolder
4089  */
4090 
SelectionManagerHolder()4091 SelectionManagerHolder::SelectionManagerHolder() :
4092         ::cppu::WeakComponentImplHelper3<
4093     XDragSource,
4094     XInitialization,
4095     XServiceInfo > (m_aMutex)
4096 {
4097 }
4098 
4099 // ------------------------------------------------------------------------
4100 
~SelectionManagerHolder()4101 SelectionManagerHolder::~SelectionManagerHolder()
4102 {
4103 }
4104 
4105 // ------------------------------------------------------------------------
4106 
initialize(const Sequence<Any> & arguments)4107 void SelectionManagerHolder::initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception )
4108 {
4109     OUString aDisplayName;
4110 
4111     if( arguments.getLength() > 0 )
4112     {
4113         css::uno::Reference< XDisplayConnection > xConn;
4114         arguments.getConstArray()[0] >>= xConn;
4115         if( xConn.is() )
4116         {
4117             Any aIdentifier;
4118             aIdentifier >>= aDisplayName;
4119         }
4120     }
4121 
4122     SelectionManager& rManager = SelectionManager::get( aDisplayName );
4123     rManager.initialize( arguments );
4124     m_xRealDragSource = static_cast< XDragSource* >(&rManager);
4125 }
4126 
4127 /*
4128  *  XDragSource
4129  */
4130 
isDragImageSupported()4131 sal_Bool SelectionManagerHolder::isDragImageSupported() throw()
4132 {
4133     return m_xRealDragSource.is() ? m_xRealDragSource->isDragImageSupported() : sal_False;
4134 }
4135 
4136 // ------------------------------------------------------------------------
4137 
getDefaultCursor(sal_Int8 dragAction)4138 sal_Int32 SelectionManagerHolder::getDefaultCursor( sal_Int8 dragAction ) throw()
4139 {
4140     return m_xRealDragSource.is() ? m_xRealDragSource->getDefaultCursor( dragAction ) : 0;
4141 }
4142 
4143 // ------------------------------------------------------------------------
4144 
startDrag(const::com::sun::star::datatransfer::dnd::DragGestureEvent & trigger,sal_Int8 sourceActions,sal_Int32 cursor,sal_Int32 image,const css::uno::Reference<::com::sun::star::datatransfer::XTransferable> & transferable,const css::uno::Reference<::com::sun::star::datatransfer::dnd::XDragSourceListener> & listener)4145 void SelectionManagerHolder::startDrag(
4146                                        const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
4147                                        sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
4148                                        const css::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
4149                                        const css::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
4150                                        ) throw()
4151 {
4152     if( m_xRealDragSource.is() )
4153         m_xRealDragSource->startDrag( trigger, sourceActions, cursor, image, transferable, listener );
4154 }
4155 
4156 // ------------------------------------------------------------------------
4157 
4158 /*
4159  *  XServiceInfo
4160  */
4161 
4162 // ------------------------------------------------------------------------
4163 
getImplementationName()4164 OUString SelectionManagerHolder::getImplementationName() throw()
4165 {
4166     return OUString::createFromAscii(XDND_IMPLEMENTATION_NAME);
4167 }
4168 
4169 // ------------------------------------------------------------------------
4170 
supportsService(const OUString & ServiceName)4171 sal_Bool SelectionManagerHolder::supportsService( const OUString& ServiceName ) throw()
4172 {
4173     Sequence < OUString > SupportedServicesNames = Xdnd_getSupportedServiceNames();
4174 
4175     for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
4176         if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
4177             return sal_True;
4178 
4179     return sal_False;
4180 }
4181 
4182 // ------------------------------------------------------------------------
4183 
getSupportedServiceNames()4184 Sequence< OUString > SelectionManagerHolder::getSupportedServiceNames() throw()
4185 {
4186     return Xdnd_getSupportedServiceNames();
4187 }
4188 
4189 
4190 // ------------------------------------------------------------------------
4191 
4192