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