LCOV - code coverage report
Current view: top level - vcl/unx/generic/dtrans - X11_selection.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 249 1944 12.8 %
Date: 2015-06-13 12:38:46 Functions: 22 77 28.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11