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