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