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