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