blob: 76081c0430ef4374606c70148a0250603ddd0065 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#ifndef _DTRANS_X11_SELECTION_HXX_
#define _DTRANS_X11_SELECTION_HXX_
#include <cppuhelper/compbase3.hxx>
#include <cppuhelper/compbase4.hxx>
#include <com/sun/star/datatransfer/XTransferable.hpp>
#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
#include <com/sun/star/awt/XDisplayConnection.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/script/XInvocation.hpp>
#include <com/sun/star/frame/XDesktop.hpp>
#include <osl/thread.h>
#ifndef _OSL_CONDITION_HXX_
#include <osl/conditn.hxx>
#endif
#include <hash_map>
#include <list>
#include "tools/prex.h"
#include <X11/Xlib.h>
#include "tools/postx.h"
#define XDND_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndSupport"
#define XDND_DROPTARGET_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndDropTarget"
using namespace ::com::sun::star::uno;
namespace x11 {
class PixmapHolder; // in bmp.hxx
// ------------------------------------------------------------------------
rtl_TextEncoding getTextPlainEncoding( const ::rtl::OUString& rMimeType );
class SelectionAdaptor
{
public:
virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() = 0;
virtual void clearTransferable() = 0;
virtual void fireContentsChanged() = 0;
virtual com::sun::star::uno::Reference< XInterface > getReference() = 0;
// returns a reference that will keep the SelectionAdaptor alive until the
// refernce is released
};
class DropTarget :
public ::cppu::WeakComponentImplHelper3<
::com::sun::star::datatransfer::dnd::XDropTarget,
::com::sun::star::lang::XInitialization,
::com::sun::star::lang::XServiceInfo
>
{
public:
::osl::Mutex m_aMutex;
bool m_bActive;
sal_Int8 m_nDefaultActions;
XLIB_Window m_aTargetWindow;
class SelectionManager* m_pSelectionManager;
com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource >
m_xSelectionManager;
::std::list< com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener > >
m_aListeners;
DropTarget();
virtual ~DropTarget();
// convenience functions that loop over listeners
void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtde ) throw();
void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw();
void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw();
void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw();
// XInitialization
virtual void SAL_CALL initialize( const Sequence< Any >& args ) throw ( ::com::sun::star::uno::Exception );
// XDropTarget
virtual void SAL_CALL addDropTargetListener( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw();
virtual void SAL_CALL removeDropTargetListener( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw();
virtual sal_Bool SAL_CALL isActive() throw();
virtual void SAL_CALL setActive( sal_Bool active ) throw();
virtual sal_Int8 SAL_CALL getDefaultActions() throw();
virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) throw();
// XServiceInfo
virtual ::rtl::OUString SAL_CALL getImplementationName() throw();
virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw();
virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >
SAL_CALL getSupportedServiceNames() throw();
};
class SelectionManagerHolder :
public ::cppu::WeakComponentImplHelper3<
::com::sun::star::datatransfer::dnd::XDragSource,
::com::sun::star::lang::XInitialization,
::com::sun::star::lang::XServiceInfo
>
{
::osl::Mutex m_aMutex;
com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource >
m_xRealDragSource;
public:
SelectionManagerHolder();
virtual ~SelectionManagerHolder();
// XServiceInfo
virtual ::rtl::OUString SAL_CALL getImplementationName() throw();
virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw();
virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >
SAL_CALL getSupportedServiceNames() throw();
// XInitialization
virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
// XDragSource
virtual sal_Bool SAL_CALL isDragImageSupported() throw();
virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw();
virtual void SAL_CALL startDrag(
const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
) throw();
};
class SelectionManager :
public ::cppu::WeakImplHelper4<
::com::sun::star::datatransfer::dnd::XDragSource,
::com::sun::star::lang::XInitialization,
::com::sun::star::awt::XEventHandler,
::com::sun::star::frame::XTerminateListener
>,
public SelectionAdaptor
{
static ::std::hash_map< ::rtl::OUString, SelectionManager*, ::rtl::OUStringHash >& getInstances();
// for INCR type selection transfer
// INCR protocol is used if the data cannot
// be transported at once but in parts
// IncrementalTransfer holds the bytes to be transmitted
// as well a the current position
// INCR triggers the delivery of the next part by deleting the
// property used to transfer the data
struct IncrementalTransfer
{
Sequence< sal_Int8 > m_aData;
int m_nBufferPos;
XLIB_Window m_aRequestor;
Atom m_aProperty;
Atom m_aTarget;
int m_nFormat;
int m_nTransferStartTime;
};
int m_nIncrementalThreshold;
// a struct to hold the data associated with a selection
struct Selection
{
enum State
{
Inactive, WaitingForResponse, WaitingForData, IncrementalTransfer
};
State m_eState;
SelectionAdaptor* m_pAdaptor;
Atom m_aAtom;
::osl::Condition m_aDataArrived;
Sequence< sal_Int8 > m_aData;
Sequence< ::com::sun::star::datatransfer::DataFlavor >
m_aTypes;
std::vector< Atom > m_aNativeTypes;
// this is used for caching
// m_aTypes is invalid after 2 seconds
// m_aNativeTypes contains the corresponding original atom
Atom m_aRequestedType;
// m_aRequestedType is only valid while WaitingForResponse and WaitingFotData
int m_nLastTimestamp;
bool m_bHaveUTF16;
Atom m_aUTF8Type;
bool m_bHaveCompound;
bool m_bOwner;
XLIB_Window m_aLastOwner;
PixmapHolder* m_pPixmap;
// m_nOrigXLIB_Timestamp contains the XLIB_Timestamp at which the seclection
// was acquired; needed for XLIB_TimeSTAMP target
XLIB_Time m_nOrigTimestamp;
Selection() : m_eState( Inactive ),
m_pAdaptor( NULL ),
m_aAtom( None ),
m_aRequestedType( None ),
m_nLastTimestamp( 0 ),
m_bHaveUTF16( false ),
m_aUTF8Type( None ),
m_bHaveCompound( false ),
m_bOwner( false ),
m_aLastOwner( None ),
m_pPixmap( NULL ),
m_nOrigTimestamp( CurrentTime )
{}
};
// a struct to hold data associated with a XDropTarget
struct DropTargetEntry
{
DropTarget* m_pTarget;
XLIB_Window m_aRootWindow;
DropTargetEntry() : m_pTarget( NULL ), m_aRootWindow( None ) {}
DropTargetEntry( DropTarget* pTarget ) :
m_pTarget( pTarget ),
m_aRootWindow( None )
{}
DropTargetEntry( const DropTargetEntry& rEntry ) :
m_pTarget( rEntry.m_pTarget ),
m_aRootWindow( rEntry.m_aRootWindow )
{}
~DropTargetEntry() {}
DropTarget* operator->() const { return m_pTarget; }
DropTargetEntry& operator=(const DropTargetEntry& rEntry)
{ m_pTarget = rEntry.m_pTarget; m_aRootWindow = rEntry.m_aRootWindow; return *this; }
};
// internal data
Display* m_pDisplay;
oslThread m_aThread;
oslThread m_aDragExecuteThread;
::osl::Condition m_aDragRunning;
XLIB_Window m_aWindow;
com::sun::star::uno::Reference< ::com::sun::star::awt::XDisplayConnection >
m_xDisplayConnection;
com::sun::star::uno::Reference< com::sun::star::script::XInvocation >
m_xBitmapConverter;
sal_Int32 m_nSelectionTimeout;
XLIB_Time m_nSelectionTimestamp;
// members used for Xdnd
// drop only
// contains the XdndEnterEvent of a drop action running
// with one of our targets. The data.l[0] member
// (conatining the drag source XLIB_Window) is set
// to None while that is not the case
XClientMessageEvent m_aDropEnterEvent;
// set to false on XdndEnter
// set to true on first XdndPosition or XdndLeave
bool m_bDropEnterSent;
XLIB_Window m_aCurrentDropWindow;
// XLIB_Time code of XdndDrop
XLIB_Time m_nDropTime;
sal_Int8 m_nLastDropAction;
// XTransferable for Xdnd with foreign drag source
com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >
m_xDropTransferable;
int m_nLastX, m_nLastY;
XLIB_Time m_nDropTimestamp;
// set to true when calling drop()
// if another XdndEnter is received this shows that
// someone forgot to call dropComplete - we should reset
// and react to the new drop
bool m_bDropWaitingForCompletion;
// drag only
// None if no Dnd action is running with us as source
XLIB_Window m_aDropWindow;
// either m_aDropXLIB_Window or its XdndProxy
XLIB_Window m_aDropProxy;
XLIB_Window m_aDragSourceWindow;
// XTransferable for Xdnd when we are drag source
com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >
m_xDragSourceTransferable;
com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >
m_xDragSourceListener;
// root coordinates
int m_nLastDragX, m_nLastDragY;
Sequence< ::com::sun::star::datatransfer::DataFlavor >
m_aDragFlavors;
// the rectangle the pointer must leave until a new XdndPosition should
// be sent. empty unless the drop target told to fill
int m_nNoPosX, m_nNoPosY, m_nNoPosWidth, m_nNoPosHeight;
unsigned int m_nDragButton;
sal_Int8 m_nUserDragAction;
sal_Int8 m_nTargetAcceptAction;
sal_Int8 m_nSourceActions;
bool m_bLastDropAccepted;
bool m_bDropSuccess;
bool m_bDropSent;
time_t m_nDropTimeout;
bool m_bWaitingForPrimaryConversion;
XLIB_Time m_nDragTimestamp;
// drag cursors
XLIB_Cursor m_aMoveCursor;
XLIB_Cursor m_aCopyCursor;
XLIB_Cursor m_aLinkCursor;
XLIB_Cursor m_aNoneCursor;
XLIB_Cursor m_aCurrentCursor;
// drag and drop
int m_nCurrentProtocolVersion;
::std::hash_map< XLIB_Window, DropTargetEntry >
m_aDropTargets;
// some special atoms that are needed often
Atom m_nCLIPBOARDAtom;
Atom m_nTARGETSAtom;
Atom m_nTIMESTAMPAtom;
Atom m_nTEXTAtom;
Atom m_nINCRAtom;
Atom m_nCOMPOUNDAtom;
Atom m_nMULTIPLEAtom;
Atom m_nUTF16Atom;
Atom m_nImageBmpAtom;
Atom m_nXdndAware;
Atom m_nXdndEnter;
Atom m_nXdndLeave;
Atom m_nXdndPosition;
Atom m_nXdndStatus;
Atom m_nXdndDrop;
Atom m_nXdndFinished;
Atom m_nXdndSelection;
Atom m_nXdndTypeList;
Atom m_nXdndProxy;
Atom m_nXdndActionCopy;
Atom m_nXdndActionMove;
Atom m_nXdndActionLink;
Atom m_nXdndActionAsk;
Atom m_nXdndActionPrivate;
// caching for atoms
::std::hash_map< Atom, ::rtl::OUString >
m_aAtomToString;
::std::hash_map< ::rtl::OUString, Atom, ::rtl::OUStringHash >
m_aStringToAtom;
// the registered selections
::std::hash_map< Atom, Selection* >
m_aSelections;
// IncrementalTransfers in progress
std::hash_map< XLIB_Window, std::hash_map< Atom, IncrementalTransfer > >
m_aIncrementals;
// do not use X11 multithreading capabilities
// since this leads to deadlocks in different Xlib implentations
// (XFree as well as Xsun) use an own mutex instead
::osl::Mutex m_aMutex;
bool m_bShutDown;
SelectionManager();
~SelectionManager();
SelectionAdaptor* getAdaptor( Atom selection );
PixmapHolder* getPixmapHolder( Atom selection );
// handle various events
bool handleSelectionRequest( XSelectionRequestEvent& rRequest );
bool handleSendPropertyNotify( XPropertyEvent& rNotify );
bool handleReceivePropertyNotify( XPropertyEvent& rNotify );
bool handleSelectionNotify( XSelectionEvent& rNotify );
bool handleDragEvent( XEvent& rMessage );
bool handleDropEvent( XClientMessageEvent& rMessage );
// dnd helpers
void sendDragStatus( Atom nDropAction );
void sendDropPosition( bool bForce, XLIB_Time eventXLIB_Time );
bool updateDragAction( int modifierState );
int getXdndVersion( XLIB_Window aXLIB_Window, XLIB_Window& rProxy );
XLIB_Cursor createCursor( const char* pPointerData, const char* pMaskData, int width, int height, int hotX, int hotY );
// coordinates on root XLIB_Window
void updateDragWindow( int nX, int nY, XLIB_Window aRoot );
bool getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData );
// returns true if conversion was successful
bool convertData( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable,
Atom nType,
Atom nSelection,
int & rFormat,
Sequence< sal_Int8 >& rData );
bool sendData( SelectionAdaptor* pAdaptor, XLIB_Window requestor, Atom target, Atom property, Atom selection );
// thread dispatch loop
public:
// public for extern "C" stub
static void run( void* );
private:
void dispatchEvent( int millisec );
// drag thread dispatch
public:
// public for extern "C" stub
static void runDragExecute( void* );
private:
void dragDoDispatch();
bool handleXEvent( XEvent& rEvent );
// compound text conversion
::rtl::OString convertToCompound( const ::rtl::OUString& rText );
::rtl::OUString convertFromCompound( const char* pText, int nLen = -1 );
sal_Int8 getUserDragAction() const;
sal_Int32 getSelectionTimeout();
public:
static SelectionManager& get( const ::rtl::OUString& rDisplayName = ::rtl::OUString() );
Display * getDisplay() { return m_pDisplay; };
XLIB_Window getWindow() { return m_aWindow; };
void registerHandler( Atom selection, SelectionAdaptor& rAdaptor );
void deregisterHandler( Atom selection );
bool requestOwnership( Atom selection );
// allow for synchronization over one mutex for XClipboard
osl::Mutex& getMutex() { return m_aMutex; }
Atom getAtom( const ::rtl::OUString& rString );
const ::rtl::OUString& getString( Atom nAtom );
// type conversion
// note: convertTypeToNative does NOT clear the list, so you can append
// multiple types to the same list
void convertTypeToNative( const ::rtl::OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront = false );
::rtl::OUString convertTypeFromNative( Atom nType, Atom selection, int& rFormat );
void getNativeTypeList( const Sequence< com::sun::star::datatransfer::DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection );
// methods for transferable
bool getPasteDataTypes( Atom selection, Sequence< ::com::sun::star::datatransfer::DataFlavor >& rTypes );
bool getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData );
// for XDropTarget to register/deregister itself
void registerDropTarget( XLIB_Window aXLIB_Window, DropTarget* pTarget );
void deregisterDropTarget( XLIB_Window aXLIB_Window );
// for XDropTarget{Drag|Drop}Context
void accept( sal_Int8 dragOperation, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
void reject( XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
void dropComplete( sal_Bool success, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
// for XDragSourceContext
sal_Int32 getCurrentCursor();
void setCursor( sal_Int32 cursor, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
void setImage( sal_Int32 image, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
void transferablesFlavorsChanged();
void shutdown() throw();
// XInitialization
virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
// XEventHandler
virtual sal_Bool SAL_CALL handleEvent( const Any& event ) throw();
// XDragSource
virtual sal_Bool SAL_CALL isDragImageSupported() throw();
virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw();
virtual void SAL_CALL startDrag(
const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
) throw();
// SelectionAdaptor for XdndSelection Drag (we are drag source)
virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() throw();
virtual void clearTransferable() throw();
virtual void fireContentsChanged() throw();
virtual com::sun::star::uno::Reference< XInterface > getReference() throw();
// XEventListener
virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw( ::com::sun::star::uno::RuntimeException );
// XTerminateListener
virtual void SAL_CALL queryTermination( const ::com::sun::star::lang::EventObject& aEvent )
throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException );
virtual void SAL_CALL notifyTermination( const ::com::sun::star::lang::EventObject& aEvent )
throw( ::com::sun::star::uno::RuntimeException );
};
// ------------------------------------------------------------------------
::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_getSupportedServiceNames();
::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_createInstance(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_dropTarget_getSupportedServiceNames();
::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_dropTarget_createInstance(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
// ------------------------------------------------------------------------
}
#endif