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