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