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