diff options
author | Caolán McNamara <caolanm@redhat.com> | 2019-11-29 10:21:11 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2019-12-01 20:51:12 +0100 |
commit | 19d17a739cc61341ca74cfa485e919c6012fe28c (patch) | |
tree | be3823e68681d796275149d08059872dde680534 /vcl/unx | |
parent | b1f9e704cb9148b6e211005dab0cd153957a1b2b (diff) |
weld FmFieldWin
needs drag source support
fixes a leak of ColumnInfo data as well
Change-Id: I671834726aed3fd4de096b56baaa592f51a9e73e
Reviewed-on: https://gerrit.libreoffice.org/84147
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl/unx')
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkframe.cxx | 34 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 98 |
2 files changed, 120 insertions, 12 deletions
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx index 91df150c26cf..8483304923e9 100644 --- a/vcl/unx/gtk3/gtk3gtkframe.cxx +++ b/vcl/unx/gtk3/gtk3gtkframe.cxx @@ -4231,18 +4231,38 @@ sal_uIntPtr GtkSalFrame::GetNativeWindowHandle() return GetNativeWindowHandle(m_pWindow); } +void GtkDragSource::set_datatransfer(const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, + const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener) +{ + m_xListener = rListener; + m_xTrans = rTrans; +} + +void GtkDragSource::setActiveDragSource() +{ + // For LibreOffice internal D&D we provide the Transferable without Gtk + // intermediaries as a shortcut, see tdf#100097 for how dbaccess depends on this + g_ActiveDragSource = this; + g_DropSuccessSet = false; + g_DropSuccess = false; +} + +std::vector<GtkTargetEntry> GtkDragSource::FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats) +{ + return m_aConversionHelper.FormatsToGtk(rFormats); +} + 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) { - m_xListener = rListener; - m_xTrans = rTrans; + set_datatransfer(rTrans, rListener); if (m_pFrame) { - css::uno::Sequence<css::datatransfer::DataFlavor> aFormats = rTrans->getTransferDataFlavors(); - std::vector<GtkTargetEntry> aGtkTargets(m_aConversionHelper.FormatsToGtk(aFormats)); + auto aFormats = m_xTrans->getTransferDataFlavors(); + std::vector<GtkTargetEntry> aGtkTargets(FormatsToGtk(aFormats)); GtkTargetList *pTargetList = gtk_target_list_new(aGtkTargets.data(), aGtkTargets.size()); gint nDragButton = 1; // default to left button @@ -4257,11 +4277,7 @@ void GtkDragSource::startDrag(const datatransfer::dnd::DragGestureEvent& rEvent, nDragButton = 2; } - // For LibreOffice internal D&D we provide the Transferable without Gtk - // intermediaries as a shortcut, see tdf#100097 for how dbaccess depends on this - g_ActiveDragSource = this; - g_DropSuccessSet = false; - g_DropSuccess = false; + setActiveDragSource(); m_pFrame->startDrag(nDragButton, rEvent.DragOriginX, rEvent.DragOriginY, VclToGdk(sourceActions), pTargetList); diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 976ed97be496..39b3357fe4a2 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -22,6 +22,7 @@ #include <headless/svpvd.hxx> #include <headless/svpbmp.hxx> #include <vcl/inputtypes.hxx> +#include <vcl/transfer.hxx> #include <unx/genpspgraphics.h> #include <rtl/strbuf.hxx> #include <sal/log.hxx> @@ -7945,6 +7946,18 @@ namespace return -1; } + GdkDragAction VclToGdk(sal_Int8 dragOperation) + { + GdkDragAction eRet(static_cast<GdkDragAction>(0)); + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) + eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_COPY); + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) + eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_MOVE); + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) + eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_LINK); + return eRet; + } + struct GtkInstanceTreeIter : public weld::TreeIter { GtkInstanceTreeIter(const GtkInstanceTreeIter* pOrig) @@ -7993,6 +8006,7 @@ private: std::vector<int> m_aSavedSortColumns; std::vector<int> m_aViewColToModelCol; std::vector<int> m_aModelColToViewCol; + rtl::Reference<GtkDragSource> m_xDragSource; bool m_bWorkAroundBadDragRegion; bool m_bInDrag; gint m_nTextCol; @@ -8008,6 +8022,9 @@ private: gulong m_nPopupMenuSignalId; gulong m_nDragBeginSignalId; gulong m_nDragEndSignalId; + gulong m_nDragFailedSignalId; + gulong m_nDragDataDeleteignalId; + gulong m_nDragGetSignalId; gulong m_nKeyPressSignalId; ImplSVEvent* m_pChangeEvent; @@ -8392,15 +8409,63 @@ private: return default_sort_func(pModel, a, b, m_xSorter.get()); } - static void signalDragBegin(GtkWidget*, GdkDragContext*, gpointer widget) + static void signalDragBegin(GtkWidget*, GdkDragContext* context, gpointer widget) { GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); - g_DragSource = pThis; + pThis->signal_drag_begin(context); + } + + void ensure_drag_source() + { + if (!m_xDragSource) + { + m_xDragSource.set(new GtkDragSource); + + m_nDragFailedSignalId = g_signal_connect(m_pWidget, "drag-failed", G_CALLBACK(signalDragFailed), this); + m_nDragDataDeleteignalId = g_signal_connect(m_pWidget, "drag-data-delete", G_CALLBACK(signalDragDelete), this); + m_nDragGetSignalId = g_signal_connect(m_pWidget, "drag-data-get", G_CALLBACK(signalDragDataGet), this); + } } - static void signalDragEnd(GtkWidget*, GdkDragContext*, gpointer) + void signal_drag_begin(GdkDragContext* context) + { + if (m_aDragBeginHdl.Call(*this)) + { + gtk_drag_cancel(context); + return; + } + g_DragSource = this; + if (!m_xDragSource) + return; + m_xDragSource->setActiveDragSource(); + } + + static void signalDragEnd(GtkWidget* /*widget*/, GdkDragContext* context, gpointer widget) { g_DragSource = nullptr; + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + if (pThis->m_xDragSource.is()) + pThis->m_xDragSource->dragEnd(context); + } + + static gboolean signalDragFailed(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkDragResult /*result*/, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->m_xDragSource->dragFailed(); + return false; + } + + static void signalDragDelete(GtkWidget* /*widget*/, GdkDragContext* /*context*/, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->m_xDragSource->dragDelete(); + } + + static void signalDragDataGet(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkSelectionData *data, guint info, + guint /*time*/, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->m_xDragSource->dragDataGet(data, info); } bool signal_key_press(GdkEventKey* pEvent) @@ -8463,6 +8528,9 @@ public: , m_nPopupMenuSignalId(g_signal_connect(pTreeView, "popup-menu", G_CALLBACK(signalPopupMenu), this)) , m_nDragBeginSignalId(g_signal_connect(pTreeView, "drag-begin", G_CALLBACK(signalDragBegin), this)) , m_nDragEndSignalId(g_signal_connect(pTreeView, "drag-end", G_CALLBACK(signalDragEnd), this)) + , m_nDragFailedSignalId(0) + , m_nDragDataDeleteignalId(0) + , m_nDragGetSignalId(0) , m_nKeyPressSignalId(g_signal_connect(pTreeView, "key-press-event", G_CALLBACK(signalKeyPress), this)) , m_pChangeEvent(nullptr) { @@ -9649,6 +9717,24 @@ public: gtk_widget_hide(m_pWidget); } + virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants) override + { + css::uno::Reference<css::datatransfer::XTransferable> xTrans(rHelper.get()); + css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> xListener(rHelper.get()); + + ensure_drag_source(); + + auto aFormats = xTrans->getTransferDataFlavors(); + std::vector<GtkTargetEntry> aGtkTargets(m_xDragSource->FormatsToGtk(aFormats)); + + gtk_tree_view_enable_model_drag_source(m_pTreeView, GDK_BUTTON1_MASK, aGtkTargets.data(), aGtkTargets.size(), VclToGdk(eDNDConstants)); + + for (auto &a : aGtkTargets) + g_free(a.target); + + m_xDragSource->set_datatransfer(xTrans, xListener); + } + virtual void set_selection_mode(SelectionMode eMode) override { disable_notify_events(); @@ -9876,6 +9962,12 @@ public: g_signal_handler_disconnect(m_pTreeView, m_nKeyPressSignalId); g_signal_handler_disconnect(m_pTreeView, m_nDragEndSignalId); g_signal_handler_disconnect(m_pTreeView, m_nDragBeginSignalId); + if (m_nDragFailedSignalId) + g_signal_handler_disconnect(m_pTreeView, m_nDragFailedSignalId); + if (m_nDragDataDeleteignalId) + g_signal_handler_disconnect(m_pTreeView, m_nDragDataDeleteignalId); + if (m_nDragGetSignalId) + g_signal_handler_disconnect(m_pTreeView, m_nDragGetSignalId); g_signal_handler_disconnect(m_pTreeView, m_nPopupMenuSignalId); GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore); g_signal_handler_disconnect(pModel, m_nRowDeletedSignalId); |