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