summaryrefslogtreecommitdiff
path: root/vcl/unx/generic/dtrans
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic/dtrans')
-rw-r--r--vcl/unx/generic/dtrans/X11_clipboard.cxx296
-rw-r--r--vcl/unx/generic/dtrans/X11_clipboard.hxx150
-rw-r--r--vcl/unx/generic/dtrans/X11_dndcontext.cxx141
-rw-r--r--vcl/unx/generic/dtrans/X11_dndcontext.hxx107
-rw-r--r--vcl/unx/generic/dtrans/X11_droptarget.cxx231
-rw-r--r--vcl/unx/generic/dtrans/X11_selection.cxx4193
-rw-r--r--vcl/unx/generic/dtrans/X11_selection.hxx533
-rw-r--r--vcl/unx/generic/dtrans/X11_service.cxx144
-rw-r--r--vcl/unx/generic/dtrans/X11_transferable.cxx136
-rw-r--r--vcl/unx/generic/dtrans/X11_transferable.hxx73
-rw-r--r--vcl/unx/generic/dtrans/bmp.cxx742
-rw-r--r--vcl/unx/generic/dtrans/bmp.hxx108
-rw-r--r--vcl/unx/generic/dtrans/config.cxx151
-rw-r--r--vcl/unx/generic/dtrans/copydata_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/copydata_mask.h45
-rw-r--r--vcl/unx/generic/dtrans/linkdata_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/linkdata_mask.h45
-rw-r--r--vcl/unx/generic/dtrans/movedata_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/movedata_mask.h45
-rw-r--r--vcl/unx/generic/dtrans/nodrop_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/nodrop_mask.h45
21 files changed, 7365 insertions, 0 deletions
diff --git a/vcl/unx/generic/dtrans/X11_clipboard.cxx b/vcl/unx/generic/dtrans/X11_clipboard.cxx
new file mode 100644
index 000000000000..4f1934397397
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_clipboard.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <X11/Xatom.h>
+#include <X11_clipboard.hxx>
+#include <X11_transferable.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/datatransfer/clipboard/RenderingCapabilities.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <uno/dispatcher.h> // declaration of generic uno interface
+#include <uno/mapping.hxx> // mapping stuff
+#include <cppuhelper/factory.hxx>
+#include <rtl/tencinfo.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt;
+using namespace cppu;
+using namespace osl;
+using namespace x11;
+
+using ::rtl::OUString;
+
+X11Clipboard::X11Clipboard( SelectionManager& rManager, Atom aSelection ) :
+ ::cppu::WeakComponentImplHelper4<
+ ::com::sun::star::datatransfer::clipboard::XClipboardEx,
+ ::com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ ::com::sun::star::lang::XServiceInfo,
+ ::com::sun::star::lang::XInitialization
+ >( rManager.getMutex() ),
+
+ m_rSelectionManager( rManager ),
+ m_xSelectionManager( & rManager ),
+ m_aSelection( aSelection )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating instance of X11Clipboard (this=%p)\n", this );
+#endif
+
+ if( m_aSelection != None )
+ {
+ m_rSelectionManager.registerHandler( m_aSelection, *this );
+ }
+ else
+ {
+ m_rSelectionManager.registerHandler( XA_PRIMARY, *this );
+ m_rSelectionManager.registerHandler( m_rSelectionManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ), *this );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+X11Clipboard::~X11Clipboard()
+{
+ MutexGuard aGuard( *Mutex::getGlobalMutex() );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "shutting down instance of X11Clipboard (this=%p, Selecttion=\"%s\")\n", this, OUStringToOString( m_rSelectionManager.getString( m_aSelection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( m_aSelection != None )
+ m_rSelectionManager.deregisterHandler( m_aSelection );
+ else
+ {
+ m_rSelectionManager.deregisterHandler( XA_PRIMARY );
+ m_rSelectionManager.deregisterHandler( m_rSelectionManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ) );
+ }
+}
+
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::fireChangedContentsEvent()
+{
+ ClearableMutexGuard aGuard( m_rSelectionManager.getMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "X11Clipboard::fireChangedContentsEvent for %s (%" SAL_PRI_SIZET "u listeners)\n",
+ OUStringToOString( m_rSelectionManager.getString( m_aSelection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), m_aListeners.size() );
+#endif
+ ::std::list< Reference< XClipboardListener > > listeners( m_aListeners );
+ aGuard.clear();
+
+ ClipboardEvent aEvent( static_cast<OWeakObject*>(this), m_aContents);
+ while( listeners.begin() != listeners.end() )
+ {
+ if( listeners.front().is() )
+ listeners.front()->changedContents(aEvent);
+ listeners.pop_front();
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::clearContents()
+{
+ ClearableMutexGuard aGuard(m_rSelectionManager.getMutex());
+ // protect against deletion during outside call
+ Reference< XClipboard > xThis( static_cast<XClipboard*>(this));
+ // copy member references on stack so they can be called
+ // without having the mutex
+ Reference< XClipboardOwner > xOwner( m_aOwner );
+ Reference< XTransferable > xTrans( m_aContents );
+ // clear members
+ m_aOwner.clear();
+ m_aContents.clear();
+
+ // release the mutex
+ aGuard.clear();
+
+ // inform previous owner of lost ownership
+ if ( xOwner.is() )
+ xOwner->lostOwnership(xThis, m_aContents);
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XTransferable > SAL_CALL X11Clipboard::getContents()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard(m_rSelectionManager.getMutex());
+
+ if( ! m_aContents.is() )
+ m_aContents = new X11Transferable( SelectionManager::get(), static_cast< OWeakObject* >(this), m_aSelection );
+ return m_aContents;
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::setContents(
+ const Reference< XTransferable >& xTrans,
+ const Reference< XClipboardOwner >& xClipboardOwner )
+ throw(RuntimeException)
+{
+ // remember old values for callbacks before setting the new ones.
+ ClearableMutexGuard aGuard(m_rSelectionManager.getMutex());
+
+ Reference< XClipboardOwner > oldOwner( m_aOwner );
+ m_aOwner = xClipboardOwner;
+
+ Reference< XTransferable > oldContents( m_aContents );
+ m_aContents = xTrans;
+
+ aGuard.clear();
+
+ // for now request ownership for both selections
+ if( m_aSelection != None )
+ m_rSelectionManager.requestOwnership( m_aSelection );
+ else
+ {
+ m_rSelectionManager.requestOwnership( XA_PRIMARY );
+ m_rSelectionManager.requestOwnership( m_rSelectionManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ) );
+ }
+
+ // notify old owner on loss of ownership
+ if( oldOwner.is() )
+ oldOwner->lostOwnership(static_cast < XClipboard * > (this), oldContents);
+
+ // notify all listeners on content changes
+ fireChangedContentsEvent();
+}
+
+// ------------------------------------------------------------------------
+
+OUString SAL_CALL X11Clipboard::getName()
+ throw(RuntimeException)
+{
+ return m_rSelectionManager.getString( m_aSelection );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int8 SAL_CALL X11Clipboard::getRenderingCapabilities()
+ throw(RuntimeException)
+{
+ return RenderingCapabilities::Delayed;
+}
+
+
+// ------------------------------------------------------------------------
+void SAL_CALL X11Clipboard::addClipboardListener( const Reference< XClipboardListener >& listener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( m_rSelectionManager.getMutex() );
+ m_aListeners.push_back( listener );
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::removeClipboardListener( const Reference< XClipboardListener >& listener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( m_rSelectionManager.getMutex() );
+ m_aListeners.remove( listener );
+}
+
+
+// ------------------------------------------------------------------------
+
+Reference< XTransferable > X11Clipboard::getTransferable()
+{
+ return getContents();
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::clearTransferable()
+{
+ clearContents();
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::fireContentsChanged()
+{
+ fireChangedContentsEvent();
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > X11Clipboard::getReference() throw()
+{
+ return Reference< XInterface >( static_cast< OWeakObject* >(this) );
+}
+
+// ------------------------------------------------------------------------
+
+OUString SAL_CALL X11Clipboard::getImplementationName( )
+ throw(RuntimeException)
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM(X11_CLIPBOARD_IMPLEMENTATION_NAME));
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SAL_CALL X11Clipboard::supportsService( const OUString& ServiceName )
+ throw(RuntimeException)
+{
+ Sequence < OUString > SupportedServicesNames = X11Clipboard_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::initialize( const Sequence< Any >& ) throw( ::com::sun::star::uno::Exception )
+{
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > SAL_CALL X11Clipboard::getSupportedServiceNames( )
+ throw(RuntimeException)
+{
+ return X11Clipboard_getSupportedServiceNames();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_clipboard.hxx b/vcl/unx/generic/dtrans/X11_clipboard.hxx
new file mode 100644
index 000000000000..73240d8715e6
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_clipboard.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_CLIPBOARD_HXX_
+#define _DTRANS_X11_CLIPBOARD_HXX_
+
+#include <X11_selection.hxx>
+
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <cppuhelper/compbase4.hxx>
+
+// ------------------------------------------------------------------------
+
+#define X11_CLIPBOARD_IMPLEMENTATION_NAME "com.sun.star.datatransfer.X11ClipboardSupport"
+
+namespace x11 {
+
+ class X11Clipboard :
+ public ::cppu::WeakComponentImplHelper4 <
+ ::com::sun::star::datatransfer::clipboard::XClipboardEx,
+ ::com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ ::com::sun::star::lang::XServiceInfo,
+ ::com::sun::star::lang::XInitialization
+ >,
+ public SelectionAdaptor
+ {
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > m_aContents;
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner > m_aOwner;
+
+ SelectionManager& m_rSelectionManager;
+ com::sun::star::uno::Reference< ::com::sun::star::lang::XInitialization > m_xSelectionManager;
+ ::std::list< com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > m_aListeners;
+ Atom m_aSelection;
+
+ protected:
+
+
+ friend class SelectionManager;
+ friend class X11_Transferable;
+
+ void fireChangedContentsEvent();
+ void clearContents();
+
+ public:
+
+ X11Clipboard( SelectionManager& rManager, Atom aSelection );
+ virtual ~X11Clipboard();
+
+ static X11Clipboard* get( const ::rtl::OUString& rDisplayName, Atom aSelection );
+
+ /*
+ * XInitialization
+ */
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ /*
+ * XServiceInfo
+ */
+
+ virtual ::rtl::OUString SAL_CALL getImplementationName( )
+ throw(RuntimeException);
+
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(RuntimeException);
+
+ virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( )
+ throw(RuntimeException);
+
+ /*
+ * XClipboard
+ */
+
+ virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents()
+ throw(RuntimeException);
+
+ virtual void SAL_CALL setContents(
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTrans,
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw(RuntimeException);
+
+ virtual ::rtl::OUString SAL_CALL getName()
+ throw(RuntimeException);
+
+ /*
+ * XClipboardEx
+ */
+
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities()
+ throw(RuntimeException);
+
+ /*
+ * XClipboardNotifier
+ */
+ virtual void SAL_CALL addClipboardListener(
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException);
+
+ virtual void SAL_CALL removeClipboardListener(
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException);
+
+ /*
+ * SelectionAdaptor
+ */
+ virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable();
+ virtual void clearTransferable();
+ virtual void fireContentsChanged();
+ virtual com::sun::star::uno::Reference< XInterface > getReference() throw();
+ };
+
+// ------------------------------------------------------------------------
+
+ Sequence< ::rtl::OUString > SAL_CALL X11Clipboard_getSupportedServiceNames();
+ com::sun::star::uno::Reference< XInterface > SAL_CALL X11Clipboard_createInstance(
+ const com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
+
+// ------------------------------------------------------------------------
+
+} // namepspace
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_dndcontext.cxx b/vcl/unx/generic/dtrans/X11_dndcontext.cxx
new file mode 100644
index 000000000000..988dce430a51
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_dndcontext.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <X11_dndcontext.hxx>
+#include <X11_selection.hxx>
+
+using namespace cppu;
+using namespace x11;
+
+/*
+ * DropTargetDropContext
+ */
+
+DropTargetDropContext::DropTargetDropContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DropTargetDropContext::~DropTargetDropContext()
+{
+}
+
+void DropTargetDropContext::acceptDrop( sal_Int8 dragOperation ) throw()
+{
+ m_rManager.accept( dragOperation, m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDropContext::rejectDrop() throw()
+{
+ m_rManager.reject( m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDropContext::dropComplete( sal_Bool success ) throw()
+{
+ m_rManager.dropComplete( success, m_aDropWindow, m_nTimestamp );
+}
+
+
+/*
+ * DropTargetDragContext
+ */
+
+DropTargetDragContext::DropTargetDragContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DropTargetDragContext::~DropTargetDragContext()
+{
+}
+
+void DropTargetDragContext::acceptDrag( sal_Int8 dragOperation ) throw()
+{
+ m_rManager.accept( dragOperation, m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDragContext::rejectDrag() throw()
+{
+ m_rManager.reject( m_aDropWindow, m_nTimestamp );
+}
+
+/*
+ * DragSourceContext
+ */
+
+DragSourceContext::DragSourceContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DragSourceContext::~DragSourceContext()
+{
+}
+
+sal_Int32 DragSourceContext::getCurrentCursor() throw()
+{
+ return m_rManager.getCurrentCursor();
+}
+
+void DragSourceContext::setCursor( sal_Int32 cursorId ) throw()
+{
+ m_rManager.setCursor( cursorId, m_aDropWindow, m_nTimestamp );
+}
+
+void DragSourceContext::setImage( sal_Int32 imageId ) throw()
+{
+ m_rManager.setImage( imageId, m_aDropWindow, m_nTimestamp );
+}
+
+void DragSourceContext::transferablesFlavorsChanged() throw()
+{
+ m_rManager.transferablesFlavorsChanged();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_dndcontext.hxx b/vcl/unx/generic/dtrans/X11_dndcontext.hxx
new file mode 100644
index 000000000000..bca708eb24c7
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_dndcontext.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_DNDCONTEXT_HXX
+#define _DTRANS_X11_DNDCONTEXT_HXX
+
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include "tools/prex.h"
+#include <X11/Xlib.h>
+#include "tools/postx.h"
+
+using namespace com::sun::star::uno;
+
+namespace x11 {
+
+ class SelectionManager;
+
+ class DropTargetDropContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDropTargetDropContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xManagerRef;
+ public:
+ DropTargetDropContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DropTargetDropContext();
+
+ // XDropTargetDropContext
+ virtual void SAL_CALL acceptDrop( sal_Int8 dragOperation ) throw();
+ virtual void SAL_CALL rejectDrop() throw();
+ virtual void SAL_CALL dropComplete( sal_Bool success ) throw();
+ };
+
+ class DropTargetDragContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDropTargetDragContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xManagerRef;
+ public:
+ DropTargetDragContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DropTargetDragContext();
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrag( sal_Int8 dragOperation ) throw();
+ virtual void SAL_CALL rejectDrag() throw();
+ };
+
+ class DragSourceContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDragSourceContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xManagerRef;
+ public:
+ DragSourceContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DragSourceContext();
+
+ // XDragSourceContext
+ virtual sal_Int32 SAL_CALL getCurrentCursor() throw();
+ virtual void SAL_CALL setCursor( sal_Int32 cursorId ) throw();
+ virtual void SAL_CALL setImage( sal_Int32 imageId ) throw();
+ virtual void SAL_CALL transferablesFlavorsChanged() throw();
+ };
+} // namespace
+
+#endif // _DTRANS_X11_DNDCONTEXT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_droptarget.cxx b/vcl/unx/generic/dtrans/X11_droptarget.cxx
new file mode 100644
index 000000000000..d72c5c4c7eeb
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_droptarget.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <X11_selection.hxx>
+
+using namespace x11;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+
+using ::rtl::OUString;
+
+DropTarget::DropTarget() :
+ ::cppu::WeakComponentImplHelper3<
+ XDropTarget,
+ XInitialization,
+ XServiceInfo
+ >( m_aMutex ),
+ m_bActive( false ),
+ m_nDefaultActions( 0 ),
+ m_aTargetWindow( None ),
+ m_pSelectionManager( NULL )
+{
+}
+
+DropTarget::~DropTarget()
+{
+ if( m_pSelectionManager )
+ m_pSelectionManager->deregisterDropTarget( m_aTargetWindow );
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception )
+{
+ if( arguments.getLength() > 1 )
+ {
+ OUString aDisplayName;
+ Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+ if( xConn.is() )
+ {
+ Any aIdentifier;
+ aIdentifier >>= aDisplayName;
+ }
+
+ m_pSelectionManager = &SelectionManager::get( aDisplayName );
+ m_xSelectionManager = static_cast< XDragSource* >(m_pSelectionManager);
+ m_pSelectionManager->initialize( arguments );
+
+ if( m_pSelectionManager->getDisplay() ) // #136582# sanity check
+ {
+ sal_Size aWindow = None;
+ arguments.getConstArray()[1] >>= aWindow;
+ m_pSelectionManager->registerDropTarget( aWindow, this );
+ m_aTargetWindow = aWindow;
+ m_bActive = true;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& xListener ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_aListeners.push_back( xListener );
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& xListener ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_aListeners.remove( xListener );
+}
+
+// --------------------------------------------------------------------------
+
+sal_Bool DropTarget::isActive() throw()
+{
+ return m_bActive;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::setActive( sal_Bool active ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_bActive = active;
+}
+
+// --------------------------------------------------------------------------
+
+sal_Int8 DropTarget::getDefaultActions() throw()
+{
+ return m_nDefaultActions;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::setDefaultActions( sal_Int8 actions ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_nDefaultActions = actions;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::drop( const DropTargetDropEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->drop( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragEnter( const DropTargetDragEnterEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragEnter( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragExit( const DropTargetEvent& dte ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragExit( dte );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragOver( const DropTargetDragEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragOver( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+/*
+ * XServiceInfo
+ */
+
+// ------------------------------------------------------------------------
+
+OUString DropTarget::getImplementationName() throw()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM(XDND_DROPTARGET_IMPLEMENTATION_NAME));
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool DropTarget::supportsService( const OUString& ServiceName ) throw()
+{
+ Sequence < OUString > SupportedServicesNames = Xdnd_dropTarget_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > DropTarget::getSupportedServiceNames() throw()
+{
+ return Xdnd_dropTarget_getSupportedServiceNames();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_selection.cxx b/vcl/unx/generic/dtrans/X11_selection.cxx
new file mode 100644
index 000000000000..facc134b3b56
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_selection.cxx
@@ -0,0 +1,4193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "tools/prex.h"
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+#include "tools/postx.h"
+#if defined(LINUX) || defined(NETBSD) || defined (FREEBSD) || defined(OPENBSD)
+#include <sys/poll.h>
+#else
+#include <poll.h>
+#endif
+#include <sal/alloca.h>
+#include <sal/macros.h>
+
+#include <X11_selection.hxx>
+#include <X11_clipboard.hxx>
+#include <X11_transferable.hxx>
+#include <X11_dndcontext.hxx>
+#include <bmp.hxx>
+
+#include "vcl/svapp.hxx"
+
+// pointer bitmaps
+#include <copydata_curs.h>
+#include <copydata_mask.h>
+#include <movedata_curs.h>
+#include <movedata_mask.h>
+#include <linkdata_curs.h>
+#include <linkdata_mask.h>
+#include <nodrop_curs.h>
+#include <nodrop_mask.h>
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <rtl/tencinfo.h>
+#include <osl/process.h>
+
+#include <comphelper/processfactory.hxx>
+#include <osl/mutex.hxx>
+
+#define DRAG_EVENT_MASK ButtonPressMask |\
+ ButtonReleaseMask |\
+ PointerMotionMask |\
+ EnterWindowMask |\
+ LeaveWindowMask
+
+namespace {
+
+namespace css = com::sun::star;
+
+}
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::frame;
+using namespace cppu;
+
+using namespace x11;
+
+using ::rtl::OUString;
+using ::rtl::OUStringHash;
+using ::rtl::OStringToOUString;
+
+// stubs to satisfy solaris compiler's rather rigid linking warning
+extern "C"
+{
+ static void call_SelectionManager_run( void * pMgr )
+ {
+ SelectionManager::run( pMgr );
+ }
+
+ static void call_SelectionManager_runDragExecute( void * pMgr )
+ {
+ SelectionManager::runDragExecute( pMgr );
+ }
+}
+
+
+static const long nXdndProtocolRevision = 5;
+
+// mapping between mime types (or what the office thinks of mime types)
+// and X convention types
+struct NativeTypeEntry
+{
+ Atom nAtom;
+ const char* pType; // Mime encoding on our side
+ const char* pNativeType; // string corresponding to nAtom for the case of nAtom being uninitialized
+ int nFormat; // the corresponding format
+};
+
+// the convention for Xdnd is mime types as specified by the corresponding
+// RFC's with the addition that text/plain without charset tag contains iso8859-1
+// sadly some applications (e.g. gtk) do not honor the mimetype only rule,
+// so for compatibility add UTF8_STRING
+static NativeTypeEntry aXdndConversionTab[] =
+{
+ { 0, "text/plain;charset=iso8859-1", "text/plain", 8 },
+ { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 }
+};
+
+// for clipboard and primary selections there is only a convention for text
+// that the encoding name of the text is taken as type in all capitalized letters
+static NativeTypeEntry aNativeConversionTab[] =
+{
+ { 0, "text/plain;charset=utf-16", "ISO10646-1", 16 },
+ { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 },
+ { 0, "text/plain;charset=utf-8", "UTF-8", 8 },
+ { 0, "text/plain;charset=utf-8", "text/plain;charset=UTF-8", 8 },
+ // ISO encodings
+ { 0, "text/plain;charset=iso8859-2", "ISO8859-2", 8 },
+ { 0, "text/plain;charset=iso8859-3", "ISO8859-3", 8 },
+ { 0, "text/plain;charset=iso8859-4", "ISO8859-4", 8 },
+ { 0, "text/plain;charset=iso8859-5", "ISO8859-5", 8 },
+ { 0, "text/plain;charset=iso8859-6", "ISO8859-6", 8 },
+ { 0, "text/plain;charset=iso8859-7", "ISO8859-7", 8 },
+ { 0, "text/plain;charset=iso8859-8", "ISO8859-8", 8 },
+ { 0, "text/plain;charset=iso8859-9", "ISO8859-9", 8 },
+ { 0, "text/plain;charset=iso8859-10", "ISO8859-10", 8 },
+ { 0, "text/plain;charset=iso8859-13", "ISO8859-13", 8 },
+ { 0, "text/plain;charset=iso8859-14", "ISO8859-14", 8 },
+ { 0, "text/plain;charset=iso8859-15", "ISO8859-15", 8 },
+ // asian encodings
+ { 0, "text/plain;charset=jisx0201.1976-0", "JISX0201.1976-0", 8 },
+ { 0, "text/plain;charset=jisx0208.1983-0", "JISX0208.1983-0", 8 },
+ { 0, "text/plain;charset=jisx0208.1990-0", "JISX0208.1990-0", 8 },
+ { 0, "text/plain;charset=jisx0212.1990-0", "JISX0212.1990-0", 8 },
+ { 0, "text/plain;charset=gb2312.1980-0", "GB2312.1980-0", 8 },
+ { 0, "text/plain;charset=ksc5601.1992-0", "KSC5601.1992-0", 8 },
+ // eastern european encodings
+ { 0, "text/plain;charset=koi8-r", "KOI8-R", 8 },
+ { 0, "text/plain;charset=koi8-u", "KOI8-U", 8 },
+ // String (== iso8859-1)
+ { XA_STRING, "text/plain;charset=iso8859-1", "STRING", 8 },
+ // special for compound text
+ { 0, "text/plain;charset=compound_text", "COMPOUND_TEXT", 8 },
+
+ // PIXMAP
+ { XA_PIXMAP, "image/bmp", "PIXMAP", 32 }
+};
+
+rtl_TextEncoding x11::getTextPlainEncoding( const OUString& rMimeType )
+{
+ rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
+ OUString aMimeType( rMimeType.toAsciiLowerCase() );
+ sal_Int32 nIndex = 0;
+ if( aMimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain" , 10 ) )
+ {
+ if( aMimeType.getLength() == 10 ) // only "text/plain"
+ aEncoding = RTL_TEXTENCODING_ISO_8859_1;
+ else
+ {
+ while( nIndex != -1 )
+ {
+ OUString aToken = aMimeType.getToken( 0, ';', nIndex );
+ sal_Int32 nPos = 0;
+ if( aToken.getToken( 0, '=', nPos ).equalsAsciiL( "charset", 7 ) )
+ {
+ OString aEncToken = OUStringToOString( aToken.getToken( 0, '=', nPos ), RTL_TEXTENCODING_ISO_8859_1 );
+ aEncoding = rtl_getTextEncodingFromUnixCharset( aEncToken.getStr() );
+ if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ {
+ if( aEncToken.equalsIgnoreAsciiCase( "utf-8" ) )
+ aEncoding = RTL_TEXTENCODING_UTF8;
+ }
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW )
+ break;
+ }
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ fprintf( stderr, "getTextPlainEncoding( %s ) failed\n", OUStringToOString( rMimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ return aEncoding;
+}
+
+// ------------------------------------------------------------------------
+
+::boost::unordered_map< OUString, SelectionManager*, OUStringHash >& SelectionManager::getInstances()
+{
+ static ::boost::unordered_map< OUString, SelectionManager*, OUStringHash > aInstances;
+ return aInstances;
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager::SelectionManager() :
+ m_nIncrementalThreshold( 15*1024 ),
+ m_pDisplay( NULL ),
+ m_aThread( NULL ),
+ m_aDragExecuteThread( NULL ),
+ m_aWindow( None ),
+ m_nSelectionTimeout( 0 ),
+ m_nSelectionTimestamp( CurrentTime ),
+ m_bDropEnterSent( true ),
+ m_aCurrentDropWindow( None ),
+ m_nDropTime( None ),
+ m_nLastDropAction( 0 ),
+ m_nLastX( 0 ),
+ m_nLastY( 0 ),
+ m_nDropTimestamp( 0 ),
+ m_bDropWaitingForCompletion( false ),
+ m_aDropWindow( None ),
+ m_aDropProxy( None ),
+ m_aDragSourceWindow( None ),
+ m_nLastDragX( 0 ),
+ m_nLastDragY( 0 ),
+ m_nNoPosX( 0 ),
+ m_nNoPosY( 0 ),
+ m_nNoPosWidth( 0 ),
+ m_nNoPosHeight( 0 ),
+ m_nDragButton( 0 ),
+ m_nUserDragAction( 0 ),
+ m_nTargetAcceptAction( 0 ),
+ m_nSourceActions( 0 ),
+ m_bLastDropAccepted( false ),
+ m_bDropSuccess( false ),
+ m_bDropSent( false ),
+ m_bWaitingForPrimaryConversion( false ),
+ m_nDragTimestamp( None ),
+ m_aMoveCursor( None ),
+ m_aCopyCursor( None ),
+ m_aLinkCursor( None ),
+ m_aNoneCursor( None ),
+ m_aCurrentCursor( None ),
+ m_nCurrentProtocolVersion( nXdndProtocolRevision ),
+ m_nCLIPBOARDAtom( None ),
+ m_nTARGETSAtom( None ),
+ m_nTIMESTAMPAtom( None ),
+ m_nTEXTAtom( None ),
+ m_nINCRAtom( None ),
+ m_nCOMPOUNDAtom( None ),
+ m_nMULTIPLEAtom( None ),
+ m_nUTF16Atom( None ),
+ m_nImageBmpAtom( None ),
+ m_nXdndAware( None ),
+ m_nXdndEnter( None ),
+ m_nXdndLeave( None ),
+ m_nXdndPosition( None ),
+ m_nXdndStatus( None ),
+ m_nXdndDrop( None ),
+ m_nXdndFinished( None ),
+ m_nXdndSelection( None ),
+ m_nXdndTypeList( None ),
+ m_nXdndProxy( None ),
+ m_nXdndActionCopy( None ),
+ m_nXdndActionMove( None ),
+ m_nXdndActionLink( None ),
+ m_nXdndActionAsk( None ),
+ m_nXdndActionPrivate( None ),
+ m_bShutDown( false )
+{
+ m_aDropEnterEvent.data.l[0] = None;
+ m_aDragRunning.reset();
+}
+
+XLIB_Cursor SelectionManager::createCursor( const unsigned char* pPointerData, const unsigned char* pMaskData, int width, int height, int hotX, int hotY )
+{
+ Pixmap aPointer;
+ Pixmap aMask;
+ XColor aBlack, aWhite;
+
+ aBlack.pixel = BlackPixel( m_pDisplay, 0 );
+ aBlack.red = aBlack.green = aBlack.blue = 0;
+ aBlack.flags = DoRed | DoGreen | DoBlue;
+
+ aWhite.pixel = WhitePixel( m_pDisplay, 0 );
+ aWhite.red = aWhite.green = aWhite.blue = 0xffff;
+ aWhite.flags = DoRed | DoGreen | DoBlue;
+
+ aPointer =
+ XCreateBitmapFromData( m_pDisplay,
+ m_aWindow,
+ reinterpret_cast<const char*>(pPointerData),
+ width,
+ height );
+ aMask
+ = XCreateBitmapFromData( m_pDisplay,
+ m_aWindow,
+ reinterpret_cast<const char*>(pMaskData),
+ width,
+ height );
+ XLIB_Cursor aCursor =
+ XCreatePixmapCursor( m_pDisplay, aPointer, aMask,
+ &aBlack, &aWhite,
+ hotX,
+ hotY );
+ XFreePixmap( m_pDisplay, aPointer );
+ XFreePixmap( m_pDisplay, aMask );
+
+ return aCursor;
+}
+
+void SelectionManager::initialize( const Sequence< Any >& arguments ) throw (::com::sun::star::uno::Exception)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ if( ! m_xDisplayConnection.is() )
+ {
+ /*
+ * first argument must be a ::com::sun::star::awt::XDisplayConnection
+ * from this we will get the XEvents of the vcl event loop by
+ * registering us as XEventHandler on it.
+ *
+ * implementor's note:
+ * FIXME:
+ * finally the clipboard and XDND service is back in the module it belongs
+ * now cleanup and sharing of resources with the normal vcl event loop
+ * needs to be added. The display used whould be that of the normal event loop
+ * and synchronization should be done via the SolarMutex.
+ */
+ if( arguments.getLength() > 0 )
+ arguments.getConstArray()[0] >>= m_xDisplayConnection;
+ if( ! m_xDisplayConnection.is() )
+ {
+ }
+ else
+ m_xDisplayConnection->addEventHandler( Any(), this, ~0 );
+ }
+
+ if( !m_xBitmapConverter.is() )
+ {
+ if( arguments.getLength() > 2 )
+ arguments.getConstArray()[2] >>= m_xBitmapConverter;
+ }
+
+ OUString aParam;
+ if( ! m_pDisplay )
+ {
+ OUString aUDisplay;
+ if( m_xDisplayConnection.is() )
+ {
+ Any aIdentifier;
+ aIdentifier = m_xDisplayConnection->getIdentifier();
+ aIdentifier >>= aUDisplay;
+ }
+
+ OString aDisplayName( OUStringToOString( aUDisplay, RTL_TEXTENCODING_ISO_8859_1 ) );
+
+ m_pDisplay = XOpenDisplay( aDisplayName.getLength() ? aDisplayName.getStr() : NULL );
+
+ if( m_pDisplay )
+ {
+#ifdef SYNCHRONIZE
+ XSynchronize( m_pDisplay, True );
+#endif
+ // clipboard selection
+ m_nCLIPBOARDAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) );
+
+ // special targets
+ m_nTARGETSAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("TARGETS")) );
+ m_nTIMESTAMPAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("TIMESTAMP")) );
+ m_nTEXTAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("TEXT")) );
+ m_nINCRAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("INCR")) );
+ m_nCOMPOUNDAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("COMPOUND_TEXT")) );
+ m_nMULTIPLEAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("MULTIPLE")) );
+ m_nUTF16Atom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("ISO10646-1")) );
+ m_nImageBmpAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("image/bmp")) );
+
+ // Atoms for Xdnd protocol
+ m_nXdndAware = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndAware")) );
+ m_nXdndEnter = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndEnter")) );
+ m_nXdndLeave = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndLeave")) );
+ m_nXdndPosition = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndPosition")) );
+ m_nXdndStatus = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndStatus")) );
+ m_nXdndDrop = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndDrop")) );
+ m_nXdndFinished = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndFinished")) );
+ m_nXdndSelection = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndSelection")) );
+ m_nXdndTypeList = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndTypeList")) );
+ m_nXdndProxy = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndProxy")) );
+ m_nXdndActionCopy = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionCopy")) );
+ m_nXdndActionMove = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionMove")) );
+ m_nXdndActionLink = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionLink")) );
+ m_nXdndActionAsk = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionAsk")) );
+ m_nXdndActionPrivate= getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionPrivate")) );
+
+ // initialize map with member none
+ m_aAtomToString[ 0 ]= OUString(RTL_CONSTASCII_USTRINGPARAM("None"));
+ m_aAtomToString[ XA_PRIMARY ] = OUString(RTL_CONSTASCII_USTRINGPARAM("PRIMARY"));
+
+ // create a (invisible) message window
+ m_aWindow = XCreateSimpleWindow( m_pDisplay, DefaultRootWindow( m_pDisplay ),
+ 10, 10, 10, 10, 0, 0, 1 );
+
+ // initialize threshold for incremetal transfers
+ // ICCCM says it should be smaller that the max request size
+ // which in turn is guaranteed to be at least 16k bytes
+ m_nIncrementalThreshold = XMaxRequestSize( m_pDisplay ) - 1024;
+
+ if( m_aWindow )
+ {
+ // initialize default cursors
+ m_aMoveCursor = createCursor( movedata_curs_bits,
+ movedata_mask_bits,
+ movedata_curs_width,
+ movedata_curs_height,
+ movedata_curs_x_hot,
+ movedata_curs_y_hot );
+ m_aCopyCursor = createCursor( copydata_curs_bits,
+ copydata_mask_bits,
+ copydata_curs_width,
+ copydata_curs_height,
+ copydata_curs_x_hot,
+ copydata_curs_y_hot );
+ m_aLinkCursor = createCursor( linkdata_curs_bits,
+ linkdata_mask_bits,
+ linkdata_curs_width,
+ linkdata_curs_height,
+ linkdata_curs_x_hot,
+ linkdata_curs_y_hot );
+ m_aNoneCursor = createCursor( nodrop_curs_bits,
+ nodrop_mask_bits,
+ nodrop_curs_width,
+ nodrop_curs_height,
+ nodrop_curs_x_hot,
+ nodrop_curs_y_hot );
+
+
+
+
+ // just interested in SelectionClear/Notify/Request and PropertyChange
+ XSelectInput( m_pDisplay, m_aWindow, PropertyChangeMask );
+ // create the transferable for Drag operations
+ m_xDropTransferable = new X11Transferable( *this, static_cast< OWeakObject* >(this), m_nXdndSelection );
+ registerHandler( m_nXdndSelection, *this );
+
+ m_aThread = osl_createSuspendedThread( call_SelectionManager_run, this );
+ if( m_aThread )
+ osl_resumeThread( m_aThread );
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "SelectionManager::initialize: creation of dispatch thread failed !\n" );
+#endif
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager::~SelectionManager()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager::~SelectionManager (%s)\n", m_pDisplay ? DisplayString(m_pDisplay) : "no display" );
+#endif
+ {
+ osl::MutexGuard aGuard( *osl::Mutex::getGlobalMutex() );
+
+ ::boost::unordered_map< OUString, SelectionManager*, OUStringHash >::iterator it;
+ for( it = getInstances().begin(); it != getInstances().end(); ++it )
+ if( it->second == this )
+ {
+ getInstances().erase( it );
+ break;
+ }
+ }
+
+ if( m_aThread )
+ {
+ osl_terminateThread( m_aThread );
+ osl_joinWithThread( m_aThread );
+ osl_destroyThread( m_aThread );
+ }
+
+ if( m_aDragExecuteThread )
+ {
+ osl_terminateThread( m_aDragExecuteThread );
+ osl_joinWithThread( m_aDragExecuteThread );
+ m_aDragExecuteThread = NULL;
+ // thread handle is freed in dragDoDispatch()
+ }
+
+ osl::MutexGuard aGuard(m_aMutex);
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "shutting down SelectionManager\n" );
+#endif
+
+ if( m_xDisplayConnection.is() )
+ {
+ m_xDisplayConnection->removeEventHandler( Any(), this );
+ m_xDisplayConnection.clear();
+ }
+
+ if( m_pDisplay )
+ {
+ deregisterHandler( m_nXdndSelection );
+ // destroy message window
+ if( m_aWindow )
+ XDestroyWindow( m_pDisplay, m_aWindow );
+ // release cursors
+ if (m_aMoveCursor != None)
+ XFreeCursor(m_pDisplay, m_aMoveCursor);
+ if (m_aCopyCursor != None)
+ XFreeCursor(m_pDisplay, m_aCopyCursor);
+ if (m_aLinkCursor != None)
+ XFreeCursor(m_pDisplay, m_aLinkCursor);
+ if (m_aNoneCursor != None)
+ XFreeCursor(m_pDisplay, m_aNoneCursor);
+
+ // paranoia setting, the drag thread should have
+ // done that already
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+
+ XCloseDisplay( m_pDisplay );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+SelectionAdaptor* SelectionManager::getAdaptor( Atom selection )
+{
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( selection );
+ return it != m_aSelections.end() ? it->second->m_pAdaptor : NULL;
+}
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManager::convertFromCompound( const char* pText, int nLen )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ OUString aRet;
+ if( nLen < 0 )
+ nLen = strlen( pText );
+
+ char** pTextList = NULL;
+ int nTexts = 0;
+
+ XTextProperty aProp;
+ aProp.value = (unsigned char*)pText;
+ aProp.encoding = m_nCOMPOUNDAtom;
+ aProp.format = 8;
+ aProp.nitems = nLen;
+ XmbTextPropertyToTextList( m_pDisplay,
+ &aProp,
+ &pTextList,
+ &nTexts );
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ for( int i = 0; i < nTexts; i++ )
+ aRet += OStringToOUString( pTextList[i], aEncoding );
+
+ if( pTextList )
+ XFreeStringList( pTextList );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+OString SelectionManager::convertToCompound( const OUString& rText )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ XTextProperty aProp;
+ aProp.value = NULL;
+ aProp.encoding = XA_STRING;
+ aProp.format = 8;
+ aProp.nitems = 0;
+
+ OString aRet( rText.getStr(), rText.getLength(), osl_getThreadTextEncoding() );
+ char* pT = const_cast<char*>(aRet.getStr());
+
+ XmbTextListToTextProperty( m_pDisplay,
+ &pT,
+ 1,
+ XCompoundTextStyle,
+ &aProp );
+ if( aProp.value )
+ {
+ aRet = (char*)aProp.value;
+ XFree( aProp.value );
+#ifdef SOLARIS
+ /*
+ * for currently unknown reasons XmbTextListToTextProperty on Solaris returns
+ * no data in ISO8859-n encodings (at least for n = 1, 15)
+ * in these encodings the directly converted text does the
+ * trick, also.
+ */
+ if( ! aRet.getLength() && rText.getLength() )
+ aRet = OUStringToOString( rText, osl_getThreadTextEncoding() );
+#endif
+ }
+ else
+ aRet = OString();
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::convertData(
+ const css::uno::Reference< XTransferable >& xTransferable,
+ Atom nType,
+ Atom nSelection,
+ int& rFormat,
+ Sequence< sal_Int8 >& rData )
+{
+ bool bSuccess = false;
+
+ if( ! xTransferable.is() )
+ return bSuccess;
+
+ try
+ {
+
+ DataFlavor aFlavor;
+ aFlavor.MimeType = convertTypeFromNative( nType, nSelection, rFormat );
+
+ sal_Int32 nIndex = 0;
+ if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "text/plain" ) == 0 )
+ {
+ if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "charset=utf-16" ) == 0 )
+ aFlavor.DataType = getCppuType( (OUString *) 0 );
+ else
+ aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+ }
+ else
+ aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+
+ if( xTransferable->isDataFlavorSupported( aFlavor ) )
+ {
+ Any aValue( xTransferable->getTransferData( aFlavor ) );
+ if( aValue.getValueTypeClass() == TypeClass_STRING )
+ {
+ OUString aString;
+ aValue >>= aString;
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aString.getStr(), aString.getLength() * sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else if( aValue.getValueType() == getCppuType( (Sequence< sal_Int8 >*)0 ) )
+ {
+ aValue >>= rData;
+ bSuccess = true;
+ }
+ }
+ else if( aFlavor.MimeType.compareToAscii( "text/plain", 10 ) == 0 )
+ {
+ rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
+ bool bCompoundText = false;
+ if( nType == m_nCOMPOUNDAtom )
+ bCompoundText = true;
+ else
+ aEncoding = getTextPlainEncoding( aFlavor.MimeType );
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW || bCompoundText )
+ {
+ aFlavor.MimeType = OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16"));
+ aFlavor.DataType = getCppuType( (OUString *) 0 );
+ if( xTransferable->isDataFlavorSupported( aFlavor ) )
+ {
+ Any aValue( xTransferable->getTransferData( aFlavor ) );
+ OUString aString;
+ aValue >>= aString;
+ OString aByteString( bCompoundText ? convertToCompound( aString ) : OUStringToOString( aString, aEncoding ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aByteString.getStr(), aByteString.getLength() * sizeof( sal_Char ) );
+ bSuccess = true;
+ }
+ }
+ }
+ }
+ // various exceptions possible ... which all lead to a failed conversion
+ // so simplify here to a catch all
+ catch(...)
+ {
+ }
+
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager& SelectionManager::get( const OUString& rDisplayName )
+{
+ osl::MutexGuard aGuard( *osl::Mutex::getGlobalMutex() );
+
+ OUString aDisplayName( rDisplayName );
+ if( ! aDisplayName.getLength() )
+ aDisplayName = OStringToOUString( getenv( "DISPLAY" ), RTL_TEXTENCODING_ISO_8859_1 );
+ SelectionManager* pInstance = NULL;
+
+ ::boost::unordered_map< OUString, SelectionManager*, OUStringHash >::iterator it = getInstances().find( aDisplayName );
+ if( it != getInstances().end() )
+ pInstance = it->second;
+ else pInstance = getInstances()[ aDisplayName ] = new SelectionManager();
+
+ return *pInstance;
+}
+
+// ------------------------------------------------------------------------
+
+const OUString& SelectionManager::getString( Atom aAtom )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ::boost::unordered_map< Atom, OUString >::const_iterator it;
+ if( ( it = m_aAtomToString.find( aAtom ) ) == m_aAtomToString.end() )
+ {
+ static OUString aEmpty;
+ char* pAtom = m_pDisplay ? XGetAtomName( m_pDisplay, aAtom ) : NULL;
+ if( ! pAtom )
+ return aEmpty;
+ OUString aString( OStringToOUString( pAtom, RTL_TEXTENCODING_ISO_8859_1 ) );
+ XFree( pAtom );
+ m_aStringToAtom[ aString ] = aAtom;
+ m_aAtomToString[ aAtom ] = aString;
+ }
+ return m_aAtomToString[ aAtom ];
+}
+
+// ------------------------------------------------------------------------
+
+Atom SelectionManager::getAtom( const OUString& rString )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ::boost::unordered_map< OUString, Atom, OUStringHash >::const_iterator it;
+ if( ( it = m_aStringToAtom.find( rString ) ) == m_aStringToAtom.end() )
+ {
+ static Atom nNoDisplayAtoms = 1;
+ Atom aAtom = m_pDisplay ? XInternAtom( m_pDisplay, OUStringToOString( rString, RTL_TEXTENCODING_ISO_8859_1 ), False ) : nNoDisplayAtoms++;
+ m_aStringToAtom[ rString ] = aAtom;
+ m_aAtomToString[ aAtom ] = rString;
+ }
+ return m_aStringToAtom[ rString ];
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::requestOwnership( Atom selection )
+{
+ bool bSuccess = false;
+ if( m_pDisplay && m_aWindow )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ SelectionAdaptor* pAdaptor = getAdaptor( selection );
+ if( pAdaptor )
+ {
+ XSetSelectionOwner( m_pDisplay, selection, m_aWindow, CurrentTime );
+ if( XGetSelectionOwner( m_pDisplay, selection ) == m_aWindow )
+ bSuccess = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s ownership for selection %s\n",
+ bSuccess ? "acquired" : "failed to acquire",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ Selection* pSel = m_aSelections[ selection ];
+ pSel->m_bOwner = bSuccess;
+ delete pSel->m_pPixmap;
+ pSel->m_pPixmap = NULL;
+ pSel->m_nOrigTimestamp = m_nSelectionTimestamp;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no adaptor for selection %s\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+
+ if( pAdaptor->getTransferable().is() )
+ {
+ Sequence< DataFlavor > aTypes = pAdaptor->getTransferable()->getTransferDataFlavors();
+ for( int i = 0; i < aTypes.getLength(); i++ )
+ {
+ fprintf( stderr, " %s\n", OUStringToOString( aTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ }
+ }
+#endif
+ }
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::convertTypeToNative( const OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront )
+{
+ NativeTypeEntry* pTab = selection == m_nXdndSelection ? aXdndConversionTab : aNativeConversionTab;
+ int nTabEntries = selection == m_nXdndSelection ? SAL_N_ELEMENTS(aXdndConversionTab) : SAL_N_ELEMENTS(aNativeConversionTab);
+
+ OString aType( OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ rFormat = 0;
+ for( int i = 0; i < nTabEntries; i++ )
+ {
+ if( aType.equalsIgnoreAsciiCase( pTab[i].pType ) )
+ {
+ if( ! pTab[i].nAtom )
+ pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ rFormat = pTab[i].nFormat;
+ if( bPushFront )
+ rConversions.push_front( pTab[i].nAtom );
+ else
+ rConversions.push_back( pTab[i].nAtom );
+ if( pTab[i].nFormat == XA_PIXMAP )
+ {
+ if( bPushFront )
+ {
+ rConversions.push_front( XA_VISUALID );
+ rConversions.push_front( XA_COLORMAP );
+ }
+ else
+ {
+ rConversions.push_back( XA_VISUALID );
+ rConversions.push_back( XA_COLORMAP );
+ }
+ }
+ }
+ }
+ if( ! rFormat )
+ rFormat = 8; // byte buffer
+ if( bPushFront )
+ rConversions.push_front( getAtom( rType ) );
+ else
+ rConversions.push_back( getAtom( rType ) );
+};
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::getNativeTypeList( const Sequence< DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection )
+{
+ rOutTypeList.clear();
+
+ int nFormat;
+ int nFlavors = rTypes.getLength();
+ const DataFlavor* pFlavors = rTypes.getConstArray();
+ bool bHaveText = false;
+ for( int i = 0; i < nFlavors; i++ )
+ {
+ if( pFlavors[i].MimeType.compareToAscii( "text/plain", 10 ) == 0)
+ bHaveText = true;
+ else
+ convertTypeToNative( pFlavors[i].MimeType, targetselection, nFormat, rOutTypeList );
+ }
+ if( bHaveText )
+ {
+ if( targetselection != m_nXdndSelection )
+ {
+ // only mimetypes should go into Xdnd type list
+ rOutTypeList.push_front( XA_STRING );
+ rOutTypeList.push_front( m_nCOMPOUNDAtom );
+ }
+ convertTypeToNative( OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-8")), targetselection, nFormat, rOutTypeList, true );
+ }
+ if( targetselection != m_nXdndSelection )
+ rOutTypeList.push_back( m_nMULTIPLEAtom );
+}
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManager::convertTypeFromNative( Atom nType, Atom selection, int& rFormat )
+{
+ NativeTypeEntry* pTab = (selection == m_nXdndSelection) ? aXdndConversionTab : aNativeConversionTab;
+ int nTabEntries = (selection == m_nXdndSelection) ? SAL_N_ELEMENTS(aXdndConversionTab) : SAL_N_ELEMENTS(aNativeConversionTab);
+
+ for( int i = 0; i < nTabEntries; i++ )
+ {
+ if( ! pTab[i].nAtom )
+ pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( nType == pTab[i].nAtom )
+ {
+ rFormat = pTab[i].nFormat;
+ return OStringToOUString( pTab[i].pType, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ rFormat = 8;
+ return getString( nType );
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData )
+{
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+ ::boost::unordered_map< Atom, Selection* >::iterator it;
+ bool bSuccess = false;
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString aSelection( getString( selection ) );
+ OUString aType( getString( type ) );
+ fprintf( stderr, "getPasteData( %s, native: %s )\n",
+ OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ if( ! m_pDisplay )
+ return false;
+
+ it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return false;
+
+ XLIB_Window aSelectionOwner = XGetSelectionOwner( m_pDisplay, selection );
+ if( aSelectionOwner == None )
+ return false;
+ if( aSelectionOwner == m_aWindow )
+ {
+ // probably bad timing led us here
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Innere Nabelschau\n" );
+#endif
+ return false;
+ }
+
+ // ICCCM recommends to destroy property before convert request unless
+ // parameters are transported; we do only in case of MULTIPLE,
+ // so destroy property unless target is MULTIPLE
+ if( type != m_nMULTIPLEAtom )
+ XDeleteProperty( m_pDisplay, m_aWindow, selection );
+
+ XConvertSelection( m_pDisplay, selection, type, selection, m_aWindow, selection == m_nXdndSelection ? m_nDropTime : CurrentTime );
+ it->second->m_eState = Selection::WaitingForResponse;
+ it->second->m_aRequestedType = type;
+ it->second->m_aData = Sequence< sal_Int8 >();
+ it->second->m_aDataArrived.reset();
+ // really start the request; if we don't flush the
+ // queue the request won't leave it because there are no more
+ // X calls after this until the data arrived or timeout
+ XFlush( m_pDisplay );
+
+ // do a reschedule
+ struct timeval tv_last, tv_current;
+ gettimeofday( &tv_last, NULL );
+ tv_current = tv_last;
+
+ XEvent aEvent;
+ do
+ {
+ bool bAdjustTime = false;
+ {
+ bool bHandle = false;
+
+ if( XCheckTypedEvent( m_pDisplay,
+ PropertyNotify,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ if( aEvent.xproperty.window == m_aWindow
+ && aEvent.xproperty.atom == selection )
+ bAdjustTime = true;
+ }
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionClear,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ }
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionRequest,
+ &aEvent
+ ) )
+ bHandle = true;
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionNotify,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ if( aEvent.xselection.selection == selection
+ && ( aEvent.xselection.requestor == m_aWindow ||
+ aEvent.xselection.requestor == m_aCurrentDropWindow )
+ )
+ bAdjustTime = true;
+ }
+ else
+ {
+ TimeValue aTVal;
+ aTVal.Seconds = 0;
+ aTVal.Nanosec = 100000000;
+ aGuard.clear();
+ osl_waitThread( &aTVal );
+ aGuard.reset();
+ }
+ if( bHandle )
+ {
+ aGuard.clear();
+ handleXEvent( aEvent );
+ aGuard.reset();
+ }
+ }
+ gettimeofday( &tv_current, NULL );
+ if( bAdjustTime )
+ tv_last = tv_current;
+ } while( ! it->second->m_aDataArrived.check() && (tv_current.tv_sec - tv_last.tv_sec) < getSelectionTimeout() );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( (tv_current.tv_sec - tv_last.tv_sec) > getSelectionTimeout() )
+ fprintf( stderr, "timed out\n" );
+#endif
+ if( it->second->m_aDataArrived.check() &&
+ it->second->m_aData.getLength() )
+ {
+ rData = it->second->m_aData;
+ bSuccess = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "conversion unsuccessfull\n" );
+#endif
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData )
+{
+ bool bSuccess = false;
+
+ ::boost::unordered_map< Atom, Selection* >::iterator it;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return false;
+ }
+
+ if( it->second->m_aTypes.getLength() == 0 )
+ {
+ Sequence< DataFlavor > aFlavors;
+ getPasteDataTypes( selection, aFlavors );
+ if( it->second->m_aTypes.getLength() == 0 )
+ return false;
+ }
+
+ const Sequence< DataFlavor >& rTypes( it->second->m_aTypes );
+ const std::vector< Atom >& rNativeTypes( it->second->m_aNativeTypes );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "getPasteData( \"%s\", \"%s\" )\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ if( rType.equalsAsciiL( "text/plain;charset=utf-16", 25 ) )
+ {
+ // lets see if we have UTF16 else try to find something convertible
+ if( it->second->m_aTypes.getLength() && ! it->second->m_bHaveUTF16 )
+ {
+ Sequence< sal_Int8 > aData;
+ if( it->second->m_aUTF8Type != None &&
+ getPasteData( selection,
+ it->second->m_aUTF8Type,
+ aData )
+ )
+ {
+ OUString aRet( (const sal_Char*)aData.getConstArray(), aData.getLength(), RTL_TEXTENCODING_UTF8 );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else if( it->second->m_bHaveCompound &&
+ getPasteData( selection,
+ m_nCOMPOUNDAtom,
+ aData )
+ )
+ {
+ OUString aRet( convertFromCompound( (const char*)aData.getConstArray(), aData.getLength() ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else
+ {
+ for( int i = 0; i < rTypes.getLength(); i++ )
+ {
+ rtl_TextEncoding aEncoding = getTextPlainEncoding( rTypes.getConstArray()[i].MimeType );
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW &&
+ aEncoding != RTL_TEXTENCODING_UNICODE &&
+ getPasteData( selection,
+ rNativeTypes[i],
+ aData )
+ )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "using \"%s\" instead of \"%s\"\n",
+ OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ OString aConvert( (sal_Char*)aData.getConstArray(), aData.getLength() );
+ OUString aUTF( OStringToOUString( aConvert, aEncoding ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aUTF.getStr(), (aUTF.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if( rType.equalsAsciiL( "image/bmp", 9 ) )
+ {
+ // #i83376# try if someone has the data in image/bmp already before
+ // doing the PIXMAP stuff (e.g. the gimp has this)
+ bSuccess = getPasteData( selection, m_nImageBmpAtom, rData );
+ #if OSL_DEBUG_LEVEL > 1
+ if( bSuccess )
+ fprintf( stderr, "got %d bytes of image/bmp\n", (int)rData.getLength() );
+ #endif
+ if( ! bSuccess )
+ {
+ Pixmap aPixmap = None;
+ Colormap aColormap = None;
+
+ // prepare property for MULTIPLE request
+ Sequence< sal_Int8 > aData;
+ Atom pTypes[4] = { XA_PIXMAP, XA_PIXMAP,
+ XA_COLORMAP, XA_COLORMAP };
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ XChangeProperty( m_pDisplay,
+ m_aWindow,
+ selection,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*)pTypes,
+ 4 );
+ }
+
+ // try MULTIPLE request
+ if( getPasteData( selection, m_nMULTIPLEAtom, aData ) )
+ {
+ Atom* pReturnedTypes = (Atom*)aData.getArray();
+ if( pReturnedTypes[0] == XA_PIXMAP && pReturnedTypes[1] == XA_PIXMAP )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ Atom type = None;
+ int format = 0;
+ unsigned long nItems = 0;
+ unsigned long nBytes = 0;
+ unsigned char* pReturn = NULL;
+ XGetWindowProperty( m_pDisplay, m_aWindow, XA_PIXMAP, 0, 1, True, XA_PIXMAP, &type, &format, &nItems, &nBytes, &pReturn );
+ if( pReturn )
+ {
+ if( type == XA_PIXMAP )
+ aPixmap = *(Pixmap*)pReturn;
+ XFree( pReturn );
+ pReturn = NULL;
+ if( pReturnedTypes[2] == XA_COLORMAP && pReturnedTypes[3] == XA_COLORMAP )
+ {
+ XGetWindowProperty( m_pDisplay, m_aWindow, XA_COLORMAP, 0, 1, True, XA_COLORMAP, &type, &format, &nItems, &nBytes, &pReturn );
+ if( pReturn )
+ {
+ if( type == XA_COLORMAP )
+ aColormap = *(Colormap*)pReturn;
+ XFree( pReturn );
+ }
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ 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 );
+ }
+ #endif
+ }
+ }
+
+ if( aPixmap == None )
+ {
+ // perhaps two normal requests will work
+ if( getPasteData( selection, XA_PIXMAP, aData ) )
+ {
+ aPixmap = *(Pixmap*)aData.getArray();
+ if( aColormap == None && getPasteData( selection, XA_COLORMAP, aData ) )
+ aColormap = *(Colormap*)aData.getArray();
+ }
+ }
+
+ // convert data if possible
+ if( aPixmap != None )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ sal_Int32 nOutSize = 0;
+ sal_uInt8* pBytes = X11_getBmpFromPixmap( m_pDisplay, aPixmap, aColormap, nOutSize );
+ if( pBytes && nOutSize )
+ {
+ rData = Sequence< sal_Int8 >( nOutSize );
+ memcpy( rData.getArray(), pBytes, nOutSize );
+ X11_freeBmp( pBytes );
+ bSuccess = true;
+ }
+ }
+ }
+ }
+
+ if( ! bSuccess )
+ {
+ int nFormat;
+ ::std::list< Atom > aTypes;
+ convertTypeToNative( rType, selection, nFormat, aTypes );
+ ::std::list< Atom >::const_iterator type_it;
+ Atom nSelectedType = None;
+ for( type_it = aTypes.begin(); type_it != aTypes.end() && nSelectedType == None; ++type_it )
+ {
+ for( unsigned int i = 0; i < rNativeTypes.size() && nSelectedType == None; i++ )
+ if( rNativeTypes[i] == *type_it )
+ nSelectedType = *type_it;
+ }
+ if( nSelectedType != None )
+ bSuccess = getPasteData( selection, nSelectedType, rData );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "getPasteData for selection %s and data type %s returns %s, returned sequence has length %" SAL_PRIdINT32 "\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ bSuccess ? "true" : "false",
+ rData.getLength()
+ );
+#endif
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteDataTypes( Atom selection, Sequence< DataFlavor >& rTypes )
+{
+ ::boost::unordered_map< Atom, Selection* >::iterator it;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it != m_aSelections.end() &&
+ it->second->m_aTypes.getLength() &&
+ abs( it->second->m_nLastTimestamp - time( NULL ) ) < 2
+ )
+ {
+ rTypes = it->second->m_aTypes;
+ return true;
+ }
+ }
+
+ bool bSuccess = false;
+ bool bHaveUTF16 = false;
+ Atom aUTF8Type = None;
+ bool bHaveCompound = false;
+ bool bHaveText = false;
+ Sequence< sal_Int8 > aAtoms;
+
+ if( selection == m_nXdndSelection )
+ {
+ // xdnd sends first three types with XdndEnter
+ // if more than three types are supported then the XDndTypeList
+ // property on the source window is used
+ if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ if( m_aDropEnterEvent.data.l[1] & 1 )
+ {
+ const unsigned int atomcount = 256;
+ // more than three types; look in property
+ osl::MutexGuard aGuard(m_aMutex);
+
+ Atom nType;
+ int nFormat;
+ unsigned long nItems, nBytes;
+ unsigned char* pBytes = NULL;
+
+ XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ m_nXdndTypeList, 0, atomcount, False,
+ XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "have %ld data types in XdndTypeList\n", nItems );
+#endif
+ if( nItems == atomcount && nBytes > 0 )
+ {
+ // wow ... more than 256 types !
+ aAtoms.realloc( sizeof( Atom )*atomcount+nBytes );
+ memcpy( aAtoms.getArray(), pBytes, sizeof( Atom )*atomcount );
+ XFree( pBytes );
+ pBytes = NULL;
+ XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ m_nXdndTypeList, atomcount, nBytes/sizeof(Atom),
+ False, XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ {
+ memcpy( aAtoms.getArray()+atomcount*sizeof(Atom), pBytes, nItems*sizeof(Atom) );
+ XFree( pBytes );
+ }
+ }
+ else
+ {
+ aAtoms.realloc( sizeof(Atom)*nItems );
+ memcpy( aAtoms.getArray(), pBytes, nItems*sizeof(Atom) );
+ XFree( pBytes );
+ }
+ }
+ else
+ {
+ // one to three types
+ int n = 0, i;
+ for( i = 0; i < 3; i++ )
+ if( m_aDropEnterEvent.data.l[2+i] )
+ n++;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "have %d data types in XdndEnter\n", n );
+#endif
+ aAtoms.realloc( sizeof(Atom)*n );
+ for( i = 0, n = 0; i < 3; i++ )
+ if( m_aDropEnterEvent.data.l[2+i] )
+ ((Atom*)aAtoms.getArray())[n++] = m_aDropEnterEvent.data.l[2+i];
+ }
+ }
+ }
+ // get data of type TARGETS
+ else if( ! getPasteData( selection, m_nTARGETSAtom, aAtoms ) )
+ aAtoms = Sequence< sal_Int8 >();
+
+ std::vector< Atom > aNativeTypes;
+ if( aAtoms.getLength() )
+ {
+ sal_Int32 nAtoms = aAtoms.getLength() / sizeof(Atom);
+ Atom* pAtoms = (Atom*)aAtoms.getArray();
+ rTypes.realloc( nAtoms );
+ aNativeTypes.resize( nAtoms );
+ DataFlavor* pFlavors = rTypes.getArray();
+ sal_Int32 nNativeTypesIndex = 0;
+ while( nAtoms-- )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ if( *pAtoms && *pAtoms < 0x01000000 )
+ fprintf( stderr, "native type: %s\n", OUStringToOString( getString( *pAtoms ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( *pAtoms == m_nCOMPOUNDAtom )
+ bHaveText = bHaveCompound = true;
+ else if( *pAtoms && *pAtoms < 0x01000000 )
+ {
+ int nFormat;
+ pFlavors->MimeType = convertTypeFromNative( *pAtoms, selection, nFormat );
+ pFlavors->DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+ sal_Int32 nIndex = 0;
+ if( pFlavors->MimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain", 10 ) )
+ {
+ OUString aToken(pFlavors->MimeType.getToken( 0, ';', nIndex ));
+ // omit text/plain;charset=unicode since it is not well defined
+ if( aToken.compareToAscii( "charset=unicode" ) == 0 )
+ {
+ pAtoms++;
+ continue;
+ }
+ bHaveText = true;
+ if( aToken.compareToAscii( "charset=utf-16" ) == 0 )
+ {
+ bHaveUTF16 = true;
+ pFlavors->DataType = getCppuType( (OUString*)0 );
+ }
+ else if( aToken.compareToAscii( "charset=utf-8" ) == 0 )
+ {
+ aUTF8Type = *pAtoms;
+ }
+ }
+ pFlavors++;
+ aNativeTypes[ nNativeTypesIndex ] = *pAtoms;
+ nNativeTypesIndex++;
+ }
+ pAtoms++;
+ }
+ if( (pFlavors - rTypes.getArray()) < rTypes.getLength() )
+ rTypes.realloc(pFlavors - rTypes.getArray());
+ bSuccess = rTypes.getLength() ? true : false;
+ if( bHaveText && ! bHaveUTF16 )
+ {
+ int i = 0;
+
+ int nNewFlavors = rTypes.getLength()+1;
+ Sequence< DataFlavor > aTemp( nNewFlavors );
+ for( i = 0; i < nNewFlavors-1; i++ )
+ aTemp.getArray()[i+1] = rTypes.getConstArray()[i];
+ aTemp.getArray()[0].MimeType = OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16"));
+ aTemp.getArray()[0].DataType = getCppuType( (OUString*)0 );
+ rTypes = aTemp;
+
+ std::vector< Atom > aNativeTemp( nNewFlavors );
+ for( i = 0; i < nNewFlavors-1; i++ )
+ aNativeTemp[ i + 1 ] = aNativeTypes[ i ];
+ aNativeTemp[0] = None;
+ aNativeTypes = aNativeTemp;
+ }
+ }
+
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it != m_aSelections.end() )
+ {
+ if( bSuccess )
+ {
+ it->second->m_aTypes = rTypes;
+ it->second->m_aNativeTypes = aNativeTypes;
+ it->second->m_nLastTimestamp = time( NULL );
+ it->second->m_bHaveUTF16 = bHaveUTF16;
+ it->second->m_aUTF8Type = aUTF8Type;
+ it->second->m_bHaveCompound = bHaveCompound;
+ }
+ else
+ {
+ it->second->m_aTypes = Sequence< DataFlavor >();
+ it->second->m_aNativeTypes = std::vector< Atom >();
+ it->second->m_nLastTimestamp = 0;
+ it->second->m_bHaveUTF16 = false;
+ it->second->m_aUTF8Type = None;
+ it->second->m_bHaveCompound = false;
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ {
+ fprintf( stderr, "SelectionManager::getPasteDataTypes( %s ) = %s\n", OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), bSuccess ? "true" : "false" );
+ for( int i = 0; i < rTypes.getLength(); i++ )
+ fprintf( stderr, "type: %s\n", OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ }
+#endif
+
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+PixmapHolder* SelectionManager::getPixmapHolder( Atom selection )
+{
+ boost::unordered_map< Atom, Selection* >::const_iterator it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return NULL;
+ if( ! it->second->m_pPixmap )
+ it->second->m_pPixmap = new PixmapHolder( m_pDisplay );
+ return it->second->m_pPixmap;
+}
+
+static sal_Size GetTrueFormatSize(int nFormat)
+{
+ // http://mail.gnome.org/archives/wm-spec-list/2003-March/msg00067.html
+ return nFormat == 32 ? sizeof(long) : nFormat/8;
+}
+
+bool SelectionManager::sendData( SelectionAdaptor* pAdaptor,
+ XLIB_Window requestor,
+ Atom target,
+ Atom property,
+ Atom selection )
+{
+ osl::ResettableMutexGuard aGuard( m_aMutex );
+
+ // handle targets related to image/bmp
+ if( target == XA_COLORMAP || target == XA_PIXMAP || target == XA_BITMAP || target == XA_VISUALID )
+ {
+ PixmapHolder* pPixmap = getPixmapHolder( selection );
+ if( ! pPixmap ) return false;
+ XID nValue = None;
+
+ // handle colormap request
+ if( target == XA_COLORMAP )
+ nValue = (XID)pPixmap->getColormap();
+ else if( target == XA_VISUALID )
+ nValue = (XID)pPixmap->getVisualID();
+ else if( target == XA_PIXMAP || target == XA_BITMAP )
+ {
+ nValue = (XID)pPixmap->getPixmap();
+ if( nValue == None )
+ {
+ // first conversion
+ Sequence< sal_Int8 > aData;
+ int nFormat;
+ aGuard.clear();
+ bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
+ aGuard.reset();
+ if( bConverted )
+ {
+ // get pixmap again since clearing the guard could have invalidated
+ // the pixmap in another thread
+ pPixmap = getPixmapHolder( selection );
+ // conversion succeeded, so aData contains image/bmp now
+ if( pPixmap->needsConversion( (const sal_uInt8*)aData.getConstArray() )
+ && m_xBitmapConverter.is() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "trying bitmap conversion\n" );
+#endif
+ css::uno::Reference<XBitmap> xBM( new BmpTransporter( aData ) );
+ Sequence<Any> aArgs(2), aOutArgs;
+ Sequence<sal_Int16> aOutIndex;
+ aArgs.getArray()[0] = makeAny( xBM );
+ aArgs.getArray()[1] = makeAny( (sal_uInt16)pPixmap->getDepth() );
+ aGuard.clear();
+ try
+ {
+ Any aResult =
+ m_xBitmapConverter->invoke( OUString(RTL_CONSTASCII_USTRINGPARAM("convert-bitmap-depth")),
+ aArgs, aOutIndex, aOutArgs );
+ if( aResult >>= xBM )
+ aData = xBM->getDIB();
+ }
+ catch(...)
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "exception in bitmap converter\n" );
+#endif
+ }
+ aGuard.reset();
+ }
+ // get pixmap again since clearing the guard could have invalidated
+ // the pixmap in another thread
+ pPixmap = getPixmapHolder( selection );
+ nValue = (XID)pPixmap->setBitmapData( (const sal_uInt8*)aData.getConstArray() );
+ }
+ if( nValue == None )
+ return false;
+ }
+ if( target == XA_BITMAP )
+ nValue = (XID)pPixmap->getBitmap();
+ }
+
+ XChangeProperty( m_pDisplay,
+ requestor,
+ property,
+ target,
+ 32,
+ PropModeReplace,
+ (const unsigned char*)&nValue,
+ 1);
+ return true;
+ }
+
+ /*
+ * special target TEXT allows us to transfer
+ * the data in an encoding of our choice
+ * COMPOUND_TEXT will work with most applications
+ */
+ if( target == m_nTEXTAtom )
+ target = m_nCOMPOUNDAtom;
+
+ Sequence< sal_Int8 > aData;
+ int nFormat;
+ aGuard.clear();
+ bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
+ aGuard.reset();
+ if( bConverted )
+ {
+ // conversion succeeded
+ if( aData.getLength() > m_nIncrementalThreshold )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "using INCR protocol\n" );
+ boost::unordered_map< XLIB_Window, boost::unordered_map< Atom, IncrementalTransfer > >::const_iterator win_it = m_aIncrementals.find( requestor );
+ if( win_it != m_aIncrementals.end() )
+ {
+ boost::unordered_map< Atom, IncrementalTransfer >::const_iterator inc_it = win_it->second.find( property );
+ if( inc_it != win_it->second.end() )
+ {
+ const IncrementalTransfer& rInc = inc_it->second;
+ fprintf( stderr, "premature end and new start for INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+ }
+ }
+#endif
+
+ // insert IncrementalTransfer
+ IncrementalTransfer& rInc = m_aIncrementals[ requestor ][ property ];
+ rInc.m_aData = aData;
+ rInc.m_nBufferPos = 0;
+ rInc.m_aRequestor = requestor;
+ rInc.m_aProperty = property;
+ rInc.m_aTarget = target;
+ rInc.m_nFormat = nFormat;
+ rInc.m_nTransferStartTime = time( NULL );
+
+ // use incr protocol, signal start to requestor
+ long nMinSize = m_nIncrementalThreshold;
+ XSelectInput( m_pDisplay, requestor, PropertyChangeMask );
+ XChangeProperty( m_pDisplay, requestor, property,
+ m_nINCRAtom, 32, PropModeReplace, (unsigned char*)&nMinSize, 1 );
+ XFlush( m_pDisplay );
+ }
+ else
+ {
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+ XChangeProperty( m_pDisplay,
+ requestor,
+ property,
+ target,
+ nFormat,
+ PropModeReplace,
+ (const unsigned char*)aData.getConstArray(),
+ aData.getLength()/nUnitSize );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "convertData failed for type: %s \n",
+ OUStringToOString( convertTypeFromNative( target, selection, nFormat ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ return bConverted;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSelectionRequest( XSelectionRequestEvent& rRequest )
+{
+ osl::ResettableMutexGuard aGuard( m_aMutex );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleSelectionRequest for selection %s and target %s\n",
+ OUStringToOString( getString( rRequest.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rRequest.target ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ XEvent aNotify;
+
+ aNotify.type = SelectionNotify;
+ aNotify.xselection.display = rRequest.display;
+ aNotify.xselection.send_event = True;
+ aNotify.xselection.requestor = rRequest.requestor;
+ aNotify.xselection.selection = rRequest.selection;
+ aNotify.xselection.time = rRequest.time;
+ aNotify.xselection.target = rRequest.target;
+ aNotify.xselection.property = None;
+
+ SelectionAdaptor* pAdaptor = getAdaptor( rRequest.selection );
+ // ensure that we still own that selection
+ if( pAdaptor &&
+ XGetSelectionOwner( m_pDisplay, rRequest.selection ) == m_aWindow )
+ {
+ css::uno::Reference< XTransferable > xTrans( pAdaptor->getTransferable() );
+ if( rRequest.target == m_nTARGETSAtom )
+ {
+ // someone requests our types
+ if( xTrans.is() )
+ {
+ aGuard.clear();
+ Sequence< DataFlavor > aFlavors = xTrans->getTransferDataFlavors();
+ aGuard.reset();
+
+ ::std::list< Atom > aConversions;
+ getNativeTypeList( aFlavors, aConversions, rRequest.selection );
+
+ int i, nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( nTypes * sizeof( Atom ) );
+ std::list< Atom >::const_iterator it;
+ for( i = 0, it = aConversions.begin(); i < nTypes; i++, ++it )
+ pTypes[i] = *it;
+ XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
+ XA_ATOM, 32, PropModeReplace, (const unsigned char*)pTypes, nTypes );
+ aNotify.xselection.property = rRequest.property;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending type list:\n" );
+ for( int k = 0; k < nTypes; k++ )
+ fprintf( stderr, " %s\n", pTypes[k] ? XGetAtomName( m_pDisplay, pTypes[k] ) : "<None>" );
+#endif
+ }
+ }
+ else if( rRequest.target == m_nTIMESTAMPAtom )
+ {
+ long nTimeStamp = (long)m_aSelections[rRequest.selection]->m_nOrigTimestamp;
+ XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
+ XA_INTEGER, 32, PropModeReplace, (const unsigned char*)&nTimeStamp, 1 );
+ aNotify.xselection.property = rRequest.property;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending timestamp: %d\n", (int)nTimeStamp );
+#endif
+ }
+ else
+ {
+ bool bEventSuccess = false;
+ if( rRequest.target == m_nMULTIPLEAtom )
+ {
+ // get all targets
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get number of atoms
+ XGetWindowProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ 0, 0,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( nFormat == 32 && nBytes/4 )
+ {
+ if( pData ) // ?? should not happen
+ {
+ XFree( pData );
+ pData = NULL;
+ }
+ XGetWindowProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ 0, nBytes/4,
+ False,
+ nType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( pData && nItems )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %ld atoms in MULTIPLE request\n", nItems );
+#endif
+ bEventSuccess = true;
+ bool bResetAtoms = false;
+ Atom* pAtoms = (Atom*)pData;
+ aGuard.clear();
+ for( unsigned int i = 0; i < nItems; i += 2 )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, " %s => %s: ",
+ OUStringToOString( getString( pAtoms[i] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( pAtoms[i+1] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ bool bSuccess = sendData( pAdaptor, rRequest.requestor, pAtoms[i], pAtoms[i+1], rRequest.selection );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s\n", bSuccess ? "succeeded" : "failed" );
+#endif
+ if( ! bSuccess )
+ {
+ pAtoms[i] = None;
+ bResetAtoms = true;
+ }
+ }
+ aGuard.reset();
+ if( bResetAtoms )
+ XChangeProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ pData,
+ nBytes/4 );
+ }
+ if( pData )
+ XFree( pData );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ fprintf( stderr, "could not get type list from \"%s\" of type \"%s\" on requestor 0x%lx, requestor has properties:",
+ OUStringToOString( getString( rRequest.property ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rRequest.requestor );
+ int nProps = 0;
+ Atom* pProps = XListProperties( m_pDisplay, rRequest.requestor, &nProps );
+ if( pProps )
+ {
+ for( int i = 0; i < nProps; i++ )
+ fprintf( stderr, " \"%s\"", OUStringToOString( getString( pProps[i]), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ XFree( pProps );
+ }
+ }
+#endif
+ }
+ else
+ {
+ aGuard.clear();
+ bEventSuccess = sendData( pAdaptor, rRequest.requestor, rRequest.target, rRequest.property, rRequest.selection );
+ aGuard.reset();
+ }
+ if( bEventSuccess )
+ {
+ aNotify.xselection.target = rRequest.target;
+ aNotify.xselection.property = rRequest.property;
+ }
+ }
+ aGuard.clear();
+ xTrans.clear();
+ aGuard.reset();
+ }
+ XSendEvent( m_pDisplay, rRequest.requestor, False, 0, &aNotify );
+
+ if( rRequest.selection == XA_PRIMARY &&
+ m_bWaitingForPrimaryConversion &&
+ m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, rRequest.time, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ if( aNotify.xselection.property != None )
+ {
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ dsde.DropSuccess = sal_True;
+ }
+ else
+ {
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ }
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ if( xListener.is() )
+ xListener->dragDropEnd( dsde );
+ }
+
+ // we handled the event in any case by answering
+ return true;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleReceivePropertyNotify( XPropertyEvent& rNotify )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ // data we requested arrived
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleReceivePropertyNotify for property %s\n",
+ OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ bool bHandled = false;
+
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( rNotify.atom );
+ if( it != m_aSelections.end() &&
+ rNotify.state == PropertyNewValue &&
+ ( it->second->m_eState == Selection::WaitingForResponse ||
+ it->second->m_eState == Selection::WaitingForData ||
+ it->second->m_eState == Selection::IncrementalTransfer
+ )
+ )
+ {
+ // MULTIPLE requests are only complete after selection notify
+ if( it->second->m_aRequestedType == m_nMULTIPLEAtom &&
+ ( it->second->m_eState == Selection::WaitingForResponse ||
+ it->second->m_eState == Selection::WaitingForData ) )
+ return false;
+
+ bHandled = true;
+
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get type and length
+ XGetWindowProperty( m_pDisplay,
+ rNotify.window,
+ rNotify.atom,
+ 0, 0,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %ld bytes data of type %s and format %d, items = %ld\n",
+ nBytes,
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ nFormat, nItems );
+#endif
+ if( pData )
+ {
+ XFree( pData );
+ pData = NULL;
+ }
+
+ if( nType == m_nINCRAtom )
+ {
+ // start data transfer
+ XDeleteProperty( m_pDisplay, rNotify.window, rNotify.atom );
+ it->second->m_eState = Selection::IncrementalTransfer;
+ }
+ else if( nType != None )
+ {
+ XGetWindowProperty( m_pDisplay,
+ rNotify.window,
+ rNotify.atom,
+ 0, nBytes/4 +1,
+ True,
+ nType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "read %ld items data of type %s and format %d, %ld bytes left in property\n",
+ nItems,
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ nFormat, nBytes );
+#endif
+
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+
+ if( it->second->m_eState == Selection::WaitingForData ||
+ it->second->m_eState == Selection::WaitingForResponse )
+ {
+ // copy data
+ it->second->m_aData = Sequence< sal_Int8 >( (sal_Int8*)pData, nItems*nUnitSize );
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ else if( it->second->m_eState == Selection::IncrementalTransfer )
+ {
+ if( nItems )
+ {
+ // append data
+ Sequence< sal_Int8 > aData( it->second->m_aData.getLength() + nItems*nUnitSize );
+ memcpy( aData.getArray(), it->second->m_aData.getArray(), it->second->m_aData.getLength() );
+ memcpy( aData.getArray() + it->second->m_aData.getLength(), pData, nItems*nUnitSize );
+ it->second->m_aData = aData;
+ }
+ else
+ {
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ }
+ if( pData )
+ XFree( pData );
+ }
+ else if( it->second->m_eState == Selection::IncrementalTransfer )
+ {
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSendPropertyNotify( XPropertyEvent& rNotify )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // ready for next part of a IncrementalTransfer
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleSendPropertyNotify for property %s (%s)\n",
+ OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rNotify.state == PropertyNewValue ? "new value" : ( rNotify.state == PropertyDelete ? "deleted" : "unknown")
+ );
+#endif
+
+ bool bHandled = false;
+ // feed incrementals
+ if( rNotify.state == PropertyDelete )
+ {
+ boost::unordered_map< XLIB_Window, boost::unordered_map< Atom, IncrementalTransfer > >::iterator it;
+ it = m_aIncrementals.find( rNotify.window );
+ if( it != m_aIncrementals.end() )
+ {
+ bHandled = true;
+ int nCurrentTime = time( NULL );
+ boost::unordered_map< Atom, IncrementalTransfer >::iterator inc_it;
+ // throw out aborted transfers
+ std::list< Atom > aTimeouts;
+ for( inc_it = it->second.begin(); inc_it != it->second.end(); ++inc_it )
+ {
+ if( (nCurrentTime - inc_it->second.m_nTransferStartTime) > (getSelectionTimeout()+2) )
+ {
+ aTimeouts.push_back( inc_it->first );
+#if OSL_DEBUG_LEVEL > 1
+ const IncrementalTransfer& rInc = inc_it->second;
+ fprintf( stderr, "timeout on INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ }
+ }
+
+ while( aTimeouts.begin() != aTimeouts.end() )
+ {
+ // transfer broken, might even be a new client with the
+ // same window id
+ it->second.erase( aTimeouts.front() );
+ aTimeouts.pop_front();
+ }
+
+ inc_it = it->second.find( rNotify.atom );
+ if( inc_it != it->second.end() )
+ {
+ IncrementalTransfer& rInc = inc_it->second;
+
+ int nBytes = rInc.m_aData.getLength() - rInc.m_nBufferPos;
+ nBytes = (nBytes > m_nIncrementalThreshold) ? m_nIncrementalThreshold : nBytes;
+ if( nBytes < 0 ) // sanity check
+ nBytes = 0;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "pushing %d bytes: \"%.*s\"...\n",
+ nBytes, nBytes > 32 ? 32 : nBytes,
+ (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos );
+#endif
+
+ sal_Size nUnitSize = GetTrueFormatSize(rInc.m_nFormat);
+
+ XChangeProperty( m_pDisplay,
+ rInc.m_aRequestor,
+ rInc.m_aProperty,
+ rInc.m_aTarget,
+ rInc.m_nFormat,
+ PropModeReplace,
+ (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos,
+ nBytes/nUnitSize );
+ rInc.m_nBufferPos += nBytes;
+ rInc.m_nTransferStartTime = nCurrentTime;
+
+ if( nBytes == 0 ) // transfer finished
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "finished INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ it->second.erase( inc_it );
+ }
+
+ }
+ // eventually clean up the hash map
+ if( it->second.begin() == it->second.end() )
+ m_aIncrementals.erase( it );
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSelectionNotify( XSelectionEvent& rNotify )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ bool bHandled = false;
+
+ // notification about success/failure of one of our conversion requests
+#if OSL_DEBUG_LEVEL > 1
+ OUString aSelection( getString( rNotify.selection ) );
+ OUString aProperty(RTL_CONSTASCII_USTRINGPARAM("None"));
+ if( rNotify.property )
+ aProperty = getString( rNotify.property );
+ fprintf( stderr, "handleSelectionNotify for selection %s and property %s (0x%lx)\n",
+ OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aProperty, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rNotify.property
+ );
+ if( rNotify.requestor != m_aWindow && rNotify.requestor != m_aCurrentDropWindow )
+ fprintf( stderr, "Warning: selection notify for unknown window 0x%lx\n", rNotify.requestor );
+#endif
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( rNotify.selection );
+ if (
+ (rNotify.requestor == m_aWindow || rNotify.requestor == m_aCurrentDropWindow) &&
+ it != m_aSelections.end() &&
+ (
+ (it->second->m_eState == Selection::WaitingForResponse) ||
+ (it->second->m_eState == Selection::WaitingForData)
+ )
+ )
+ {
+ bHandled = true;
+ if( it->second->m_aRequestedType == m_nMULTIPLEAtom )
+ {
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get type and length
+ XGetWindowProperty( m_pDisplay,
+ rNotify.requestor,
+ rNotify.property,
+ 0, 256,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( nBytes ) // HUGE request !!!
+ {
+ if( pData )
+ XFree( pData );
+ XGetWindowProperty( m_pDisplay,
+ rNotify.requestor,
+ rNotify.property,
+ 0, 256+(nBytes+3)/4,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ }
+ it->second->m_eState = Selection::Inactive;
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+ it->second->m_aData = Sequence< sal_Int8 >((sal_Int8*)pData, nItems * nUnitSize);
+ it->second->m_aDataArrived.set();
+ if( pData )
+ XFree( pData );
+ }
+ // WaitingForData can actually happen; some
+ // applications (e.g. cmdtool on Solaris) first send
+ // a success and then cancel it. Weird !
+ else if( rNotify.property == None )
+ {
+ // conversion failed, stop transfer
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aData = Sequence< sal_Int8 >();
+ it->second->m_aDataArrived.set();
+ }
+ // get the bytes, by INCR if necessary
+ else
+ it->second->m_eState = Selection::WaitingForData;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else if( it != m_aSelections.end() )
+ fprintf( stderr, "Warning: selection in state %d\n", it->second->m_eState );
+#endif
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleDropEvent( XClientMessageEvent& rMessage )
+{
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+
+ // handle drop related events
+ XLIB_Window aSource = rMessage.data.l[0];
+ XLIB_Window aTarget = rMessage.window;
+
+ bool bHandled = false;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::iterator it =
+ m_aDropTargets.find( aTarget );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( rMessage.message_type == m_nXdndEnter ||
+ rMessage.message_type == m_nXdndLeave ||
+ rMessage.message_type == m_nXdndDrop ||
+ rMessage.message_type == m_nXdndPosition )
+ {
+ fprintf( stderr, "got drop event %s, ", OUStringToOString( getString( rMessage.message_type ), RTL_TEXTENCODING_ASCII_US).getStr() );
+ if( it == m_aDropTargets.end() )
+ fprintf( stderr, "but no target found\n" );
+ else if( ! it->second.m_pTarget->m_bActive )
+ fprintf( stderr, "but target is inactive\n" );
+ else if( m_aDropEnterEvent.data.l[0] != None && (XLIB_Window)m_aDropEnterEvent.data.l[0] != aSource )
+ fprintf( stderr, "but source 0x%lx is unknown (expected 0x%lx or 0)\n", aSource, m_aDropEnterEvent.data.l[0] );
+ else
+ fprintf( stderr, "processing.\n" );
+ }
+#endif
+
+ if( it != m_aDropTargets.end() && it->second.m_pTarget->m_bActive &&
+ m_bDropWaitingForCompletion && m_aDropEnterEvent.data.l[0] )
+ {
+ bHandled = true;
+ OSL_FAIL( "someone forgot to call dropComplete ?" );
+ // some listener forgot to call dropComplete in the last operation
+ // let us end it now and accept the new enter event
+ aGuard.clear();
+ dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
+ aGuard.reset();
+ }
+
+ if( it != m_aDropTargets.end() &&
+ it->second.m_pTarget->m_bActive &&
+ ( m_aDropEnterEvent.data.l[0] == None || XLIB_Window(m_aDropEnterEvent.data.l[0]) == aSource )
+ )
+ {
+ if( rMessage.message_type == m_nXdndEnter )
+ {
+ bHandled = true;
+ m_aDropEnterEvent = rMessage;
+ m_bDropEnterSent = false;
+ m_aCurrentDropWindow = aTarget;
+ m_nCurrentProtocolVersion = m_aDropEnterEvent.data.l[1] >> 24;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndEnter on 0x%lx\n", aTarget );
+#endif
+ }
+ else if(
+ rMessage.message_type == m_nXdndPosition &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+ m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[3] : CurrentTime;
+ if( ! m_bDropEnterSent )
+ m_nDropTimestamp = m_nDropTime;
+
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay,
+ it->second.m_aRootWindow,
+ it->first,
+ rMessage.data.l[2] >> 16,
+ rMessage.data.l[2] & 0xffff,
+ &m_nLastX, &m_nLastY,
+ &aChild );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndPosition on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
+#endif
+ DropTargetDragEnterEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aEvent.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ aEvent.LocationX = m_nLastX;
+ aEvent.LocationY = m_nLastY;
+ aEvent.SourceActions = m_nSourceActions;
+ if( m_nCurrentProtocolVersion < 2 )
+ aEvent.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionCopy )
+ aEvent.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionMove )
+ aEvent.DropAction = DNDConstants::ACTION_MOVE;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionLink )
+ aEvent.DropAction = DNDConstants::ACTION_LINK;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionAsk )
+ // currently no interface to implement ask
+ aEvent.DropAction = ~0;
+ else
+ aEvent.DropAction = DNDConstants::ACTION_NONE;
+
+ m_nLastDropAction = aEvent.DropAction;
+ if( ! m_bDropEnterSent )
+ {
+ m_bDropEnterSent = true;
+ aEvent.SupportedDataFlavors = m_xDropTransferable->getTransferDataFlavors();
+ aGuard.clear();
+ it->second->dragEnter( aEvent );
+ }
+ else
+ {
+ aGuard.clear();
+ it->second->dragOver( aEvent );
+ }
+ }
+ else if(
+ rMessage.message_type == m_nXdndLeave &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndLeave on 0x%lx\n", aTarget );
+#endif
+ DropTargetEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ m_aDropEnterEvent.data.l[0] = None;
+ if( m_aCurrentDropWindow == aTarget )
+ m_aCurrentDropWindow = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ aGuard.clear();
+ it->second->dragExit( aEvent );
+ }
+ else if(
+ rMessage.message_type == m_nXdndDrop &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+ m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[2] : CurrentTime;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndDrop on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
+#endif
+ if( m_bLastDropAccepted )
+ {
+ DropTargetDropEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aEvent.Context = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ aEvent.LocationX = m_nLastX;
+ aEvent.LocationY = m_nLastY;
+ aEvent.DropAction = m_nLastDropAction;
+ // there is nothing corresponding to source supported actions
+ // every source can do link, copy and move
+ aEvent.SourceActions= m_nLastDropAction;
+ aEvent.Transferable = m_xDropTransferable;
+
+ m_bDropWaitingForCompletion = true;
+ aGuard.clear();
+ it->second->drop( aEvent );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "XdndDrop canceled due to m_bLastDropAccepted = fale\n" );
+#endif
+ DropTargetEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aGuard.clear();
+ it->second->dragExit( aEvent );
+ // reset the drop status, notify source
+ dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
+ }
+ }
+ }
+ return bHandled;
+}
+
+/*
+ * methods for XDropTargetDropContext
+ */
+
+void SelectionManager::dropComplete( sal_Bool bSuccess, XLIB_Window aDropWindow, XLIB_Time )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+ if( m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = getUserDragAction();
+ dsde.DropSuccess = bSuccess;
+ css::uno::Reference< XDragSourceListener > xListener = m_xDragSourceListener;
+ m_xDragSourceListener.clear();
+
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_aDropEnterEvent.data.l[0];
+ aEvent.xclient.message_type = m_nXdndFinished;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = m_aCurrentDropWindow;
+ aEvent.xclient.data.l[1] = bSuccess ? 1 : 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ if( bSuccess )
+ {
+ if( m_nLastDropAction & DNDConstants::ACTION_MOVE )
+ aEvent.xclient.data.l[2] = m_nXdndActionMove;
+ else if( m_nLastDropAction & DNDConstants::ACTION_COPY )
+ aEvent.xclient.data.l[2] = m_nXdndActionCopy;
+ else if( m_nLastDropAction & DNDConstants::ACTION_LINK )
+ aEvent.xclient.data.l[2] = m_nXdndActionLink;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Sending XdndFinished to 0x%lx\n",
+ m_aDropEnterEvent.data.l[0]
+ );
+#endif
+
+ XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ False, NoEventMask, & aEvent );
+
+ m_aDropEnterEvent.data.l[0] = None;
+ m_aCurrentDropWindow = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ }
+ m_bDropWaitingForCompletion = false;
+ }
+ else
+ OSL_FAIL( "dropComplete from invalid DropTargetDropContext" );
+}
+
+/*
+ * methods for XDropTargetDragContext
+ */
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::sendDragStatus( Atom nDropAction )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ if( m_xDragSourceListener.is() )
+ {
+ sal_Int8 nNewDragAction;
+ if( nDropAction == m_nXdndActionMove )
+ nNewDragAction = DNDConstants::ACTION_MOVE;
+ else if( nDropAction == m_nXdndActionCopy )
+ nNewDragAction = DNDConstants::ACTION_COPY;
+ else if( nDropAction == m_nXdndActionLink )
+ nNewDragAction = DNDConstants::ACTION_LINK;
+ else
+ nNewDragAction = DNDConstants::ACTION_NONE;
+ nNewDragAction &= m_nSourceActions;
+
+ if( nNewDragAction != m_nTargetAcceptAction )
+ {
+ setCursor( getDefaultCursor( nNewDragAction ), m_aDropWindow, m_nDragTimestamp );
+ m_nTargetAcceptAction = nNewDragAction;
+ }
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nSourceActions;
+ dsde.UserAction = getUserDragAction();
+
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ // caution: do not change anything after this
+ aGuard.clear();
+ if( xListener.is() )
+ xListener->dragOver( dsde );
+ }
+ else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_aDropEnterEvent.data.l[0];
+ aEvent.xclient.message_type = m_nXdndStatus;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = m_aCurrentDropWindow;
+ aEvent.xclient.data.l[1] = 2;
+ if( nDropAction == m_nXdndActionMove ||
+ nDropAction == m_nXdndActionLink ||
+ nDropAction == m_nXdndActionCopy )
+ aEvent.xclient.data.l[1] |= 1;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = m_nCurrentProtocolVersion > 1 ? nDropAction : 0;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Sending XdndStatus to 0x%lx with action %s\n",
+ m_aDropEnterEvent.data.l[0],
+ OUStringToOString( getString( nDropAction ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ False, NoEventMask, & aEvent );
+ XFlush( m_pDisplay );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int8 SelectionManager::getUserDragAction() const
+{
+ return (m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT) ? m_nTargetAcceptAction : m_nUserDragAction;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::updateDragAction( int modifierState )
+{
+ bool bRet = false;
+
+ sal_Int8 nNewDropAction = DNDConstants::ACTION_MOVE;
+ if( ( modifierState & ShiftMask ) && ! ( modifierState & ControlMask ) )
+ nNewDropAction = DNDConstants::ACTION_MOVE;
+ else if( ( modifierState & ControlMask ) && ! ( modifierState & ShiftMask ) )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ else if( ( modifierState & ShiftMask ) && ( modifierState & ControlMask ) )
+ nNewDropAction = DNDConstants::ACTION_LINK;
+ if( m_nCurrentProtocolVersion < 0 && m_aDropWindow != None )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ nNewDropAction &= m_nSourceActions;
+
+ if( ! ( modifierState & ( ControlMask | ShiftMask ) ) )
+ {
+ if( ! nNewDropAction )
+ {
+ // default to an action so the user does not have to press
+ // keys explicitly
+ if( m_nSourceActions & DNDConstants::ACTION_MOVE )
+ nNewDropAction = DNDConstants::ACTION_MOVE;
+ else if( m_nSourceActions & DNDConstants::ACTION_COPY )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ else if( m_nSourceActions & DNDConstants::ACTION_LINK )
+ nNewDropAction = DNDConstants::ACTION_LINK;
+ }
+ nNewDropAction |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ if( nNewDropAction != m_nUserDragAction || m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "updateDragAction: %x -> %x\n", (int)m_nUserDragAction, (int)nNewDropAction );
+#endif
+ bRet = true;
+ m_nUserDragAction = nNewDropAction;
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nUserDragAction;
+ dsde.UserAction = m_nUserDragAction;
+ m_nTargetAcceptAction = DNDConstants::ACTION_DEFAULT; // invalidate last accept
+ m_xDragSourceListener->dropActionChanged( dsde );
+ }
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::sendDropPosition( bool bForce, XLIB_Time eventTime )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ if( m_bDropSent )
+ return;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ if( it->second.m_pTarget->m_bActive )
+ {
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay, it->second.m_aRootWindow, m_aDropWindow, m_nLastDragX, m_nLastDragY, &x, &y, &aChild );
+ DropTargetDragEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >(it->second.m_pTarget );
+ dtde.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = x;
+ dtde.LocationY = y;
+ dtde.DropAction = getUserDragAction();
+ dtde.SourceActions = m_nSourceActions;
+ aGuard.clear();
+ it->second->dragOver( dtde );
+ }
+ }
+ else if( bForce ||
+
+ m_nLastDragX < m_nNoPosX || m_nLastDragX >= m_nNoPosX+m_nNoPosWidth ||
+ m_nLastDragY < m_nNoPosY || m_nLastDragY >= m_nNoPosY+m_nNoPosHeight
+ )
+ {
+ // send XdndPosition
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndPosition;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = m_nLastDragX << 16 | (m_nLastDragY&0xffff);
+ aEvent.xclient.data.l[3] = eventTime;
+
+ if( m_nUserDragAction & DNDConstants::ACTION_COPY )
+ aEvent.xclient.data.l[4]=m_nXdndActionCopy;
+ else if( m_nUserDragAction & DNDConstants::ACTION_MOVE )
+ aEvent.xclient.data.l[4]=m_nXdndActionMove;
+ else if( m_nUserDragAction & DNDConstants::ACTION_LINK )
+ aEvent.xclient.data.l[4]=m_nXdndActionLink;
+ else
+ aEvent.xclient.data.l[4]=m_nXdndActionCopy;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleDragEvent( XEvent& rMessage )
+{
+ if( ! m_xDragSourceListener.is() )
+ return false;
+
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+
+ bool bHandled = false;
+
+ // for shortcut
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+#if OSL_DEBUG_LEVEL > 1
+ switch( rMessage.type )
+ {
+ case ClientMessage:
+ fprintf( stderr, "handleDragEvent: %s\n", OUStringToOString( getString( rMessage.xclient.message_type ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ break;
+ case MotionNotify:
+ break;
+ case EnterNotify:
+ fprintf( stderr, "handleDragEvent: EnterNotify\n" );
+ break;
+ case LeaveNotify:
+ fprintf( stderr, "handleDragEvent: LeaveNotify\n" );
+ break;
+ case ButtonPress:
+ fprintf( stderr, "handleDragEvent: ButtonPress %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
+ break;
+ case ButtonRelease:
+ fprintf( stderr, "handleDragEvent: ButtonRelease %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
+ break;
+ case XLIB_KeyPress:
+ fprintf( stderr, "handleDragEvent: KeyPress\n" );
+ break;
+ case KeyRelease:
+ fprintf( stderr, "handleDragEvent: KeyRelease\n" );
+ break;
+ default:
+ fprintf( stderr, "handleDragEvent: <unknown type %d>\n", rMessage.type );
+ break;
+ }
+#endif
+
+ // handle drag related events
+ if( rMessage.type == ClientMessage )
+ {
+ if( Atom(rMessage.xclient.message_type) == m_nXdndStatus && Atom(rMessage.xclient.data.l[0]) == m_aDropWindow )
+ {
+ bHandled = true;
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >( this );
+ dsde.UserAction = getUserDragAction();
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ m_bDropSuccess = rMessage.xclient.data.l[1] & 1 ? true : false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "status drop action: accept = %s, %s\n",
+ m_bDropSuccess ? "true" : "false",
+ OUStringToOString( getString( rMessage.xclient.data.l[4] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( rMessage.xclient.data.l[1] & 1 )
+ {
+ if( m_nCurrentProtocolVersion > 1 )
+ {
+ if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionCopy )
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionMove )
+ dsde.DropAction = DNDConstants::ACTION_MOVE;
+ else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionLink )
+ dsde.DropAction = DNDConstants::ACTION_LINK;
+ }
+ else
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ }
+ m_nTargetAcceptAction = dsde.DropAction;
+
+ if( ! ( rMessage.xclient.data.l[1] & 2 ) )
+ {
+ m_nNoPosX = rMessage.xclient.data.l[2] >> 16;
+ m_nNoPosY = rMessage.xclient.data.l[2] & 0xffff;
+ m_nNoPosWidth = rMessage.xclient.data.l[3] >> 16;
+ m_nNoPosHeight = rMessage.xclient.data.l[3] & 0xffff;
+ }
+ else
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+
+ setCursor( getDefaultCursor( dsde.DropAction ), m_aDropWindow, m_nDragTimestamp );
+ aGuard.clear();
+ m_xDragSourceListener->dragOver( dsde );
+ }
+ else if( Atom(rMessage.xclient.message_type) == m_nXdndFinished && m_aDropWindow == Atom(rMessage.xclient.data.l[0]) )
+ {
+ bHandled = true;
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nTargetAcceptAction;
+ dsde.DropSuccess = m_bDropSuccess;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ }
+ else if( rMessage.type == MotionNotify ||
+ rMessage.type == EnterNotify || rMessage.type == LeaveNotify
+ )
+ {
+ bHandled = true;
+ bool bForce = false;
+ int root_x = rMessage.type == MotionNotify ? rMessage.xmotion.x_root : rMessage.xcrossing.x_root;
+ int root_y = rMessage.type == MotionNotify ? rMessage.xmotion.y_root : rMessage.xcrossing.y_root;
+ XLIB_Window root = rMessage.type == MotionNotify ? rMessage.xmotion.root : rMessage.xcrossing.root;
+ m_nDragTimestamp = rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time;
+
+ aGuard.clear();
+ if( rMessage.type == MotionNotify )
+ {
+ bForce = updateDragAction( rMessage.xmotion.state );
+ }
+ updateDragWindow( root_x, root_y, root );
+ aGuard.reset();
+
+ if( m_nCurrentProtocolVersion >= 0 && m_aDropProxy != None )
+ {
+ aGuard.clear();
+ sendDropPosition( bForce, rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time );
+ }
+ }
+ else if( rMessage.type == XLIB_KeyPress || rMessage.type == KeyRelease )
+ {
+ bHandled = true;
+ KeySym aKey = XKeycodeToKeysym( m_pDisplay, rMessage.xkey.keycode, 0 );
+ if( aKey == XK_Escape )
+ {
+ // abort drag
+ if( it != m_aDropTargets.end() )
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ }
+ else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
+ m_aDropWindow = m_aDropProxy = None;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ else
+ {
+ /*
+ * man page says: state is state immediate PRIOR to the
+ * event. It would seem that this is a somewhat arguable
+ * design decision.
+ */
+ int nState = rMessage.xkey.state;
+ int nNewState = 0;
+ switch( aKey )
+ {
+ case XK_Shift_R:
+ case XK_Shift_L: nNewState = ShiftMask;break;
+ case XK_Control_R:
+ case XK_Control_L: nNewState = ControlMask;break;
+ // just interested in shift and ctrl for dnd
+ }
+ if( rMessage.type == XLIB_KeyPress )
+ nState |= nNewState;
+ else
+ nState &= ~nNewState;
+ aGuard.clear();
+ if( updateDragAction( nState ) )
+ sendDropPosition( true, rMessage.xkey.time );
+ }
+ }
+ else if(
+ ( rMessage.type == ButtonPress || rMessage.type == ButtonRelease ) &&
+ rMessage.xbutton.button == m_nDragButton )
+ {
+ bool bCancel = true;
+ if( m_aDropWindow != None )
+ {
+ if( it != m_aDropTargets.end() )
+ {
+ if( it->second.m_pTarget->m_bActive && m_nUserDragAction != DNDConstants::ACTION_NONE && m_bLastDropAccepted )
+ {
+ bHandled = true;
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay, rMessage.xbutton.root, m_aDropWindow, rMessage.xbutton.x_root, rMessage.xbutton.y_root, &x, &y, &aChild );
+ DropTargetDropEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >(it->second.m_pTarget );
+ dtde.Context = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = x;
+ dtde.LocationY = y;
+ dtde.DropAction = m_nUserDragAction;
+ dtde.SourceActions = m_nSourceActions;
+ dtde.Transferable = m_xDragSourceTransferable;
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ m_bDropWaitingForCompletion = true;
+ aGuard.clear();
+ it->second->drop( dtde );
+ bCancel = false;
+ }
+ else bCancel = true;
+ }
+ else if( m_nCurrentProtocolVersion >= 0 )
+ {
+ bHandled = true;
+
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndDrop;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = rMessage.xbutton.time;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ bCancel = false;
+ }
+ else
+ {
+ // dropping on non XdndWindows: acquire ownership of
+ // PRIMARY and send a middle mouse button click down/up to
+ // target window
+ SelectionAdaptor* pAdaptor = getAdaptor( XA_PRIMARY );
+ if( pAdaptor )
+ {
+ bHandled = true;
+
+ XLIB_Window aDummy;
+ XEvent aEvent;
+ aEvent.type = ButtonPress;
+ aEvent.xbutton.display = m_pDisplay;
+ aEvent.xbutton.window = m_aDropWindow;
+ aEvent.xbutton.root = rMessage.xbutton.root;
+ aEvent.xbutton.subwindow = m_aDropWindow;
+ aEvent.xbutton.time = rMessage.xbutton.time+1;
+ aEvent.xbutton.x_root = rMessage.xbutton.x_root;
+ aEvent.xbutton.y_root = rMessage.xbutton.y_root;
+ aEvent.xbutton.state = rMessage.xbutton.state;
+ aEvent.xbutton.button = Button2;
+ aEvent.xbutton.same_screen = True;
+ XTranslateCoordinates( m_pDisplay,
+ rMessage.xbutton.root, m_aDropWindow,
+ rMessage.xbutton.x_root, rMessage.xbutton.y_root,
+ &aEvent.xbutton.x, &aEvent.xbutton.y,
+ &aDummy );
+ XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonPressMask, &aEvent );
+ aEvent.xbutton.type = ButtonRelease;
+ aEvent.xbutton.time++;
+ aEvent.xbutton.state |= Button2Mask;
+ XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonReleaseMask, &aEvent );
+
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ m_bWaitingForPrimaryConversion = true;
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ // HACK :-)
+ aGuard.clear();
+ static_cast< X11Clipboard* >( pAdaptor )->setContents( m_xDragSourceTransferable, css::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >() );
+ aGuard.reset();
+ bCancel = false;
+ }
+ }
+ }
+ if( bCancel )
+ {
+ // cancel drag
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ bHandled = true;
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::accept( sal_Int8 dragOperation, XLIB_Window aDropWindow, XLIB_Time )
+{
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "accept: %x\n", dragOperation );
+#endif
+ Atom nAction = None;
+ dragOperation &= (DNDConstants::ACTION_MOVE | DNDConstants::ACTION_COPY | DNDConstants::ACTION_LINK);
+ if( dragOperation & DNDConstants::ACTION_MOVE )
+ nAction = m_nXdndActionMove;
+ else if( dragOperation & DNDConstants::ACTION_COPY )
+ nAction = m_nXdndActionCopy;
+ else if( dragOperation & DNDConstants::ACTION_LINK )
+ nAction = m_nXdndActionLink;
+ m_bLastDropAccepted = true;
+ sendDragStatus( nAction );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::reject( XLIB_Window aDropWindow, XLIB_Time )
+{
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "reject\n" );
+#endif
+ m_bLastDropAccepted = false;
+ sendDragStatus( None );
+ if( m_bDropSent && m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ m_xDragSourceListener->dragDropEnd( dsde );
+ m_xDragSourceListener.clear();
+ }
+ }
+}
+
+/*
+ * XDragSource
+ */
+
+sal_Bool SelectionManager::isDragImageSupported() throw()
+{
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int32 SelectionManager::getDefaultCursor( sal_Int8 dragAction ) throw()
+{
+ XLIB_Cursor aCursor = m_aNoneCursor;
+ if( dragAction & DNDConstants::ACTION_MOVE )
+ aCursor = m_aMoveCursor;
+ else if( dragAction & DNDConstants::ACTION_COPY )
+ aCursor = m_aCopyCursor;
+ else if( dragAction & DNDConstants::ACTION_LINK )
+ aCursor = m_aLinkCursor;
+ return aCursor;
+}
+
+// ------------------------------------------------------------------------
+
+int SelectionManager::getXdndVersion( XLIB_Window aWindow, XLIB_Window& rProxy )
+{
+ Atom* pProperties = NULL;
+ int nProperties = 0;
+ Atom nType;
+ int nFormat;
+ unsigned long nItems, nBytes;
+ unsigned char* pBytes = NULL;
+
+ int nVersion = -1;
+ rProxy = None;
+
+ /*
+ * XListProperties is used here to avoid unnecessary XGetWindowProperty calls
+ * and therefore reducing latency penalty
+ */
+ pProperties = XListProperties( m_pDisplay, aWindow, &nProperties );
+ // first look for proxy
+ int i;
+ for( i = 0; i < nProperties; i++ )
+ {
+ if( pProperties[i] == m_nXdndProxy )
+ {
+ XGetWindowProperty( m_pDisplay, aWindow, m_nXdndProxy, 0, 1, False, XA_WINDOW,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_WINDOW )
+ rProxy = *(XLIB_Window*)pBytes;
+ XFree( pBytes );
+ pBytes = NULL;
+ if( rProxy != None )
+ {
+ // now check proxy wether it points to itself
+ XGetWindowProperty( m_pDisplay, rProxy, m_nXdndProxy, 0, 1, False, XA_WINDOW,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_WINDOW && *(XLIB_Window*)pBytes != rProxy )
+ rProxy = None;
+ XFree( pBytes );
+ pBytes = NULL;
+ }
+ else
+ rProxy = None;
+ }
+ }
+ break;
+ }
+ }
+ XLIB_Window aAwareWindow = rProxy != None ? rProxy : aWindow;
+
+ XGetWindowProperty( m_pDisplay, aAwareWindow, m_nXdndAware, 0, 1, False, XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_ATOM )
+ nVersion = *(Atom*)pBytes;
+ XFree( pBytes );
+ }
+
+ nVersion = nVersion > nXdndProtocolRevision ? nXdndProtocolRevision : nVersion;
+
+ return nVersion;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::updateDragWindow( int nX, int nY, XLIB_Window aRoot )
+{
+ osl::ResettableMutexGuard aGuard( m_aMutex );
+
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+
+ m_nLastDragX = nX;
+ m_nLastDragY = nY;
+
+ XLIB_Window aParent = aRoot;
+ XLIB_Window aChild;
+ XLIB_Window aNewProxy = None, aNewCurrentWindow = None;
+ int nNewProtocolVersion = -1;
+ int nWinX, nWinY;
+
+ // find the first XdndAware window or check if root window is
+ // XdndAware or has XdndProxy
+ do
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, aParent, nX, nY, &nWinX, &nWinY, &aChild );
+ if( aChild != None )
+ {
+ if( aChild == m_aCurrentDropWindow && aChild != aRoot && m_nCurrentProtocolVersion >= 0 )
+ {
+ aParent = aChild;
+ break;
+ }
+ nNewProtocolVersion = getXdndVersion( aChild, aNewProxy );
+ aParent = aChild;
+ }
+ } while( aChild != None && nNewProtocolVersion < 0 );
+
+ aNewCurrentWindow = aParent;
+ if( aNewCurrentWindow == aRoot )
+ {
+ // no children, try root drop
+ nNewProtocolVersion = getXdndVersion( aNewCurrentWindow, aNewProxy );
+ if( nNewProtocolVersion < 3 )
+ {
+ aNewCurrentWindow = aNewProxy = None;
+ nNewProtocolVersion = nXdndProtocolRevision;
+ }
+ }
+
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
+ dsde.UserAction = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it;
+ if( aNewCurrentWindow != m_aDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "drag left window 0x%lx (rev. %d), entered window 0x%lx (rev %d)\n", m_aDropWindow, m_nCurrentProtocolVersion, aNewCurrentWindow, nNewProtocolVersion );
+#endif
+
+ if( m_aDropWindow != None )
+ {
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ // shortcut for own drop targets
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ aGuard.reset();
+ }
+ else
+ {
+ // send old drop target a XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ if( xListener.is() )
+ {
+ aGuard.clear();
+ xListener->dragExit( dsde );
+ aGuard.reset();
+ }
+ }
+
+ m_nCurrentProtocolVersion = nNewProtocolVersion;
+ m_aDropWindow = aNewCurrentWindow;
+ m_aDropProxy = aNewProxy != None ? aNewProxy : m_aDropWindow;
+
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() && ! it->second.m_pTarget->m_bActive )
+ m_aDropProxy = None;
+
+ if( m_aDropProxy != None && xListener.is() )
+ {
+ aGuard.clear();
+ xListener->dragEnter( dsde );
+ aGuard.reset();
+ }
+ // send XdndEnter
+ if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, m_aDropWindow, nX, nY, &nWinX, &nWinY, &aChild );
+ DropTargetDragEnterEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ dtde.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = nWinX;
+ dtde.LocationY = nWinY;
+ dtde.DropAction = m_nUserDragAction;
+ dtde.SourceActions = m_nSourceActions;
+ dtde.SupportedDataFlavors = m_xDragSourceTransferable->getTransferDataFlavors();
+ aGuard.clear();
+ it->second.m_pTarget->dragEnter( dtde );
+ aGuard.reset();
+ }
+ else
+ {
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndEnter;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = m_nCurrentProtocolVersion << 24;
+ memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
+ // fill in data types
+ ::std::list< Atom > aConversions;
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+ if( aConversions.size() > 3 )
+ aEvent.xclient.data.l[1] |= 1;
+ ::std::list< Atom >::const_iterator type_it = aConversions.begin();
+ for( int i = 0; type_it != aConversions.end() && i < 3; i++, ++type_it )
+ aEvent.xclient.data.l[i+2] = *type_it;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ }
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+ }
+ else if( m_aDropProxy != None && xListener.is() )
+ {
+ aGuard.clear();
+ // drag over for XdndAware windows comes when receiving XdndStatus
+ xListener->dragOver( dsde );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::startDrag(
+ const DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32,
+ sal_Int32,
+ const css::uno::Reference< XTransferable >& transferable,
+ const css::uno::Reference< XDragSourceListener >& listener
+ ) throw()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "startDrag( sourceActions = %x )\n", (int)sourceActions );
+#endif
+
+ DragSourceDropEvent aDragFailedEvent;
+ aDragFailedEvent.Source = static_cast< OWeakObject* >(this);
+ aDragFailedEvent.DragSource = static_cast< XDragSource* >(this);
+ aDragFailedEvent.DragSourceContext = new DragSourceContext( None, CurrentTime, *this );
+ aDragFailedEvent.DropAction = DNDConstants::ACTION_NONE;
+ aDragFailedEvent.DropSuccess = sal_False;
+
+ if( m_aDragRunning.check() )
+ {
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "*** ERROR *** second drag and drop started.\n" );
+ if( m_xDragSourceListener.is() )
+ fprintf( stderr, "*** ERROR *** drag source listener already set.\n" );
+ else
+ fprintf( stderr, "*** ERROR *** drag thread already running.\n" );
+#endif
+ return;
+ }
+
+ SalFrame* pCaptureFrame = NULL;
+
+ {
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ // first get the current pointer position and the window that
+ // the pointer is located in. since said window should be one
+ // of our DropTargets at the time of executeDrag we can use
+ // them for a start
+ XLIB_Window aRoot, aParent, aChild;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it;
+ it = m_aDropTargets.begin();
+ while( it != m_aDropTargets.end() )
+ {
+ if( XQueryPointer( m_pDisplay, it->second.m_aRootWindow,
+ &aRoot, &aParent,
+ &root_x, &root_y,
+ &win_x, &win_y,
+ &mask ) )
+ {
+ aParent = it->second.m_aRootWindow;
+ break;
+ }
+ ++it;
+ }
+
+ // don't start DnD if there is none of our windows on the same screen as
+ // the pointer or if no mouse button is pressed
+ if( it == m_aDropTargets.end() || (mask & (Button1Mask|Button2Mask|Button3Mask)) == 0 )
+ {
+ aGuard.clear();
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ return;
+ }
+
+ // try to find which of our drop targets is the drag source
+ // if that drop target is deregistered we should stop executing
+ // the drag (actually this is a poor substitute for an "endDrag"
+ // method ).
+ m_aDragSourceWindow = None;
+ aParent = aRoot = it->second.m_aRootWindow;
+ do
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, aParent, root_x, root_y, &win_x, &win_y, &aChild );
+ if( aChild != None && m_aDropTargets.find( aChild ) != m_aDropTargets.end() )
+ {
+ m_aDragSourceWindow = aChild;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found drag source window 0x%lx\n", m_aDragSourceWindow );
+#endif
+ break;
+ }
+ aParent = aChild;
+ } while( aChild != None );
+
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to grab pointer ... " );
+#endif
+ int nPointerGrabSuccess =
+ XGrabPointer( m_pDisplay, it->second.m_aRootWindow, True,
+ DRAG_EVENT_MASK,
+ GrabModeAsync, GrabModeAsync,
+ None,
+ None,
+ CurrentTime );
+ /* if we could not grab the pointer here, there is a chance
+ that the pointer is grabbed by the other vcl display (the main loop)
+ so let's break that grab an reset it later
+
+ remark: this whole code should really be molten into normal vcl so only
+ one display is used ....
+ */
+ if( nPointerGrabSuccess != GrabSuccess )
+ {
+ osl::SolarMutex& rSolarMutex( Application::GetSolarMutex() );
+ if( rSolarMutex.tryToAcquire() )
+ {
+ pCaptureFrame = GetX11SalData()->GetDisplay()->GetCaptureFrame();
+ if( pCaptureFrame )
+ {
+ GetX11SalData()->GetDisplay()->CaptureMouse( NULL );
+ nPointerGrabSuccess =
+ XGrabPointer( m_pDisplay, it->second.m_aRootWindow, True,
+ DRAG_EVENT_MASK,
+ GrabModeAsync, GrabModeAsync,
+ None,
+ None,
+ CurrentTime );
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%d\n", nPointerGrabSuccess );
+#endif
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to grab keyboard ... " );
+#endif
+ int nKeyboardGrabSuccess =
+ XGrabKeyboard( m_pDisplay, it->second.m_aRootWindow, True,
+ GrabModeAsync, GrabModeAsync, CurrentTime );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%d\n", nKeyboardGrabSuccess );
+#endif
+ if( nPointerGrabSuccess != GrabSuccess || nKeyboardGrabSuccess != GrabSuccess )
+ {
+ if( nPointerGrabSuccess == GrabSuccess )
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ if( nKeyboardGrabSuccess == GrabSuccess )
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+ aGuard.clear();
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ if( pCaptureFrame )
+ {
+ osl::SolarMutex& rSolarMutex( Application::GetSolarMutex() );
+ if( rSolarMutex.tryToAcquire() )
+ GetX11SalData()->GetDisplay()->CaptureMouse( pCaptureFrame );
+#if OSL_DEBUG_LEVEL > 0
+ else
+ OSL_FAIL( "failed to acquire SolarMutex to reset capture frame" );
+#endif
+ }
+ return;
+ }
+
+ m_xDragSourceTransferable = transferable;
+ m_xDragSourceListener = listener;
+ m_aDragFlavors = transferable->getTransferDataFlavors();
+ m_aCurrentCursor = None;
+
+ requestOwnership( m_nXdndSelection );
+
+ ::std::list< Atom > aConversions;
+ ::std::list< Atom >::const_iterator type_it;
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+
+ int nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( sizeof(Atom)*nTypes );
+ type_it = aConversions.begin();
+ for( int n = 0; n < nTypes; n++, ++type_it )
+ pTypes[n] = *type_it;
+
+ XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
+
+ m_nSourceActions = sourceActions | DNDConstants::ACTION_DEFAULT;
+ m_nUserDragAction = DNDConstants::ACTION_MOVE & m_nSourceActions;
+ if( ! m_nUserDragAction )
+ m_nUserDragAction = DNDConstants::ACTION_COPY & m_nSourceActions;
+ if( ! m_nUserDragAction )
+ m_nUserDragAction = DNDConstants::ACTION_LINK & m_nSourceActions;
+ m_nTargetAcceptAction = DNDConstants::ACTION_DEFAULT;
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_nDragButton = Button1; // default to left button
+ com::sun::star::awt::MouseEvent aEvent;
+ if( trigger.Event >>= aEvent )
+ {
+ if( aEvent.Buttons & MouseButton::LEFT )
+ m_nDragButton = Button1;
+ else if( aEvent.Buttons & MouseButton::RIGHT )
+ m_nDragButton = Button3;
+ else if( aEvent.Buttons & MouseButton::MIDDLE )
+ m_nDragButton = Button2;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "m_nUserDragAction = %x\n", (int)m_nUserDragAction );
+#endif
+ updateDragWindow( root_x, root_y, aRoot );
+ m_nUserDragAction = ~0;
+ updateDragAction( mask );
+ }
+
+ m_aDragRunning.set();
+ m_aDragExecuteThread = osl_createSuspendedThread( call_SelectionManager_runDragExecute, this );
+ if( m_aDragExecuteThread )
+ osl_resumeThread( m_aDragExecuteThread );
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "osl_createSuspendedThread failed for drag execute\n" );
+#endif
+ m_xDragSourceListener.clear();
+ m_xDragSourceTransferable.clear();
+
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_aDropWindow = None;
+ m_aDropProxy = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ m_nNoPosX = 0;
+ m_nNoPosY = 0;
+ m_nNoPosWidth = 0;
+ m_nNoPosHeight = 0;
+ m_aCurrentCursor = None;
+
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+
+ if( pCaptureFrame )
+ {
+ osl::SolarMutex& rSolarMutex( Application::GetSolarMutex() );
+ if( rSolarMutex.tryToAcquire() )
+ GetX11SalData()->GetDisplay()->CaptureMouse( pCaptureFrame );
+#if OSL_DEBUG_LEVEL > 0
+ else
+ OSL_FAIL( "failed to acquire SolarMutex to reset capture frame" );
+#endif
+ }
+
+ m_aDragRunning.reset();
+
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ }
+}
+
+void SelectionManager::runDragExecute( void* pThis )
+{
+ SelectionManager* This = (SelectionManager*)pThis;
+ This->dragDoDispatch();
+}
+
+void SelectionManager::dragDoDispatch()
+{
+
+ // do drag
+ // m_xDragSourceListener will be cleared on finished drop
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "begin executeDrag dispatching\n" );
+#endif
+ TimeValue aTVal;
+ aTVal.Seconds = 0;
+ aTVal.Nanosec = 200000000;
+ oslThread aThread = m_aDragExecuteThread;
+ while( m_xDragSourceListener.is() && ( ! m_bDropSent || time(NULL)-m_nDropTimeout < 5 ) && osl_scheduleThread( aThread ) )
+ {
+ // let the thread in the run method do the dispatching
+ // just look occasionally here whether drop timed out or is completed
+ osl_waitThread( &aTVal );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "end executeDrag dispatching\n" );
+#endif
+ {
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ css::uno::Reference< XTransferable > xTransferable( m_xDragSourceTransferable );
+ m_xDragSourceListener.clear();
+ m_xDragSourceTransferable.clear();
+
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+
+ // cleanup after drag
+ if( m_bWaitingForPrimaryConversion )
+ getAdaptor( XA_PRIMARY )->clearTransferable();
+
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_aDropWindow = None;
+ m_aDropProxy = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ m_nNoPosX = 0;
+ m_nNoPosY = 0;
+ m_nNoPosWidth = 0;
+ m_nNoPosHeight = 0;
+ m_aCurrentCursor = None;
+
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+
+ m_aDragExecuteThread = NULL;
+ m_aDragRunning.reset();
+
+ aGuard.clear();
+ if( xListener.is() )
+ {
+ xTransferable.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ }
+ osl_destroyThread( aThread );
+}
+
+/*
+ * XDragSourceContext
+ */
+
+sal_Int32 SelectionManager::getCurrentCursor()
+{
+ return m_aCurrentCursor;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::setCursor( sal_Int32 cursor, XLIB_Window aDropWindow, XLIB_Time )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ if( aDropWindow == m_aDropWindow && XLIB_Cursor(cursor) != m_aCurrentCursor )
+ {
+ if( m_xDragSourceListener.is() && ! m_bDropSent )
+ {
+ m_aCurrentCursor = cursor;
+ XChangeActivePointerGrab( m_pDisplay, DRAG_EVENT_MASK, cursor, CurrentTime );
+ XFlush( m_pDisplay );
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::setImage( sal_Int32, XLIB_Window, XLIB_Time )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::transferablesFlavorsChanged()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ m_aDragFlavors = m_xDragSourceTransferable->getTransferDataFlavors();
+ int i;
+
+ std::list< Atom > aConversions;
+ std::list< Atom >::const_iterator type_it;
+
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+
+ int nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( sizeof(Atom)*aConversions.size() );
+ for( i = 0, type_it = aConversions.begin(); type_it != aConversions.end(); ++type_it, i++ )
+ pTypes[i] = *type_it;
+ XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
+
+ if( m_aCurrentDropWindow != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send synthetic leave and enter events
+
+ XEvent aEvent;
+
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.data.l[1] = 0;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+
+ aEvent.xclient.message_type = m_nXdndEnter;
+ aEvent.xclient.data.l[1] = m_nCurrentProtocolVersion << 24;
+ memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
+ // fill in data types
+ if( nTypes > 3 )
+ aEvent.xclient.data.l[1] |= 1;
+ for( int j = 0; j < nTypes && j < 3; j++ )
+ aEvent.xclient.data.l[j+2] = pTypes[j];
+
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+}
+
+/*
+ * dispatch loop
+ */
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleXEvent( XEvent& rEvent )
+{
+ /*
+ * since we are XConnectionListener to a second X display
+ * to get client messages it is essential not to dispatch
+ * events twice that we get on both connections
+ *
+ * between dispatching ButtonPress and startDrag
+ * the user can already have released the mouse. The ButtonRelease
+ * will then be dispatched in VCLs queue and never turn up here.
+ * Which is not so good, since startDrag will XGrabPointer and
+ * XGrabKeyboard -> solid lock.
+ */
+ if( rEvent.xany.display != m_pDisplay
+ && rEvent.type != ClientMessage
+ && rEvent.type != ButtonPress
+ && rEvent.type != ButtonRelease
+ )
+ return false;
+
+ bool bHandled = false;
+ switch (rEvent.type)
+ {
+ case SelectionClear:
+ {
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionClear for selection %s\n",
+ OUStringToOString( getString( rEvent.xselectionclear.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ SelectionAdaptor* pAdaptor = getAdaptor( rEvent.xselectionclear.selection );
+ boost::unordered_map< Atom, Selection* >::iterator it( m_aSelections.find( rEvent.xselectionclear.selection ) );
+ if( it != m_aSelections.end() )
+ it->second->m_bOwner = false;
+ aGuard.clear();
+ if ( pAdaptor )
+ pAdaptor->clearTransferable();
+ }
+ break;
+
+ case SelectionRequest:
+ bHandled = handleSelectionRequest( rEvent.xselectionrequest );
+ break;
+ case PropertyNotify:
+ if( rEvent.xproperty.window == m_aWindow ||
+ rEvent.xproperty.window == m_aCurrentDropWindow
+ )
+ bHandled = handleReceivePropertyNotify( rEvent.xproperty );
+ else
+ bHandled = handleSendPropertyNotify( rEvent.xproperty );
+ break;
+ case SelectionNotify:
+ bHandled = handleSelectionNotify( rEvent.xselection );
+ break;
+ case ClientMessage:
+ // messages from drag target
+ if( rEvent.xclient.message_type == m_nXdndStatus ||
+ rEvent.xclient.message_type == m_nXdndFinished )
+ bHandled = handleDragEvent( rEvent );
+ // messages from drag source
+ else if(
+ rEvent.xclient.message_type == m_nXdndEnter ||
+ rEvent.xclient.message_type == m_nXdndLeave ||
+ rEvent.xclient.message_type == m_nXdndPosition ||
+ rEvent.xclient.message_type == m_nXdndDrop
+ )
+ bHandled = handleDropEvent( rEvent.xclient );
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ case ButtonPress:
+ case ButtonRelease:
+ case XLIB_KeyPress:
+ case KeyRelease:
+ bHandled = handleDragEvent( rEvent );
+ break;
+ default:
+ ;
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::dispatchEvent( int millisec )
+{
+ // acquire the mutex to prevent other threads
+ // from using the same X connection
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+
+ if( !XPending( m_pDisplay ))
+ { // wait for any events if none are already queued
+ pollfd aPollFD;
+ aPollFD.fd = XConnectionNumber( m_pDisplay );
+ aPollFD.events = POLLIN;
+ aPollFD.revents = 0;
+ // release mutex for the time of waiting for possible data
+ aGuard.clear();
+ if( poll( &aPollFD, 1, millisec ) <= 0 )
+ return;
+ aGuard.reset();
+ }
+ while( XPending( m_pDisplay ))
+ {
+ XEvent event;
+ XNextEvent( m_pDisplay, &event );
+ aGuard.clear();
+ handleXEvent( event );
+ aGuard.reset();
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::run( void* pThis )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "SelectionManager::run\n" );
+#endif
+ // dispatch until the cows come home
+
+ SelectionManager* This = (SelectionManager*)pThis;
+
+ timeval aLast;
+ gettimeofday( &aLast, 0 );
+
+ css::uno::Reference< XMultiServiceFactory > xFact( ::comphelper::getProcessServiceFactory() );
+ if( xFact.is() )
+ {
+ css::uno::Reference< XDesktop > xDesktop( xFact->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ), UNO_QUERY );
+ if( xDesktop.is() )
+ xDesktop->addTerminateListener(This);
+ }
+
+ while( osl_scheduleThread(This->m_aThread) )
+ {
+ This->dispatchEvent( 1000 );
+
+ timeval aNow;
+ gettimeofday( &aNow, 0 );
+
+ if( (aNow.tv_sec - aLast.tv_sec) > 0 )
+ {
+ osl::ClearableMutexGuard aGuard(This->m_aMutex);
+ std::list< std::pair< SelectionAdaptor*, css::uno::Reference< XInterface > > > aChangeList;
+
+ for( boost::unordered_map< Atom, Selection* >::iterator it = This->m_aSelections.begin(); it != This->m_aSelections.end(); ++it )
+ {
+ if( it->first != This->m_nXdndSelection && ! it->second->m_bOwner )
+ {
+ XLIB_Window aOwner = XGetSelectionOwner( This->m_pDisplay, it->first );
+ if( aOwner != it->second->m_aLastOwner )
+ {
+ it->second->m_aLastOwner = aOwner;
+ std::pair< SelectionAdaptor*, css::uno::Reference< XInterface > >
+ aKeep( it->second->m_pAdaptor, it->second->m_pAdaptor->getReference() );
+ aChangeList.push_back( aKeep );
+ }
+ }
+ }
+ aGuard.clear();
+ while( aChangeList.begin() != aChangeList.end() )
+ {
+ aChangeList.front().first->fireContentsChanged();
+ aChangeList.pop_front();
+ }
+ aLast = aNow;
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "SelectionManager::run end\n" );
+#endif
+}
+
+void SelectionManager::shutdown() throw()
+{
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+ if( m_bShutDown )
+ {
+ return;
+ }
+ m_bShutDown = true;
+ // stop dispatching
+ if( m_aThread )
+ {
+ osl_terminateThread( m_aThread );
+ /*
+ * Allow thread to finish before app exits to avoid pulling the carpet
+ * out from under it if pasting is occuring during shutdown
+ *
+ * a) allow it to have the Mutex and
+ * b) reschedule to allow it to complete callbacks to any
+ * Application::GetSolarMutex protected regions, etc. e.g.
+ * TransferableHelper::getTransferDataFlavors (via
+ * SelectionManager::handleSelectionRequest) which it might
+ * currently be trying to enter.
+ *
+ * Otherwise the thread may be left still waiting on a GlobalMutex
+ * when that gets destroyed, letting the thread blow up and die
+ * when enters the section in a now dead OOo instance.
+ */
+ aGuard.clear();
+ while (osl_isThreadRunning(m_aThread))
+ {
+ SolarMutexGuard guard2;
+ Application::Reschedule();
+ }
+ osl_joinWithThread( m_aThread );
+ osl_destroyThread( m_aThread );
+ m_aThread = NULL;
+ aGuard.reset();
+ }
+ m_xDisplayConnection->removeEventHandler( Any(), this );
+ m_xDisplayConnection.clear();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SelectionManager::handleEvent( const Any& event ) throw()
+{
+ Sequence< sal_Int8 > aSeq;
+ if( (event >>= aSeq) )
+ {
+ XEvent* pEvent = (XEvent*)aSeq.getArray();
+ XLIB_Time nTimestamp = CurrentTime;
+ if( pEvent->type == ButtonPress || pEvent->type == ButtonRelease )
+ nTimestamp = pEvent->xbutton.time;
+ else if( pEvent->type == XLIB_KeyPress || pEvent->type == KeyRelease )
+ nTimestamp = pEvent->xkey.time;
+ else if( pEvent->type == MotionNotify )
+ nTimestamp = pEvent->xmotion.time;
+ else if( pEvent->type == PropertyNotify )
+ nTimestamp = pEvent->xproperty.time;
+
+ if( nTimestamp != CurrentTime )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ m_nSelectionTimestamp = nTimestamp;
+ }
+
+ return sal_Bool( handleXEvent( *pEvent ) );
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager got downing event\n" );
+ #endif
+ shutdown();
+ }
+ return sal_True;
+}
+
+void SAL_CALL SelectionManager::disposing( const ::com::sun::star::lang::EventObject& )
+ throw( ::com::sun::star::uno::RuntimeException )
+{
+}
+
+void SAL_CALL SelectionManager::queryTermination( const ::com::sun::star::lang::EventObject& )
+ throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException )
+{
+}
+
+/*
+ * To be safe, shutdown needs to be called before the ~SfxApplication is called, waiting until
+ * the downing event can be too late if paste are requested during shutdown and ~SfxApplication
+ * has been called before vcl is shutdown
+ */
+void SAL_CALL SelectionManager::notifyTermination( const ::com::sun::star::lang::EventObject& rEvent )
+ throw( ::com::sun::star::uno::RuntimeException )
+{
+ css::uno::Reference< XDesktop > xDesktop( rEvent.Source, UNO_QUERY );
+ if( xDesktop.is() == sal_True )
+ xDesktop->removeTerminateListener( this );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager got app termination event\n" );
+ #endif
+ shutdown();
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::registerHandler( Atom selection, SelectionAdaptor& rAdaptor )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ Selection* pNewSelection = new Selection();
+ pNewSelection->m_pAdaptor = &rAdaptor;
+ pNewSelection->m_aAtom = selection;
+ m_aSelections[ selection ] = pNewSelection;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::deregisterHandler( Atom selection )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( selection );
+ if( it != m_aSelections.end() )
+ {
+ delete it->second->m_pPixmap;
+ delete it->second;
+ m_aSelections.erase( it );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+static bool bWasError = false;
+
+extern "C"
+{
+ int local_xerror_handler(Display* , XErrorEvent*)
+ {
+ bWasError = true;
+ return 0;
+ }
+ typedef int(*xerror_hdl_t)(Display*,XErrorEvent*);
+}
+
+void SelectionManager::registerDropTarget( XLIB_Window aWindow, DropTarget* pTarget )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ // sanity check
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( aWindow );
+ if( it != m_aDropTargets.end() )
+ OSL_FAIL( "attempt to register window as drop target twice" );
+ else if( aWindow && m_pDisplay )
+ {
+ DropTargetEntry aEntry( pTarget );
+ bWasError=false;
+ /* #i100000# ugly workaround: gtk sets its own XErrorHandler which is not suitable for us
+ unfortunately XErrorHandler is not per display, so this is just and ugly hack
+ Need to remove separate display and integrate clipboard/dnd into vcl's unx code ASAP
+ */
+ xerror_hdl_t pOldHandler = XSetErrorHandler( local_xerror_handler );
+ XSelectInput( m_pDisplay, aWindow, PropertyChangeMask );
+ if( ! bWasError )
+ {
+ // set XdndAware
+ XChangeProperty( m_pDisplay, aWindow, m_nXdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&nXdndProtocolRevision, 1 );
+ if( ! bWasError )
+ {
+ // get root window of window (in 99.999% of all cases this will be
+ // DefaultRootWindow( m_pDisplay )
+ int x, y;
+ unsigned int w, h, bw, d;
+ XGetGeometry( m_pDisplay, aWindow, &aEntry.m_aRootWindow,
+ &x, &y, &w, &h, &bw, &d );
+ }
+ }
+ XSetErrorHandler( pOldHandler );
+ if(bWasError)
+ return;
+ m_aDropTargets[ aWindow ] = aEntry;
+ }
+ else
+ OSL_FAIL( "attempt to register None as drop target" );
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::deregisterDropTarget( XLIB_Window aWindow )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ m_aDropTargets.erase( aWindow );
+ if( aWindow == m_aDragSourceWindow && m_aDragRunning.check() )
+ {
+ // abort drag
+ boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ }
+ else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
+ m_aDropWindow = m_aDropProxy = None;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+}
+
+/*
+ * SelectionAdaptor
+ */
+
+css::uno::Reference< XTransferable > SelectionManager::getTransferable() throw()
+{
+ return m_xDragSourceTransferable;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::clearTransferable() throw()
+{
+ m_xDragSourceTransferable.clear();
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::fireContentsChanged() throw()
+{
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > SelectionManager::getReference() throw()
+{
+ return css::uno::Reference< XInterface >( static_cast<OWeakObject*>(this) );
+}
+
+// ------------------------------------------------------------------------
+
+/*
+ * SelectionManagerHolder
+ */
+
+SelectionManagerHolder::SelectionManagerHolder() :
+ ::cppu::WeakComponentImplHelper3<
+ XDragSource,
+ XInitialization,
+ XServiceInfo > (m_aMutex)
+{
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManagerHolder::~SelectionManagerHolder()
+{
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManagerHolder::initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception )
+{
+ OUString aDisplayName;
+
+ if( arguments.getLength() > 0 )
+ {
+ css::uno::Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+ if( xConn.is() )
+ {
+ Any aIdentifier;
+ aIdentifier >>= aDisplayName;
+ }
+ }
+
+ SelectionManager& rManager = SelectionManager::get( aDisplayName );
+ rManager.initialize( arguments );
+ m_xRealDragSource = static_cast< XDragSource* >(&rManager);
+}
+
+/*
+ * XDragSource
+ */
+
+sal_Bool SelectionManagerHolder::isDragImageSupported() throw()
+{
+ return m_xRealDragSource.is() ? m_xRealDragSource->isDragImageSupported() : sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int32 SelectionManagerHolder::getDefaultCursor( sal_Int8 dragAction ) throw()
+{
+ return m_xRealDragSource.is() ? m_xRealDragSource->getDefaultCursor( dragAction ) : 0;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManagerHolder::startDrag(
+ const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const css::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
+ const css::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
+ ) throw()
+{
+ if( m_xRealDragSource.is() )
+ m_xRealDragSource->startDrag( trigger, sourceActions, cursor, image, transferable, listener );
+}
+
+// ------------------------------------------------------------------------
+
+/*
+ * XServiceInfo
+ */
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManagerHolder::getImplementationName() throw()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM(XDND_IMPLEMENTATION_NAME));
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SelectionManagerHolder::supportsService( const OUString& ServiceName ) throw()
+{
+ Sequence < OUString > SupportedServicesNames = Xdnd_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > SelectionManagerHolder::getSupportedServiceNames() throw()
+{
+ return Xdnd_getSupportedServiceNames();
+}
+
+
+// ------------------------------------------------------------------------
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_selection.hxx b/vcl/unx/generic/dtrans/X11_selection.hxx
new file mode 100644
index 000000000000..42158e99802b
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_selection.hxx
@@ -0,0 +1,533 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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>
+
+#include <osl/conditn.hxx>
+
+#include <boost/unordered_map.hpp>
+#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 ::boost::unordered_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;
+ ::boost::unordered_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
+ ::boost::unordered_map< Atom, ::rtl::OUString >
+ m_aAtomToString;
+ ::boost::unordered_map< ::rtl::OUString, Atom, ::rtl::OUStringHash >
+ m_aStringToAtom;
+
+ // the registered selections
+ ::boost::unordered_map< Atom, Selection* >
+ m_aSelections;
+ // IncrementalTransfers in progress
+ boost::unordered_map< XLIB_Window, boost::unordered_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 unsigned char* pPointerData, const unsigned 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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_service.cxx b/vcl/unx/generic/dtrans/X11_service.cxx
new file mode 100644
index 000000000000..bdfdd4bb7a91
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_service.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "unx/salinst.h"
+
+#include <X11_clipboard.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <uno/dispatcher.h> // declaration of generic uno interface
+#include <uno/mapping.hxx> // mapping stuff
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/compbase1.hxx>
+
+namespace {
+
+namespace css = com::sun::star;
+
+}
+
+using namespace cppu;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::awt;
+using namespace x11;
+
+using ::rtl::OUString;
+
+Sequence< OUString > SAL_CALL x11::X11Clipboard_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.SystemClipboard"));
+ return aRet;
+}
+
+Sequence< OUString > SAL_CALL x11::Xdnd_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.X11DragSource"));
+ return aRet;
+}
+
+Sequence< OUString > SAL_CALL x11::Xdnd_dropTarget_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.X11DropTarget"));
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > X11SalInstance::CreateClipboard( const Sequence< Any >& arguments )
+{
+ static boost::unordered_map< OUString, ::boost::unordered_map< Atom, Reference< XClipboard > >, ::rtl::OUStringHash > m_aInstances;
+
+ OUString aDisplayName;
+ Atom nSelection;
+
+ // extract display name from connection argument. An exception is thrown
+ // by SelectionManager.initialize() if no display connection is given.
+ if( arguments.getLength() > 0 )
+ {
+ css::uno::Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+
+ if( xConn.is() )
+ {
+ Any aIdentifier = xConn->getIdentifier();
+ aIdentifier >>= aDisplayName;
+ }
+ }
+
+ SelectionManager& rManager = SelectionManager::get( aDisplayName );
+ rManager.initialize( arguments );
+
+ // check if any other selection than clipboard selection is specified
+ if( arguments.getLength() > 1 )
+ {
+ OUString aSelectionName;
+
+ arguments.getConstArray()[1] >>= aSelectionName;
+ nSelection = rManager.getAtom( aSelectionName );
+ }
+ else
+ {
+ // default atom is clipboard selection
+ nSelection = rManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) );
+ }
+
+ ::boost::unordered_map< Atom, css::uno::Reference< XClipboard > >& rMap( m_aInstances[ aDisplayName ] );
+ ::boost::unordered_map< Atom, css::uno::Reference< XClipboard > >::iterator it = rMap.find( nSelection );
+ if( it != rMap.end() )
+ return it->second;
+
+ X11Clipboard* pClipboard = new X11Clipboard( rManager, nSelection );
+ rMap[ nSelection ] = pClipboard;
+
+ return static_cast<OWeakObject*>(pClipboard);
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > X11SalInstance::CreateDragSource()
+{
+ return css::uno::Reference < XInterface >( ( OWeakObject * ) new SelectionManagerHolder() );
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > X11SalInstance::CreateDropTarget()
+{
+ return css::uno::Reference < XInterface >( ( OWeakObject * ) new DropTarget() );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_transferable.cxx b/vcl/unx/generic/dtrans/X11_transferable.cxx
new file mode 100644
index 000000000000..076da0917a40
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_transferable.cxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+#include <X11_transferable.hxx>
+#include <X11/Xatom.h>
+#include <com/sun/star/io/IOException.hpp>
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::io;
+using namespace com::sun::star::uno;
+using namespace cppu;
+using namespace osl;
+
+using namespace x11;
+
+using ::rtl::OUString;
+
+
+X11Transferable::X11Transferable(
+ SelectionManager& rManager,
+ const Reference< XInterface >& xCreator,
+ Atom selection
+ ) :
+ m_rManager( rManager ),
+ m_xCreator( xCreator ),
+ m_aSelection( selection )
+{
+}
+
+//==================================================================================================
+
+X11Transferable::~X11Transferable()
+{
+}
+
+//==================================================================================================
+
+Any SAL_CALL X11Transferable::getTransferData( const DataFlavor& rFlavor )
+ throw(UnsupportedFlavorException, IOException, RuntimeException)
+{
+ Any aRet;
+ Sequence< sal_Int8 > aData;
+ bool bSuccess = m_rManager.getPasteData( m_aSelection ? m_aSelection : XA_PRIMARY, rFlavor.MimeType, aData );
+ if( ! bSuccess && m_aSelection == 0 )
+ bSuccess = m_rManager.getPasteData( m_rManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ), rFlavor.MimeType, aData );
+
+ if( ! bSuccess )
+ {
+ throw UnsupportedFlavorException( rFlavor.MimeType, static_cast < XTransferable * > ( this ) );
+ }
+ if( rFlavor.MimeType.equalsIgnoreAsciiCase( OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16")) ) )
+ {
+ int nLen = aData.getLength()/2;
+ if( ((sal_Unicode*)aData.getConstArray())[nLen-1] == 0 )
+ nLen--;
+ OUString aString( (sal_Unicode*)aData.getConstArray(), nLen );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "X11Transferable::getTransferData( \"%s\" )\n -> \"%s\"\n",
+ OUStringToOString( rFlavor.MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aString, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ aRet <<= aString;
+ }
+ else
+ aRet <<= aData;
+ return aRet;
+}
+
+//==================================================================================================
+
+Sequence< DataFlavor > SAL_CALL X11Transferable::getTransferDataFlavors()
+ throw(RuntimeException)
+{
+ Sequence< DataFlavor > aFlavorList;
+ bool bSuccess = m_rManager.getPasteDataTypes( m_aSelection ? m_aSelection : XA_PRIMARY, aFlavorList );
+ if( ! bSuccess && m_aSelection == 0 )
+ bSuccess = m_rManager.getPasteDataTypes( m_rManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ), aFlavorList );
+
+ return aFlavorList;
+}
+
+//==================================================================================================
+
+sal_Bool SAL_CALL X11Transferable::isDataFlavorSupported( const DataFlavor& aFlavor )
+ throw(RuntimeException)
+{
+ if( aFlavor.DataType != getCppuType( (Sequence< sal_Int8 >*)0 ) )
+ {
+ if( ! aFlavor.MimeType.equalsIgnoreAsciiCase( OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16")) ) &&
+ aFlavor.DataType == getCppuType( (OUString*)0 ) )
+ return false;
+ }
+
+ Sequence< DataFlavor > aFlavors( getTransferDataFlavors() );
+ for( int i = 0; i < aFlavors.getLength(); i++ )
+ if( aFlavor.MimeType.equalsIgnoreAsciiCase( aFlavors.getConstArray()[i].MimeType ) &&
+ aFlavor.DataType == aFlavors.getConstArray()[i].DataType )
+ return sal_True;
+
+ return sal_False;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_transferable.hxx b/vcl/unx/generic/dtrans/X11_transferable.hxx
new file mode 100644
index 000000000000..683faa0a7f87
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_transferable.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_TRANSFERABLE_HXX_
+#define _DTRANS_X11_TRANSFERABLE_HXX_
+
+#include <X11_selection.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+namespace x11 {
+
+ class X11Transferable : public ::cppu::WeakImplHelper1 <
+ ::com::sun::star::datatransfer::XTransferable >
+ {
+ ::osl::Mutex m_aMutex;
+
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xCreator;
+ Atom m_aSelection;
+ public:
+ X11Transferable( SelectionManager& rManager, const com::sun::star::uno::Reference< XInterface >& xCreator, Atom selection = None );
+ virtual ~X11Transferable();
+
+ /*
+ * XTransferable
+ */
+
+ virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw(::com::sun::star::datatransfer::UnsupportedFlavorException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException
+ );
+
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw(::com::sun::star::uno::RuntimeException);
+ };
+
+} // namespace
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/bmp.cxx b/vcl/unx/generic/dtrans/bmp.cxx
new file mode 100644
index 000000000000..57ad8ecf8a4d
--- /dev/null
+++ b/vcl/unx/generic/dtrans/bmp.cxx
@@ -0,0 +1,742 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <unistd.h>
+#include <cstdio>
+#include <cstring>
+
+#include <bmp.hxx>
+
+#include <X11_selection.hxx>
+#include <sal/macros.h>
+
+using namespace x11;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+using namespace com::sun::star::awt;
+
+/*
+ * helper functions
+ */
+
+inline void writeLE( sal_uInt16 nNumber, sal_uInt8* pBuffer )
+{
+ pBuffer[ 0 ] = (nNumber & 0xff);
+ pBuffer[ 1 ] = ((nNumber>>8)&0xff);
+}
+
+inline void writeLE( sal_uInt32 nNumber, sal_uInt8* pBuffer )
+{
+ pBuffer[ 0 ] = (nNumber & 0xff);
+ pBuffer[ 1 ] = ((nNumber>>8)&0xff);
+ pBuffer[ 2 ] = ((nNumber>>16)&0xff);
+ pBuffer[ 3 ] = ((nNumber>>24)&0xff);
+}
+
+inline sal_uInt16 readLE16( const sal_uInt8* pBuffer )
+{
+ return (((sal_uInt16)pBuffer[1]) << 8 ) | pBuffer[0];
+}
+
+inline sal_uInt16 readLE32( const sal_uInt8* pBuffer )
+{
+ return
+ (((sal_uInt32)pBuffer[3]) << 24 ) |
+ (((sal_uInt32)pBuffer[2]) << 16 ) |
+ (((sal_uInt32)pBuffer[1]) << 8 ) |
+ pBuffer[0];
+}
+
+
+/*
+ * BmpTransporter
+ */
+
+BmpTransporter::BmpTransporter( const Sequence<sal_Int8>& rBmp ) :
+ m_aBM( rBmp )
+{
+ const sal_uInt8* pData = (const sal_uInt8*)rBmp.getConstArray();
+
+ if( pData[0] == 'B' || pData[1] == 'M' )
+ {
+ pData = pData+14;
+ m_aSize.Width = readLE32( pData+4 );
+ m_aSize.Height = readLE32( pData+8 );
+ }
+ else
+ m_aSize.Width = m_aSize.Height = 0;
+}
+
+BmpTransporter::~BmpTransporter()
+{
+}
+
+com::sun::star::awt::Size SAL_CALL BmpTransporter::getSize() throw()
+{
+ return m_aSize;
+}
+
+Sequence< sal_Int8 > SAL_CALL BmpTransporter::getDIB() throw()
+{
+ return m_aBM;
+}
+
+Sequence< sal_Int8 > SAL_CALL BmpTransporter::getMaskDIB() throw()
+{
+ return Sequence< sal_Int8 >();
+}
+
+/*
+ * scanline helpers
+ */
+
+inline void X11_writeScanlinePixel( unsigned long nColor, sal_uInt8* pScanline, int depth, int x )
+{
+ switch( depth )
+ {
+ case 1:
+ pScanline[ x/8 ] &= ~(1 << (x&7));
+ pScanline[ x/8 ] |= ((nColor & 1) << (x&7));
+ break;
+ case 4:
+ pScanline[ x/2 ] &= ((x&1) ? 0x0f : 0xf0);
+ pScanline[ x/2 ] |= ((x&1) ? (nColor & 0x0f) : ((nColor & 0x0f) << 4));
+ break;
+ default:
+ case 8:
+ pScanline[ x ] = (nColor & 0xff);
+ break;
+ }
+}
+
+static sal_uInt8* X11_getPaletteBmpFromImage(
+ Display* pDisplay,
+ XImage* pImage,
+ Colormap aColormap,
+ sal_Int32& rOutSize
+ )
+{
+ sal_uInt32 nColors = 0;
+
+ rOutSize = 0;
+
+ sal_uInt8* pBuffer = 0;
+ sal_uInt32 nHeaderSize, nScanlineSize;
+ sal_uInt16 nBitCount;
+ // determine header and scanline size
+ switch( pImage->depth )
+ {
+ case 1:
+ nHeaderSize = 64;
+ nScanlineSize = (pImage->width+31)/32;
+ nBitCount = 1;
+ break;
+ case 4:
+ nHeaderSize = 72;
+ nScanlineSize = (pImage->width+1)/2;
+ nBitCount = 4;
+ break;
+ default:
+ case 8:
+ nHeaderSize = 1084;
+ nScanlineSize = pImage->width;
+ nBitCount = 8;
+ break;
+ }
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ rOutSize = nHeaderSize + nScanlineSize*pImage->height;
+ pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize );
+ for( int y = 0; y < pImage->height; y++ )
+ {
+ sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize;
+ for( int x = 0; x < pImage->width; x++ )
+ {
+ unsigned long nPixel = XGetPixel( pImage, x, y );
+ if( nPixel >= nColors )
+ nColors = nPixel+1;
+ X11_writeScanlinePixel( nPixel, pScanline, pImage->depth, x );
+ }
+ }
+
+ // fill in header fields
+ pBuffer[ 0 ] = 'B';
+ pBuffer[ 1 ] = 'M';
+
+ writeLE( nHeaderSize, pBuffer+10 );
+ writeLE( (sal_uInt32)40, pBuffer+14 );
+ writeLE( (sal_uInt32)pImage->width, pBuffer+18 );
+ writeLE( (sal_uInt32)pImage->height, pBuffer+22 );
+ writeLE( (sal_uInt16)1, pBuffer+26 );
+ writeLE( nBitCount, pBuffer+28 );
+ writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38);
+ writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42);
+ writeLE( nColors, pBuffer+46 );
+ writeLE( nColors, pBuffer+50 );
+
+ XColor aColors[256];
+ if( nColors > (1U << nBitCount) ) // paranoia
+ nColors = (1U << nBitCount);
+ for( unsigned long nPixel = 0; nPixel < nColors; nPixel++ )
+ {
+ aColors[nPixel].flags = DoRed | DoGreen | DoBlue;
+ aColors[nPixel].pixel = nPixel;
+ }
+ XQueryColors( pDisplay, aColormap, aColors, nColors );
+ for( sal_uInt32 i = 0; i < nColors; i++ )
+ {
+ pBuffer[ 54 + i*4 ] = (sal_uInt8)(aColors[i].blue >> 8);
+ pBuffer[ 55 + i*4 ] = (sal_uInt8)(aColors[i].green >> 8);
+ pBuffer[ 56 + i*4 ] = (sal_uInt8)(aColors[i].red >> 8);
+ }
+
+ // done
+
+ return pBuffer;
+}
+
+inline unsigned long doRightShift( unsigned long nValue, int nShift )
+{
+ return (nShift > 0) ? (nValue >> nShift) : (nValue << (-nShift));
+}
+
+inline unsigned long doLeftShift( unsigned long nValue, int nShift )
+{
+ return (nShift > 0) ? (nValue << nShift) : (nValue >> (-nShift));
+}
+
+static void getShift( unsigned long nMask, int& rShift, int& rSigBits, int& rShift2 )
+{
+ unsigned long nUseMask = nMask;
+ rShift = 0;
+ while( nMask & 0xffffff00 )
+ {
+ rShift++;
+ nMask >>= 1;
+ }
+ if( rShift == 0 )
+ while( ! (nMask & 0x00000080) )
+ {
+ rShift--;
+ nMask <<= 1;
+ }
+
+ int nRotate = sizeof(unsigned long)*8 - rShift;
+ rSigBits = 0;
+ nMask = doRightShift( nUseMask, rShift) ;
+ while( nRotate-- )
+ {
+ if( nMask & 1 )
+ rSigBits++;
+ nMask >>= 1;
+ }
+
+ rShift2 = 0;
+ if( rSigBits < 8 )
+ rShift2 = 8-rSigBits;
+}
+
+static sal_uInt8* X11_getTCBmpFromImage(
+ Display* pDisplay,
+ XImage* pImage,
+ sal_Int32& rOutSize,
+ int nScreenNo
+ )
+{
+ // get masks from visual info (guesswork)
+ XVisualInfo aVInfo;
+ if( ! XMatchVisualInfo( pDisplay, nScreenNo, pImage->depth, TrueColor, &aVInfo ) )
+ return NULL;
+
+ rOutSize = 0;
+
+ sal_uInt8* pBuffer = 0;
+ sal_uInt32 nHeaderSize = 60;
+ sal_uInt32 nScanlineSize = pImage->width*3;
+
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+ int nRedShift, nRedSig, nRedShift2 = 0;
+ getShift( aVInfo.red_mask, nRedShift, nRedSig, nRedShift2 );
+ int nGreenShift, nGreenSig, nGreenShift2 = 0;
+ getShift( aVInfo.green_mask, nGreenShift, nGreenSig, nGreenShift2 );
+ int nBlueShift, nBlueSig, nBlueShift2 = 0;
+ getShift( aVInfo.blue_mask, nBlueShift, nBlueSig, nBlueShift2 );
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ rOutSize = nHeaderSize + nScanlineSize*pImage->height;
+ pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize );
+ for( int y = 0; y < pImage->height; y++ )
+ {
+ sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize;
+ for( int x = 0; x < pImage->width; x++ )
+ {
+ unsigned long nPixel = XGetPixel( pImage, x, y );
+
+ sal_uInt8 nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.blue_mask, nBlueShift);
+ if( nBlueShift2 )
+ nValue |= (nValue >> nBlueShift2 );
+ *pScanline++ = nValue;
+
+ nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.green_mask, nGreenShift);
+ if( nGreenShift2 )
+ nValue |= (nValue >> nGreenShift2 );
+ *pScanline++ = nValue;
+
+ nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.red_mask, nRedShift);
+ if( nRedShift2 )
+ nValue |= (nValue >> nRedShift2 );
+ *pScanline++ = nValue;
+ }
+ }
+
+ // fill in header fields
+ pBuffer[ 0 ] = 'B';
+ pBuffer[ 1 ] = 'M';
+
+ writeLE( nHeaderSize, pBuffer+10 );
+ writeLE( (sal_uInt32)40, pBuffer+14 );
+ writeLE( (sal_uInt32)pImage->width, pBuffer+18 );
+ writeLE( (sal_uInt32)pImage->height, pBuffer+22 );
+ writeLE( (sal_uInt16)1, pBuffer+26 );
+ writeLE( (sal_uInt16)24, pBuffer+28 );
+ writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38);
+ writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42);
+
+ // done
+
+ return pBuffer;
+}
+
+sal_uInt8* x11::X11_getBmpFromPixmap(
+ Display* pDisplay,
+ Drawable aDrawable,
+ Colormap aColormap,
+ sal_Int32& rOutSize
+ )
+{
+ // get geometry of drawable
+ XLIB_Window aRoot;
+ int x,y;
+ unsigned int w, h, bw, d;
+ XGetGeometry( pDisplay, aDrawable, &aRoot, &x, &y, &w, &h, &bw, &d );
+
+ // find which screen we are on
+ int nScreenNo = ScreenCount( pDisplay );
+ while( nScreenNo-- )
+ {
+ if( RootWindow( pDisplay, nScreenNo ) == aRoot )
+ break;
+ }
+ if( nScreenNo < 0 )
+ return NULL;
+
+ if( aColormap == None )
+ aColormap = DefaultColormap( pDisplay, nScreenNo );
+
+ // get the image
+ XImage* pImage = XGetImage( pDisplay, aDrawable, 0, 0, w, h, AllPlanes, ZPixmap );
+ if( ! pImage )
+ return NULL;
+
+ sal_uInt8* pBmp = d <= 8 ?
+ X11_getPaletteBmpFromImage( pDisplay, pImage, aColormap, rOutSize ) :
+ X11_getTCBmpFromImage( pDisplay, pImage, rOutSize, nScreenNo );
+ XDestroyImage( pImage );
+
+ return pBmp;
+}
+
+void x11::X11_freeBmp( sal_uInt8* pBmp )
+{
+ rtl_freeMemory( pBmp );
+}
+
+/*
+ * PixmapHolder
+ */
+
+PixmapHolder::PixmapHolder( Display* pDisplay ) :
+ m_pDisplay( pDisplay ),
+ m_aColormap( None ),
+ m_aPixmap( None ),
+ m_aBitmap( None )
+{
+ /* try to get a 24 bit true color visual, if that fails,
+ * revert to default visual
+ */
+ if( ! XMatchVisualInfo( m_pDisplay, DefaultScreen( m_pDisplay ), 24, TrueColor, &m_aInfo ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PixmapHolder reverting to default visual\n" );
+#endif
+ Visual* pVisual = DefaultVisual( m_pDisplay, DefaultScreen( m_pDisplay ) );
+ m_aInfo.screen = DefaultScreen( m_pDisplay );
+ m_aInfo.visual = pVisual;
+ m_aInfo.visualid = pVisual->visualid;
+ m_aInfo.c_class = pVisual->c_class;
+ m_aInfo.red_mask = pVisual->red_mask;
+ m_aInfo.green_mask = pVisual->green_mask;
+ m_aInfo.blue_mask = pVisual->blue_mask;
+ m_aInfo.depth = DefaultDepth( m_pDisplay, m_aInfo.screen );
+ }
+ m_aColormap = DefaultColormap( m_pDisplay, m_aInfo.screen );
+#if OSL_DEBUG_LEVEL > 1
+ static const char* pClasses[] =
+ { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" };
+ fprintf( stderr, "PixmapHolder visual: id = 0x%lx, class = %s (%d), depth=%d; color map = 0x%lx\n",
+ m_aInfo.visualid,
+ (m_aInfo.c_class >= 0 && unsigned(m_aInfo.c_class) < SAL_N_ELEMENTS(pClasses)) ? pClasses[m_aInfo.c_class] : "<unknown>",
+ m_aInfo.c_class,
+ m_aInfo.depth,
+ m_aColormap );
+#endif
+ if( m_aInfo.c_class == TrueColor )
+ {
+ int nRedSig, nGreenSig, nBlueSig;
+ m_nRedShift = m_nRedShift2 = 0;
+ getShift( m_aInfo.red_mask, m_nRedShift, nRedSig, m_nRedShift2 );
+ m_nGreenShift = m_nGreenShift2 = 0;
+ getShift( m_aInfo.green_mask, m_nGreenShift, nGreenSig, m_nGreenShift2 );
+ m_nBlueShift = m_nBlueShift2 = 0;
+ getShift( m_aInfo.blue_mask, m_nBlueShift, nBlueSig, m_nBlueShift2 );
+
+ m_nBlueShift2Mask = m_nBlueShift2 ? ~((unsigned long)((1<<m_nBlueShift2)-1)) : ~0L;
+ m_nGreenShift2Mask = m_nGreenShift2 ? ~((unsigned long)((1<<m_nGreenShift2)-1)) : ~0L;
+ m_nRedShift2Mask = m_nRedShift2 ? ~((unsigned long)((1<<m_nRedShift2)-1)) : ~0L;
+ }
+}
+
+PixmapHolder::~PixmapHolder()
+{
+ if( m_aPixmap != None )
+ XFreePixmap( m_pDisplay, m_aPixmap );
+ if( m_aBitmap != None )
+ XFreePixmap( m_pDisplay, m_aBitmap );
+}
+
+unsigned long PixmapHolder::getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const
+{
+ unsigned long nPixel = 0;
+ unsigned long nValue = (unsigned long)b;
+ nValue &= m_nBlueShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nBlueShift );
+
+ nValue = (unsigned long)g;
+ nValue &= m_nGreenShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nGreenShift );
+
+ nValue = (unsigned long)r;
+ nValue &= m_nRedShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nRedShift );
+
+ return nPixel;
+}
+
+void PixmapHolder::setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage )
+{
+ // setup palette
+ XColor aPalette[256];
+
+ sal_uInt32 nColors = readLE32( pData+32 );
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+ sal_uInt16 nDepth = readLE16( pData+14 );
+
+ for( sal_uInt16 i = 0 ; i < nColors; i++ )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ {
+ aPalette[i].red = ((unsigned short)pData[42 + i*4]) << 8 | ((unsigned short)pData[42 + i*4]);
+ aPalette[i].green = ((unsigned short)pData[41 + i*4]) << 8 | ((unsigned short)pData[41 + i*4]);
+ aPalette[i].blue = ((unsigned short)pData[40 + i*4]) << 8 | ((unsigned short)pData[40 + i*4]);
+ XAllocColor( m_pDisplay, m_aColormap, aPalette+i );
+ }
+ else
+ aPalette[i].pixel = getTCPixel( pData[42+i*4], pData[41+i*4], pData[40+i*4] );
+ }
+ const sal_uInt8* pBMData = pData + readLE32( pData ) + 4*nColors;
+
+ sal_uInt32 nScanlineSize = 0;
+ switch( nDepth )
+ {
+ case 1:
+ nScanlineSize = (nWidth+31)/32;
+ break;
+ case 4:
+ nScanlineSize = (nWidth+1)/2;
+ break;
+ case 8:
+ nScanlineSize = nWidth;
+ break;
+ }
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ for( unsigned int y = 0; y < nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-y)*nScanlineSize;
+ for( unsigned int x = 0; x < nWidth; x++ )
+ {
+ int nCol = 0;
+ switch( nDepth )
+ {
+ case 1: nCol = (pScanline[ x/8 ] & (0x80 >> (x&7))) != 0 ? 0 : 1; break;
+ case 4:
+ if( x & 1 )
+ nCol = (int)(pScanline[ x/2 ] >> 4);
+ else
+ nCol = (int)(pScanline[ x/2 ] & 0x0f);
+ break;
+ case 8: nCol = (int)pScanline[x];
+ }
+ XPutPixel( pImage, x, y, aPalette[nCol].pixel );
+ }
+ }
+}
+
+void PixmapHolder::setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage )
+{
+ XColor aPalette[216];
+
+ int nNonAllocs = 0;
+
+ for( int r = 0; r < 6; r++ )
+ {
+ for( int g = 0; g < 6; g++ )
+ {
+ for( int b = 0; b < 6; b++ )
+ {
+ int i = r*36+g*6+b;
+ aPalette[i].red = r == 5 ? 0xffff : r*10922;
+ aPalette[i].green = g == 5 ? 0xffff : g*10922;
+ aPalette[i].blue = b == 5 ? 0xffff : b*10922;
+ aPalette[i].pixel = 0;
+ if( ! XAllocColor( m_pDisplay, m_aColormap, aPalette+i ) )
+ nNonAllocs++;
+ }
+ }
+ }
+
+ if( nNonAllocs )
+ {
+ XColor aRealPalette[256];
+ int nColors = 1 << m_aInfo.depth;
+ int i;
+ for( i = 0; i < nColors; i++ )
+ aRealPalette[i].pixel = (unsigned long)i;
+ XQueryColors( m_pDisplay, m_aColormap, aRealPalette, nColors );
+ for( i = 0; i < nColors; i++ )
+ {
+ sal_uInt8 nIndex =
+ 36*(sal_uInt8)(aRealPalette[i].red/10923) +
+ 6*(sal_uInt8)(aRealPalette[i].green/10923) +
+ (sal_uInt8)(aRealPalette[i].blue/10923);
+ if( aPalette[nIndex].pixel == 0 )
+ aPalette[nIndex] = aRealPalette[i];
+ }
+ }
+
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ const sal_uInt8* pBMData = pData + readLE32( pData );
+ sal_uInt32 nScanlineSize = nWidth*3;
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ for( int y = 0; y < (int)nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize;
+ for( int x = 0; x < (int)nWidth; x++ )
+ {
+ sal_uInt8 b = pScanline[3*x];
+ sal_uInt8 g = pScanline[3*x+1];
+ sal_uInt8 r = pScanline[3*x+2];
+ sal_uInt8 i = 36*(r/43) + 6*(g/43) + (b/43);
+
+ XPutPixel( pImage, x, y, aPalette[ i ].pixel );
+ }
+ }
+}
+
+void PixmapHolder::setBitmapDataTC( const sal_uInt8* pData, XImage* pImage )
+{
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ const sal_uInt8* pBMData = pData + readLE32( pData );
+ sal_uInt32 nScanlineSize = nWidth*3;
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ for( int y = 0; y < (int)nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize;
+ for( int x = 0; x < (int)nWidth; x++ )
+ {
+ unsigned long nPixel = getTCPixel( pScanline[3*x+2], pScanline[3*x+1], pScanline[3*x] );
+ XPutPixel( pImage, x, y, nPixel );
+ }
+ }
+}
+
+bool PixmapHolder::needsConversion( const sal_uInt8* pData )
+{
+ if( pData[0] != 'B' || pData[1] != 'M' )
+ return true;
+
+ pData = pData+14;
+ sal_uInt32 nDepth = readLE32( pData+14 );
+ if( nDepth == 24 )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ return true;
+ }
+ else if( nDepth != (sal_uInt32)m_aInfo.depth )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ return true;
+ }
+
+ return false;
+}
+
+Pixmap PixmapHolder::setBitmapData( const sal_uInt8* pData )
+{
+ if( pData[0] != 'B' || pData[1] != 'M' )
+ return None;
+
+ pData = pData+14;
+
+ // reject compressed data
+ if( readLE32( pData + 16 ) != 0 )
+ return None;
+
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ if( m_aPixmap != None )
+ XFreePixmap( m_pDisplay, m_aPixmap ), m_aPixmap = None;
+ if( m_aBitmap != None )
+ XFreePixmap( m_pDisplay, m_aBitmap ), m_aBitmap = None;
+
+ m_aPixmap = XCreatePixmap( m_pDisplay,
+ RootWindow( m_pDisplay, m_aInfo.screen ),
+ nWidth, nHeight, m_aInfo.depth );
+
+ if( m_aPixmap != None )
+ {
+ XImage aImage;
+ aImage.width = (int)nWidth;
+ aImage.height = (int)nHeight;
+ aImage.xoffset = 0;
+ aImage.format = ZPixmap;
+ aImage.data = NULL;
+ aImage.byte_order = ImageByteOrder( m_pDisplay );
+ aImage.bitmap_unit = BitmapUnit( m_pDisplay );
+ aImage.bitmap_bit_order = BitmapBitOrder( m_pDisplay );
+ aImage.bitmap_pad = BitmapPad( m_pDisplay );
+ aImage.depth = m_aInfo.depth;
+ aImage.red_mask = m_aInfo.red_mask;
+ aImage.green_mask = m_aInfo.green_mask;
+ aImage.blue_mask = m_aInfo.blue_mask;
+ aImage.bytes_per_line = 0; // filled in by XInitImage
+ if( m_aInfo.depth <= 8 )
+ aImage.bits_per_pixel = m_aInfo.depth;
+ else
+ aImage.bits_per_pixel = 8*((m_aInfo.depth+7)/8);
+ aImage.obdata = NULL;
+
+ XInitImage( &aImage );
+ aImage.data = (char*)rtl_allocateMemory( nHeight*aImage.bytes_per_line );
+
+ if( readLE32( pData+14 ) == 24 )
+ {
+ if( m_aInfo.c_class == TrueColor )
+ setBitmapDataTC( pData, &aImage );
+ else
+ setBitmapDataTCDither( pData, &aImage );
+ }
+ else
+ setBitmapDataPalette( pData, &aImage );
+
+ // put the image
+ XPutImage( m_pDisplay,
+ m_aPixmap,
+ DefaultGC( m_pDisplay, m_aInfo.screen ),
+ &aImage,
+ 0, 0,
+ 0, 0,
+ nWidth, nHeight );
+
+ // clean up
+ rtl_freeMemory( aImage.data );
+
+ // prepare bitmap (mask)
+ m_aBitmap = XCreatePixmap( m_pDisplay,
+ RootWindow( m_pDisplay, m_aInfo.screen ),
+ nWidth, nHeight, 1 );
+ XGCValues aVal;
+ aVal.function = GXcopy;
+ aVal.foreground = 0xffffffff;
+ GC aGC = XCreateGC( m_pDisplay, m_aBitmap, GCFunction | GCForeground, &aVal );
+ XFillRectangle( m_pDisplay, m_aBitmap, aGC, 0, 0, nWidth, nHeight );
+ XFreeGC( m_pDisplay, aGC );
+ }
+
+ return m_aPixmap;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/bmp.hxx b/vcl/unx/generic/dtrans/bmp.hxx
new file mode 100644
index 000000000000..6d2e76bae0bb
--- /dev/null
+++ b/vcl/unx/generic/dtrans/bmp.hxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_BMP_HXX_
+#define _DTRANS_BMP_HXX_
+
+#include "tools/prex.h"
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "tools/postx.h"
+
+#include <sal/types.h>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <cppuhelper/compbase1.hxx>
+
+
+
+namespace x11 {
+
+// helper methods
+sal_uInt8* X11_getBmpFromPixmap( Display* pDisplay,
+ Drawable aDrawable,
+ Colormap aColormap,
+ sal_Int32& rOutSize );
+
+void X11_freeBmp( sal_uInt8* pBmp );
+
+class PixmapHolder
+{
+ Display* m_pDisplay;
+ Colormap m_aColormap;
+ Pixmap m_aPixmap;
+ Pixmap m_aBitmap;
+ XVisualInfo m_aInfo;
+
+ int m_nRedShift, m_nRedShift2;
+ int m_nGreenShift, m_nGreenShift2;
+ int m_nBlueShift, m_nBlueShift2;
+ unsigned long m_nBlueShift2Mask, m_nRedShift2Mask, m_nGreenShift2Mask;
+
+ // these expect data pointers to bitmapinfo header
+ void setBitmapDataTC( const sal_uInt8* pData, XImage* pImage );
+ void setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage );
+ void setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage );
+
+ unsigned long getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const;
+public:
+ PixmapHolder( Display* pDisplay );
+ ~PixmapHolder();
+
+ // accepts bitmap file (including bitmap file header)
+ Pixmap setBitmapData( const sal_uInt8* pData );
+ bool needsConversion( const sal_uInt8* pData );
+
+ Colormap getColormap() const { return m_aColormap; }
+ Pixmap getPixmap() const { return m_aPixmap; }
+ Pixmap getBitmap() const { return m_aBitmap; }
+ VisualID getVisualID() const { return m_aInfo.visualid; }
+ int getClass() const { return m_aInfo.c_class; }
+ int getDepth() const { return m_aInfo.depth; }
+};
+
+class BmpTransporter :
+ public cppu::WeakImplHelper1< com::sun::star::awt::XBitmap >
+{
+ com::sun::star::uno::Sequence<sal_Int8> m_aBM;
+ com::sun::star::awt::Size m_aSize;
+public:
+ BmpTransporter( const com::sun::star::uno::Sequence<sal_Int8>& rBmp );
+ virtual ~BmpTransporter();
+
+ virtual com::sun::star::awt::Size SAL_CALL getSize() throw();
+ virtual com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getDIB() throw();
+ virtual com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getMaskDIB() throw();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/config.cxx b/vcl/unx/generic/dtrans/config.cxx
new file mode 100644
index 000000000000..5f711da47434
--- /dev/null
+++ b/vcl/unx/generic/dtrans/config.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <cstdio>
+#include <unotools/configitem.hxx>
+
+#include "X11_selection.hxx"
+
+#define SETTINGS_CONFIGNODE "VCL/Settings/Transfer"
+#define SELECTION_PROPERTY "SelectionTimeout"
+
+namespace x11
+{
+
+class DtransX11ConfigItem : public ::utl::ConfigItem
+{
+ sal_Int32 m_nSelectionTimeout;
+
+ virtual void Notify( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rPropertyNames );
+ virtual void Commit();
+public:
+ DtransX11ConfigItem();
+ virtual ~DtransX11ConfigItem();
+
+ sal_Int32 getSelectionTimeout() const { return m_nSelectionTimeout; }
+};
+
+}
+
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace x11;
+
+using ::rtl::OUString;
+
+sal_Int32 SelectionManager::getSelectionTimeout()
+{
+ if( m_nSelectionTimeout < 1 )
+ {
+ DtransX11ConfigItem aCfg;
+ m_nSelectionTimeout = aCfg.getSelectionTimeout();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "initialized selection timeout to %" SAL_PRIdINT32 " seconds\n", m_nSelectionTimeout );
+#endif
+ }
+ return m_nSelectionTimeout;
+}
+
+/*
+ * DtransX11ConfigItem constructor
+ */
+
+DtransX11ConfigItem::DtransX11ConfigItem() :
+ ConfigItem( OUString( RTL_CONSTASCII_USTRINGPARAM( SETTINGS_CONFIGNODE ) ),
+ CONFIG_MODE_DELAYED_UPDATE ),
+ m_nSelectionTimeout( 3 )
+{
+ if( IsValidConfigMgr() )
+ {
+ Sequence< OUString > aKeys( 1 );
+ aKeys.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( SELECTION_PROPERTY ) );
+ Sequence< Any > aValues = GetProperties( aKeys );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %" SAL_PRIdINT32 " properties for %s\n", aValues.getLength(), SELECTION_PROPERTY );
+#endif
+ Any* pValue = aValues.getArray();
+ for( int i = 0; i < aValues.getLength(); i++, pValue++ )
+ {
+ if( pValue->getValueTypeClass() == TypeClass_STRING )
+ {
+ const OUString* pLine = (const OUString*)pValue->getValue();
+ if( pLine->getLength() )
+ {
+ m_nSelectionTimeout = pLine->toInt32();
+ if( m_nSelectionTimeout < 1 )
+ m_nSelectionTimeout = 1;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found SelectionTimeout \"%s\"\n",
+ OUStringToOString( *pLine, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "found SelectionTimeout of type \"%s\"\n",
+ OUStringToOString( pValue->getValueType().getTypeName(), osl_getThreadTextEncoding() ).getStr() );
+#endif
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no valid configmanager, could not read timeout setting\n" );
+#endif
+}
+
+/*
+ * DtransX11ConfigItem destructor
+ */
+
+DtransX11ConfigItem::~DtransX11ConfigItem()
+{
+}
+
+/*
+ * DtransX11ConfigItem::Commit
+ */
+
+void DtransX11ConfigItem::Commit()
+{
+ // for the clipboard service this is readonly, so
+ // there is nothing to commit
+}
+
+/*
+ * DtransX11ConfigItem::Notify
+ */
+
+void DtransX11ConfigItem::Notify( const Sequence< OUString >& /*rPropertyNames*/ )
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/copydata_curs.h b/vcl/unx/generic/dtrans/copydata_curs.h
new file mode 100644
index 000000000000..a882a541a6d7
--- /dev/null
+++ b/vcl/unx/generic/dtrans/copydata_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define copydata_curs_width 32
+#define copydata_curs_height 32
+#define copydata_curs_x_hot 1
+#define copydata_curs_y_hot 1
+static unsigned char copydata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0xf0, 0x1f, 0x00, 0x10, 0xf0, 0x1e, 0x00,
+ 0xa8, 0xf2, 0x1e, 0x00, 0x50, 0x35, 0x18, 0x00, 0x00, 0xf0, 0x1e, 0x00,
+ 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/copydata_mask.h b/vcl/unx/generic/dtrans/copydata_mask.h
new file mode 100644
index 000000000000..9cd73b08d106
--- /dev/null
+++ b/vcl/unx/generic/dtrans/copydata_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define copydata_mask_width 32
+#define copydata_mask_height 32
+#define copydata_mask_x_hot 1
+#define copydata_mask_y_hot 1
+static unsigned char copydata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/linkdata_curs.h b/vcl/unx/generic/dtrans/linkdata_curs.h
new file mode 100644
index 000000000000..054ef55ef2bb
--- /dev/null
+++ b/vcl/unx/generic/dtrans/linkdata_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define linkdata_curs_width 32
+#define linkdata_curs_height 32
+#define linkdata_curs_x_hot 1
+#define linkdata_curs_y_hot 1
+static unsigned char linkdata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0x70, 0x18, 0x00, 0x10, 0xf0, 0x18, 0x00,
+ 0xa8, 0x72, 0x18, 0x00, 0x50, 0x35, 0x1a, 0x00, 0x00, 0x30, 0x1f, 0x00,
+ 0x00, 0xb0, 0x1f, 0x00, 0x00, 0x70, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/linkdata_mask.h b/vcl/unx/generic/dtrans/linkdata_mask.h
new file mode 100644
index 000000000000..429c603066dc
--- /dev/null
+++ b/vcl/unx/generic/dtrans/linkdata_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define linkdata_mask_width 32
+#define linkdata_mask_height 32
+#define linkdata_mask_x_hot 1
+#define linkdata_mask_y_hot 1
+static unsigned char linkdata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/movedata_curs.h b/vcl/unx/generic/dtrans/movedata_curs.h
new file mode 100644
index 000000000000..642bbd176e4b
--- /dev/null
+++ b/vcl/unx/generic/dtrans/movedata_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define movedata_curs_width 32
+#define movedata_curs_height 32
+#define movedata_curs_x_hot 1
+#define movedata_curs_y_hot 1
+static unsigned char movedata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00,
+ 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00,
+ 0xa8, 0xaa, 0x00, 0x00, 0x50, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/movedata_mask.h b/vcl/unx/generic/dtrans/movedata_mask.h
new file mode 100644
index 000000000000..f06c80f1728c
--- /dev/null
+++ b/vcl/unx/generic/dtrans/movedata_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define movedata_mask_width 32
+#define movedata_mask_height 32
+#define movedata_mask_x_hot 1
+#define movedata_mask_y_hot 1
+static unsigned char movedata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00,
+ 0x3c, 0xe0, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/nodrop_curs.h b/vcl/unx/generic/dtrans/nodrop_curs.h
new file mode 100644
index 000000000000..5c501d3876c4
--- /dev/null
+++ b/vcl/unx/generic/dtrans/nodrop_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define nodrop_curs_width 32
+#define nodrop_curs_height 32
+#define nodrop_curs_x_hot 9
+#define nodrop_curs_y_hot 9
+static unsigned char nodrop_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0x1c, 0xfc, 0x00, 0x00,
+ 0x1e, 0xfe, 0x01, 0x00, 0x0e, 0xdf, 0x01, 0x00, 0x8e, 0xcf, 0x01, 0x00,
+ 0xce, 0xc7, 0x01, 0x00, 0xee, 0xc3, 0x01, 0x00, 0xfe, 0xe1, 0x01, 0x00,
+ 0xfc, 0xe0, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/nodrop_mask.h b/vcl/unx/generic/dtrans/nodrop_mask.h
new file mode 100644
index 000000000000..bd315dc28df1
--- /dev/null
+++ b/vcl/unx/generic/dtrans/nodrop_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#define nodrop_mask_width 32
+#define nodrop_mask_height 32
+#define nodrop_mask_x_hot 9
+#define nodrop_mask_y_hot 9
+static unsigned char nodrop_mask_bits[] = {
+ 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xfc, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x7e, 0xfe, 0x01, 0x00,
+ 0x3f, 0xff, 0x03, 0x00, 0x9f, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x03, 0x00,
+ 0xff, 0xef, 0x03, 0x00, 0xff, 0xe7, 0x03, 0x00, 0xff, 0xf3, 0x03, 0x00,
+ 0xfe, 0xf9, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */