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