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