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