1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: X11_selection.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dtrans.hxx"
38 #include <X11/Xatom.h>
39 #include <X11/keysym.h>
42 #include <X11/Xutil.h>
43 #if defined(LINUX) || defined(NETBSD) || defined (FREEBSD)
48 #include <sal/alloca.h>
50 #include <X11_selection.hxx>
51 #include <X11_clipboard.hxx>
52 #include <X11_transferable.hxx>
53 #include <X11_dndcontext.hxx>
57 #include <copydata_curs.h>
58 #include <copydata_mask.h>
59 #include <movedata_curs.h>
60 #include <movedata_mask.h>
61 #include <linkdata_curs.h>
62 #include <linkdata_mask.h>
63 #include <nodrop_curs.h>
64 #include <nodrop_mask.h>
65 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
66 #include <com/sun/star/awt/MouseEvent.hpp>
67 #include <com/sun/star/awt/MouseButton.hpp>
68 #include <rtl/tencinfo.h>
70 #include <osl/process.h>
73 #define DRAG_EVENT_MASK ButtonPressMask |\
79 using namespace com::sun::star::datatransfer
;
80 using namespace com::sun::star::datatransfer::dnd
;
81 using namespace com::sun::star::lang
;
82 using namespace com::sun::star::awt
;
83 using namespace com::sun::star::uno
;
90 // stubs to satisfy solaris compiler's rather rigid linking warning
93 static void call_SelectionManager_run( void * pMgr
)
95 SelectionManager::run( pMgr
);
98 static void call_SelectionManager_runDragExecute( void * pMgr
)
100 SelectionManager::runDragExecute( pMgr
);
105 static const long nXdndProtocolRevision
= 5;
107 // mapping between mime types (or what the office thinks of mime types)
108 // and X convention types
109 struct NativeTypeEntry
112 const char* pType
; // Mime encoding on our side
113 const char* pNativeType
; // string corresponding to nAtom for the case of nAtom being uninitialized
114 int nFormat
; // the corresponding format
117 // the convention for Xdnd is mime types as specified by the corresponding
118 // RFC's with the addition that text/plain without charset tag contains iso8859-1
119 // sadly some applications (e.g. gtk) do not honor the mimetype only rule,
120 // so for compatibility add UTF8_STRING
121 static NativeTypeEntry aXdndConversionTab
[] =
123 { 0, "text/plain;charset=iso8859-1", "text/plain", 8 },
124 { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 }
127 // for clipboard and primary selections there is only a convention for text
128 // that the encoding name of the text is taken as type in all capitalized letters
129 static NativeTypeEntry aNativeConversionTab
[] =
131 { 0, "text/plain;charset=utf-16", "ISO10646-1", 16 },
132 { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 },
133 { 0, "text/plain;charset=utf-8", "UTF-8", 8 },
134 { 0, "text/plain;charset=utf-8", "text/plain;charset=UTF-8", 8 },
136 { 0, "text/plain;charset=iso8859-2", "ISO8859-2", 8 },
137 { 0, "text/plain;charset=iso8859-3", "ISO8859-3", 8 },
138 { 0, "text/plain;charset=iso8859-4", "ISO8859-4", 8 },
139 { 0, "text/plain;charset=iso8859-5", "ISO8859-5", 8 },
140 { 0, "text/plain;charset=iso8859-6", "ISO8859-6", 8 },
141 { 0, "text/plain;charset=iso8859-7", "ISO8859-7", 8 },
142 { 0, "text/plain;charset=iso8859-8", "ISO8859-8", 8 },
143 { 0, "text/plain;charset=iso8859-9", "ISO8859-9", 8 },
144 { 0, "text/plain;charset=iso8859-10", "ISO8859-10", 8 },
145 { 0, "text/plain;charset=iso8859-13", "ISO8859-13", 8 },
146 { 0, "text/plain;charset=iso8859-14", "ISO8859-14", 8 },
147 { 0, "text/plain;charset=iso8859-15", "ISO8859-15", 8 },
149 { 0, "text/plain;charset=jisx0201.1976-0", "JISX0201.1976-0", 8 },
150 { 0, "text/plain;charset=jisx0208.1983-0", "JISX0208.1983-0", 8 },
151 { 0, "text/plain;charset=jisx0208.1990-0", "JISX0208.1990-0", 8 },
152 { 0, "text/plain;charset=jisx0212.1990-0", "JISX0212.1990-0", 8 },
153 { 0, "text/plain;charset=gb2312.1980-0", "GB2312.1980-0", 8 },
154 { 0, "text/plain;charset=ksc5601.1992-0", "KSC5601.1992-0", 8 },
155 // eastern european encodings
156 { 0, "text/plain;charset=koi8-r", "KOI8-R", 8 },
157 { 0, "text/plain;charset=koi8-u", "KOI8-U", 8 },
158 // String (== iso8859-1)
159 { XA_STRING
, "text/plain;charset=iso8859-1", "STRING", 8 },
160 // special for compound text
161 { 0, "text/plain;charset=compound_text", "COMPOUND_TEXT", 8 },
164 { XA_PIXMAP
, "image/bmp", "PIXMAP", 32 }
167 rtl_TextEncoding
x11::getTextPlainEncoding( const OUString
& rMimeType
)
169 rtl_TextEncoding aEncoding
= RTL_TEXTENCODING_DONTKNOW
;
170 OUString
aMimeType( rMimeType
.toAsciiLowerCase() );
171 sal_Int32 nIndex
= 0;
172 if( aMimeType
.getToken( 0, ';', nIndex
).equalsAsciiL( "text/plain" , 10 ) )
174 if( aMimeType
.getLength() == 10 ) // only "text/plain"
175 aEncoding
= RTL_TEXTENCODING_ISO_8859_1
;
178 while( nIndex
!= -1 )
180 OUString aToken
= aMimeType
.getToken( 0, ';', nIndex
);
182 if( aToken
.getToken( 0, '=', nPos
).equalsAsciiL( "charset", 7 ) )
184 OString aEncToken
= OUStringToOString( aToken
.getToken( 0, '=', nPos
), RTL_TEXTENCODING_ISO_8859_1
);
185 aEncoding
= rtl_getTextEncodingFromUnixCharset( aEncToken
.getStr() );
186 if( aEncoding
== RTL_TEXTENCODING_DONTKNOW
)
188 if( aEncToken
.equalsIgnoreAsciiCase( "utf-8" ) )
189 aEncoding
= RTL_TEXTENCODING_UTF8
;
191 if( aEncoding
!= RTL_TEXTENCODING_DONTKNOW
)
197 #if OSL_DEBUG_LEVEL > 1
198 if( aEncoding
== RTL_TEXTENCODING_DONTKNOW
)
199 fprintf( stderr
, "getTextPlainEncoding( %s ) failed\n", OUStringToOString( rMimeType
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
204 // ------------------------------------------------------------------------
206 ::std::hash_map
< OUString
, SelectionManager
*, OUStringHash
>& SelectionManager::getInstances()
208 static ::std::hash_map
< OUString
, SelectionManager
*, OUStringHash
> aInstances
;
212 // ------------------------------------------------------------------------
214 SelectionManager::SelectionManager() :
215 m_nIncrementalThreshold( 15*1024 ),
218 m_aDragExecuteThread( NULL
),
220 m_nSelectionTimeout( 0 ),
221 m_nSelectionTimestamp( CurrentTime
),
222 m_aCurrentDropWindow( None
),
223 m_bDropWaitingForCompletion( false ),
224 m_aDropWindow( None
),
225 m_aDropProxy( None
),
226 m_aDragSourceWindow( None
),
231 m_bLastDropAccepted( false ),
232 m_bDropSuccess( false ),
233 m_bDropSent( false ),
234 m_bWaitingForPrimaryConversion( false ),
235 m_aMoveCursor( None
),
236 m_aCopyCursor( None
),
237 m_aLinkCursor( None
),
238 m_aNoneCursor( None
),
239 m_aCurrentCursor( None
),
240 m_nCurrentProtocolVersion( nXdndProtocolRevision
)
242 m_aDropEnterEvent
.data
.l
[0] = None
;
243 m_bDropEnterSent
= true;
244 m_aDragRunning
.reset();
247 Cursor
SelectionManager::createCursor( const char* pPointerData
, const char* pMaskData
, int width
, int height
, int hotX
, int hotY
)
251 XColor aBlack
, aWhite
;
253 aBlack
.pixel
= BlackPixel( m_pDisplay
, 0 );
254 aBlack
.red
= aBlack
.green
= aBlack
.blue
= 0;
255 aBlack
.flags
= DoRed
| DoGreen
| DoBlue
;
257 aWhite
.pixel
= WhitePixel( m_pDisplay
, 0 );
258 aWhite
.red
= aWhite
.green
= aWhite
.blue
= 0xffff;
259 aWhite
.flags
= DoRed
| DoGreen
| DoBlue
;
262 XCreateBitmapFromData( m_pDisplay
,
268 = XCreateBitmapFromData( m_pDisplay
,
274 XCreatePixmapCursor( m_pDisplay
, aPointer
, aMask
,
278 XFreePixmap( m_pDisplay
, aPointer
);
279 XFreePixmap( m_pDisplay
, aMask
);
284 void SelectionManager::initialize( const Sequence
< Any
>& arguments
) throw (::com::sun::star::uno::Exception
)
286 MutexGuard
aGuard(m_aMutex
);
288 if( ! m_xDisplayConnection
.is() )
291 * first argument must be a ::com::sun::star::awt::XDisplayConnection
292 * from this we will get the XEvents of the vcl event loop by
293 * registering us as XEventHandler on it.
295 * implementor's note:
297 * Because XDND implementations send their ClientMessage events with
298 * XSendEvent and event mask 0 (which is perfectly sensible)
299 * these events get only sent to the connection that created
300 * the window in question: the vcl display.
302 * So this whole service should be implemented in vcl where
303 * it belongs. But as usual the dogmatics win and the dogma says:
304 * "vcl bad, service good". So instead of making vcl a service
305 * providing library we make a new one that is "independent" of vcl,
306 * because it is not linked against it and dispatch every event of
307 * the vcl event loop to here via uno mechanisms (that is copying it,
308 * locking and unlocking mutexes). Well, the user has fast computers
309 * these days, so why do we need performance where more memory and
310 * a faster CPU will do the job ?
311 * And that is why this runs under the title:
312 * How NOT to implement a service
313 * or the victory of dogma over common sense.
316 if( arguments
.getLength() > 0 )
317 arguments
.getConstArray()[0] >>= m_xDisplayConnection
;
318 if( ! m_xDisplayConnection
.is() )
321 // for the time being try to live without XDisplayConnection
322 // for the sake of clipboard service
323 // clipboard service should be initialized with a XDisplayConnection
326 aExc
.Message
= OUString::createFromAscii( "initialize me with a valid XDisplayConnection" );
327 aExc
.Context
= static_cast< OWeakObject
* >(this);
332 m_xDisplayConnection
->addEventHandler( Any(), this, ~0 );
335 if( !m_xBitmapConverter
.is() )
337 if( arguments
.getLength() > 2 )
338 arguments
.getConstArray()[2] >>= m_xBitmapConverter
;
341 int nParams
= osl_getCommandArgCount();
343 bool bIsHeadless
= false;
344 for( int i
= 0; i
< nParams
; i
++ )
346 osl_getCommandArg( i
, &aParam
.pData
);
347 if( aParam
.equalsAscii( "-headless" ) )
354 if( ! m_pDisplay
&& ! bIsHeadless
)
357 if( m_xDisplayConnection
.is() )
360 aIdentifier
= m_xDisplayConnection
->getIdentifier();
361 aIdentifier
>>= aUDisplay
;
364 OString
aDisplayName( OUStringToOString( aUDisplay
, RTL_TEXTENCODING_ISO_8859_1
) );
366 m_pDisplay
= XOpenDisplay( aDisplayName
.getLength() ? aDisplayName
.getStr() : NULL
);
371 XSynchronize( m_pDisplay
, True
);
373 // clipboard selection
374 m_nCLIPBOARDAtom
= getAtom( OUString::createFromAscii( "CLIPBOARD" ) );
377 m_nTARGETSAtom
= getAtom( OUString::createFromAscii( "TARGETS" ) );
378 m_nTIMESTAMPAtom
= getAtom( OUString::createFromAscii( "TIMESTAMP" ) );
379 m_nTEXTAtom
= getAtom( OUString::createFromAscii( "TEXT" ) );
380 m_nINCRAtom
= getAtom( OUString::createFromAscii( "INCR" ) );
381 m_nCOMPOUNDAtom
= getAtom( OUString::createFromAscii( "COMPOUND_TEXT" ) );
382 m_nMULTIPLEAtom
= getAtom( OUString::createFromAscii( "MULTIPLE" ) );
383 m_nUTF16Atom
= getAtom( OUString::createFromAscii( "ISO10646-1" ) );
384 // m_nUTF16Atom = getAtom( OUString::createFromAscii( "text/plain;charset=ISO-10646-UCS-2" ) );
385 m_nImageBmpAtom
= getAtom( OUString::createFromAscii( "image/bmp" ) );
387 // Atoms for Xdnd protocol
388 m_nXdndAware
= getAtom( OUString::createFromAscii( "XdndAware" ) );
389 m_nXdndEnter
= getAtom( OUString::createFromAscii( "XdndEnter" ) );
390 m_nXdndLeave
= getAtom( OUString::createFromAscii( "XdndLeave" ) );
391 m_nXdndPosition
= getAtom( OUString::createFromAscii( "XdndPosition" ) );
392 m_nXdndStatus
= getAtom( OUString::createFromAscii( "XdndStatus" ) );
393 m_nXdndDrop
= getAtom( OUString::createFromAscii( "XdndDrop" ) );
394 m_nXdndFinished
= getAtom( OUString::createFromAscii( "XdndFinished" ) );
395 m_nXdndSelection
= getAtom( OUString::createFromAscii( "XdndSelection" ) );
396 m_nXdndTypeList
= getAtom( OUString::createFromAscii( "XdndTypeList" ) );
397 m_nXdndProxy
= getAtom( OUString::createFromAscii( "XdndProxy" ) );
398 m_nXdndActionCopy
= getAtom( OUString::createFromAscii( "XdndActionCopy" ) );
399 m_nXdndActionMove
= getAtom( OUString::createFromAscii( "XdndActionMove" ) );
400 m_nXdndActionLink
= getAtom( OUString::createFromAscii( "XdndActionLink" ) );
401 m_nXdndActionAsk
= getAtom( OUString::createFromAscii( "XdndActionAsk" ) );
402 m_nXdndActionPrivate
= getAtom( OUString::createFromAscii( "XdndActionPrivate" ) );
404 // initialize map with member none
405 m_aAtomToString
[ 0 ]= OUString::createFromAscii( "None" );
406 m_aAtomToString
[ XA_PRIMARY
] = OUString::createFromAscii( "PRIMARY" );
408 // create a (invisible) message window
409 m_aWindow
= XCreateSimpleWindow( m_pDisplay
, DefaultRootWindow( m_pDisplay
),
410 10, 10, 10, 10, 0, 0, 1 );
412 // initialize threshold for incremetal transfers
413 // ICCCM says it should be smaller that the max request size
414 // which in turn is guaranteed to be at least 16k bytes
415 m_nIncrementalThreshold
= XMaxRequestSize( m_pDisplay
) - 1024;
419 // initialize default cursors
420 m_aMoveCursor
= createCursor( movedata_curs_bits
,
423 movedata_curs_height
,
425 movedata_curs_y_hot
);
426 m_aCopyCursor
= createCursor( copydata_curs_bits
,
429 copydata_curs_height
,
431 copydata_curs_y_hot
);
432 m_aLinkCursor
= createCursor( linkdata_curs_bits
,
435 linkdata_curs_height
,
437 linkdata_curs_y_hot
);
438 m_aNoneCursor
= createCursor( nodrop_curs_bits
,
448 // just interested in SelectionClear/Notify/Request and PropertyChange
449 XSelectInput( m_pDisplay
, m_aWindow
, PropertyChangeMask
);
450 // create the transferable for Drag operations
451 m_xDropTransferable
= new X11Transferable( *this, static_cast< OWeakObject
* >(this), m_nXdndSelection
);
452 registerHandler( m_nXdndSelection
, *this );
454 m_aThread
= osl_createSuspendedThread( call_SelectionManager_run
, this );
456 osl_resumeThread( m_aThread
);
457 #if OSL_DEBUG_LEVEL > 1
459 fprintf( stderr
, "SelectionManager::initialize: creation of dispatch thread failed !\n" );
466 // ------------------------------------------------------------------------
468 SelectionManager::~SelectionManager()
470 #if OSL_DEBUG_LEVEL > 1
471 fprintf( stderr
, "SelectionManager::~SelectionManager (%s)\n", m_pDisplay
? DisplayString(m_pDisplay
) : "no display" );
474 MutexGuard
aGuard( *Mutex::getGlobalMutex() );
476 ::std::hash_map
< OUString
, SelectionManager
*, OUStringHash
>::iterator it
;
477 for( it
= getInstances().begin(); it
!= getInstances().end(); ++it
)
478 if( it
->second
== this )
480 getInstances().erase( it
);
487 osl_terminateThread( m_aThread
);
488 osl_joinWithThread( m_aThread
);
489 osl_destroyThread( m_aThread
);
492 if( m_aDragExecuteThread
)
494 osl_terminateThread( m_aDragExecuteThread
);
495 osl_joinWithThread( m_aDragExecuteThread
);
496 m_aDragExecuteThread
= NULL
;
497 // thread handle is freed in dragDoDispatch()
500 MutexGuard
aGuard(m_aMutex
);
502 #if OSL_DEBUG_LEVEL > 1
503 fprintf( stderr
, "shutting down SelectionManager\n" );
506 if( m_xDisplayConnection
.is() )
508 m_xDisplayConnection
->removeEventHandler( Any(), this );
509 m_xDisplayConnection
.clear();
514 deregisterHandler( m_nXdndSelection
);
515 // destroy message window
517 XDestroyWindow( m_pDisplay
, m_aWindow
);
519 if (m_aMoveCursor
!= None
)
520 XFreeCursor(m_pDisplay
, m_aMoveCursor
);
521 if (m_aCopyCursor
!= None
)
522 XFreeCursor(m_pDisplay
, m_aCopyCursor
);
523 if (m_aLinkCursor
!= None
)
524 XFreeCursor(m_pDisplay
, m_aLinkCursor
);
525 if (m_aNoneCursor
!= None
)
526 XFreeCursor(m_pDisplay
, m_aNoneCursor
);
528 // paranoia setting, the drag thread should have
530 XUngrabPointer( m_pDisplay
, CurrentTime
);
531 XUngrabKeyboard( m_pDisplay
, CurrentTime
);
533 XCloseDisplay( m_pDisplay
);
537 // ------------------------------------------------------------------------
539 SelectionAdaptor
* SelectionManager::getAdaptor( Atom selection
)
541 ::std::hash_map
< Atom
, Selection
* >::iterator it
=
542 m_aSelections
.find( selection
);
543 return it
!= m_aSelections
.end() ? it
->second
->m_pAdaptor
: NULL
;
546 // ------------------------------------------------------------------------
548 OUString
SelectionManager::convertFromCompound( const char* pText
, int nLen
)
550 MutexGuard
aGuard( m_aMutex
);
553 nLen
= strlen( pText
);
555 char** pTextList
= NULL
;
559 aProp
.value
= (unsigned char*)pText
;
560 aProp
.encoding
= m_nCOMPOUNDAtom
;
563 XmbTextPropertyToTextList( m_pDisplay
,
567 rtl_TextEncoding aEncoding
= osl_getThreadTextEncoding();
568 for( int i
= 0; i
< nTexts
; i
++ )
569 aRet
+= OStringToOUString( pTextList
[i
], aEncoding
);
572 XFreeStringList( pTextList
);
577 // ------------------------------------------------------------------------
579 OString
SelectionManager::convertToCompound( const OUString
& rText
)
581 MutexGuard
aGuard( m_aMutex
);
584 aProp
.encoding
= XA_STRING
;
588 OString
aRet( rText
.getStr(), rText
.getLength(), osl_getThreadTextEncoding() );
589 char* pT
= const_cast<char*>(aRet
.getStr());
591 XmbTextListToTextProperty( m_pDisplay
,
598 aRet
= (char*)aProp
.value
;
599 XFree( aProp
.value
);
602 * for currently unknown reasons XmbTextListToTextProperty on Solaris returns
603 * no data in ISO8859-n encodings (at least for n = 1, 15)
604 * in these encodings the directly converted text does the
607 if( ! aRet
.getLength() && rText
.getLength() )
608 aRet
= OUStringToOString( rText
, osl_getThreadTextEncoding() );
617 // ------------------------------------------------------------------------
619 bool SelectionManager::convertData(
620 const Reference
< XTransferable
>& xTransferable
,
624 Sequence
< sal_Int8
>& rData
)
626 bool bSuccess
= false;
628 if( ! xTransferable
.is() )
635 aFlavor
.MimeType
= convertTypeFromNative( nType
, nSelection
, rFormat
);
637 sal_Int32 nIndex
= 0;
638 if( aFlavor
.MimeType
.getToken( 0, ';', nIndex
).compareToAscii( "text/plain" ) == 0 )
640 if( aFlavor
.MimeType
.getToken( 0, ';', nIndex
).compareToAscii( "charset=utf-16" ) == 0 )
641 aFlavor
.DataType
= getCppuType( (OUString
*) 0 );
643 aFlavor
.DataType
= getCppuType( (Sequence
< sal_Int8
>*)0 );
646 aFlavor
.DataType
= getCppuType( (Sequence
< sal_Int8
>*)0 );
648 if( xTransferable
->isDataFlavorSupported( aFlavor
) )
650 Any
aValue( xTransferable
->getTransferData( aFlavor
) );
651 if( aValue
.getValueTypeClass() == TypeClass_STRING
)
655 rData
= Sequence
< sal_Int8
>( (sal_Int8
*)aString
.getStr(), aString
.getLength() * sizeof( sal_Unicode
) );
658 else if( aValue
.getValueType() == getCppuType( (Sequence
< sal_Int8
>*)0 ) )
664 else if( aFlavor
.MimeType
.compareToAscii( "text/plain", 10 ) == 0 )
666 rtl_TextEncoding aEncoding
= RTL_TEXTENCODING_DONTKNOW
;
667 bool bCompoundText
= false;
668 if( nType
== m_nCOMPOUNDAtom
)
669 bCompoundText
= true;
671 aEncoding
= getTextPlainEncoding( aFlavor
.MimeType
);
672 if( aEncoding
!= RTL_TEXTENCODING_DONTKNOW
|| bCompoundText
)
674 aFlavor
.MimeType
= OUString::createFromAscii( "text/plain;charset=utf-16" );
675 aFlavor
.DataType
= getCppuType( (OUString
*) 0 );
676 if( xTransferable
->isDataFlavorSupported( aFlavor
) )
678 Any
aValue( xTransferable
->getTransferData( aFlavor
) );
681 OString
aByteString( bCompoundText
? convertToCompound( aString
) : OUStringToOString( aString
, aEncoding
) );
682 rData
= Sequence
< sal_Int8
>( (sal_Int8
*)aByteString
.getStr(), aByteString
.getLength() * sizeof( sal_Char
) );
688 // various exceptions possible ... which all lead to a failed conversion
689 // so simplify here to a catch all
697 // ------------------------------------------------------------------------
699 SelectionManager
& SelectionManager::get( const OUString
& rDisplayName
)
701 MutexGuard
aGuard( *Mutex::getGlobalMutex() );
703 OUString
aDisplayName( rDisplayName
);
704 if( ! aDisplayName
.getLength() )
705 aDisplayName
= OStringToOUString( getenv( "DISPLAY" ), RTL_TEXTENCODING_ISO_8859_1
);
706 SelectionManager
* pInstance
= NULL
;
708 ::std::hash_map
< OUString
, SelectionManager
*, OUStringHash
>::iterator it
= getInstances().find( aDisplayName
);
709 if( it
!= getInstances().end() )
710 pInstance
= it
->second
;
711 else pInstance
= getInstances()[ aDisplayName
] = new SelectionManager();
716 // ------------------------------------------------------------------------
718 const OUString
& SelectionManager::getString( Atom aAtom
)
720 MutexGuard
aGuard(m_aMutex
);
722 ::std::hash_map
< Atom
, OUString
>::const_iterator it
;
723 if( ( it
= m_aAtomToString
.find( aAtom
) ) == m_aAtomToString
.end() )
725 static OUString aEmpty
;
726 char* pAtom
= m_pDisplay
? XGetAtomName( m_pDisplay
, aAtom
) : NULL
;
729 OUString
aString( OStringToOUString( pAtom
, RTL_TEXTENCODING_ISO_8859_1
) );
731 m_aStringToAtom
[ aString
] = aAtom
;
732 m_aAtomToString
[ aAtom
] = aString
;
734 return m_aAtomToString
[ aAtom
];
737 // ------------------------------------------------------------------------
739 Atom
SelectionManager::getAtom( const OUString
& rString
)
741 MutexGuard
aGuard(m_aMutex
);
743 ::std::hash_map
< OUString
, Atom
, OUStringHash
>::const_iterator it
;
744 if( ( it
= m_aStringToAtom
.find( rString
) ) == m_aStringToAtom
.end() )
746 static Atom nNoDisplayAtoms
= 1;
747 Atom aAtom
= m_pDisplay
? XInternAtom( m_pDisplay
, OUStringToOString( rString
, RTL_TEXTENCODING_ISO_8859_1
), False
) : nNoDisplayAtoms
++;
748 m_aStringToAtom
[ rString
] = aAtom
;
749 m_aAtomToString
[ aAtom
] = rString
;
751 return m_aStringToAtom
[ rString
];
754 // ------------------------------------------------------------------------
756 bool SelectionManager::requestOwnership( Atom selection
)
758 bool bSuccess
= false;
759 if( m_pDisplay
&& m_aWindow
)
761 MutexGuard
aGuard(m_aMutex
);
763 SelectionAdaptor
* pAdaptor
= getAdaptor( selection
);
766 XSetSelectionOwner( m_pDisplay
, selection
, m_aWindow
, CurrentTime
);
767 if( XGetSelectionOwner( m_pDisplay
, selection
) == m_aWindow
)
769 #if OSL_DEBUG_LEVEL > 1
770 fprintf( stderr
, "%s ownership for selection %s\n",
771 bSuccess
? "acquired" : "failed to acquire",
772 OUStringToOString( getString( selection
), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
774 Selection
* pSel
= m_aSelections
[ selection
];
775 pSel
->m_bOwner
= bSuccess
;
776 delete pSel
->m_pPixmap
;
777 pSel
->m_pPixmap
= NULL
;
778 pSel
->m_nOrigTimestamp
= m_nSelectionTimestamp
;
780 #if OSL_DEBUG_LEVEL > 1
782 fprintf( stderr
, "no adaptor for selection %s\n",
783 OUStringToOString( getString( selection
), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
785 if( pAdaptor
->getTransferable().is() )
787 Sequence
< DataFlavor
> aTypes
= pAdaptor
->getTransferable()->getTransferDataFlavors();
788 for( int i
= 0; i
< aTypes
.getLength(); i
++ )
790 fprintf( stderr
, " %s\n", OUStringToOString( aTypes
.getConstArray()[i
].MimeType
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
798 // ------------------------------------------------------------------------
800 void SelectionManager::convertTypeToNative( const OUString
& rType
, Atom selection
, int& rFormat
, ::std::list
< Atom
>& rConversions
, bool bPushFront
)
802 NativeTypeEntry
* pTab
= selection
== m_nXdndSelection
? aXdndConversionTab
: aNativeConversionTab
;
803 int nTabEntries
= selection
== m_nXdndSelection
804 ? sizeof(aXdndConversionTab
)/sizeof(aXdndConversionTab
[0]) :
805 sizeof(aNativeConversionTab
)/sizeof(aNativeConversionTab
[0]);
807 OString
aType( OUStringToOString( rType
, RTL_TEXTENCODING_ISO_8859_1
) );
809 for( int i
= 0; i
< nTabEntries
; i
++ )
811 if( aType
.equalsIgnoreAsciiCase( pTab
[i
].pType
) )
813 if( ! pTab
[i
].nAtom
)
814 pTab
[i
].nAtom
= getAtom( OStringToOUString( pTab
[i
].pNativeType
, RTL_TEXTENCODING_ISO_8859_1
) );
815 rFormat
= pTab
[i
].nFormat
;
817 rConversions
.push_front( pTab
[i
].nAtom
);
819 rConversions
.push_back( pTab
[i
].nAtom
);
820 if( pTab
[i
].nFormat
== XA_PIXMAP
)
824 rConversions
.push_front( XA_VISUALID
);
825 rConversions
.push_front( XA_COLORMAP
);
829 rConversions
.push_back( XA_VISUALID
);
830 rConversions
.push_back( XA_COLORMAP
);
836 rFormat
= 8; // byte buffer
838 rConversions
.push_front( getAtom( rType
) );
840 rConversions
.push_back( getAtom( rType
) );
843 // ------------------------------------------------------------------------
845 void SelectionManager::getNativeTypeList( const Sequence
< DataFlavor
>& rTypes
, std::list
< Atom
>& rOutTypeList
, Atom targetselection
)
847 rOutTypeList
.clear();
850 int nFlavors
= rTypes
.getLength();
851 const DataFlavor
* pFlavors
= rTypes
.getConstArray();
852 bool bHaveText
= false;
853 for( int i
= 0; i
< nFlavors
; i
++ )
855 if( pFlavors
[i
].MimeType
.compareToAscii( "text/plain", 10 ) == 0)
858 convertTypeToNative( pFlavors
[i
].MimeType
, targetselection
, nFormat
, rOutTypeList
);
862 if( targetselection
!= m_nXdndSelection
)
864 // only mimetypes should go into Xdnd type list
865 rOutTypeList
.push_front( XA_STRING
);
866 rOutTypeList
.push_front( m_nCOMPOUNDAtom
);
868 convertTypeToNative( OUString::createFromAscii( "text/plain;charset=utf-8" ), targetselection
, nFormat
, rOutTypeList
, true );
870 if( targetselection
!= m_nXdndSelection
)
871 rOutTypeList
.push_back( m_nMULTIPLEAtom
);
874 // ------------------------------------------------------------------------
876 OUString
SelectionManager::convertTypeFromNative( Atom nType
, Atom selection
, int& rFormat
)
878 NativeTypeEntry
* pTab
= selection
== m_nXdndSelection
? aXdndConversionTab
: aNativeConversionTab
;
879 int nTabEntries
= selection
== m_nXdndSelection
880 ? sizeof(aXdndConversionTab
)/sizeof(aXdndConversionTab
[0]) :
881 sizeof(aNativeConversionTab
)/sizeof(aNativeConversionTab
[0]);
883 for( int i
= 0; i
< nTabEntries
; i
++ )
885 if( ! pTab
[i
].nAtom
)
886 pTab
[i
].nAtom
= getAtom( OStringToOUString( pTab
[i
].pNativeType
, RTL_TEXTENCODING_ISO_8859_1
) );
887 if( nType
== pTab
[i
].nAtom
)
889 rFormat
= pTab
[i
].nFormat
;
890 return OStringToOUString( pTab
[i
].pType
, RTL_TEXTENCODING_ISO_8859_1
);
894 return getString( nType
);
897 // ------------------------------------------------------------------------
899 bool SelectionManager::getPasteData( Atom selection
, Atom type
, Sequence
< sal_Int8
>& rData
)
901 ResettableMutexGuard
aGuard(m_aMutex
);
902 ::std::hash_map
< Atom
, Selection
* >::iterator it
;
903 bool bSuccess
= false;
905 #if OSL_DEBUG_LEVEL > 1
906 OUString
aSelection( getString( selection
) );
907 OUString
aType( getString( type
) );
908 fprintf( stderr
, "getPasteData( %s, native: %s )\n",
909 OUStringToOString( aSelection
, RTL_TEXTENCODING_ISO_8859_1
).getStr(),
910 OUStringToOString( aType
, RTL_TEXTENCODING_ISO_8859_1
).getStr()
917 it
= m_aSelections
.find( selection
);
918 if( it
== m_aSelections
.end() )
921 Window aSelectionOwner
= XGetSelectionOwner( m_pDisplay
, selection
);
922 if( aSelectionOwner
== None
)
924 if( aSelectionOwner
== m_aWindow
)
926 // probably bad timing led us here
927 #if OSL_DEBUG_LEVEL > 1
928 fprintf( stderr
, "Innere Nabelschau\n" );
933 // ICCCM recommends to destroy property before convert request unless
934 // parameters are transported; we do only in case of MULTIPLE,
935 // so destroy property unless target is MULTIPLE
936 if( type
!= m_nMULTIPLEAtom
)
937 XDeleteProperty( m_pDisplay
, m_aWindow
, selection
);
939 XConvertSelection( m_pDisplay
, selection
, type
, selection
, m_aWindow
, selection
== m_nXdndSelection
? m_nDropTime
: CurrentTime
);
940 it
->second
->m_eState
= Selection::WaitingForResponse
;
941 it
->second
->m_aRequestedType
= type
;
942 it
->second
->m_aData
= Sequence
< sal_Int8
>();
943 it
->second
->m_aDataArrived
.reset();
944 // really start the request; if we don't flush the
945 // queue the request won't leave it because there are no more
946 // X calls after this until the data arrived or timeout
947 XFlush( m_pDisplay
);
950 struct timeval tv_last
, tv_current
;
951 gettimeofday( &tv_last
, NULL
);
952 tv_current
= tv_last
;
957 bool bAdjustTime
= false;
959 bool bHandle
= false;
961 if( XCheckTypedEvent( m_pDisplay
,
967 if( aEvent
.xproperty
.window
== m_aWindow
968 && aEvent
.xproperty
.atom
== selection
)
972 if( XCheckTypedEvent( m_pDisplay
,
980 if( XCheckTypedEvent( m_pDisplay
,
986 if( XCheckTypedEvent( m_pDisplay
,
992 if( aEvent
.xselection
.selection
== selection
993 && ( aEvent
.xselection
.requestor
== m_aWindow
||
994 aEvent
.xselection
.requestor
== m_aCurrentDropWindow
)
1002 aTVal
.Nanosec
= 100000000;
1004 osl_waitThread( &aTVal
);
1010 handleXEvent( aEvent
);
1014 gettimeofday( &tv_current
, NULL
);
1016 tv_last
= tv_current
;
1017 } while( ! it
->second
->m_aDataArrived
.check() && (tv_current
.tv_sec
- tv_last
.tv_sec
) < getSelectionTimeout() );
1019 #if OSL_DEBUG_LEVEL > 1
1020 if( (tv_current
.tv_sec
- tv_last
.tv_sec
) > getSelectionTimeout() )
1021 fprintf( stderr
, "timed out\n" );
1023 if( it
->second
->m_aDataArrived
.check() &&
1024 it
->second
->m_aData
.getLength() )
1026 rData
= it
->second
->m_aData
;
1029 #if OSL_DEBUG_LEVEL > 1
1031 fprintf( stderr
, "conversion unsuccessfull\n" );
1036 // ------------------------------------------------------------------------
1038 bool SelectionManager::getPasteData( Atom selection
, const ::rtl::OUString
& rType
, Sequence
< sal_Int8
>& rData
)
1041 bool bSuccess
= false;
1043 ::std::hash_map
< Atom
, Selection
* >::iterator it
;
1045 MutexGuard
aGuard(m_aMutex
);
1047 it
= m_aSelections
.find( selection
);
1048 if( it
== m_aSelections
.end() )
1052 if( it
->second
->m_aTypes
.getLength() == 0 )
1054 Sequence
< DataFlavor
> aFlavors
;
1055 getPasteDataTypes( selection
, aFlavors
);
1056 if( it
->second
->m_aTypes
.getLength() == 0 )
1060 const Sequence
< DataFlavor
>& rTypes( it
->second
->m_aTypes
);
1061 const std::vector
< Atom
>& rNativeTypes( it
->second
->m_aNativeTypes
);
1062 #if OSL_DEBUG_LEVEL > 1
1063 fprintf( stderr
, "getPasteData( \"%s\", \"%s\" )\n",
1064 OUStringToOString( getString( selection
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1065 OUStringToOString( rType
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1068 if( rType
.equalsAsciiL( "text/plain;charset=utf-16", 25 ) )
1070 // lets see if we have UTF16 else try to find something convertible
1071 if( it
->second
->m_aTypes
.getLength() && ! it
->second
->m_bHaveUTF16
)
1073 Sequence
< sal_Int8
> aData
;
1074 if( it
->second
->m_aUTF8Type
!= None
&&
1075 getPasteData( selection
,
1076 it
->second
->m_aUTF8Type
,
1080 OUString
aRet( (const sal_Char
*)aData
.getConstArray(), aData
.getLength(), RTL_TEXTENCODING_UTF8
);
1081 rData
= Sequence
< sal_Int8
>( (sal_Int8
*)aRet
.getStr(), (aRet
.getLength()+1)*sizeof( sal_Unicode
) );
1084 else if( it
->second
->m_bHaveCompound
&&
1085 getPasteData( selection
,
1090 OUString
aRet( convertFromCompound( (const char*)aData
.getConstArray(), aData
.getLength() ) );
1091 rData
= Sequence
< sal_Int8
>( (sal_Int8
*)aRet
.getStr(), (aRet
.getLength()+1)*sizeof( sal_Unicode
) );
1096 for( int i
= 0; i
< rTypes
.getLength(); i
++ )
1098 rtl_TextEncoding aEncoding
= getTextPlainEncoding( rTypes
.getConstArray()[i
].MimeType
);
1099 if( aEncoding
!= RTL_TEXTENCODING_DONTKNOW
&&
1100 aEncoding
!= RTL_TEXTENCODING_UNICODE
&&
1101 getPasteData( selection
,
1106 #if OSL_DEBUG_LEVEL > 1
1107 fprintf( stderr
, "using \"%s\" instead of \"%s\"\n",
1108 OUStringToOString( rTypes
.getConstArray()[i
].MimeType
, RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1109 OUStringToOString( rType
, RTL_TEXTENCODING_ISO_8859_1
).getStr()
1112 OString
aConvert( (sal_Char
*)aData
.getConstArray(), aData
.getLength() );
1113 OUString
aUTF( OStringToOUString( aConvert
, aEncoding
) );
1114 rData
= Sequence
< sal_Int8
>( (sal_Int8
*)aUTF
.getStr(), (aUTF
.getLength()+1)*sizeof( sal_Unicode
) );
1122 else if( rType
.equalsAsciiL( "image/bmp", 9 ) )
1124 // #i83376# try if someone has the data in image/bmp already before
1125 // doing the PIXMAP stuff (e.g. the gimp has this)
1126 bSuccess
= getPasteData( selection
, m_nImageBmpAtom
, rData
);
1127 #if OSL_DEBUG_LEVEL > 1
1129 fprintf( stderr
, "got %d bytes of image/bmp\n", (int)rData
.getLength() );
1133 Pixmap aPixmap
= None
;
1134 Colormap aColormap
= None
;
1136 // prepare property for MULTIPLE request
1137 Sequence
< sal_Int8
> aData
;
1138 Atom pTypes
[4] = { XA_PIXMAP
, XA_PIXMAP
,
1139 XA_COLORMAP
, XA_COLORMAP
};
1141 MutexGuard
aGuard(m_aMutex
);
1143 XChangeProperty( m_pDisplay
,
1149 (unsigned char*)pTypes
,
1153 // try MULTIPLE request
1154 if( getPasteData( selection
, m_nMULTIPLEAtom
, aData
) )
1156 Atom
* pReturnedTypes
= (Atom
*)aData
.getArray();
1157 if( pReturnedTypes
[0] == XA_PIXMAP
&& pReturnedTypes
[1] == XA_PIXMAP
)
1159 MutexGuard
aGuard(m_aMutex
);
1163 unsigned long nItems
= 0;
1164 unsigned long nBytes
= 0;
1165 unsigned char* pReturn
= NULL
;
1166 XGetWindowProperty( m_pDisplay
, m_aWindow
, XA_PIXMAP
, 0, 1, True
, XA_PIXMAP
, &type
, &format
, &nItems
, &nBytes
, &pReturn
);
1169 if( type
== XA_PIXMAP
)
1170 aPixmap
= *(Pixmap
*)pReturn
;
1173 if( pReturnedTypes
[2] == XA_COLORMAP
&& pReturnedTypes
[3] == XA_COLORMAP
)
1175 XGetWindowProperty( m_pDisplay
, m_aWindow
, XA_COLORMAP
, 0, 1, True
, XA_COLORMAP
, &type
, &format
, &nItems
, &nBytes
, &pReturn
);
1178 if( type
== XA_COLORMAP
)
1179 aColormap
= *(Colormap
*)pReturn
;
1184 #if OSL_DEBUG_LEVEL > 1
1187 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
);
1193 if( aPixmap
== None
)
1195 // perhaps two normal requests will work
1196 if( getPasteData( selection
, XA_PIXMAP
, aData
) )
1198 aPixmap
= *(Pixmap
*)aData
.getArray();
1199 if( aColormap
== None
&& getPasteData( selection
, XA_COLORMAP
, aData
) )
1200 aColormap
= *(Colormap
*)aData
.getArray();
1204 // convert data if possible
1205 if( aPixmap
!= None
)
1207 MutexGuard
aGuard(m_aMutex
);
1209 sal_Int32 nOutSize
= 0;
1210 sal_uInt8
* pBytes
= X11_getBmpFromPixmap( m_pDisplay
, aPixmap
, aColormap
, nOutSize
);
1211 if( pBytes
&& nOutSize
)
1213 rData
= Sequence
< sal_Int8
>( nOutSize
);
1214 memcpy( rData
.getArray(), pBytes
, nOutSize
);
1215 X11_freeBmp( pBytes
);
1224 ::std::list
< Atom
> aTypes
;
1225 convertTypeToNative( rType
, selection
, nFormat
, aTypes
);
1226 ::std::list
< Atom
>::const_iterator type_it
;
1227 Atom nSelectedType
= None
;
1228 for( type_it
= aTypes
.begin(); type_it
!= aTypes
.end() && nSelectedType
== None
; ++type_it
)
1230 for( unsigned int i
= 0; i
< rNativeTypes
.size() && nSelectedType
== None
; i
++ )
1231 if( rNativeTypes
[i
] == *type_it
)
1232 nSelectedType
= *type_it
;
1234 if( nSelectedType
!= None
)
1235 bSuccess
= getPasteData( selection
, nSelectedType
, rData
);
1237 #if OSL_DEBUG_LEVEL > 1
1238 fprintf( stderr
, "getPasteData for selection %s and data type %s returns %s, returned sequence has length %ld\n",
1239 OUStringToOString( getString( selection
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1240 OUStringToOString( rType
, RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1241 bSuccess
? "true" : "false",
1248 // ------------------------------------------------------------------------
1250 bool SelectionManager::getPasteDataTypes( Atom selection
, Sequence
< DataFlavor
>& rTypes
)
1252 ::std::hash_map
< Atom
, Selection
* >::iterator it
;
1254 MutexGuard
aGuard(m_aMutex
);
1256 it
= m_aSelections
.find( selection
);
1257 if( it
!= m_aSelections
.end() &&
1258 it
->second
->m_aTypes
.getLength() &&
1259 abs( it
->second
->m_nLastTimestamp
- time( NULL
) ) < 2
1262 rTypes
= it
->second
->m_aTypes
;
1267 bool bSuccess
= false;
1268 bool bHaveUTF16
= false;
1269 Atom aUTF8Type
= None
;
1270 bool bHaveCompound
= false;
1271 bool bHaveText
= false;
1272 Sequence
< sal_Int8
> aAtoms
;
1274 if( selection
== m_nXdndSelection
)
1276 // xdnd sends first three types with XdndEnter
1277 // if more than three types are supported then the XDndTypeList
1278 // property on the source window is used
1279 if( m_aDropEnterEvent
.data
.l
[0] && m_aCurrentDropWindow
)
1281 if( m_aDropEnterEvent
.data
.l
[1] & 1 )
1283 const unsigned int atomcount
= 256;
1284 // more than three types; look in property
1285 MutexGuard
aGuard(m_aMutex
);
1289 unsigned long nItems
, nBytes
;
1290 unsigned char* pBytes
= NULL
;
1292 XGetWindowProperty( m_pDisplay
, m_aDropEnterEvent
.data
.l
[0],
1293 m_nXdndTypeList
, 0, atomcount
, False
,
1295 &nType
, &nFormat
, &nItems
, &nBytes
, &pBytes
);
1296 #if OSL_DEBUG_LEVEL > 1
1297 fprintf( stderr
, "have %ld data types in XdndTypeList\n", nItems
);
1299 if( nItems
== atomcount
&& nBytes
> 0 )
1301 // wow ... more than 256 types !
1302 aAtoms
.realloc( sizeof( Atom
)*atomcount
+nBytes
);
1303 memcpy( aAtoms
.getArray(), pBytes
, sizeof( Atom
)*atomcount
);
1306 XGetWindowProperty( m_pDisplay
, m_aDropEnterEvent
.data
.l
[0],
1307 m_nXdndTypeList
, atomcount
, nBytes
/sizeof(Atom
),
1309 &nType
, &nFormat
, &nItems
, &nBytes
, &pBytes
);
1311 memcpy( aAtoms
.getArray()+atomcount
*sizeof(Atom
), pBytes
, nItems
*sizeof(Atom
) );
1317 aAtoms
.realloc( sizeof(Atom
)*nItems
);
1318 memcpy( aAtoms
.getArray(), pBytes
, nItems
*sizeof(Atom
) );
1324 // one to three types
1326 for( i
= 0; i
< 3; i
++ )
1327 if( m_aDropEnterEvent
.data
.l
[2+i
] )
1329 #if OSL_DEBUG_LEVEL > 1
1330 fprintf( stderr
, "have %d data types in XdndEnter\n", n
);
1332 aAtoms
.realloc( sizeof(Atom
)*n
);
1333 for( i
= 0, n
= 0; i
< 3; i
++ )
1334 if( m_aDropEnterEvent
.data
.l
[2+i
] )
1335 ((Atom
*)aAtoms
.getArray())[n
++] = m_aDropEnterEvent
.data
.l
[2+i
];
1339 // get data of type TARGETS
1340 else if( ! getPasteData( selection
, m_nTARGETSAtom
, aAtoms
) )
1341 aAtoms
= Sequence
< sal_Int8
>();
1343 std::vector
< Atom
> aNativeTypes
;
1344 if( aAtoms
.getLength() )
1346 sal_Int32 nAtoms
= aAtoms
.getLength() / sizeof(Atom
);
1347 Atom
* pAtoms
= (Atom
*)aAtoms
.getArray();
1348 rTypes
.realloc( nAtoms
);
1349 aNativeTypes
.resize( nAtoms
);
1350 DataFlavor
* pFlavors
= rTypes
.getArray();
1351 sal_Int32 nNativeTypesIndex
= 0;
1354 #if OSL_DEBUG_LEVEL > 1
1355 if( *pAtoms
&& *pAtoms
< 0x01000000 )
1356 fprintf( stderr
, "native type: %s\n", OUStringToOString( getString( *pAtoms
), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1358 if( *pAtoms
== m_nCOMPOUNDAtom
)
1359 bHaveText
= bHaveCompound
= true;
1360 else if( *pAtoms
&& *pAtoms
< 0x01000000 )
1363 pFlavors
->MimeType
= convertTypeFromNative( *pAtoms
, selection
, nFormat
);
1364 pFlavors
->DataType
= getCppuType( (Sequence
< sal_Int8
>*)0 );
1365 sal_Int32 nIndex
= 0;
1366 if( pFlavors
->MimeType
.getToken( 0, ';', nIndex
).equalsAsciiL( "text/plain", 10 ) )
1368 OUString
aToken(pFlavors
->MimeType
.getToken( 0, ';', nIndex
));
1369 // omit text/plain;charset=unicode since it is not well defined
1370 if( aToken
.compareToAscii( "charset=unicode" ) == 0 )
1376 if( aToken
.compareToAscii( "charset=utf-16" ) == 0 )
1379 pFlavors
->DataType
= getCppuType( (OUString
*)0 );
1381 else if( aToken
.compareToAscii( "charset=utf-8" ) == 0 )
1383 aUTF8Type
= *pAtoms
;
1387 aNativeTypes
[ nNativeTypesIndex
] = *pAtoms
;
1388 nNativeTypesIndex
++;
1392 if( (pFlavors
- rTypes
.getArray()) < rTypes
.getLength() )
1393 rTypes
.realloc(pFlavors
- rTypes
.getArray());
1394 bSuccess
= rTypes
.getLength() ? true : false;
1395 if( bHaveText
&& ! bHaveUTF16
)
1399 int nNewFlavors
= rTypes
.getLength()+1;
1400 Sequence
< DataFlavor
> aTemp( nNewFlavors
);
1401 for( i
= 0; i
< nNewFlavors
-1; i
++ )
1402 aTemp
.getArray()[i
+1] = rTypes
.getConstArray()[i
];
1403 aTemp
.getArray()[0].MimeType
= OUString::createFromAscii( "text/plain;charset=utf-16" );
1404 aTemp
.getArray()[0].DataType
= getCppuType( (OUString
*)0 );
1407 std::vector
< Atom
> aNativeTemp( nNewFlavors
);
1408 for( i
= 0; i
< nNewFlavors
-1; i
++ )
1409 aNativeTemp
[ i
+ 1 ] = aNativeTypes
[ i
];
1410 aNativeTemp
[0] = None
;
1411 aNativeTypes
= aNativeTemp
;
1416 MutexGuard
aGuard(m_aMutex
);
1418 it
= m_aSelections
.find( selection
);
1419 if( it
!= m_aSelections
.end() )
1423 it
->second
->m_aTypes
= rTypes
;
1424 it
->second
->m_aNativeTypes
= aNativeTypes
;
1425 it
->second
->m_nLastTimestamp
= time( NULL
);
1426 it
->second
->m_bHaveUTF16
= bHaveUTF16
;
1427 it
->second
->m_aUTF8Type
= aUTF8Type
;
1428 it
->second
->m_bHaveCompound
= bHaveCompound
;
1432 it
->second
->m_aTypes
= Sequence
< DataFlavor
>();
1433 it
->second
->m_aNativeTypes
= std::vector
< Atom
>();
1434 it
->second
->m_nLastTimestamp
= 0;
1435 it
->second
->m_bHaveUTF16
= false;
1436 it
->second
->m_aUTF8Type
= None
;
1437 it
->second
->m_bHaveCompound
= false;
1442 #if OSL_DEBUG_LEVEL > 1
1443 // if( selection != m_nCLIPBOARDAtom )
1445 fprintf( stderr
, "SelectionManager::getPasteDataTypes( %s ) = %s\n", OUStringToOString( getString( selection
), RTL_TEXTENCODING_ISO_8859_1
).getStr(), bSuccess
? "true" : "false" );
1446 for( int i
= 0; i
< rTypes
.getLength(); i
++ )
1447 fprintf( stderr
, "type: %s\n", OUStringToOString( rTypes
.getConstArray()[i
].MimeType
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1454 // ------------------------------------------------------------------------
1456 PixmapHolder
* SelectionManager::getPixmapHolder( Atom selection
)
1458 std::hash_map
< Atom
, Selection
* >::const_iterator it
= m_aSelections
.find( selection
);
1459 if( it
== m_aSelections
.end() )
1461 if( ! it
->second
->m_pPixmap
)
1462 it
->second
->m_pPixmap
= new PixmapHolder( m_pDisplay
);
1463 return it
->second
->m_pPixmap
;
1466 static sal_Size
GetTrueFormatSize(int nFormat
)
1468 // http://mail.gnome.org/archives/wm-spec-list/2003-March/msg00067.html
1469 return nFormat
== 32 ? sizeof(long) : nFormat
/8;
1472 bool SelectionManager::sendData( SelectionAdaptor
* pAdaptor
,
1478 ResettableMutexGuard
aGuard( m_aMutex
);
1480 // handle targets related to image/bmp
1481 if( target
== XA_COLORMAP
|| target
== XA_PIXMAP
|| target
== XA_BITMAP
|| target
== XA_VISUALID
)
1483 PixmapHolder
* pPixmap
= getPixmapHolder( selection
);
1484 if( ! pPixmap
) return false;
1487 // handle colormap request
1488 if( target
== XA_COLORMAP
)
1489 nValue
= (XID
)pPixmap
->getColormap();
1490 else if( target
== XA_VISUALID
)
1491 nValue
= (XID
)pPixmap
->getVisualID();
1492 else if( target
== XA_PIXMAP
|| target
== XA_BITMAP
)
1494 nValue
= (XID
)pPixmap
->getPixmap();
1495 if( nValue
== None
)
1498 Sequence
< sal_Int8
> aData
;
1501 bool bConverted
= convertData( pAdaptor
->getTransferable(), target
, selection
, nFormat
, aData
);
1505 // get pixmap again since clearing the guard could have invalidated
1506 // the pixmap in another thread
1507 pPixmap
= getPixmapHolder( selection
);
1508 // conversion succeeded, so aData contains image/bmp now
1509 if( pPixmap
->needsConversion( (const sal_uInt8
*)aData
.getConstArray() )
1510 && m_xBitmapConverter
.is() )
1512 #if OSL_DEBUG_LEVEL > 1
1513 fprintf( stderr
, "trying bitmap conversion\n" );
1515 Reference
<XBitmap
> xBM( new BmpTransporter( aData
) );
1516 Sequence
<Any
> aArgs(2), aOutArgs
;
1517 Sequence
<sal_Int16
> aOutIndex
;
1518 aArgs
.getArray()[0] = makeAny( xBM
);
1519 aArgs
.getArray()[1] = makeAny( (sal_uInt16
)pPixmap
->getDepth() );
1524 m_xBitmapConverter
->invoke( OUString::createFromAscii( "convert-bitmap-depth" ),
1525 aArgs
, aOutIndex
, aOutArgs
);
1526 if( aResult
>>= xBM
)
1527 aData
= xBM
->getDIB();
1531 #if OSL_DEBUG_LEVEL > 1
1532 fprintf( stderr
, "exception in bitmap converter\n" );
1537 // get pixmap again since clearing the guard could have invalidated
1538 // the pixmap in another thread
1539 pPixmap
= getPixmapHolder( selection
);
1540 nValue
= (XID
)pPixmap
->setBitmapData( (const sal_uInt8
*)aData
.getConstArray() );
1542 if( nValue
== None
)
1545 if( target
== XA_BITMAP
)
1546 nValue
= (XID
)pPixmap
->getBitmap();
1549 XChangeProperty( m_pDisplay
,
1555 (const unsigned char*)&nValue
,
1561 * special target TEXT allows us to transfer
1562 * the data in an encoding of our choice
1563 * COMPOUND_TEXT will work with most applications
1565 if( target
== m_nTEXTAtom
)
1566 target
= m_nCOMPOUNDAtom
;
1568 Sequence
< sal_Int8
> aData
;
1571 bool bConverted
= convertData( pAdaptor
->getTransferable(), target
, selection
, nFormat
, aData
);
1575 // conversion succeeded
1576 if( aData
.getLength() > m_nIncrementalThreshold
)
1578 #if OSL_DEBUG_LEVEL > 1
1579 fprintf( stderr
, "using INCR protocol\n" );
1580 std::hash_map
< Window
, std::hash_map
< Atom
, IncrementalTransfer
> >::const_iterator win_it
= m_aIncrementals
.find( requestor
);
1581 if( win_it
!= m_aIncrementals
.end() )
1583 std::hash_map
< Atom
, IncrementalTransfer
>::const_iterator inc_it
= win_it
->second
.find( property
);
1584 if( inc_it
!= win_it
->second
.end() )
1586 const IncrementalTransfer
& rInc
= inc_it
->second
;
1587 fprintf( stderr
, "premature end and new start for INCR transfer for window 0x%lx, property %s, type %s\n",
1589 OUStringToOString( getString( rInc
.m_aProperty
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1590 OUStringToOString( getString( rInc
.m_aTarget
), RTL_TEXTENCODING_ISO_8859_1
).getStr()
1596 // insert IncrementalTransfer
1597 IncrementalTransfer
& rInc
= m_aIncrementals
[ requestor
][ property
];
1598 rInc
.m_aData
= aData
;
1599 rInc
.m_nBufferPos
= 0;
1600 rInc
.m_aRequestor
= requestor
;
1601 rInc
.m_aProperty
= property
;
1602 rInc
.m_aTarget
= target
;
1603 rInc
.m_nFormat
= nFormat
;
1604 rInc
.m_nTransferStartTime
= time( NULL
);
1606 // use incr protocol, signal start to requestor
1607 long nMinSize
= m_nIncrementalThreshold
;
1608 XSelectInput( m_pDisplay
, requestor
, PropertyChangeMask
);
1609 XChangeProperty( m_pDisplay
, requestor
, property
,
1610 m_nINCRAtom
, 32, PropModeReplace
, (unsigned char*)&nMinSize
, 1 );
1611 XFlush( m_pDisplay
);
1615 sal_Size nUnitSize
= GetTrueFormatSize(nFormat
);
1616 XChangeProperty( m_pDisplay
,
1622 (const unsigned char*)aData
.getConstArray(),
1623 aData
.getLength()/nUnitSize
);
1626 #if OSL_DEBUG_LEVEL > 1
1628 fprintf( stderr
, "convertData failed for type: %s \n",
1629 OUStringToOString( convertTypeFromNative( target
, selection
, nFormat
), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1634 // ------------------------------------------------------------------------
1636 bool SelectionManager::handleSelectionRequest( XSelectionRequestEvent
& rRequest
)
1638 ResettableMutexGuard
aGuard( m_aMutex
);
1639 #if OSL_DEBUG_LEVEL > 1
1640 fprintf( stderr
, "handleSelectionRequest for selection %s and target %s\n",
1641 OUStringToOString( getString( rRequest
.selection
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1642 OUStringToOString( getString( rRequest
.target
), RTL_TEXTENCODING_ISO_8859_1
).getStr()
1648 aNotify
.type
= SelectionNotify
;
1649 aNotify
.xselection
.display
= rRequest
.display
;
1650 aNotify
.xselection
.send_event
= True
;
1651 aNotify
.xselection
.requestor
= rRequest
.requestor
;
1652 aNotify
.xselection
.selection
= rRequest
.selection
;
1653 aNotify
.xselection
.time
= rRequest
.time
;
1654 aNotify
.xselection
.target
= rRequest
.target
;
1655 aNotify
.xselection
.property
= None
;
1657 SelectionAdaptor
* pAdaptor
= getAdaptor( rRequest
.selection
);
1658 // ensure that we still own that selection
1660 XGetSelectionOwner( m_pDisplay
, rRequest
.selection
) == m_aWindow
)
1662 Reference
< XTransferable
> xTrans( pAdaptor
->getTransferable() );
1663 if( rRequest
.target
== m_nTARGETSAtom
)
1665 // someone requests our types
1669 Sequence
< DataFlavor
> aFlavors
= xTrans
->getTransferDataFlavors();
1672 ::std::list
< Atom
> aConversions
;
1673 getNativeTypeList( aFlavors
, aConversions
, rRequest
.selection
);
1675 int i
, nTypes
= aConversions
.size();
1676 Atom
* pTypes
= (Atom
*)alloca( nTypes
* sizeof( Atom
) );
1677 std::list
< Atom
>::const_iterator it
;
1678 for( i
= 0, it
= aConversions
.begin(); i
< nTypes
; i
++, ++it
)
1680 XChangeProperty( m_pDisplay
, rRequest
.requestor
, rRequest
.property
,
1681 XA_ATOM
, 32, PropModeReplace
, (const unsigned char*)pTypes
, nTypes
);
1682 aNotify
.xselection
.property
= rRequest
.property
;
1683 #if OSL_DEBUG_LEVEL > 1
1684 fprintf( stderr
, "sending type list:\n" );
1685 for( int k
= 0; k
< nTypes
; k
++ )
1686 fprintf( stderr
, " %s\n", pTypes
[k
] ? XGetAtomName( m_pDisplay
, pTypes
[k
] ) : "<None>" );
1690 else if( rRequest
.target
== m_nTIMESTAMPAtom
)
1692 long nTimeStamp
= (long)m_aSelections
[rRequest
.selection
]->m_nOrigTimestamp
;
1693 XChangeProperty( m_pDisplay
, rRequest
.requestor
, rRequest
.property
,
1694 XA_INTEGER
, 32, PropModeReplace
, (const unsigned char*)&nTimeStamp
, 1 );
1695 aNotify
.xselection
.property
= rRequest
.property
;
1696 #if OSL_DEBUG_LEVEL > 1
1697 fprintf( stderr
, "sending timestamp: %d\n", (int)nTimeStamp
);
1702 bool bEventSuccess
= false;
1703 if( rRequest
.target
== m_nMULTIPLEAtom
)
1708 unsigned long nItems
= 0, nBytes
= 0;
1709 unsigned char* pData
= NULL
;
1711 // get number of atoms
1712 XGetWindowProperty( m_pDisplay
,
1721 if( nFormat
== 32 && nBytes
/4 )
1723 if( pData
) // ?? should not happen
1728 XGetWindowProperty( m_pDisplay
,
1737 if( pData
&& nItems
)
1739 #if OSL_DEBUG_LEVEL > 1
1740 fprintf( stderr
, "found %ld atoms in MULTIPLE request\n", nItems
);
1742 bEventSuccess
= true;
1743 bool bResetAtoms
= false;
1744 Atom
* pAtoms
= (Atom
*)pData
;
1746 for( unsigned int i
= 0; i
< nItems
; i
+= 2 )
1748 #if OSL_DEBUG_LEVEL > 1
1749 fprintf( stderr
, " %s => %s: ",
1750 OUStringToOString( getString( pAtoms
[i
] ), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1751 OUStringToOString( getString( pAtoms
[i
+1] ), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1753 bool bSuccess
= sendData( pAdaptor
, rRequest
.requestor
, pAtoms
[i
], pAtoms
[i
+1], rRequest
.selection
);
1754 #if OSL_DEBUG_LEVEL > 1
1755 fprintf( stderr
, "%s\n", bSuccess
? "succeeded" : "failed" );
1765 XChangeProperty( m_pDisplay
,
1777 #if OSL_DEBUG_LEVEL > 1
1780 fprintf( stderr
, "could not get type list from \"%s\" of type \"%s\" on requestor 0x%lx, requestor has properties:",
1781 OUStringToOString( getString( rRequest
.property
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1782 OUStringToOString( getString( nType
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1783 rRequest
.requestor
);
1785 Atom
* pProps
= XListProperties( m_pDisplay
, rRequest
.requestor
, &nProps
);
1788 for( int i
= 0; i
< nProps
; i
++ )
1789 fprintf( stderr
, " \"%s\"", OUStringToOString( getString( pProps
[i
]), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1798 bEventSuccess
= sendData( pAdaptor
, rRequest
.requestor
, rRequest
.target
, rRequest
.property
, rRequest
.selection
);
1803 aNotify
.xselection
.target
= rRequest
.target
;
1804 aNotify
.xselection
.property
= rRequest
.property
;
1811 XSendEvent( m_pDisplay
, rRequest
.requestor
, False
, 0, &aNotify
);
1813 if( rRequest
.selection
== XA_PRIMARY
&&
1814 m_bWaitingForPrimaryConversion
&&
1815 m_xDragSourceListener
.is() )
1817 DragSourceDropEvent dsde
;
1818 dsde
.Source
= static_cast< OWeakObject
* >(this);
1819 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, rRequest
.time
, *this );
1820 dsde
.DragSource
= static_cast< XDragSource
* >(this);
1821 if( aNotify
.xselection
.property
!= None
)
1823 dsde
.DropAction
= DNDConstants::ACTION_COPY
;
1824 dsde
.DropSuccess
= sal_True
;
1828 dsde
.DropAction
= DNDConstants::ACTION_NONE
;
1829 dsde
.DropSuccess
= sal_False
;
1831 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
1832 m_xDragSourceListener
.clear();
1834 if( xListener
.is() )
1835 xListener
->dragDropEnd( dsde
);
1838 // we handled the event in any case by answering
1842 // ------------------------------------------------------------------------
1844 bool SelectionManager::handleReceivePropertyNotify( XPropertyEvent
& rNotify
)
1846 MutexGuard
aGuard( m_aMutex
);
1847 // data we requested arrived
1848 #if OSL_DEBUG_LEVEL > 1
1849 fprintf( stderr
, "handleReceivePropertyNotify for property %s\n",
1850 OUStringToOString( getString( rNotify
.atom
), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1852 bool bHandled
= false;
1854 ::std::hash_map
< Atom
, Selection
* >::iterator it
=
1855 m_aSelections
.find( rNotify
.atom
);
1856 if( it
!= m_aSelections
.end() &&
1857 rNotify
.state
== PropertyNewValue
&&
1858 ( it
->second
->m_eState
== Selection::WaitingForResponse
||
1859 it
->second
->m_eState
== Selection::WaitingForData
||
1860 it
->second
->m_eState
== Selection::IncrementalTransfer
1864 // MULTIPLE requests are only complete after selection notify
1865 if( it
->second
->m_aRequestedType
== m_nMULTIPLEAtom
&&
1866 ( it
->second
->m_eState
== Selection::WaitingForResponse
||
1867 it
->second
->m_eState
== Selection::WaitingForData
) )
1874 unsigned long nItems
= 0, nBytes
= 0;
1875 unsigned char* pData
= NULL
;
1877 // get type and length
1878 XGetWindowProperty( m_pDisplay
,
1887 #if OSL_DEBUG_LEVEL > 1
1888 fprintf( stderr
, "found %ld bytes data of type %s and format %d, items = %ld\n",
1890 OUStringToOString( getString( nType
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1899 if( nType
== m_nINCRAtom
)
1901 // start data transfer
1902 XDeleteProperty( m_pDisplay
, rNotify
.window
, rNotify
.atom
);
1903 it
->second
->m_eState
= Selection::IncrementalTransfer
;
1905 else if( nType
!= None
)
1907 XGetWindowProperty( m_pDisplay
,
1916 #if OSL_DEBUG_LEVEL > 1
1917 fprintf( stderr
, "read %ld items data of type %s and format %d, %ld bytes left in property\n",
1919 OUStringToOString( getString( nType
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1923 sal_Size nUnitSize
= GetTrueFormatSize(nFormat
);
1925 if( it
->second
->m_eState
== Selection::WaitingForData
||
1926 it
->second
->m_eState
== Selection::WaitingForResponse
)
1929 it
->second
->m_aData
= Sequence
< sal_Int8
>( (sal_Int8
*)pData
, nItems
*nUnitSize
);
1930 it
->second
->m_eState
= Selection::Inactive
;
1931 it
->second
->m_aDataArrived
.set();
1933 else if( it
->second
->m_eState
== Selection::IncrementalTransfer
)
1938 Sequence
< sal_Int8
> aData( it
->second
->m_aData
.getLength() + nItems
*nUnitSize
);
1939 memcpy( aData
.getArray(), it
->second
->m_aData
.getArray(), it
->second
->m_aData
.getLength() );
1940 memcpy( aData
.getArray() + it
->second
->m_aData
.getLength(), pData
, nItems
*nUnitSize
);
1941 it
->second
->m_aData
= aData
;
1945 it
->second
->m_eState
= Selection::Inactive
;
1946 it
->second
->m_aDataArrived
.set();
1952 else if( it
->second
->m_eState
== Selection::IncrementalTransfer
)
1954 it
->second
->m_eState
= Selection::Inactive
;
1955 it
->second
->m_aDataArrived
.set();
1961 // ------------------------------------------------------------------------
1963 bool SelectionManager::handleSendPropertyNotify( XPropertyEvent
& rNotify
)
1965 MutexGuard
aGuard( m_aMutex
);
1967 // ready for next part of a IncrementalTransfer
1968 #if OSL_DEBUG_LEVEL > 1
1969 fprintf( stderr
, "handleSendPropertyNotify for property %s (%s)\n",
1970 OUStringToOString( getString( rNotify
.atom
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1971 rNotify
.state
== PropertyNewValue
? "new value" : ( rNotify
.state
== PropertyDelete
? "deleted" : "unknown")
1975 bool bHandled
= false;
1976 // feed incrementals
1977 if( rNotify
.state
== PropertyDelete
)
1979 std::hash_map
< Window
, std::hash_map
< Atom
, IncrementalTransfer
> >::iterator it
;
1980 it
= m_aIncrementals
.find( rNotify
.window
);
1981 if( it
!= m_aIncrementals
.end() )
1984 int nCurrentTime
= time( NULL
);
1985 std::hash_map
< Atom
, IncrementalTransfer
>::iterator inc_it
;
1986 // throw out aborted transfers
1987 std::list
< Atom
> aTimeouts
;
1988 for( inc_it
= it
->second
.begin(); inc_it
!= it
->second
.end(); ++inc_it
)
1990 if( (nCurrentTime
- inc_it
->second
.m_nTransferStartTime
) > (getSelectionTimeout()+2) )
1992 aTimeouts
.push_back( inc_it
->first
);
1993 #if OSL_DEBUG_LEVEL > 1
1994 const IncrementalTransfer
& rInc
= inc_it
->second
;
1995 fprintf( stderr
, "timeout on INCR transfer for window 0x%lx, property %s, type %s\n",
1997 OUStringToOString( getString( rInc
.m_aProperty
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1998 OUStringToOString( getString( rInc
.m_aTarget
), RTL_TEXTENCODING_ISO_8859_1
).getStr()
2004 while( aTimeouts
.begin() != aTimeouts
.end() )
2006 // transfer broken, might even be a new client with the
2008 it
->second
.erase( aTimeouts
.front() );
2009 aTimeouts
.pop_front();
2012 inc_it
= it
->second
.find( rNotify
.atom
);
2013 if( inc_it
!= it
->second
.end() )
2015 IncrementalTransfer
& rInc
= inc_it
->second
;
2017 int nBytes
= rInc
.m_aData
.getLength() - rInc
.m_nBufferPos
;
2018 nBytes
= (nBytes
> m_nIncrementalThreshold
) ? m_nIncrementalThreshold
: nBytes
;
2019 if( nBytes
< 0 ) // sanity check
2021 #if OSL_DEBUG_LEVEL > 1
2022 fprintf( stderr
, "pushing %d bytes: \"%.*s\"...\n",
2023 nBytes
, nBytes
> 32 ? 32 : nBytes
,
2024 (const unsigned char*)rInc
.m_aData
.getConstArray()+rInc
.m_nBufferPos
);
2027 sal_Size nUnitSize
= GetTrueFormatSize(rInc
.m_nFormat
);
2029 XChangeProperty( m_pDisplay
,
2035 (const unsigned char*)rInc
.m_aData
.getConstArray()+rInc
.m_nBufferPos
,
2037 rInc
.m_nBufferPos
+= nBytes
;
2038 rInc
.m_nTransferStartTime
= nCurrentTime
;
2040 if( nBytes
== 0 ) // transfer finished
2042 #if OSL_DEBUG_LEVEL > 1
2043 fprintf( stderr
, "finished INCR transfer for window 0x%lx, property %s, type %s\n",
2045 OUStringToOString( getString( rInc
.m_aProperty
), RTL_TEXTENCODING_ISO_8859_1
).getStr(),
2046 OUStringToOString( getString( rInc
.m_aTarget
), RTL_TEXTENCODING_ISO_8859_1
).getStr()
2049 it
->second
.erase( inc_it
);
2053 // eventually clean up the hash map
2054 if( it
->second
.begin() == it
->second
.end() )
2055 m_aIncrementals
.erase( it
);
2061 // ------------------------------------------------------------------------
2063 bool SelectionManager::handleSelectionNotify( XSelectionEvent
& rNotify
)
2065 MutexGuard
aGuard( m_aMutex
);
2067 bool bHandled
= false;
2069 // notification about success/failure of one of our conversion requests
2070 #if OSL_DEBUG_LEVEL > 1
2071 OUString
aSelection( getString( rNotify
.selection
) );
2072 OUString
aProperty( OUString::createFromAscii( "None" ) );
2073 if( rNotify
.property
)
2074 aProperty
= getString( rNotify
.property
);
2075 fprintf( stderr
, "handleSelectionNotify for selection %s and property %s (0x%lx)\n",
2076 OUStringToOString( aSelection
, RTL_TEXTENCODING_ISO_8859_1
).getStr(),
2077 OUStringToOString( aProperty
, RTL_TEXTENCODING_ISO_8859_1
).getStr(),
2080 if( rNotify
.requestor
!= m_aWindow
&& rNotify
.requestor
!= m_aCurrentDropWindow
)
2081 fprintf( stderr
, "Warning: selection notify for unknown window 0x%lx\n", rNotify
.requestor
);
2083 ::std::hash_map
< Atom
, Selection
* >::iterator it
=
2084 m_aSelections
.find( rNotify
.selection
);
2086 (rNotify
.requestor
== m_aWindow
|| rNotify
.requestor
== m_aCurrentDropWindow
) &&
2087 it
!= m_aSelections
.end() &&
2089 (it
->second
->m_eState
== Selection::WaitingForResponse
) ||
2090 (it
->second
->m_eState
== Selection::WaitingForData
)
2095 if( it
->second
->m_aRequestedType
== m_nMULTIPLEAtom
)
2099 unsigned long nItems
= 0, nBytes
= 0;
2100 unsigned char* pData
= NULL
;
2102 // get type and length
2103 XGetWindowProperty( m_pDisplay
,
2112 if( nBytes
) // HUGE request !!!
2116 XGetWindowProperty( m_pDisplay
,
2119 0, 256+(nBytes
+3)/4,
2126 it
->second
->m_eState
= Selection::Inactive
;
2127 sal_Size nUnitSize
= GetTrueFormatSize(nFormat
);
2128 it
->second
->m_aData
= Sequence
< sal_Int8
>((sal_Int8
*)pData
, nItems
* nUnitSize
);
2129 it
->second
->m_aDataArrived
.set();
2133 // WaitingForData can actually happen; some
2134 // applications (e.g. cmdtool on Solaris) first send
2135 // a success and then cancel it. Weird !
2136 else if( rNotify
.property
== None
)
2138 // conversion failed, stop transfer
2139 it
->second
->m_eState
= Selection::Inactive
;
2140 it
->second
->m_aData
= Sequence
< sal_Int8
>();
2141 it
->second
->m_aDataArrived
.set();
2143 // get the bytes, by INCR if necessary
2145 it
->second
->m_eState
= Selection::WaitingForData
;
2147 #if OSL_DEBUG_LEVEL > 1
2148 else if( it
!= m_aSelections
.end() )
2149 fprintf( stderr
, "Warning: selection in state %d\n", it
->second
->m_eState
);
2154 // ------------------------------------------------------------------------
2156 bool SelectionManager::handleDropEvent( XClientMessageEvent
& rMessage
)
2158 ResettableMutexGuard
aGuard(m_aMutex
);
2160 // handle drop related events
2161 Window aSource
= rMessage
.data
.l
[0];
2162 Window aTarget
= rMessage
.window
;
2164 bool bHandled
= false;
2166 ::std::hash_map
< Window
, DropTargetEntry
>::iterator it
=
2167 m_aDropTargets
.find( aTarget
);
2169 #if OSL_DEBUG_LEVEL > 1
2170 if( rMessage
.message_type
== m_nXdndEnter
||
2171 rMessage
.message_type
== m_nXdndLeave
||
2172 rMessage
.message_type
== m_nXdndDrop
||
2173 rMessage
.message_type
== m_nXdndPosition
)
2175 fprintf( stderr
, "got drop event %s, ", OUStringToOString( getString( rMessage
.message_type
), RTL_TEXTENCODING_ASCII_US
).getStr() );
2176 if( it
== m_aDropTargets
.end() )
2177 fprintf( stderr
, "but no target found\n" );
2178 else if( ! it
->second
.m_pTarget
->m_bActive
)
2179 fprintf( stderr
, "but target is inactive\n" );
2180 else if( m_aDropEnterEvent
.data
.l
[0] != None
&& (Window
)m_aDropEnterEvent
.data
.l
[0] != aSource
)
2181 fprintf( stderr
, "but source 0x%lx is unknown (expected 0x%lx or 0)\n", aSource
, m_aDropEnterEvent
.data
.l
[0] );
2183 fprintf( stderr
, "processing.\n" );
2187 if( it
!= m_aDropTargets
.end() && it
->second
.m_pTarget
->m_bActive
&&
2188 m_bDropWaitingForCompletion
&& m_aDropEnterEvent
.data
.l
[0] )
2191 OSL_ENSURE( 0, "someone forgot to call dropComplete ?" );
2192 // some listener forgot to call dropComplete in the last operation
2193 // let us end it now and accept the new enter event
2195 dropComplete( sal_False
, m_aCurrentDropWindow
, m_nDropTime
);
2199 if( it
!= m_aDropTargets
.end() &&
2200 it
->second
.m_pTarget
->m_bActive
&&
2201 ( m_aDropEnterEvent
.data
.l
[0] == None
|| Window(m_aDropEnterEvent
.data
.l
[0]) == aSource
)
2204 if( rMessage
.message_type
== m_nXdndEnter
)
2207 m_aDropEnterEvent
= rMessage
;
2208 m_bDropEnterSent
= false;
2209 m_aCurrentDropWindow
= aTarget
;
2210 m_nCurrentProtocolVersion
= m_aDropEnterEvent
.data
.l
[1] >> 24;
2211 #if OSL_DEBUG_LEVEL > 1
2212 fprintf( stderr
, "received XdndEnter on 0x%lx\n", aTarget
);
2216 rMessage
.message_type
== m_nXdndPosition
&&
2217 aSource
== Window(m_aDropEnterEvent
.data
.l
[0])
2221 m_nDropTime
= m_nCurrentProtocolVersion
> 0 ? rMessage
.data
.l
[3] : CurrentTime
;
2222 if( ! m_bDropEnterSent
)
2223 m_nDropTimestamp
= m_nDropTime
;
2226 XTranslateCoordinates( m_pDisplay
,
2227 it
->second
.m_aRootWindow
,
2229 rMessage
.data
.l
[2] >> 16,
2230 rMessage
.data
.l
[2] & 0xffff,
2231 &m_nLastX
, &m_nLastY
,
2234 #if OSL_DEBUG_LEVEL > 1
2235 fprintf( stderr
, "received XdndPosition on 0x%lx (%d, %d)\n", aTarget
, m_nLastX
, m_nLastY
);
2237 DropTargetDragEnterEvent aEvent
;
2238 aEvent
.Source
= static_cast< XDropTarget
* >(it
->second
.m_pTarget
);
2239 aEvent
.Context
= new DropTargetDragContext( m_aCurrentDropWindow
, m_nDropTimestamp
, *this );
2240 aEvent
.LocationX
= m_nLastX
;
2241 aEvent
.LocationY
= m_nLastY
;
2242 aEvent
.SourceActions
= m_nSourceActions
;
2243 if( m_nCurrentProtocolVersion
< 2 )
2244 aEvent
.DropAction
= DNDConstants::ACTION_COPY
;
2245 else if( Atom(rMessage
.data
.l
[4]) == m_nXdndActionCopy
)
2246 aEvent
.DropAction
= DNDConstants::ACTION_COPY
;
2247 else if( Atom(rMessage
.data
.l
[4]) == m_nXdndActionMove
)
2248 aEvent
.DropAction
= DNDConstants::ACTION_MOVE
;
2249 else if( Atom(rMessage
.data
.l
[4]) == m_nXdndActionLink
)
2250 aEvent
.DropAction
= DNDConstants::ACTION_LINK
;
2251 else if( Atom(rMessage
.data
.l
[4]) == m_nXdndActionAsk
)
2252 // currently no interface to implement ask
2253 aEvent
.DropAction
= ~0;
2255 aEvent
.DropAction
= DNDConstants::ACTION_NONE
;
2257 m_nLastDropAction
= aEvent
.DropAction
;
2258 if( ! m_bDropEnterSent
)
2260 m_bDropEnterSent
= true;
2261 aEvent
.SupportedDataFlavors
= m_xDropTransferable
->getTransferDataFlavors();
2263 it
->second
->dragEnter( aEvent
);
2268 it
->second
->dragOver( aEvent
);
2272 rMessage
.message_type
== m_nXdndLeave
&&
2273 aSource
== Window(m_aDropEnterEvent
.data
.l
[0])
2277 #if OSL_DEBUG_LEVEL > 1
2278 fprintf( stderr
, "received XdndLeave on 0x%lx\n", aTarget
);
2280 DropTargetEvent aEvent
;
2281 aEvent
.Source
= static_cast< XDropTarget
* >(it
->second
.m_pTarget
);
2282 m_aDropEnterEvent
.data
.l
[0] = None
;
2283 if( m_aCurrentDropWindow
== aTarget
)
2284 m_aCurrentDropWindow
= None
;
2285 m_nCurrentProtocolVersion
= nXdndProtocolRevision
;
2287 it
->second
->dragExit( aEvent
);
2290 rMessage
.message_type
== m_nXdndDrop
&&
2291 aSource
== Window(m_aDropEnterEvent
.data
.l
[0])
2295 m_nDropTime
= m_nCurrentProtocolVersion
> 0 ? rMessage
.data
.l
[2] : CurrentTime
;
2297 #if OSL_DEBUG_LEVEL > 1
2298 fprintf( stderr
, "received XdndDrop on 0x%lx (%d, %d)\n", aTarget
, m_nLastX
, m_nLastY
);
2300 if( m_bLastDropAccepted
)
2302 DropTargetDropEvent aEvent
;
2303 aEvent
.Source
= static_cast< XDropTarget
* >(it
->second
.m_pTarget
);
2304 aEvent
.Context
= new DropTargetDropContext( m_aCurrentDropWindow
, m_nDropTimestamp
, *this );
2305 aEvent
.LocationX
= m_nLastX
;
2306 aEvent
.LocationY
= m_nLastY
;
2307 aEvent
.DropAction
= m_nLastDropAction
;
2308 // there is nothing corresponding to source supported actions
2309 // every source can do link, copy and move
2310 aEvent
.SourceActions
= m_nLastDropAction
;
2311 aEvent
.Transferable
= m_xDropTransferable
;
2313 m_bDropWaitingForCompletion
= true;
2315 it
->second
->drop( aEvent
);
2319 #if OSL_DEBUG_LEVEL > 1
2320 fprintf( stderr
, "XdndDrop canceled due to m_bLastDropAccepted = fale\n" );
2322 DropTargetEvent aEvent
;
2323 aEvent
.Source
= static_cast< XDropTarget
* >(it
->second
.m_pTarget
);
2325 it
->second
->dragExit( aEvent
);
2326 // reset the drop status, notify source
2327 dropComplete( sal_False
, m_aCurrentDropWindow
, m_nDropTime
);
2335 * methods for XDropTargetDropContext
2338 void SelectionManager::dropComplete( sal_Bool bSuccess
, Window aDropWindow
, Time
)
2340 ClearableMutexGuard
aGuard(m_aMutex
);
2342 if( aDropWindow
== m_aCurrentDropWindow
)
2344 if( m_xDragSourceListener
.is() )
2346 DragSourceDropEvent dsde
;
2347 dsde
.Source
= static_cast< OWeakObject
* >(this);
2348 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2349 dsde
.DragSource
= static_cast< XDragSource
* >(this);
2350 dsde
.DropAction
= getUserDragAction();
2351 dsde
.DropSuccess
= bSuccess
;
2352 Reference
< XDragSourceListener
> xListener
= m_xDragSourceListener
;
2353 m_xDragSourceListener
.clear();
2356 xListener
->dragDropEnd( dsde
);
2358 else if( m_aDropEnterEvent
.data
.l
[0] && m_aCurrentDropWindow
)
2361 aEvent
.xclient
.type
= ClientMessage
;
2362 aEvent
.xclient
.display
= m_pDisplay
;
2363 aEvent
.xclient
.window
= m_aDropEnterEvent
.data
.l
[0];
2364 aEvent
.xclient
.message_type
= m_nXdndFinished
;
2365 aEvent
.xclient
.format
= 32;
2366 aEvent
.xclient
.data
.l
[0] = m_aCurrentDropWindow
;
2367 aEvent
.xclient
.data
.l
[1] = bSuccess
? 1 : 0;
2368 aEvent
.xclient
.data
.l
[2] = 0;
2369 aEvent
.xclient
.data
.l
[3] = 0;
2370 aEvent
.xclient
.data
.l
[4] = 0;
2373 if( m_nLastDropAction
& DNDConstants::ACTION_MOVE
)
2374 aEvent
.xclient
.data
.l
[2] = m_nXdndActionMove
;
2375 else if( m_nLastDropAction
& DNDConstants::ACTION_COPY
)
2376 aEvent
.xclient
.data
.l
[2] = m_nXdndActionCopy
;
2377 else if( m_nLastDropAction
& DNDConstants::ACTION_LINK
)
2378 aEvent
.xclient
.data
.l
[2] = m_nXdndActionLink
;
2381 #if OSL_DEBUG_LEVEL > 1
2382 fprintf( stderr
, "Sending XdndFinished to 0x%lx\n",
2383 m_aDropEnterEvent
.data
.l
[0]
2387 XSendEvent( m_pDisplay
, m_aDropEnterEvent
.data
.l
[0],
2388 False
, NoEventMask
, & aEvent
);
2390 m_aDropEnterEvent
.data
.l
[0] = None
;
2391 m_aCurrentDropWindow
= None
;
2392 m_nCurrentProtocolVersion
= nXdndProtocolRevision
;
2394 m_bDropWaitingForCompletion
= false;
2397 OSL_ASSERT( "dropComplete from invalid DropTargetDropContext" );
2401 * methods for XDropTargetDragContext
2404 // ------------------------------------------------------------------------
2406 void SelectionManager::sendDragStatus( Atom nDropAction
)
2408 ClearableMutexGuard
aGuard(m_aMutex
);
2410 if( m_xDragSourceListener
.is() )
2412 sal_Int8 nNewDragAction
;
2413 if( nDropAction
== m_nXdndActionMove
)
2414 nNewDragAction
= DNDConstants::ACTION_MOVE
;
2415 else if( nDropAction
== m_nXdndActionCopy
)
2416 nNewDragAction
= DNDConstants::ACTION_COPY
;
2417 else if( nDropAction
== m_nXdndActionLink
)
2418 nNewDragAction
= DNDConstants::ACTION_LINK
;
2420 nNewDragAction
= DNDConstants::ACTION_NONE
;
2421 nNewDragAction
&= m_nSourceActions
;
2423 if( nNewDragAction
!= m_nTargetAcceptAction
)
2425 setCursor( getDefaultCursor( nNewDragAction
), m_aDropWindow
, m_nDragTimestamp
);
2426 m_nTargetAcceptAction
= nNewDragAction
;
2429 DragSourceDragEvent dsde
;
2430 dsde
.Source
= static_cast< OWeakObject
* >(this);
2431 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2432 dsde
.DragSource
= static_cast< XDragSource
* >(this);
2433 dsde
.DropAction
= m_nSourceActions
;
2434 dsde
.UserAction
= getUserDragAction();
2436 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
2437 // caution: do not change anything after this
2439 if( xListener
.is() )
2440 xListener
->dragOver( dsde
);
2442 else if( m_aDropEnterEvent
.data
.l
[0] && m_aCurrentDropWindow
)
2445 aEvent
.xclient
.type
= ClientMessage
;
2446 aEvent
.xclient
.display
= m_pDisplay
;
2447 aEvent
.xclient
.window
= m_aDropEnterEvent
.data
.l
[0];
2448 aEvent
.xclient
.message_type
= m_nXdndStatus
;
2449 aEvent
.xclient
.format
= 32;
2450 aEvent
.xclient
.data
.l
[0] = m_aCurrentDropWindow
;
2451 aEvent
.xclient
.data
.l
[1] = 2;
2452 if( nDropAction
== m_nXdndActionMove
||
2453 nDropAction
== m_nXdndActionLink
||
2454 nDropAction
== m_nXdndActionCopy
)
2455 aEvent
.xclient
.data
.l
[1] |= 1;
2456 aEvent
.xclient
.data
.l
[2] = 0;
2457 aEvent
.xclient
.data
.l
[3] = 0;
2458 aEvent
.xclient
.data
.l
[4] = m_nCurrentProtocolVersion
> 1 ? nDropAction
: 0;
2460 #if OSL_DEBUG_LEVEL > 1
2461 fprintf( stderr
, "Sending XdndStatus to 0x%lx with action %s\n",
2462 m_aDropEnterEvent
.data
.l
[0],
2463 OUStringToOString( getString( nDropAction
), RTL_TEXTENCODING_ISO_8859_1
).getStr()
2467 XSendEvent( m_pDisplay
, m_aDropEnterEvent
.data
.l
[0],
2468 False
, NoEventMask
, & aEvent
);
2469 XFlush( m_pDisplay
);
2473 // ------------------------------------------------------------------------
2475 sal_Int8
SelectionManager::getUserDragAction() const
2477 return (m_nTargetAcceptAction
!= DNDConstants::ACTION_DEFAULT
) ? m_nTargetAcceptAction
: m_nUserDragAction
;
2480 // ------------------------------------------------------------------------
2482 bool SelectionManager::updateDragAction( int modifierState
)
2486 sal_Int8 nNewDropAction
= DNDConstants::ACTION_MOVE
;
2487 if( ( modifierState
& ShiftMask
) && ! ( modifierState
& ControlMask
) )
2488 nNewDropAction
= DNDConstants::ACTION_MOVE
;
2489 else if( ( modifierState
& ControlMask
) && ! ( modifierState
& ShiftMask
) )
2490 nNewDropAction
= DNDConstants::ACTION_COPY
;
2491 else if( ( modifierState
& ShiftMask
) && ( modifierState
& ControlMask
) )
2492 nNewDropAction
= DNDConstants::ACTION_LINK
;
2493 if( m_nCurrentProtocolVersion
< 0 && m_aDropWindow
!= None
)
2494 nNewDropAction
= DNDConstants::ACTION_COPY
;
2495 nNewDropAction
&= m_nSourceActions
;
2497 if( ! ( modifierState
& ( ControlMask
| ShiftMask
) ) )
2499 if( ! nNewDropAction
)
2501 // default to an action so the user does not have to press
2503 if( m_nSourceActions
& DNDConstants::ACTION_MOVE
)
2504 nNewDropAction
= DNDConstants::ACTION_MOVE
;
2505 else if( m_nSourceActions
& DNDConstants::ACTION_COPY
)
2506 nNewDropAction
= DNDConstants::ACTION_COPY
;
2507 else if( m_nSourceActions
& DNDConstants::ACTION_LINK
)
2508 nNewDropAction
= DNDConstants::ACTION_LINK
;
2510 nNewDropAction
|= DNDConstants::ACTION_DEFAULT
;
2513 if( nNewDropAction
!= m_nUserDragAction
|| m_nTargetAcceptAction
!= DNDConstants::ACTION_DEFAULT
)
2515 #if OSL_DEBUG_LEVEL > 1
2516 fprintf( stderr
, "updateDragAction: %x -> %x\n", (int)m_nUserDragAction
, (int)nNewDropAction
);
2519 m_nUserDragAction
= nNewDropAction
;
2521 DragSourceDragEvent dsde
;
2522 dsde
.Source
= static_cast< OWeakObject
* >(this);
2523 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2524 dsde
.DragSource
= static_cast< XDragSource
* >(this);
2525 dsde
.DropAction
= m_nUserDragAction
;
2526 dsde
.UserAction
= m_nUserDragAction
;
2527 m_nTargetAcceptAction
= DNDConstants::ACTION_DEFAULT
; // invalidate last accept
2528 m_xDragSourceListener
->dropActionChanged( dsde
);
2533 // ------------------------------------------------------------------------
2535 void SelectionManager::sendDropPosition( bool bForce
, Time eventTime
)
2537 ClearableMutexGuard
aGuard(m_aMutex
);
2542 ::std::hash_map
< Window
, DropTargetEntry
>::const_iterator it
=
2543 m_aDropTargets
.find( m_aDropWindow
);
2544 if( it
!= m_aDropTargets
.end() )
2546 if( it
->second
.m_pTarget
->m_bActive
)
2550 XTranslateCoordinates( m_pDisplay
, it
->second
.m_aRootWindow
, m_aDropWindow
, m_nLastDragX
, m_nLastDragY
, &x
, &y
, &aChild
);
2551 DropTargetDragEvent dtde
;
2552 dtde
.Source
= static_cast< OWeakObject
* >(it
->second
.m_pTarget
);
2553 dtde
.Context
= new DropTargetDragContext( m_aCurrentDropWindow
, m_nDropTimestamp
, *this );
2556 dtde
.DropAction
= getUserDragAction();
2557 dtde
.SourceActions
= m_nSourceActions
;
2559 it
->second
->dragOver( dtde
);
2564 m_nLastDragX
< m_nNoPosX
|| m_nLastDragX
>= m_nNoPosX
+m_nNoPosWidth
||
2565 m_nLastDragY
< m_nNoPosY
|| m_nLastDragY
>= m_nNoPosY
+m_nNoPosHeight
2568 // send XdndPosition
2570 aEvent
.type
= ClientMessage
;
2571 aEvent
.xclient
.display
= m_pDisplay
;
2572 aEvent
.xclient
.format
= 32;
2573 aEvent
.xclient
.message_type
= m_nXdndPosition
;
2574 aEvent
.xclient
.window
= m_aDropWindow
;
2575 aEvent
.xclient
.data
.l
[0] = m_aWindow
;
2576 aEvent
.xclient
.data
.l
[1] = 0;
2577 aEvent
.xclient
.data
.l
[2] = m_nLastDragX
<< 16 | (m_nLastDragY
&0xffff);
2578 aEvent
.xclient
.data
.l
[3] = eventTime
;
2580 if( m_nUserDragAction
& DNDConstants::ACTION_COPY
)
2581 aEvent
.xclient
.data
.l
[4]=m_nXdndActionCopy
;
2582 else if( m_nUserDragAction
& DNDConstants::ACTION_MOVE
)
2583 aEvent
.xclient
.data
.l
[4]=m_nXdndActionMove
;
2584 else if( m_nUserDragAction
& DNDConstants::ACTION_LINK
)
2585 aEvent
.xclient
.data
.l
[4]=m_nXdndActionLink
;
2587 aEvent
.xclient
.data
.l
[4]=m_nXdndActionCopy
;
2588 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
2589 m_nNoPosX
= m_nNoPosY
= m_nNoPosWidth
= m_nNoPosHeight
= 0;
2593 // ------------------------------------------------------------------------
2595 bool SelectionManager::handleDragEvent( XEvent
& rMessage
)
2597 if( ! m_xDragSourceListener
.is() )
2600 ResettableMutexGuard
aGuard(m_aMutex
);
2602 bool bHandled
= false;
2605 ::std::hash_map
< Window
, DropTargetEntry
>::const_iterator it
=
2606 m_aDropTargets
.find( m_aDropWindow
);
2607 #if OSL_DEBUG_LEVEL > 1
2608 switch( rMessage
.type
)
2611 fprintf( stderr
, "handleDragEvent: %s\n", OUStringToOString( getString( rMessage
.xclient
.message_type
), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
2614 // fprintf( stderr, "handleDragEvent: MotionNotify\n" );
2617 fprintf( stderr
, "handleDragEvent: EnterNotify\n" );
2620 fprintf( stderr
, "handleDragEvent: LeaveNotify\n" );
2623 fprintf( stderr
, "handleDragEvent: ButtonPress %d (m_nDragButton = %d)\n", rMessage
.xbutton
.button
, m_nDragButton
);
2626 fprintf( stderr
, "handleDragEvent: ButtonRelease %d (m_nDragButton = %d)\n", rMessage
.xbutton
.button
, m_nDragButton
);
2629 fprintf( stderr
, "handleDragEvent: KeyPress\n" );
2632 fprintf( stderr
, "handleDragEvent: KeyRelease\n" );
2635 fprintf( stderr
, "handleDragEvent: <unknown type %d>\n", rMessage
.type
);
2640 // handle drag related events
2641 if( rMessage
.type
== ClientMessage
)
2643 if( Atom(rMessage
.xclient
.message_type
) == m_nXdndStatus
&& Atom(rMessage
.xclient
.data
.l
[0]) == m_aDropWindow
)
2646 DragSourceDragEvent dsde
;
2647 dsde
.Source
= static_cast< OWeakObject
* >(this);
2648 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2649 dsde
.DragSource
= static_cast< XDragSource
* >( this );
2650 dsde
.UserAction
= getUserDragAction();
2651 dsde
.DropAction
= DNDConstants::ACTION_NONE
;
2652 m_bDropSuccess
= rMessage
.xclient
.data
.l
[1] & 1 ? true : false;
2653 #if OSL_DEBUG_LEVEL > 1
2654 fprintf( stderr
, "status drop action: accept = %s, %s\n",
2655 m_bDropSuccess
? "true" : "false",
2656 OUStringToOString( getString( rMessage
.xclient
.data
.l
[4] ), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
2658 if( rMessage
.xclient
.data
.l
[1] & 1 )
2660 if( m_nCurrentProtocolVersion
> 1 )
2662 if( Atom(rMessage
.xclient
.data
.l
[4]) == m_nXdndActionCopy
)
2663 dsde
.DropAction
= DNDConstants::ACTION_COPY
;
2664 else if( Atom(rMessage
.xclient
.data
.l
[4]) == m_nXdndActionMove
)
2665 dsde
.DropAction
= DNDConstants::ACTION_MOVE
;
2666 else if( Atom(rMessage
.xclient
.data
.l
[4]) == m_nXdndActionLink
)
2667 dsde
.DropAction
= DNDConstants::ACTION_LINK
;
2670 dsde
.DropAction
= DNDConstants::ACTION_COPY
;
2672 m_nTargetAcceptAction
= dsde
.DropAction
;
2674 if( ! ( rMessage
.xclient
.data
.l
[1] & 2 ) )
2676 m_nNoPosX
= rMessage
.xclient
.data
.l
[2] >> 16;
2677 m_nNoPosY
= rMessage
.xclient
.data
.l
[2] & 0xffff;
2678 m_nNoPosWidth
= rMessage
.xclient
.data
.l
[3] >> 16;
2679 m_nNoPosHeight
= rMessage
.xclient
.data
.l
[3] & 0xffff;
2682 m_nNoPosX
= m_nNoPosY
= m_nNoPosWidth
= m_nNoPosHeight
= 0;
2684 setCursor( getDefaultCursor( dsde
.DropAction
), m_aDropWindow
, m_nDragTimestamp
);
2686 m_xDragSourceListener
->dragOver( dsde
);
2688 else if( Atom(rMessage
.xclient
.message_type
) == m_nXdndFinished
&& m_aDropWindow
== Atom(rMessage
.xclient
.data
.l
[0]) )
2691 // notify the listener
2692 DragSourceDropEvent dsde
;
2693 dsde
.Source
= static_cast< OWeakObject
* >(this);
2694 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2695 dsde
.DragSource
= static_cast< XDragSource
* >(this);
2696 dsde
.DropAction
= m_nTargetAcceptAction
;
2697 dsde
.DropSuccess
= m_bDropSuccess
;
2698 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
2699 m_xDragSourceListener
.clear();
2701 xListener
->dragDropEnd( dsde
);
2704 else if( rMessage
.type
== MotionNotify
||
2705 rMessage
.type
== EnterNotify
|| rMessage
.type
== LeaveNotify
2709 bool bForce
= false;
2710 int root_x
= rMessage
.type
== MotionNotify
? rMessage
.xmotion
.x_root
: rMessage
.xcrossing
.x_root
;
2711 int root_y
= rMessage
.type
== MotionNotify
? rMessage
.xmotion
.y_root
: rMessage
.xcrossing
.y_root
;
2712 Window root
= rMessage
.type
== MotionNotify
? rMessage
.xmotion
.root
: rMessage
.xcrossing
.root
;
2713 m_nDragTimestamp
= rMessage
.type
== MotionNotify
? rMessage
.xmotion
.time
: rMessage
.xcrossing
.time
;
2716 if( rMessage
.type
== MotionNotify
)
2718 bForce
= updateDragAction( rMessage
.xmotion
.state
);
2720 updateDragWindow( root_x
, root_y
, root
);
2723 if( m_nCurrentProtocolVersion
>= 0 && m_aDropProxy
!= None
)
2726 sendDropPosition( bForce
, rMessage
.type
== MotionNotify
? rMessage
.xmotion
.time
: rMessage
.xcrossing
.time
);
2729 else if( rMessage
.type
== KeyPress
|| rMessage
.type
== KeyRelease
)
2732 KeySym aKey
= XKeycodeToKeysym( m_pDisplay
, rMessage
.xkey
.keycode
, 0 );
2733 if( aKey
== XK_Escape
)
2736 if( it
!= m_aDropTargets
.end() )
2738 DropTargetEvent dte
;
2739 dte
.Source
= static_cast< OWeakObject
* >( it
->second
.m_pTarget
);
2741 it
->second
.m_pTarget
->dragExit( dte
);
2743 else if( m_aDropProxy
!= None
&& m_nCurrentProtocolVersion
>= 0 )
2747 aEvent
.type
= ClientMessage
;
2748 aEvent
.xclient
.display
= m_pDisplay
;
2749 aEvent
.xclient
.format
= 32;
2750 aEvent
.xclient
.message_type
= m_nXdndLeave
;
2751 aEvent
.xclient
.window
= m_aDropWindow
;
2752 aEvent
.xclient
.data
.l
[0] = m_aWindow
;
2753 memset( aEvent
.xclient
.data
.l
+1, 0, sizeof(long)*4);
2754 m_aDropWindow
= m_aDropProxy
= None
;
2755 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
2757 // notify the listener
2758 DragSourceDropEvent dsde
;
2759 dsde
.Source
= static_cast< OWeakObject
* >(this);
2760 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2761 dsde
.DragSource
= static_cast< XDragSource
* >(this);
2762 dsde
.DropAction
= DNDConstants::ACTION_NONE
;
2763 dsde
.DropSuccess
= sal_False
;
2764 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
2765 m_xDragSourceListener
.clear();
2767 xListener
->dragDropEnd( dsde
);
2772 * man page says: state is state immediate PRIOR to the
2773 * event. It would seem that this is a somewhat arguable
2776 int nState
= rMessage
.xkey
.state
;
2781 case XK_Shift_L
: nNewState
= ShiftMask
;break;
2783 case XK_Control_L
: nNewState
= ControlMask
;break;
2784 // just interested in shift and ctrl for dnd
2786 if( rMessage
.type
== KeyPress
)
2787 nState
|= nNewState
;
2789 nState
&= ~nNewState
;
2791 if( updateDragAction( nState
) )
2792 sendDropPosition( true, rMessage
.xkey
.time
);
2796 ( rMessage
.type
== ButtonPress
|| rMessage
.type
== ButtonRelease
) &&
2797 rMessage
.xbutton
.button
== m_nDragButton
)
2799 bool bCancel
= true;
2800 if( m_aDropWindow
!= None
)
2802 if( it
!= m_aDropTargets
.end() )
2804 if( it
->second
.m_pTarget
->m_bActive
&& m_nUserDragAction
!= DNDConstants::ACTION_NONE
&& m_bLastDropAccepted
)
2809 XTranslateCoordinates( m_pDisplay
, rMessage
.xbutton
.root
, m_aDropWindow
, rMessage
.xbutton
.x_root
, rMessage
.xbutton
.y_root
, &x
, &y
, &aChild
);
2810 DropTargetDropEvent dtde
;
2811 dtde
.Source
= static_cast< OWeakObject
* >(it
->second
.m_pTarget
);
2812 dtde
.Context
= new DropTargetDropContext( m_aCurrentDropWindow
, m_nDropTimestamp
, *this );
2815 dtde
.DropAction
= m_nUserDragAction
;
2816 dtde
.SourceActions
= m_nSourceActions
;
2817 dtde
.Transferable
= m_xDragSourceTransferable
;
2819 m_nDropTimeout
= time( NULL
);
2820 m_bDropWaitingForCompletion
= true;
2822 it
->second
->drop( dtde
);
2825 else bCancel
= true;
2827 else if( m_nCurrentProtocolVersion
>= 0 )
2832 aEvent
.type
= ClientMessage
;
2833 aEvent
.xclient
.display
= m_pDisplay
;
2834 aEvent
.xclient
.format
= 32;
2835 aEvent
.xclient
.message_type
= m_nXdndDrop
;
2836 aEvent
.xclient
.window
= m_aDropWindow
;
2837 aEvent
.xclient
.data
.l
[0] = m_aWindow
;
2838 aEvent
.xclient
.data
.l
[1] = 0;
2839 aEvent
.xclient
.data
.l
[2] = rMessage
.xbutton
.time
;
2840 aEvent
.xclient
.data
.l
[3] = 0;
2841 aEvent
.xclient
.data
.l
[4] = 0;
2844 m_nDropTimeout
= time( NULL
);
2845 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
2850 // dropping on non XdndWindows: acquire ownership of
2851 // PRIMARY and send a middle mouse button click down/up to
2853 SelectionAdaptor
* pAdaptor
= getAdaptor( XA_PRIMARY
);
2860 aEvent
.type
= ButtonPress
;
2861 aEvent
.xbutton
.display
= m_pDisplay
;
2862 aEvent
.xbutton
.window
= m_aDropWindow
;
2863 aEvent
.xbutton
.root
= rMessage
.xbutton
.root
;
2864 aEvent
.xbutton
.subwindow
= m_aDropWindow
;
2865 aEvent
.xbutton
.time
= rMessage
.xbutton
.time
+1;
2866 aEvent
.xbutton
.x_root
= rMessage
.xbutton
.x_root
;
2867 aEvent
.xbutton
.y_root
= rMessage
.xbutton
.y_root
;
2868 aEvent
.xbutton
.state
= rMessage
.xbutton
.state
;
2869 aEvent
.xbutton
.button
= Button2
;
2870 aEvent
.xbutton
.same_screen
= True
;
2871 XTranslateCoordinates( m_pDisplay
,
2872 rMessage
.xbutton
.root
, m_aDropWindow
,
2873 rMessage
.xbutton
.x_root
, rMessage
.xbutton
.y_root
,
2874 &aEvent
.xbutton
.x
, &aEvent
.xbutton
.y
,
2876 XSendEvent( m_pDisplay
, m_aDropWindow
, False
, ButtonPressMask
, &aEvent
);
2877 aEvent
.xbutton
.type
= ButtonRelease
;
2878 aEvent
.xbutton
.time
++;
2879 aEvent
.xbutton
.state
|= Button2Mask
;
2880 XSendEvent( m_pDisplay
, m_aDropWindow
, False
, ButtonReleaseMask
, &aEvent
);
2883 m_nDropTimeout
= time( NULL
);
2884 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
2885 m_bWaitingForPrimaryConversion
= true;
2887 m_nDropTimeout
= time( NULL
);
2890 static_cast< X11Clipboard
* >( pAdaptor
)->setContents( m_xDragSourceTransferable
, Reference
< ::com::sun::star::datatransfer::clipboard::XClipboardOwner
>() );
2899 DragSourceDropEvent dsde
;
2900 dsde
.Source
= static_cast< OWeakObject
* >(this);
2901 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2902 dsde
.DragSource
= static_cast< XDragSource
* >(this);
2903 dsde
.DropAction
= DNDConstants::ACTION_NONE
;
2904 dsde
.DropSuccess
= sal_False
;
2905 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
2906 m_xDragSourceListener
.clear();
2908 xListener
->dragDropEnd( dsde
);
2915 // ------------------------------------------------------------------------
2917 void SelectionManager::accept( sal_Int8 dragOperation
, Window aDropWindow
, Time
)
2919 if( aDropWindow
== m_aCurrentDropWindow
)
2921 #if OSL_DEBUG_LEVEL > 1
2922 fprintf( stderr
, "accept: %x\n", dragOperation
);
2924 Atom nAction
= None
;
2925 dragOperation
&= (DNDConstants::ACTION_MOVE
| DNDConstants::ACTION_COPY
| DNDConstants::ACTION_LINK
);
2926 if( dragOperation
& DNDConstants::ACTION_MOVE
)
2927 nAction
= m_nXdndActionMove
;
2928 else if( dragOperation
& DNDConstants::ACTION_COPY
)
2929 nAction
= m_nXdndActionCopy
;
2930 else if( dragOperation
& DNDConstants::ACTION_LINK
)
2931 nAction
= m_nXdndActionLink
;
2932 m_bLastDropAccepted
= true;
2933 sendDragStatus( nAction
);
2937 // ------------------------------------------------------------------------
2939 void SelectionManager::reject( Window aDropWindow
, Time
)
2941 if( aDropWindow
== m_aCurrentDropWindow
)
2943 #if OSL_DEBUG_LEVEL > 1
2944 fprintf( stderr
, "reject\n" );
2946 m_bLastDropAccepted
= false;
2947 sendDragStatus( None
);
2948 if( m_bDropSent
&& m_xDragSourceListener
.is() )
2950 DragSourceDropEvent dsde
;
2951 dsde
.Source
= static_cast< OWeakObject
* >(this);
2952 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
2953 dsde
.DragSource
= static_cast< XDragSource
* >(this);
2954 dsde
.DropAction
= DNDConstants::ACTION_NONE
;
2955 dsde
.DropSuccess
= sal_False
;
2956 m_xDragSourceListener
->dragDropEnd( dsde
);
2957 m_xDragSourceListener
.clear();
2966 sal_Bool
SelectionManager::isDragImageSupported() throw()
2971 // ------------------------------------------------------------------------
2973 sal_Int32
SelectionManager::getDefaultCursor( sal_Int8 dragAction
) throw()
2975 Cursor aCursor
= m_aNoneCursor
;
2976 if( dragAction
& DNDConstants::ACTION_MOVE
)
2977 aCursor
= m_aMoveCursor
;
2978 else if( dragAction
& DNDConstants::ACTION_COPY
)
2979 aCursor
= m_aCopyCursor
;
2980 else if( dragAction
& DNDConstants::ACTION_LINK
)
2981 aCursor
= m_aLinkCursor
;
2985 // ------------------------------------------------------------------------
2987 int SelectionManager::getXdndVersion( Window aWindow
, Window
& rProxy
)
2989 Atom
* pProperties
= NULL
;
2990 int nProperties
= 0;
2993 unsigned long nItems
, nBytes
;
2994 unsigned char* pBytes
= NULL
;
3000 * XListProperties is used here to avoid unnecessary XGetWindowProperty calls
3001 * and therefore reducing latency penalty
3003 pProperties
= XListProperties( m_pDisplay
, aWindow
, &nProperties
);
3004 // first look for proxy
3006 for( i
= 0; i
< nProperties
; i
++ )
3008 if( pProperties
[i
] == m_nXdndProxy
)
3010 XGetWindowProperty( m_pDisplay
, aWindow
, m_nXdndProxy
, 0, 1, False
, XA_WINDOW
,
3011 &nType
, &nFormat
, &nItems
, &nBytes
, &pBytes
);
3014 if( nType
== XA_WINDOW
)
3015 rProxy
= *(Window
*)pBytes
;
3018 if( rProxy
!= None
)
3020 // now check proxy wether it points to itself
3021 XGetWindowProperty( m_pDisplay
, rProxy
, m_nXdndProxy
, 0, 1, False
, XA_WINDOW
,
3022 &nType
, &nFormat
, &nItems
, &nBytes
, &pBytes
);
3025 if( nType
== XA_WINDOW
&& *(Window
*)pBytes
!= rProxy
)
3037 Window aAwareWindow
= rProxy
!= None
? rProxy
: aWindow
;
3039 XGetWindowProperty( m_pDisplay
, aAwareWindow
, m_nXdndAware
, 0, 1, False
, XA_ATOM
,
3040 &nType
, &nFormat
, &nItems
, &nBytes
, &pBytes
);
3043 if( nType
== XA_ATOM
)
3044 nVersion
= *(Atom
*)pBytes
;
3048 nVersion
= nVersion
> nXdndProtocolRevision
? nXdndProtocolRevision
: nVersion
;
3053 // ------------------------------------------------------------------------
3055 void SelectionManager::updateDragWindow( int nX
, int nY
, Window aRoot
)
3057 ResettableMutexGuard
aGuard( m_aMutex
);
3059 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
3064 Window aParent
= aRoot
;
3066 Window aNewProxy
= None
, aNewCurrentWindow
= None
;
3067 int nNewProtocolVersion
= -1;
3070 // find the first XdndAware window or check if root window is
3071 // XdndAware or has XdndProxy
3074 XTranslateCoordinates( m_pDisplay
, aRoot
, aParent
, nX
, nY
, &nWinX
, &nWinY
, &aChild
);
3075 if( aChild
!= None
)
3077 if( aChild
== m_aCurrentDropWindow
&& aChild
!= aRoot
&& m_nCurrentProtocolVersion
>= 0 )
3082 nNewProtocolVersion
= getXdndVersion( aChild
, aNewProxy
);
3085 } while( aChild
!= None
&& nNewProtocolVersion
< 0 );
3087 aNewCurrentWindow
= aParent
;
3088 if( aNewCurrentWindow
== aRoot
)
3090 // no children, try root drop
3091 nNewProtocolVersion
= getXdndVersion( aNewCurrentWindow
, aNewProxy
);
3092 if( nNewProtocolVersion
< 3 )
3094 aNewCurrentWindow
= aNewProxy
= None
;
3095 nNewProtocolVersion
= nXdndProtocolRevision
;
3100 DragSourceDragEvent dsde
;
3101 dsde
.Source
= static_cast< OWeakObject
* >(this);
3102 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
3103 dsde
.DragSource
= static_cast< XDragSource
* >(this);
3104 dsde
.DropAction
= nNewProtocolVersion
>= 0 ? m_nUserDragAction
: DNDConstants::ACTION_COPY
;
3105 dsde
.UserAction
= nNewProtocolVersion
>= 0 ? m_nUserDragAction
: DNDConstants::ACTION_COPY
;
3107 ::std::hash_map
< Window
, DropTargetEntry
>::const_iterator it
;
3108 if( aNewCurrentWindow
!= m_aDropWindow
)
3110 #if OSL_DEBUG_LEVEL > 1
3111 fprintf( stderr
, "drag left window 0x%lx (rev. %d), entered window 0x%lx (rev %d)\n", m_aDropWindow
, m_nCurrentProtocolVersion
, aNewCurrentWindow
, nNewProtocolVersion
);
3114 if( m_aDropWindow
!= None
)
3116 it
= m_aDropTargets
.find( m_aDropWindow
);
3117 if( it
!= m_aDropTargets
.end() )
3118 // shortcut for own drop targets
3120 DropTargetEvent dte
;
3121 dte
.Source
= static_cast< OWeakObject
* >( it
->second
.m_pTarget
);
3123 it
->second
.m_pTarget
->dragExit( dte
);
3128 // send old drop target a XdndLeave
3130 aEvent
.type
= ClientMessage
;
3131 aEvent
.xclient
.display
= m_pDisplay
;
3132 aEvent
.xclient
.format
= 32;
3133 aEvent
.xclient
.message_type
= m_nXdndLeave
;
3134 aEvent
.xclient
.window
= m_aDropWindow
;
3135 aEvent
.xclient
.data
.l
[0] = m_aWindow
;
3136 aEvent
.xclient
.data
.l
[1] = 0;
3137 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
3139 if( xListener
.is() )
3142 xListener
->dragExit( dsde
);
3147 m_nCurrentProtocolVersion
= nNewProtocolVersion
;
3148 m_aDropWindow
= aNewCurrentWindow
;
3149 m_aDropProxy
= aNewProxy
!= None
? aNewProxy
: m_aDropWindow
;
3151 it
= m_aDropTargets
.find( m_aDropWindow
);
3152 if( it
!= m_aDropTargets
.end() && ! it
->second
.m_pTarget
->m_bActive
)
3153 m_aDropProxy
= None
;
3155 if( m_aDropProxy
!= None
&& xListener
.is() )
3158 xListener
->dragEnter( dsde
);
3162 if( m_aDropProxy
!= None
&& m_nCurrentProtocolVersion
>= 0 )
3164 it
= m_aDropTargets
.find( m_aDropWindow
);
3165 if( it
!= m_aDropTargets
.end() )
3167 XTranslateCoordinates( m_pDisplay
, aRoot
, m_aDropWindow
, nX
, nY
, &nWinX
, &nWinY
, &aChild
);
3168 DropTargetDragEnterEvent dtde
;
3169 dtde
.Source
= static_cast< OWeakObject
* >( it
->second
.m_pTarget
);
3170 dtde
.Context
= new DropTargetDragContext( m_aCurrentDropWindow
, m_nDropTimestamp
, *this );
3171 dtde
.LocationX
= nWinX
;
3172 dtde
.LocationY
= nWinY
;
3173 dtde
.DropAction
= m_nUserDragAction
;
3174 dtde
.SourceActions
= m_nSourceActions
;
3175 dtde
.SupportedDataFlavors
= m_xDragSourceTransferable
->getTransferDataFlavors();
3177 it
->second
.m_pTarget
->dragEnter( dtde
);
3183 aEvent
.type
= ClientMessage
;
3184 aEvent
.xclient
.display
= m_pDisplay
;
3185 aEvent
.xclient
.format
= 32;
3186 aEvent
.xclient
.message_type
= m_nXdndEnter
;
3187 aEvent
.xclient
.window
= m_aDropWindow
;
3188 aEvent
.xclient
.data
.l
[0] = m_aWindow
;
3189 aEvent
.xclient
.data
.l
[1] = m_nCurrentProtocolVersion
<< 24;
3190 memset( aEvent
.xclient
.data
.l
+ 2, 0, sizeof( long )*3 );
3191 // fill in data types
3192 ::std::list
< Atom
> aConversions
;
3193 getNativeTypeList( m_aDragFlavors
, aConversions
, m_nXdndSelection
);
3194 if( aConversions
.size() > 3 )
3195 aEvent
.xclient
.data
.l
[1] |= 1;
3196 ::std::list
< Atom
>::const_iterator type_it
= aConversions
.begin();
3197 for( int i
= 0; type_it
!= aConversions
.end() && i
< 3; i
++, ++type_it
)
3198 aEvent
.xclient
.data
.l
[i
+2] = *type_it
;
3199 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
3202 m_nNoPosX
= m_nNoPosY
= m_nNoPosWidth
= m_nNoPosHeight
= 0;
3204 else if( m_aDropProxy
!= None
&& xListener
.is() )
3207 // drag over for XdndAware windows comes when receiving XdndStatus
3208 xListener
->dragOver( dsde
);
3212 // ------------------------------------------------------------------------
3214 void SelectionManager::startDrag(
3215 const DragGestureEvent
& trigger
,
3216 sal_Int8 sourceActions
,
3219 const Reference
< XTransferable
>& transferable
,
3220 const Reference
< XDragSourceListener
>& listener
3223 #if OSL_DEBUG_LEVEL > 1
3224 fprintf( stderr
, "startDrag( sourceActions = %x )\n", (int)sourceActions
);
3227 DragSourceDropEvent aDragFailedEvent
;
3228 aDragFailedEvent
.Source
= static_cast< OWeakObject
* >(this);
3229 aDragFailedEvent
.DragSource
= static_cast< XDragSource
* >(this);
3230 aDragFailedEvent
.DragSourceContext
= new DragSourceContext( None
, CurrentTime
, *this );
3231 aDragFailedEvent
.DropAction
= DNDConstants::ACTION_NONE
;
3232 aDragFailedEvent
.DropSuccess
= sal_False
;
3234 if( m_aDragRunning
.check() )
3237 listener
->dragDropEnd( aDragFailedEvent
);
3239 #if OSL_DEBUG_LEVEL > 1
3240 fprintf( stderr
, "*** ERROR *** second drag and drop started.\n" );
3241 if( m_xDragSourceListener
.is() )
3242 fprintf( stderr
, "*** ERROR *** drag source listener already set.\n" );
3244 fprintf( stderr
, "*** ERROR *** drag thread already running.\n" );
3250 ClearableMutexGuard
aGuard(m_aMutex
);
3252 // first get the current pointer position and the window that
3253 // the pointer is located in. since said window should be one
3254 // of our DropTargets at the time of executeDrag we can use
3256 Window aRoot
, aParent
, aChild
;
3257 int root_x
, root_y
, win_x
, win_y
;
3260 ::std::hash_map
< Window
, DropTargetEntry
>::const_iterator it
;
3261 it
= m_aDropTargets
.begin();
3262 while( it
!= m_aDropTargets
.end() )
3264 if( XQueryPointer( m_pDisplay
, it
->second
.m_aRootWindow
,
3270 aParent
= it
->second
.m_aRootWindow
;
3276 // don't start DnD if there is none of our windows on the same screen as
3277 // the pointer or if no mouse button is pressed
3278 if( it
== m_aDropTargets
.end() || (mask
& (Button1Mask
|Button2Mask
|Button3Mask
)) == 0 )
3282 listener
->dragDropEnd( aDragFailedEvent
);
3286 // try to find which of our drop targets is the drag source
3287 // if that drop target is deregistered we should stop executing
3288 // the drag (actually this is a poor substitute for an "endDrag"
3290 m_aDragSourceWindow
= None
;
3291 aParent
= aRoot
= it
->second
.m_aRootWindow
;
3294 XTranslateCoordinates( m_pDisplay
, aRoot
, aParent
, root_x
, root_y
, &win_x
, &win_y
, &aChild
);
3295 if( aChild
!= None
&& m_aDropTargets
.find( aChild
) != m_aDropTargets
.end() )
3297 m_aDragSourceWindow
= aChild
;
3298 #if OSL_DEBUG_LEVEL > 1
3299 fprintf( stderr
, "found drag source window 0x%lx\n", m_aDragSourceWindow
);
3304 } while( aChild
!= None
);
3307 #if OSL_DEBUG_LEVEL > 1
3308 fprintf( stderr
, "try to grab pointer ... " );
3310 int nPointerGrabSuccess
=
3311 XGrabPointer( m_pDisplay
, it
->second
.m_aRootWindow
, True
,
3313 GrabModeAsync
, GrabModeAsync
,
3317 #if OSL_DEBUG_LEVEL > 1
3318 fprintf( stderr
, "%d\n", nPointerGrabSuccess
);
3320 #if OSL_DEBUG_LEVEL > 1
3321 fprintf( stderr
, "try to grab keyboard ... " );
3323 int nKeyboardGrabSuccess
=
3324 XGrabKeyboard( m_pDisplay
, it
->second
.m_aRootWindow
, True
,
3325 GrabModeAsync
, GrabModeAsync
, CurrentTime
);
3326 #if OSL_DEBUG_LEVEL > 1
3327 fprintf( stderr
, "%d\n", nKeyboardGrabSuccess
);
3329 if( nPointerGrabSuccess
!= GrabSuccess
|| nKeyboardGrabSuccess
!= GrabSuccess
)
3331 if( nPointerGrabSuccess
== GrabSuccess
)
3332 XUngrabPointer( m_pDisplay
, CurrentTime
);
3333 if( nKeyboardGrabSuccess
== GrabSuccess
)
3334 XUngrabKeyboard( m_pDisplay
, CurrentTime
);
3335 XFlush( m_pDisplay
);
3338 listener
->dragDropEnd( aDragFailedEvent
);
3342 m_xDragSourceTransferable
= transferable
;
3343 m_xDragSourceListener
= listener
;
3344 m_aDragFlavors
= transferable
->getTransferDataFlavors();
3345 m_aCurrentCursor
= None
;
3347 requestOwnership( m_nXdndSelection
);
3349 ::std::list
< Atom
> aConversions
;
3350 ::std::list
< Atom
>::const_iterator type_it
;
3351 getNativeTypeList( m_aDragFlavors
, aConversions
, m_nXdndSelection
);
3353 int nTypes
= aConversions
.size();
3354 Atom
* pTypes
= (Atom
*)alloca( sizeof(Atom
)*nTypes
);
3355 type_it
= aConversions
.begin();
3356 for( int n
= 0; n
< nTypes
; n
++, ++type_it
)
3357 pTypes
[n
] = *type_it
;
3359 XChangeProperty( m_pDisplay
, m_aWindow
, m_nXdndTypeList
, XA_ATOM
, 32, PropModeReplace
, (unsigned char*)pTypes
, nTypes
);
3361 m_nSourceActions
= sourceActions
| DNDConstants::ACTION_DEFAULT
;
3362 m_nUserDragAction
= DNDConstants::ACTION_MOVE
& m_nSourceActions
;
3363 if( ! m_nUserDragAction
)
3364 m_nUserDragAction
= DNDConstants::ACTION_COPY
& m_nSourceActions
;
3365 if( ! m_nUserDragAction
)
3366 m_nUserDragAction
= DNDConstants::ACTION_LINK
& m_nSourceActions
;
3367 m_nTargetAcceptAction
= DNDConstants::ACTION_DEFAULT
;
3368 m_bDropSent
= false;
3369 m_bDropSuccess
= false;
3370 m_bWaitingForPrimaryConversion
= false;
3371 m_nDragButton
= Button1
; // default to left button
3372 if( trigger
.Event
.getValueTypeName().equalsAsciiL( "com.sun.star.awt.MouseEvent", 27 ) )
3375 trigger
.Event
>>= aEvent
;
3376 if( aEvent
.Buttons
& MouseButton::LEFT
)
3377 m_nDragButton
= Button1
;
3378 else if( aEvent
.Buttons
& MouseButton::RIGHT
)
3379 m_nDragButton
= Button3
;
3380 else if( aEvent
.Buttons
& MouseButton::MIDDLE
)
3381 m_nDragButton
= Button2
;
3383 #if OSL_DEBUG_LEVEL > 1
3384 fprintf( stderr
, "m_nUserDragAction = %x\n", (int)m_nUserDragAction
);
3386 updateDragWindow( root_x
, root_y
, aRoot
);
3387 m_nUserDragAction
= ~0;
3388 updateDragAction( mask
);
3391 m_aDragRunning
.set();
3392 m_aDragExecuteThread
= osl_createSuspendedThread( call_SelectionManager_runDragExecute
, this );
3393 if( m_aDragExecuteThread
)
3394 osl_resumeThread( m_aDragExecuteThread
);
3397 #if OSL_DEBUG_LEVEL > 1
3398 fprintf( stderr
, "osl_createSuspendedThread failed for drag execute\n" );
3400 m_xDragSourceListener
.clear();
3401 m_xDragSourceTransferable
.clear();
3403 m_bDropSent
= false;
3404 m_bDropSuccess
= false;
3405 m_bWaitingForPrimaryConversion
= false;
3406 m_aDropWindow
= None
;
3407 m_aDropProxy
= None
;
3408 m_nCurrentProtocolVersion
= nXdndProtocolRevision
;
3413 m_aCurrentCursor
= None
;
3415 XUngrabPointer( m_pDisplay
, CurrentTime
);
3416 XUngrabKeyboard( m_pDisplay
, CurrentTime
);
3417 XFlush( m_pDisplay
);
3419 m_aDragRunning
.reset();
3422 listener
->dragDropEnd( aDragFailedEvent
);
3426 void SelectionManager::runDragExecute( void* pThis
)
3428 SelectionManager
* This
= (SelectionManager
*)pThis
;
3429 This
->dragDoDispatch();
3432 void SelectionManager::dragDoDispatch()
3436 // m_xDragSourceListener will be cleared on finished drop
3437 #if OSL_DEBUG_LEVEL > 1
3438 fprintf( stderr
, "begin executeDrag dispatching\n" );
3442 aTVal
.Nanosec
= 200000000;
3443 oslThread aThread
= m_aDragExecuteThread
;
3444 while( m_xDragSourceListener
.is() && ( ! m_bDropSent
|| time(NULL
)-m_nDropTimeout
< 5 ) && osl_scheduleThread( aThread
) )
3446 // let the thread in the run method do the dispatching
3447 // just look occasionally here whether drop timed out or is completed
3448 osl_waitThread( &aTVal
);
3450 #if OSL_DEBUG_LEVEL > 1
3451 fprintf( stderr
, "end executeDrag dispatching\n" );
3454 ClearableMutexGuard
aGuard(m_aMutex
);
3456 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
3457 Reference
< XTransferable
> xTransferable( m_xDragSourceTransferable
);
3458 m_xDragSourceListener
.clear();
3459 m_xDragSourceTransferable
.clear();
3461 DragSourceDropEvent dsde
;
3462 dsde
.Source
= static_cast< OWeakObject
* >(this);
3463 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
3464 dsde
.DragSource
= static_cast< XDragSource
* >(this);
3465 dsde
.DropAction
= DNDConstants::ACTION_NONE
;
3466 dsde
.DropSuccess
= sal_False
;
3468 // cleanup after drag
3469 if( m_bWaitingForPrimaryConversion
)
3470 getAdaptor( XA_PRIMARY
)->clearTransferable();
3472 m_bDropSent
= false;
3473 m_bDropSuccess
= false;
3474 m_bWaitingForPrimaryConversion
= false;
3475 m_aDropWindow
= None
;
3476 m_aDropProxy
= None
;
3477 m_nCurrentProtocolVersion
= nXdndProtocolRevision
;
3482 m_aCurrentCursor
= None
;
3484 XUngrabPointer( m_pDisplay
, CurrentTime
);
3485 XUngrabKeyboard( m_pDisplay
, CurrentTime
);
3486 XFlush( m_pDisplay
);
3488 m_aDragExecuteThread
= NULL
;
3489 m_aDragRunning
.reset();
3492 if( xListener
.is() )
3494 xTransferable
.clear();
3495 xListener
->dragDropEnd( dsde
);
3498 osl_destroyThread( aThread
);
3502 * XDragSourceContext
3505 sal_Int32
SelectionManager::getCurrentCursor()
3507 return m_aCurrentCursor
;
3510 // ------------------------------------------------------------------------
3512 void SelectionManager::setCursor( sal_Int32 cursor
, Window aDropWindow
, Time
)
3514 MutexGuard
aGuard( m_aMutex
);
3515 if( aDropWindow
== m_aDropWindow
&& Cursor(cursor
) != m_aCurrentCursor
)
3517 if( m_xDragSourceListener
.is() && ! m_bDropSent
)
3519 m_aCurrentCursor
= cursor
;
3520 XChangeActivePointerGrab( m_pDisplay
, DRAG_EVENT_MASK
, cursor
, CurrentTime
);
3521 XFlush( m_pDisplay
);
3526 // ------------------------------------------------------------------------
3528 void SelectionManager::setImage( sal_Int32
, Window
, Time
)
3532 // ------------------------------------------------------------------------
3534 void SelectionManager::transferablesFlavorsChanged()
3536 MutexGuard
aGuard(m_aMutex
);
3538 m_aDragFlavors
= m_xDragSourceTransferable
->getTransferDataFlavors();
3541 std::list
< Atom
> aConversions
;
3542 std::list
< Atom
>::const_iterator type_it
;
3544 getNativeTypeList( m_aDragFlavors
, aConversions
, m_nXdndSelection
);
3546 int nTypes
= aConversions
.size();
3547 Atom
* pTypes
= (Atom
*)alloca( sizeof(Atom
)*aConversions
.size() );
3548 for( i
= 0, type_it
= aConversions
.begin(); type_it
!= aConversions
.end(); ++type_it
, i
++ )
3549 pTypes
[i
] = *type_it
;
3550 XChangeProperty( m_pDisplay
, m_aWindow
, m_nXdndTypeList
, XA_ATOM
, 32, PropModeReplace
, (unsigned char*)pTypes
, nTypes
);
3552 if( m_aCurrentDropWindow
!= None
&& m_nCurrentProtocolVersion
>= 0 )
3554 // send synthetic leave and enter events
3558 aEvent
.type
= ClientMessage
;
3559 aEvent
.xclient
.display
= m_pDisplay
;
3560 aEvent
.xclient
.format
= 32;
3561 aEvent
.xclient
.window
= m_aDropWindow
;
3562 aEvent
.xclient
.data
.l
[0] = m_aWindow
;
3564 aEvent
.xclient
.message_type
= m_nXdndLeave
;
3565 aEvent
.xclient
.data
.l
[1] = 0;
3566 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
3568 aEvent
.xclient
.message_type
= m_nXdndEnter
;
3569 aEvent
.xclient
.data
.l
[1] = m_nCurrentProtocolVersion
<< 24;
3570 memset( aEvent
.xclient
.data
.l
+ 2, 0, sizeof( long )*3 );
3571 // fill in data types
3573 aEvent
.xclient
.data
.l
[1] |= 1;
3574 for( int j
= 0; j
< nTypes
&& j
< 3; j
++ )
3575 aEvent
.xclient
.data
.l
[j
+2] = pTypes
[j
];
3577 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
3585 // ------------------------------------------------------------------------
3587 bool SelectionManager::handleXEvent( XEvent
& rEvent
)
3590 * since we are XConnectionListener to a second X display
3591 * to get client messages it is essential not to dispatch
3592 * events twice that we get on both connections
3594 * #95201# between dispatching ButtonPress and startDrag
3595 * the user can already have released the mouse. The ButtonRelease
3596 * will then be dispatched in VCLs queue and never turn up here.
3597 * Which is not so good, since startDrag will XGrabPointer and
3598 * XGrabKeyboard -> solid lock.
3600 if( rEvent
.xany
.display
!= m_pDisplay
3601 && rEvent
.type
!= ClientMessage
3602 && rEvent
.type
!= ButtonPress
3603 && rEvent
.type
!= ButtonRelease
3607 bool bHandled
= false;
3608 switch (rEvent
.type
)
3610 case SelectionClear
:
3612 ClearableMutexGuard
aGuard(m_aMutex
);
3613 #if OSL_DEBUG_LEVEL > 1
3614 fprintf( stderr
, "SelectionClear for selection %s\n",
3615 OUStringToOString( getString( rEvent
.xselectionclear
.selection
), RTL_TEXTENCODING_ISO_8859_1
).getStr()
3618 SelectionAdaptor
* pAdaptor
= getAdaptor( rEvent
.xselectionclear
.selection
);
3619 std::hash_map
< Atom
, Selection
* >::iterator
it( m_aSelections
.find( rEvent
.xselectionclear
.selection
) );
3620 if( it
!= m_aSelections
.end() )
3621 it
->second
->m_bOwner
= false;
3624 pAdaptor
->clearTransferable();
3628 case SelectionRequest
:
3629 bHandled
= handleSelectionRequest( rEvent
.xselectionrequest
);
3631 case PropertyNotify
:
3632 if( rEvent
.xproperty
.window
== m_aWindow
||
3633 rEvent
.xproperty
.window
== m_aCurrentDropWindow
3635 bHandled
= handleReceivePropertyNotify( rEvent
.xproperty
);
3637 bHandled
= handleSendPropertyNotify( rEvent
.xproperty
);
3639 case SelectionNotify
:
3640 bHandled
= handleSelectionNotify( rEvent
.xselection
);
3643 // messages from drag target
3644 if( rEvent
.xclient
.message_type
== m_nXdndStatus
||
3645 rEvent
.xclient
.message_type
== m_nXdndFinished
)
3646 bHandled
= handleDragEvent( rEvent
);
3647 // messages from drag source
3649 rEvent
.xclient
.message_type
== m_nXdndEnter
||
3650 rEvent
.xclient
.message_type
== m_nXdndLeave
||
3651 rEvent
.xclient
.message_type
== m_nXdndPosition
||
3652 rEvent
.xclient
.message_type
== m_nXdndDrop
3654 bHandled
= handleDropEvent( rEvent
.xclient
);
3663 bHandled
= handleDragEvent( rEvent
);
3671 // ------------------------------------------------------------------------
3673 void SelectionManager::dispatchEvent( int millisec
)
3678 // query socket handle to poll on
3679 aPollFD
.fd
= ConnectionNumber( m_pDisplay
);
3680 aPollFD
.events
= POLLIN
;
3681 aPollFD
.revents
= 0;
3683 // wait for activity (outside the xlib)
3684 if( poll( &aPollFD
, 1, millisec
) > 0 )
3686 // now acquire the mutex to prevent other threads
3687 // from using the same X connection
3688 ResettableMutexGuard
aGuard(m_aMutex
);
3690 // prevent that another thread already ate the input
3691 // this can happen if e.g. another thread does
3692 // an X request getting a response. the response
3693 // would be removed from the queue and we would end up
3694 // with an empty socket here
3695 if( poll( &aPollFD
, 1, 0 ) > 0 )
3700 nPending
= XPending( m_pDisplay
);
3703 XNextEvent( m_pDisplay
, &event
);
3705 handleXEvent( event
);
3713 // ------------------------------------------------------------------------
3715 void SelectionManager::run( void* pThis
)
3717 #if OSL_DEBUG_LEVEL > 1
3718 fprintf(stderr
, "SelectionManager::run\n" );
3720 // dispatch until the cows come home
3722 SelectionManager
* This
= (SelectionManager
*)pThis
;
3725 gettimeofday( &aLast
, 0 );
3727 while( osl_scheduleThread(This
->m_aThread
) )
3729 This
->dispatchEvent( 1000 );
3732 gettimeofday( &aNow
, 0 );
3734 if( (aNow
.tv_sec
- aLast
.tv_sec
) > 0 )
3736 ClearableMutexGuard
aGuard(This
->m_aMutex
);
3737 std::list
< std::pair
< SelectionAdaptor
*, Reference
< XInterface
> > > aChangeList
;
3739 for( std::hash_map
< Atom
, Selection
* >::iterator it
= This
->m_aSelections
.begin(); it
!= This
->m_aSelections
.end(); ++it
)
3741 if( it
->first
!= This
->m_nXdndSelection
&& ! it
->second
->m_bOwner
)
3743 Window aOwner
= XGetSelectionOwner( This
->m_pDisplay
, it
->first
);
3744 if( aOwner
!= it
->second
->m_aLastOwner
)
3746 it
->second
->m_aLastOwner
= aOwner
;
3747 std::pair
< SelectionAdaptor
*, Reference
< XInterface
> >
3748 aKeep( it
->second
->m_pAdaptor
, it
->second
->m_pAdaptor
->getReference() );
3749 aChangeList
.push_back( aKeep
);
3754 while( aChangeList
.begin() != aChangeList
.end() )
3756 aChangeList
.front().first
->fireContentsChanged();
3757 aChangeList
.pop_front();
3762 #if OSL_DEBUG_LEVEL > 1
3763 fprintf(stderr
, "SelectionManager::run end\n" );
3767 // ------------------------------------------------------------------------
3769 sal_Bool
SelectionManager::handleEvent( const Any
& event
) throw()
3771 Sequence
< sal_Int8
> aSeq
;
3772 if( (event
>>= aSeq
) )
3774 XEvent
* pEvent
= (XEvent
*)aSeq
.getArray();
3775 Time nTimestamp
= CurrentTime
;
3776 if( pEvent
->type
== ButtonPress
|| pEvent
->type
== ButtonRelease
)
3777 nTimestamp
= pEvent
->xbutton
.time
;
3778 else if( pEvent
->type
== KeyPress
|| pEvent
->type
== KeyRelease
)
3779 nTimestamp
= pEvent
->xkey
.time
;
3780 else if( pEvent
->type
== MotionNotify
)
3781 nTimestamp
= pEvent
->xmotion
.time
;
3782 else if( pEvent
->type
== PropertyNotify
)
3783 nTimestamp
= pEvent
->xproperty
.time
;
3785 if( nTimestamp
!= CurrentTime
)
3787 MutexGuard
aGuard(m_aMutex
);
3789 m_nSelectionTimestamp
= nTimestamp
;
3792 return sal_Bool( handleXEvent( *pEvent
) );
3796 #if OSL_DEBUG_LEVEL > 1
3797 fprintf( stderr
, "SelectionManager got downing event\n" );
3799 MutexGuard
aGuard(m_aMutex
);
3802 osl_terminateThread( m_aThread
);
3803 m_xDisplayConnection
->removeEventHandler( Any(), this );
3804 m_xDisplayConnection
.clear();
3809 // ------------------------------------------------------------------------
3811 void SelectionManager::registerHandler( Atom selection
, SelectionAdaptor
& rAdaptor
)
3813 MutexGuard
aGuard(m_aMutex
);
3815 Selection
* pNewSelection
= new Selection();
3816 pNewSelection
->m_pAdaptor
= &rAdaptor
;
3817 pNewSelection
->m_aAtom
= selection
;
3818 m_aSelections
[ selection
] = pNewSelection
;
3821 // ------------------------------------------------------------------------
3823 void SelectionManager::deregisterHandler( Atom selection
)
3825 MutexGuard
aGuard(m_aMutex
);
3827 ::std::hash_map
< Atom
, Selection
* >::iterator it
=
3828 m_aSelections
.find( selection
);
3829 if( it
!= m_aSelections
.end() )
3831 delete it
->second
->m_pPixmap
;
3833 m_aSelections
.erase( it
);
3837 // ------------------------------------------------------------------------
3839 void SelectionManager::registerDropTarget( Window aWindow
, DropTarget
* pTarget
)
3841 MutexGuard
aGuard(m_aMutex
);
3844 ::std::hash_map
< Window
, DropTargetEntry
>::const_iterator it
=
3845 m_aDropTargets
.find( aWindow
);
3846 if( it
!= m_aDropTargets
.end() )
3847 OSL_ASSERT( "attempt to register window as drop target twice" );
3848 else if( aWindow
&& m_pDisplay
)
3850 XSelectInput( m_pDisplay
, aWindow
, PropertyChangeMask
);
3853 XChangeProperty( m_pDisplay
, aWindow
, m_nXdndAware
, XA_ATOM
, 32, PropModeReplace
, (unsigned char*)&nXdndProtocolRevision
, 1 );
3855 DropTargetEntry
aEntry( pTarget
);
3856 // get root window of window (in 99.999% of all cases this will be
3857 // DefaultRootWindow( m_pDisplay )
3859 unsigned int w
, h
, bw
, d
;
3860 XGetGeometry( m_pDisplay
, aWindow
, &aEntry
.m_aRootWindow
,
3861 &x
, &y
, &w
, &h
, &bw
, &d
);
3862 m_aDropTargets
[ aWindow
] = aEntry
;
3865 OSL_ASSERT( "attempt to register None as drop target" );
3868 // ------------------------------------------------------------------------
3870 void SelectionManager::deregisterDropTarget( Window aWindow
)
3872 ClearableMutexGuard
aGuard(m_aMutex
);
3874 m_aDropTargets
.erase( aWindow
);
3875 if( aWindow
== m_aDragSourceWindow
&& m_aDragRunning
.check() )
3878 std::hash_map
< Window
, DropTargetEntry
>::const_iterator it
=
3879 m_aDropTargets
.find( m_aDropWindow
);
3880 if( it
!= m_aDropTargets
.end() )
3882 DropTargetEvent dte
;
3883 dte
.Source
= static_cast< OWeakObject
* >( it
->second
.m_pTarget
);
3885 it
->second
.m_pTarget
->dragExit( dte
);
3887 else if( m_aDropProxy
!= None
&& m_nCurrentProtocolVersion
>= 0 )
3891 aEvent
.type
= ClientMessage
;
3892 aEvent
.xclient
.display
= m_pDisplay
;
3893 aEvent
.xclient
.format
= 32;
3894 aEvent
.xclient
.message_type
= m_nXdndLeave
;
3895 aEvent
.xclient
.window
= m_aDropWindow
;
3896 aEvent
.xclient
.data
.l
[0] = m_aWindow
;
3897 memset( aEvent
.xclient
.data
.l
+1, 0, sizeof(long)*4);
3898 m_aDropWindow
= m_aDropProxy
= None
;
3899 XSendEvent( m_pDisplay
, m_aDropProxy
, False
, NoEventMask
, &aEvent
);
3901 // notify the listener
3902 DragSourceDropEvent dsde
;
3903 dsde
.Source
= static_cast< OWeakObject
* >(this);
3904 dsde
.DragSourceContext
= new DragSourceContext( m_aDropWindow
, m_nDragTimestamp
, *this );
3905 dsde
.DragSource
= static_cast< XDragSource
* >(this);
3906 dsde
.DropAction
= DNDConstants::ACTION_NONE
;
3907 dsde
.DropSuccess
= sal_False
;
3908 Reference
< XDragSourceListener
> xListener( m_xDragSourceListener
);
3909 m_xDragSourceListener
.clear();
3911 xListener
->dragDropEnd( dsde
);
3919 Reference
< XTransferable
> SelectionManager::getTransferable() throw()
3921 return m_xDragSourceTransferable
;
3924 // ------------------------------------------------------------------------
3926 void SelectionManager::clearTransferable() throw()
3928 m_xDragSourceTransferable
.clear();
3931 // ------------------------------------------------------------------------
3933 void SelectionManager::fireContentsChanged() throw()
3937 // ------------------------------------------------------------------------
3939 Reference
< XInterface
> SelectionManager::getReference() throw()
3941 return Reference
< XInterface
>( static_cast<OWeakObject
*>(this) );
3944 // ------------------------------------------------------------------------
3947 * SelectionManagerHolder
3950 SelectionManagerHolder::SelectionManagerHolder() :
3951 ::cppu::WeakComponentImplHelper3
<
3954 XServiceInfo
> (m_aMutex
)
3958 // ------------------------------------------------------------------------
3960 SelectionManagerHolder::~SelectionManagerHolder()
3964 // ------------------------------------------------------------------------
3966 void SelectionManagerHolder::initialize( const Sequence
< Any
>& arguments
) throw( ::com::sun::star::uno::Exception
)
3968 OUString aDisplayName
;
3970 if( arguments
.getLength() > 0 )
3972 Reference
< XDisplayConnection
> xConn
;
3973 arguments
.getConstArray()[0] >>= xConn
;
3977 aIdentifier
>>= aDisplayName
;
3981 SelectionManager
& rManager
= SelectionManager::get( aDisplayName
);
3982 rManager
.initialize( arguments
);
3983 m_xRealDragSource
= static_cast< XDragSource
* >(&rManager
);
3990 sal_Bool
SelectionManagerHolder::isDragImageSupported() throw()
3992 return m_xRealDragSource
.is() ? m_xRealDragSource
->isDragImageSupported() : sal_False
;
3995 // ------------------------------------------------------------------------
3997 sal_Int32
SelectionManagerHolder::getDefaultCursor( sal_Int8 dragAction
) throw()
3999 return m_xRealDragSource
.is() ? m_xRealDragSource
->getDefaultCursor( dragAction
) : 0;
4002 // ------------------------------------------------------------------------
4004 void SelectionManagerHolder::startDrag(
4005 const ::com::sun::star::datatransfer::dnd::DragGestureEvent
& trigger
,
4006 sal_Int8 sourceActions
, sal_Int32 cursor
, sal_Int32 image
,
4007 const Reference
< ::com::sun::star::datatransfer::XTransferable
>& transferable
,
4008 const Reference
< ::com::sun::star::datatransfer::dnd::XDragSourceListener
>& listener
4011 if( m_xRealDragSource
.is() )
4012 m_xRealDragSource
->startDrag( trigger
, sourceActions
, cursor
, image
, transferable
, listener
);
4015 // ------------------------------------------------------------------------
4021 // ------------------------------------------------------------------------
4023 OUString
SelectionManagerHolder::getImplementationName() throw()
4025 return OUString::createFromAscii(XDND_IMPLEMENTATION_NAME
);
4028 // ------------------------------------------------------------------------
4030 sal_Bool
SelectionManagerHolder::supportsService( const OUString
& ServiceName
) throw()
4032 Sequence
< OUString
> SupportedServicesNames
= Xdnd_getSupportedServiceNames();
4034 for ( sal_Int32 n
= SupportedServicesNames
.getLength(); n
--; )
4035 if (SupportedServicesNames
[n
].compareTo(ServiceName
) == 0)
4041 // ------------------------------------------------------------------------
4043 Sequence
< OUString
> SelectionManagerHolder::getSupportedServiceNames() throw()
4045 return Xdnd_getSupportedServiceNames();
4049 // ------------------------------------------------------------------------