[Libreoffice-commits] core.git: vcl/inc vcl/source vcl/unx

Caolán McNamara caolanm at redhat.com
Wed Jan 27 05:15:35 PST 2016


 vcl/inc/unx/gtk/gtkframe.hxx  |   27 ++++++
 vcl/inc/unx/gtk/gtkinst.hxx   |   46 ++++++++++
 vcl/source/window/mouse.cxx   |    1 
 vcl/unx/gtk3/gtk3gtkframe.cxx |  178 ++++++++++++++++++++++++++++++++++++++++--
 vcl/unx/gtk3/gtk3gtkinst.cxx  |  161 +++++++++++++++++++++++++++----------
 5 files changed, 364 insertions(+), 49 deletions(-)

New commits:
commit a5b4f6e456bfb735385e8d3d6945ea8f3be1ba94
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jan 27 10:16:39 2016 +0000

    Resolves: tdf#93054 gtk3: implement drag and drop
    
    Change-Id: Ib644ea36b8a9e68e023e465ef159b9a4890e5d37

diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 584a2ab..6c7058a 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -40,6 +40,9 @@
 #include "tools/link.hxx"
 
 #include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
 
 #include <list>
 #include <vector>
@@ -55,6 +58,7 @@ typedef ::Window GdkNativeWindow;
 #define gdk_set_sm_client_id(i) gdk_x11_set_sm_client_id(i)
 #define gdk_window_foreign_new_for_display(a,b) gdk_x11_window_foreign_new_for_display(a,b)
 class GtkDropTarget;
+class GtkDragSource;
 class GtkDnDTransferable;
 #endif
 
@@ -209,6 +213,7 @@ class GtkSalFrame : public SalFrame
     long                            m_nHeightRequest;
     cairo_region_t*                 m_pRegion;
     GtkDropTarget*                  m_pDropTarget;
+    GtkDragSource*                  m_pDragSource;
     bool                            m_bInDrag;
     GtkDnDTransferable*             m_pFormatConversionRequest;
 #else
@@ -249,6 +254,13 @@ class GtkSalFrame : public SalFrame
     static void         signalDragDropReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
                                                GtkSelectionData *data, guint ttype, guint time, gpointer frame);
     static void         signalDragLeave(GtkWidget *widget, GdkDragContext *context, guint time, gpointer frame);
+
+    static gboolean     signalDragFailed(GtkWidget *widget, GdkDragContext *context, GtkDragResult result, gpointer frame);
+    static void         signalDragDelete(GtkWidget *widget, GdkDragContext *context, gpointer frame);
+    static void         signalDragEnd(GtkWidget *widget, GdkDragContext *context, gpointer frame);
+    static void         signalDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData *data, guint info,
+                                          guint time, gpointer frame);
+
 #if GTK_CHECK_VERSION(3,14,0)
     static void         gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame);
     static void         gestureLongPress(GtkGestureLongPress* gesture, gpointer frame);
@@ -385,11 +397,26 @@ public:
         m_pDropTarget = nullptr;
     }
 
+    void registerDragSource(GtkDragSource* pDragSource)
+    {
+        assert(!m_pDragSource);
+        m_pDragSource = pDragSource;
+    }
+
+    void deregisterDragSource(GtkDragSource* pDragSource)
+    {
+        assert(m_pDragSource == pDragSource); (void)pDragSource;
+        m_pDragSource = nullptr;
+    }
+
     void SetFormatConversionRequest(GtkDnDTransferable *pRequest)
     {
         m_pFormatConversionRequest = pRequest;
     }
 
+    void startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY,
+                   GdkDragAction sourceActions, GtkTargetList* pTargetList);
+
 #endif
     virtual ~GtkSalFrame();
 
diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
index a649f62..93a041b 100644
--- a/vcl/inc/unx/gtk/gtkinst.hxx
+++ b/vcl/inc/unx/gtk/gtkinst.hxx
@@ -24,6 +24,7 @@
 #include <unx/gensys.h>
 #include <headless/svpinst.hxx>
 #include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
 #include <com/sun/star/lang/XInitialization.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
@@ -56,6 +57,8 @@ struct VclToGtkHelper
 {
     std::vector<css::datatransfer::DataFlavor> aInfoToFlavor;
     std::vector<GtkTargetEntry> FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats);
+    void setSelectionData(const css::uno::Reference<css::datatransfer::XTransferable> &rTrans,
+                          GtkSelectionData *selection_data, guint info);
 private:
     GtkTargetEntry makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor);
 };
@@ -123,6 +126,48 @@ public:
     void fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde);
     void fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte);
 };
+
+class GtkDragSource : public cppu::WeakComponentImplHelper<css::datatransfer::dnd::XDragSource,
+                                                           css::lang::XInitialization,
+                                                           css::lang::XServiceInfo>
+{
+    osl::Mutex m_aMutex;
+    GtkSalFrame* m_pFrame;
+    css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> m_xListener;
+    css::uno::Reference<css::datatransfer::XTransferable> m_xTrans;
+    VclToGtkHelper m_aConversionHelper;
+public:
+    GtkDragSource() : WeakComponentImplHelper( m_aMutex ) {}
+    virtual ~GtkDragSource();
+
+    // XDragSource
+    virtual sal_Bool    SAL_CALL isDragImageSupported() throw(std::exception) override;
+    virtual sal_Int32   SAL_CALL getDefaultCursor(sal_Int8 dragAction) throw(std::exception) override;
+    virtual void        SAL_CALL startDrag(
+        const css::datatransfer::dnd::DragGestureEvent& trigger, sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+        const css::uno::Reference< css::datatransfer::XTransferable >& transferable,
+        const css::uno::Reference< css::datatransfer::dnd::XDragSourceListener >& listener) throw(std::exception) override;
+
+    // XInitialization
+    virtual void        SAL_CALL initialize(const css::uno::Sequence<css::uno::Any >& rArguments)
+        throw (css::uno::Exception, std::exception) override;
+            void        deinitialize();
+
+    OUString SAL_CALL getImplementationName()
+        throw (css::uno::RuntimeException, std::exception) override;
+
+    sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
+        throw (css::uno::RuntimeException, std::exception) override;
+
+    css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
+        throw (css::uno::RuntimeException, std::exception) override;
+
+    void dragFailed();
+    void dragDelete();
+    void dragEnd(GdkDragContext* context);
+    void dragDataGet(GtkSelectionData *data, guint info);
+};
+
 #endif
 
 class GtkSalTimer;
@@ -175,6 +220,7 @@ public:
 
 #if GTK_CHECK_VERSION(3,0,0)
     virtual css::uno::Reference< css::uno::XInterface > CreateClipboard( const css::uno::Sequence< css::uno::Any >& i_rArguments ) override;
+    virtual css::uno::Reference< css::uno::XInterface > CreateDragSource() override;
     virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget() override;
 #endif
 
diff --git a/vcl/source/window/mouse.cxx b/vcl/source/window/mouse.cxx
index 3c94759..7adc5bb 100644
--- a/vcl/source/window/mouse.cxx
+++ b/vcl/source/window/mouse.cxx
@@ -751,6 +751,7 @@ Reference< css::datatransfer::dnd::XDragSource > Window::GetDragSource()
                     aDropTargetSN = "com.sun.star.datatransfer.dnd.X11DropTarget";
 
                     aDragSourceAL[ 0 ] = makeAny( Application::GetDisplayConnection() );
+                    aDragSourceAL[ 1 ] = makeAny( (sal_Size)(pEnvData->aShellWindow) );
                     aDropTargetAL[ 0 ] = makeAny( Application::GetDisplayConnection() );
                     aDropTargetAL[ 1 ] = makeAny( (sal_Size)(pEnvData->aShellWindow) );
 #endif
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index b5677a1..d98b3be 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -74,6 +74,7 @@
 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/frame/ModuleManager.hpp>
@@ -790,6 +791,12 @@ GtkSalFrame::~GtkSalFrame()
         m_pDropTarget = nullptr;
     }
 
+    if (m_pDragSource)
+    {
+        m_pDragSource->deinitialize();
+        m_pDragSource= nullptr;
+    }
+
     InvalidateGraphics();
 
     if( m_pParent )
@@ -991,12 +998,21 @@ void GtkSalFrame::InitCommon()
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-press-event", G_CALLBACK(signalButton), this ));
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "motion-notify-event", G_CALLBACK(signalMotion), this ));
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-release-event", G_CALLBACK(signalButton), this ));
+
+    //Drop Target Stuff
     gtk_drag_dest_set(GTK_WIDGET(pEventWidget), (GtkDestDefaults)0, nullptr, 0, (GdkDragAction)0);
     gtk_drag_dest_set_track_motion(GTK_WIDGET(pEventWidget), true);
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-motion", G_CALLBACK(signalDragMotion), this ));
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-drop", G_CALLBACK(signalDragDrop), this ));
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-data-received", G_CALLBACK(signalDragDropReceived), this ));
     m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-leave", G_CALLBACK(signalDragLeave), this ));
+
+    //Drag Source Stuff
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-end", G_CALLBACK(signalDragEnd), this ));
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-failed", G_CALLBACK(signalDragFailed), this ));
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-data-delete", G_CALLBACK(signalDragDelete), this ));
+    m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "drag-data-get", G_CALLBACK(signalDragDataGet), this ));
+
     g_signal_connect( G_OBJECT(m_pFixedContainer), "draw", G_CALLBACK(signalDraw), this );
     g_signal_connect( G_OBJECT(m_pFixedContainer), "size-allocate", G_CALLBACK(sizeAllocated), this );
 #if GTK_CHECK_VERSION(3,14,0)
@@ -1041,6 +1057,7 @@ void GtkSalFrame::InitCommon()
     m_nExtStyle         = 0;
     m_pRegion           = nullptr;
     m_pDropTarget       = nullptr;
+    m_pDragSource       = nullptr;
     m_bInDrag           = false;
     m_pFormatConversionRequest = nullptr;
     m_ePointerStyle     = static_cast<PointerStyle>(0xffff);
@@ -3068,7 +3085,16 @@ public:
     // XDropTargetDropContext
     virtual void SAL_CALL acceptDrop(sal_Int8 dragOperation) throw(std::exception) override
     {
-        gdk_drag_status(m_pContext, VclToGdk(dragOperation), m_nTime);
+        GdkDragAction eAct(static_cast<GdkDragAction>(0));
+
+        if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE)
+            eAct = GDK_ACTION_MOVE;
+        else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY)
+            eAct = GDK_ACTION_COPY;
+        else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK)
+            eAct = GDK_ACTION_LINK;
+
+        gdk_drag_status(m_pContext, eAct, m_nTime);
     }
 
     virtual void SAL_CALL rejectDrop() throw(std::exception) override
@@ -3188,7 +3214,7 @@ gboolean GtkSalFrame::signalDragDrop(GtkWidget* pWidget, GdkDragContext* context
     aEvent.Context = new GtkDropTargetDropContext(context, time);
     aEvent.LocationX = x;
     aEvent.LocationY = y;
-    aEvent.DropAction = GdkToVcl(gdk_drag_context_get_suggested_action(context));
+    aEvent.DropAction = GdkToVcl(gdk_drag_context_get_selected_action(context));
     aEvent.SourceActions = GdkToVcl(gdk_drag_context_get_actions(context));
     css::uno::Reference<css::datatransfer::XTransferable> xTransferable(new GtkDnDTransferable(context, time, pWidget, pThis));
     aEvent.Transferable = xTransferable;
@@ -3211,7 +3237,16 @@ public:
 
     virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) throw(std::exception) override
     {
-        gdk_drag_status(m_pContext, VclToGdk(dragOperation), m_nTime);
+        GdkDragAction eAct(static_cast<GdkDragAction>(0));
+
+        if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE)
+            eAct = GDK_ACTION_MOVE;
+        else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY)
+            eAct = GDK_ACTION_COPY;
+        else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK)
+            eAct = GDK_ACTION_LINK;
+
+        gdk_drag_status(m_pContext, eAct, m_nTime);
     }
 
     virtual void SAL_CALL rejectDrag() throw(std::exception) override
@@ -3249,10 +3284,15 @@ gboolean GtkSalFrame::signalDragMotion(GtkWidget *widget, GdkDragContext *contex
 
     css::datatransfer::dnd::DropTargetDragEnterEvent aEvent;
     aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(pThis->m_pDropTarget);
-    aEvent.Context = new GtkDropTargetDragContext(context, time);
+    GtkDropTargetDragContext* pContext = new GtkDropTargetDragContext(context, time);
+    //preliminary accept the Drag and select the preferred action, the fire_* will
+    //inform the original caller of our choice and the callsite can decide
+    //to overrule this choice. i.e. typically here we default to ACTION_MOVE
+    pContext->acceptDrag(GdkToVcl(gdk_drag_context_get_actions(context)));
+    aEvent.Context = pContext;
     aEvent.LocationX = x;
     aEvent.LocationY = y;
-    aEvent.DropAction = GdkToVcl(gdk_drag_context_get_suggested_action(context));
+    aEvent.DropAction = GdkToVcl(gdk_drag_context_get_selected_action(context));
     aEvent.SourceActions = GdkToVcl(gdk_drag_context_get_actions(context));
 
     if (!pThis->m_bInDrag)
@@ -3871,4 +3911,132 @@ Window GtkSalFrame::GetX11Window()
     return widget_get_xid(m_pWindow);
 }
 
+void GtkDragSource::startDrag(const datatransfer::dnd::DragGestureEvent& rEvent,
+                              sal_Int8 sourceActions, sal_Int32 /*cursor*/, sal_Int32 /*image*/,
+                              const css::uno::Reference<css::datatransfer::XTransferable>& rTrans,
+                              const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener) throw(std::exception)
+{
+    m_xListener = rListener;
+    m_xTrans = rTrans;
+
+    if (m_pFrame)
+    {
+        css::uno::Sequence<css::datatransfer::DataFlavor> aFormats = rTrans->getTransferDataFlavors();
+        std::vector<GtkTargetEntry> aGtkTargets(m_aConversionHelper.FormatsToGtk(aFormats));
+        GtkTargetList *pTargetList = gtk_target_list_new(aGtkTargets.data(), aGtkTargets.size());
+
+        gint nDragButton = 1; // default to left button
+        css::awt::MouseEvent aEvent;
+        if (rEvent.Event >>= aEvent)
+        {
+            if (aEvent.Buttons & css::awt::MouseButton::LEFT )
+                nDragButton = 1;
+            else if (aEvent.Buttons & css::awt::MouseButton::RIGHT)
+                nDragButton = 3;
+            else if (aEvent.Buttons & css::awt::MouseButton::MIDDLE)
+                nDragButton = 2;
+        }
+
+        m_pFrame->startDrag(nDragButton, rEvent.DragOriginX, rEvent.DragOriginY,
+                            VclToGdk(sourceActions), pTargetList);
+        gtk_target_list_unref(pTargetList);
+        for (auto &a : aGtkTargets)
+            g_free(a.target);
+    }
+    else
+        dragFailed();
+}
+
+void GtkSalFrame::startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY,
+                            GdkDragAction sourceActions, GtkTargetList* pTargetList)
+{
+    SolarMutexGuard aGuard;
+
+    assert(m_pDragSource);
+
+    GdkEvent aFakeEvent;
+    memset(&aFakeEvent, 0, sizeof(GdkEvent));
+    aFakeEvent.type = GDK_BUTTON_PRESS;
+    aFakeEvent.button.window = widget_get_window(getMouseEventWidget());
+    aFakeEvent.button.time = GDK_CURRENT_TIME;
+    GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(getGdkDisplay());
+    aFakeEvent.button.device = gdk_device_manager_get_client_pointer(pDeviceManager);
+
+
+    GdkDragContext *pContext = gtk_drag_begin_with_coordinates(getMouseEventWidget(),
+                                                               pTargetList,
+                                                               sourceActions,
+                                                               nButton,
+                                                               &aFakeEvent,
+                                                               nDragOriginX,
+                                                               nDragOriginY);
+
+    if (!pContext)
+        m_pDragSource->dragFailed();
+}
+
+void GtkDragSource::dragFailed()
+{
+    datatransfer::dnd::DragSourceDropEvent aEv;
+    aEv.DropAction = datatransfer::dnd::DNDConstants::ACTION_NONE;
+    aEv.DropSuccess = false;
+    m_xListener->dragDropEnd(aEv);
+}
+
+gboolean GtkSalFrame::signalDragFailed(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkDragResult /*result*/, gpointer frame)
+{
+    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+    if (!pThis->m_pDragSource)
+        return false;
+    pThis->m_pDragSource->dragFailed();
+    return false;
+}
+
+void GtkDragSource::dragDelete()
+{
+    datatransfer::dnd::DragSourceDropEvent aEv;
+    aEv.DropAction = datatransfer::dnd::DNDConstants::ACTION_MOVE;
+    aEv.DropSuccess = true;
+    m_xListener->dragDropEnd(aEv);
+}
+
+void GtkSalFrame::signalDragDelete(GtkWidget* /*widget*/, GdkDragContext* /*context*/, gpointer frame)
+{
+    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+    if (!pThis->m_pDragSource)
+        return;
+    pThis->m_pDragSource->dragDelete();
+}
+
+void GtkDragSource::dragEnd(GdkDragContext* context)
+{
+    datatransfer::dnd::DragSourceDropEvent aEv;
+    aEv.DropAction = GdkToVcl(gdk_drag_context_get_selected_action(context));
+    aEv.DropSuccess = gdk_drag_drop_succeeded(context);
+    m_xListener->dragDropEnd(aEv);
+}
+
+void GtkSalFrame::signalDragEnd(GtkWidget* /*widget*/, GdkDragContext* context, gpointer frame)
+{
+    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+    if (!pThis->m_pDragSource)
+        return;
+    pThis->m_pDragSource->dragEnd(context);
+}
+
+void GtkDragSource::dragDataGet(GtkSelectionData *data, guint info)
+{
+    m_aConversionHelper.setSelectionData(m_xTrans, data, info);
+}
+
+void GtkSalFrame::signalDragDataGet(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkSelectionData *data, guint info,
+                                    guint /*time*/, gpointer frame)
+{
+    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+    if (!pThis->m_pDragSource)
+        return;
+    pThis->m_pDragSource->dragDataGet(data, info);
+}
+
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 5ab81ac..f914e45 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -20,8 +20,6 @@
 #include "com/sun/star/datatransfer/clipboard/XClipboardListener.hpp"
 #include "com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp"
 #include "com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp"
-#include "com/sun/star/datatransfer/dnd/XDragSource.hpp"
-#include "com/sun/star/datatransfer/dnd/XDropTarget.hpp"
 #include "com/sun/star/datatransfer/dnd/DNDConstants.hpp"
 #include <comphelper/processfactory.hxx>
 #include <comphelper/sequence.hxx>
@@ -386,12 +384,53 @@ void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData
 {
     if (!m_aContents.is())
         return;
+    m_aConversionHelper.setSelectionData(m_aContents, selection_data, info);
+}
+
+void VclGtkClipboard::OwnerChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
+{
+    if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(clipboard))
+    {
+        //null out m_aContents to return control to the system-one which
+        //will be retrieved if getContents is called again
+        setContents(Reference<css::datatransfer::XTransferable>(),
+                    Reference<css::datatransfer::clipboard::XClipboardOwner>());
+    }
+}
+
+void VclGtkClipboard::ClipboardClear(GtkClipboard * /*clipboard*/)
+{
+    for (auto &a : m_aGtkTargets)
+        g_free(a.target);
+    m_aGtkTargets.clear();
+}
 
-    GdkAtom type(gdk_atom_intern(OUStringToOString(m_aConversionHelper.aInfoToFlavor[info].MimeType,
+GtkTargetEntry VclToGtkHelper::makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor)
+{
+    GtkTargetEntry aEntry;
+    aEntry.target =
+        g_strdup(OUStringToOString(rFlavor.MimeType, RTL_TEXTENCODING_UTF8).getStr());
+    aEntry.flags = 0;
+    auto it = std::find_if(aInfoToFlavor.begin(), aInfoToFlavor.end(),
+                        DataFlavorEq(rFlavor));
+    if (it != aInfoToFlavor.end())
+        aEntry.info = std::distance(aInfoToFlavor.begin(), it);
+    else
+    {
+        aEntry.info = aInfoToFlavor.size();
+        aInfoToFlavor.push_back(rFlavor);
+    }
+    return aEntry;
+}
+
+void VclToGtkHelper::setSelectionData(const Reference<css::datatransfer::XTransferable> &rTrans,
+                                      GtkSelectionData *selection_data, guint info)
+{
+    GdkAtom type(gdk_atom_intern(OUStringToOString(aInfoToFlavor[info].MimeType,
                                                    RTL_TEXTENCODING_UTF8).getStr(),
                                  false));
 
-    css::datatransfer::DataFlavor aFlavor(m_aConversionHelper.aInfoToFlavor[info]);
+    css::datatransfer::DataFlavor aFlavor(aInfoToFlavor[info]);
     if (aFlavor.MimeType == "UTF8_STRING" || aFlavor.MimeType == "STRING")
         aFlavor.MimeType = "text/plain;charset=utf-8";
 
@@ -400,9 +439,9 @@ void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData
 
     try
     {
-        aValue = m_aContents->getTransferData(aFlavor);
+        aValue = rTrans->getTransferData(aFlavor);
     }
-    catch(...)
+    catch (...)
     {
     }
 
@@ -423,9 +462,9 @@ void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData
         aFlavor.DataType = cppu::UnoType<OUString>::get();
         try
         {
-            aValue = m_aContents->getTransferData(aFlavor);
+            aValue = rTrans->getTransferData(aFlavor);
         }
-        catch(...)
+        catch (...)
         {
         }
         OUString aString;
@@ -442,42 +481,6 @@ void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData
                            aData.getLength());
 }
 
-void VclGtkClipboard::OwnerChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
-{
-    if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(clipboard))
-    {
-        //null out m_aContents to return control to the system-one which
-        //will be retrieved if getContents is called again
-        setContents(Reference<css::datatransfer::XTransferable>(),
-                    Reference<css::datatransfer::clipboard::XClipboardOwner>());
-    }
-}
-
-void VclGtkClipboard::ClipboardClear(GtkClipboard * /*clipboard*/)
-{
-    for (auto &a : m_aGtkTargets)
-        g_free(a.target);
-    m_aGtkTargets.clear();
-}
-
-GtkTargetEntry VclToGtkHelper::makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor)
-{
-    GtkTargetEntry aEntry;
-    aEntry.target =
-        g_strdup(OUStringToOString(rFlavor.MimeType, RTL_TEXTENCODING_UTF8).getStr());
-    aEntry.flags = 0;
-    auto it = std::find_if(aInfoToFlavor.begin(), aInfoToFlavor.end(),
-                        DataFlavorEq(rFlavor));
-    if (it != aInfoToFlavor.end())
-        aEntry.info = std::distance(aInfoToFlavor.begin(), it);
-    else
-    {
-        aEntry.info = aInfoToFlavor.size();
-        aInfoToFlavor.push_back(rFlavor);
-    }
-    return aEntry;
-}
-
 namespace
 {
     void ClipboardGetFunc(GtkClipboard *clipboard, GtkSelectionData *selection_data,
@@ -604,6 +607,10 @@ void VclGtkClipboard::setContents(
                                         ClipboardGetFunc, ClipboardClearFunc, G_OBJECT(m_pOwner));
             gtk_clipboard_set_can_store(clipboard, aGtkTargets.data(), aGtkTargets.size());
         }
+
+        for (auto &a : m_aGtkTargets)
+            g_free(a.target);
+
         m_aGtkTargets = aGtkTargets;
     }
 
@@ -810,4 +817,70 @@ Reference< XInterface > GtkInstance::CreateDropTarget()
     return Reference< XInterface >( static_cast<cppu::OWeakObject *>(new GtkDropTarget()) );
 }
 
+GtkDragSource::~GtkDragSource()
+{
+    if (m_pFrame)
+        m_pFrame->deregisterDragSource(this);
+}
+
+void GtkDragSource::deinitialize()
+{
+    m_pFrame = nullptr;
+}
+
+sal_Bool GtkDragSource::isDragImageSupported() throw(std::exception)
+{
+    return true;
+}
+
+sal_Int32 GtkDragSource::getDefaultCursor( sal_Int8 ) throw(std::exception)
+{
+    return 0;
+}
+
+void GtkDragSource::initialize(const css::uno::Sequence<css::uno::Any >& rArguments) throw(Exception, std::exception)
+{
+    if (rArguments.getLength() < 2)
+    {
+        throw RuntimeException("DragSource::initialize: Cannot install window event handler",
+                               static_cast<OWeakObject*>(this));
+    }
+
+    sal_Size nFrame = 0;
+    rArguments.getConstArray()[1] >>= nFrame;
+
+    if (!nFrame)
+    {
+        throw RuntimeException("DragSource::initialize: missing SalFrame",
+                               static_cast<OWeakObject*>(this));
+    }
+
+    m_pFrame = reinterpret_cast<GtkSalFrame*>(nFrame);
+    m_pFrame->registerDragSource(this);
+}
+
+OUString SAL_CALL GtkDragSource::getImplementationName()
+    throw (css::uno::RuntimeException, std::exception)
+{
+    return OUString("com.sun.star.datatransfer.dnd.VclGtkDragSource");
+}
+
+sal_Bool SAL_CALL GtkDragSource::supportsService(OUString const & ServiceName)
+    throw (css::uno::RuntimeException, std::exception)
+{
+    return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> SAL_CALL GtkDragSource::getSupportedServiceNames()
+    throw (css::uno::RuntimeException, std::exception)
+{
+    Sequence<OUString> aRet { "com.sun.star.datatransfer.dnd.GtkDragSource" };
+    return aRet;
+}
+
+Reference< XInterface > GtkInstance::CreateDragSource()
+{
+    return Reference< XInterface >( static_cast<cppu::OWeakObject *>(new GtkDragSource()) );
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list