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