diff options
-rw-r--r-- | compilerplugins/clang/reservedid.cxx | 4 | ||||
-rw-r--r-- | vcl/Library_vclplug_gtk4.mk | 7 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkframe.hxx | 14 | ||||
-rw-r--r-- | vcl/inc/unx/gtk/gtkinst.hxx | 6 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtkframe.cxx | 127 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtkinst.cxx | 147 | ||||
-rw-r--r-- | vcl/unx/gtk4/contentprovider.hxx | 20 | ||||
-rw-r--r-- | vcl/unx/gtk4/gtkframe.cxx | 2 | ||||
-rw-r--r-- | vcl/unx/gtk4/gtkinst.cxx | 2 | ||||
-rw-r--r-- | vcl/unx/gtk4/transferableprovider.cxx | 118 | ||||
-rw-r--r-- | vcl/unx/gtk4/transferableprovider.hxx | 51 |
11 files changed, 299 insertions, 199 deletions
diff --git a/compilerplugins/clang/reservedid.cxx b/compilerplugins/clang/reservedid.cxx index 9927e9c50307..eac62a5b9671 100644 --- a/compilerplugins/clang/reservedid.cxx +++ b/compilerplugins/clang/reservedid.cxx @@ -197,8 +197,6 @@ bool ReservedId::VisitNamedDecl(NamedDecl const * decl) { // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h && s != "_ADOUser" // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h - && s != "_ClipboardContent" // vcl/unx/gtk3/gtkinst.cxx - && s != "_ClipboardContentClass" // vcl/unx/gtk3/gtkinst.cxx && s != "_FcPattern" // vcl/inc/unx/fc_fontoptions.hxx && s != "_GdkDisplay" // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c @@ -212,6 +210,8 @@ bool ReservedId::VisitNamedDecl(NamedDecl const * decl) { && s != "_NotifyingLayout" // vcl/unx/gtk4/notifyinglayout.cxx && s != "_SurfacePaintable" // vcl/unx/gtk3/gtkinst.cxx && s != "_SurfacePaintableClass" // vcl/unx/gtk3/gtkinst.cxx + && s != "_TransferableContent" // vcl/unx/gtk4/transferableprovider.cxx + && s != "_TransferableContentClass" // vcl/unx/gtk4/transferableprovider.cxx && s != "_XRegion" // vcl/unx/generic/gdi/x11cairotextrender.cxx && s != "_XTrap") // vcl/unx/generic/gdi/xrender_peer.hxx { diff --git a/vcl/Library_vclplug_gtk4.mk b/vcl/Library_vclplug_gtk4.mk index 98349413a1d3..8b2d55d9d944 100644 --- a/vcl/Library_vclplug_gtk4.mk +++ b/vcl/Library_vclplug_gtk4.mk @@ -92,12 +92,13 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gtk4,\ vcl/unx/gtk4/salnativewidgets-gtk \ vcl/unx/gtk4/gtkframe \ vcl/unx/gtk4/gtkobject \ - vcl/unx/gtk4/gtksalmenu \ - vcl/unx/gtk4/glomenu \ - vcl/unx/gtk4/gloactiongroup \ + vcl/unx/gtk4/gtksalmenu \ + vcl/unx/gtk4/glomenu \ + vcl/unx/gtk4/gloactiongroup \ vcl/unx/gtk4/hudawareness \ vcl/unx/gtk4/notifyinglayout \ vcl/unx/gtk4/surfacepaintable \ + vcl/unx/gtk4/transferableprovider \ )) ifeq ($(OS),LINUX) diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx index 57005e89a64e..7dcb722968bc 100644 --- a/vcl/inc/unx/gtk/gtkframe.hxx +++ b/vcl/inc/unx/gtk/gtkframe.hxx @@ -61,6 +61,8 @@ class GtkDnDTransferable; class GtkSalMenu; +struct VclToGtkHelper; + class GtkSalFrame final : public SalFrame { struct IMHandler @@ -264,6 +266,10 @@ class GtkSalFrame final : public SalFrame static GdkDragAction signalDragMotion(GtkDropTargetAsync *dest, GdkDrop *drop, double x, double y, gpointer frame); static void signalDragLeave(GtkDropTargetAsync *dest, GdkDrop *drop, gpointer frame); static gboolean signalDragDrop(GtkDropTargetAsync* context, GdkDrop* drop, double x, double y, gpointer frame); + + static void signalDragFailed(GdkDrag* drag, GdkDragCancelReason reason, gpointer frame); + static void signalDragDelete(GdkDrag* drag, gpointer frame); + static void signalDragEnd(GdkDrag* drag, gpointer frame); #else static gboolean signalDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer frame); @@ -460,10 +466,10 @@ public: m_pDragSource = nullptr; } -#if !GTK_CHECK_VERSION(4, 0, 0) - void startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY, - GdkDragAction sourceActions, GtkTargetList* pTargetList); -#endif + void startDrag(const css::datatransfer::dnd::DragGestureEvent& rEvent, + const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, + VclToGtkHelper& rConversionHelper, + GdkDragAction sourceActions); void closePopup(); diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx index 56da7a6885f3..a293662791ae 100644 --- a/vcl/inc/unx/gtk/gtkinst.hxx +++ b/vcl/inc/unx/gtk/gtkinst.hxx @@ -191,9 +191,7 @@ class GtkInstDragSource final : public cppu::WeakComponentImplHelper<css::datatr GtkSalFrame* m_pFrame; css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> m_xListener; css::uno::Reference<css::datatransfer::XTransferable> m_xTrans; -#if !GTK_CHECK_VERSION(4, 0, 0) VclToGtkHelper m_aConversionHelper; -#endif public: GtkInstDragSource() : WeakComponentImplHelper(m_aMutex) @@ -232,7 +230,9 @@ public: void dragFailed(); void dragDelete(); -#if !GTK_CHECK_VERSION(4, 0, 0) +#if GTK_CHECK_VERSION(4, 0, 0) + void dragEnd(GdkDrag* drag); +#else void dragEnd(GdkDragContext* context); void dragDataGet(GtkSelectionData *data, guint info); #endif diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx index 02455ed0edb5..2b133e0868e3 100644 --- a/vcl/unx/gtk3/gtkframe.cxx +++ b/vcl/unx/gtk3/gtkframe.cxx @@ -4186,7 +4186,6 @@ void GtkSalFrame::signalWindowState(GdkToplevel* pSurface, GParamSpec*, gpointer namespace { -#if !GTK_CHECK_VERSION(4,0,0) GdkDragAction VclToGdk(sal_Int8 dragOperation) { GdkDragAction eRet(static_cast<GdkDragAction>(0)); @@ -4198,7 +4197,6 @@ namespace eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_LINK); return eRet; } -#endif sal_Int8 GdkToVcl(GdkDragAction dragOperation) { @@ -5520,58 +5518,63 @@ std::vector<GtkTargetEntry> GtkInstDragSource::FormatsToGtk(const css::uno::Sequ #endif void GtkInstDragSource::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) + 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) { -#if !GTK_CHECK_VERSION(4, 0, 0) set_datatransfer(rTrans, rListener); if (m_pFrame) { - 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 - 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; - } - setActiveDragSource(); - m_pFrame->startDrag(nDragButton, rEvent.DragOriginX, rEvent.DragOriginY, - VclToGdk(sourceActions), pTargetList); - - gtk_target_list_unref(pTargetList); - for (auto &a : aGtkTargets) - g_free(a.target); + m_pFrame->startDrag(rEvent, rTrans, m_aConversionHelper ,VclToGdk(sourceActions)); } else dragFailed(); -#else - (void)rEvent; - (void)sourceActions; - (void)rTrans; - (void)rListener; -#endif } -#if !GTK_CHECK_VERSION(4, 0, 0) -void GtkSalFrame::startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY, - GdkDragAction sourceActions, GtkTargetList* pTargetList) +void GtkSalFrame::startDrag(const css::datatransfer::dnd::DragGestureEvent& rEvent, + const css::uno::Reference<css::datatransfer::XTransferable>& rTrans, + VclToGtkHelper& rConversionHelper, + GdkDragAction sourceActions) { SolarMutexGuard aGuard; assert(m_pDragSource); +#if GTK_CHECK_VERSION(4, 0, 0) + + GdkSeat *pSeat = gdk_display_get_default_seat(getGdkDisplay()); + GdkDrag* pDrag = gdk_drag_begin(widget_get_surface(getMouseEventWidget()), + gdk_seat_get_pointer(pSeat), + transerable_content_new(&rConversionHelper, rTrans.get()), + sourceActions, + rEvent.DragOriginX, rEvent.DragOriginY); + + g_signal_connect(G_OBJECT(pDrag), "drop-performed", G_CALLBACK(signalDragEnd), this); + g_signal_connect(G_OBJECT(pDrag), "cancel", G_CALLBACK(signalDragFailed), this); + g_signal_connect(G_OBJECT(pDrag), "dnd-finished", G_CALLBACK(signalDragDelete), this); + +#else + + auto aFormats = rTrans->getTransferDataFlavors(); + auto aGtkTargets = rConversionHelper.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; + } + GdkEvent aFakeEvent; memset(&aFakeEvent, 0, sizeof(GdkEvent)); aFakeEvent.type = GDK_BUTTON_PRESS; @@ -5580,15 +5583,21 @@ void GtkSalFrame::startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY, 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); + GdkDragContext *pDrag = gtk_drag_begin_with_coordinates(getMouseEventWidget(), + pTargetList, + sourceActions, + nDragButton, + &aFakeEvent, + rEvent.DragOriginX, + rEvent.DragOriginY); + + gtk_target_list_unref(pTargetList); - if (!pContext) + for (auto &a : aGtkTargets) + g_free(a.target); +#endif + + if (!pDrag) m_pDragSource->dragFailed(); } @@ -5605,13 +5614,18 @@ void GtkInstDragSource::dragFailed() } } +#if GTK_CHECK_VERSION(4, 0, 0) +void GtkSalFrame::signalDragFailed(GdkDrag* /*drag*/, GdkDragCancelReason /*reason*/, gpointer frame) +#else gboolean GtkSalFrame::signalDragFailed(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkDragResult /*result*/, gpointer frame) +#endif { GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame); - if (!pThis->m_pDragSource) - return false; - pThis->m_pDragSource->dragFailed(); + if (pThis->m_pDragSource) + pThis->m_pDragSource->dragFailed(); +#if !GTK_CHECK_VERSION(4, 0, 0) return false; +#endif } void GtkInstDragSource::dragDelete() @@ -5627,7 +5641,11 @@ void GtkInstDragSource::dragDelete() } } +#if GTK_CHECK_VERSION(4, 0, 0) +void GtkSalFrame::signalDragDelete(GdkDrag* /*context*/, gpointer frame) +#else void GtkSalFrame::signalDragDelete(GtkWidget* /*widget*/, GdkDragContext* /*context*/, gpointer frame) +#endif { GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame); if (!pThis->m_pDragSource) @@ -5635,12 +5653,20 @@ void GtkSalFrame::signalDragDelete(GtkWidget* /*widget*/, GdkDragContext* /*cont pThis->m_pDragSource->dragDelete(); } +#if GTK_CHECK_VERSION(4, 0, 0) +void GtkInstDragSource::dragEnd(GdkDrag* context) +#else void GtkInstDragSource::dragEnd(GdkDragContext* context) +#endif { if (m_xListener.is()) { datatransfer::dnd::DragSourceDropEvent aEv; +#if GTK_CHECK_VERSION(4, 0, 0) + aEv.DropAction = GdkToVcl(gdk_drag_get_selected_action(context)); +#else aEv.DropAction = GdkToVcl(gdk_drag_context_get_selected_action(context)); +#endif // an internal drop can accept the drop but fail with dropComplete( false ) // this is different than the GTK API if (g_DropSuccessSet) @@ -5654,7 +5680,11 @@ void GtkInstDragSource::dragEnd(GdkDragContext* context) g_ActiveDragSource = nullptr; } +#if GTK_CHECK_VERSION(4, 0, 0) +void GtkSalFrame::signalDragEnd(GdkDrag* context, gpointer frame) +#else void GtkSalFrame::signalDragEnd(GtkWidget* /*widget*/, GdkDragContext* context, gpointer frame) +#endif { GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame); if (!pThis->m_pDragSource) @@ -5662,6 +5692,7 @@ void GtkSalFrame::signalDragEnd(GtkWidget* /*widget*/, GdkDragContext* context, pThis->m_pDragSource->dragEnd(context); } +#if !GTK_CHECK_VERSION(4, 0, 0) void GtkInstDragSource::dragDataGet(GtkSelectionData *data, guint info) { m_aConversionHelper.setSelectionData(m_xTrans, data, info); diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index 88e099fe93ec..ebe2eb7e635c 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -869,12 +869,18 @@ class VclGtkClipboard : std::vector< Reference<css::datatransfer::clipboard::XClipboardListener> > m_aListeners; #if GTK_CHECK_VERSION(4, 0, 0) std::vector<OString> m_aGtkTargets; + TransferableContent* m_pClipboardContent; #else std::vector<GtkTargetEntry> m_aGtkTargets; #endif VclToGtkHelper m_aConversionHelper; DECL_LINK(AsyncSetGtkClipboard, void*, void); + +#if GTK_CHECK_VERSION(4, 0, 0) + DECL_LINK(DetachClipboard, void*, void); +#endif + public: explicit VclGtkClipboard(SelectionType eSelection); @@ -920,16 +926,7 @@ public: virtual void SAL_CALL removeClipboardListener( const Reference< css::datatransfer::clipboard::XClipboardListener >& listener ) override; -#if GTK_CHECK_VERSION(4, 0, 0) - GdkContentFormats* ref_formats(); - void write_mime_type_async(GdkContentProvider* provider, - const char* mime_type, - GOutputStream* stream, - int io_priority, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -#else +#if !GTK_CHECK_VERSION(4, 0, 0) void ClipboardGet(GtkSelectionData *selection_data, guint info); #endif void OwnerPossiblyChanged(GdkClipboard *clipboard); @@ -963,29 +960,15 @@ Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents() //tdf#93887 This is the system clipboard/selection. We fetch it when we are not //the owner of the clipboard and have not already fetched it. m_aContents = new GtkClipboardTransferable(m_eSelection); +#if GTK_CHECK_VERSION(4, 0, 0) + if (m_pClipboardContent) + transerable_content_set_transferable(m_pClipboardContent, m_aContents.get()); +#endif } return m_aContents; } -#if GTK_CHECK_VERSION(4, 0, 0) -void VclGtkClipboard::write_mime_type_async(GdkContentProvider* provider, - const char* mime_type, - GOutputStream* stream, - int io_priority, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - if (!m_aContents.is()) - return; - // tdf#129809 take a reference in case m_aContents is replaced during this - // call - Reference<datatransfer::XTransferable> xCurrentContents(m_aContents); - m_aConversionHelper.setSelectionData(xCurrentContents, provider, mime_type, - stream, io_priority, cancellable, - callback, user_data); -} -#else +#if !GTK_CHECK_VERSION(4, 0, 0) void VclGtkClipboard::ClipboardGet(GtkSelectionData *selection_data, guint info) { if (!m_aContents.is()) @@ -995,9 +978,7 @@ void VclGtkClipboard::ClipboardGet(GtkSelectionData *selection_data, guint info) Reference<datatransfer::XTransferable> xCurrentContents(m_aContents); m_aConversionHelper.setSelectionData(xCurrentContents, selection_data, info); } -#endif -#if !GTK_CHECK_VERSION(4, 0, 0) namespace { const OString& getPID() @@ -1114,6 +1095,11 @@ void VclGtkClipboard::ClipboardClear() } #if GTK_CHECK_VERSION(4, 0, 0) +IMPL_LINK_NOARG(VclGtkClipboard, DetachClipboard, void*, void) +{ + ClipboardClear(); +} + OString VclToGtkHelper::makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor) { OString aEntry = OUStringToOString(rFlavor.MimeType, RTL_TEXTENCODING_UTF8); @@ -1318,6 +1304,9 @@ VclGtkClipboard::VclGtkClipboard(SelectionType eSelection) (m_aMutex) , m_eSelection(eSelection) , m_pSetClipboardEvent(nullptr) +#if GTK_CHECK_VERSION(4, 0, 0) + , m_pClipboardContent(nullptr) +#endif { GdkClipboard* clipboard = clipboard_get(m_eSelection); #if GTK_CHECK_VERSION(4, 0, 0) @@ -1350,6 +1339,7 @@ VclGtkClipboard::~VclGtkClipboard() { #if GTK_CHECK_VERSION(4, 0, 0) gdk_clipboard_set_content(clipboard, nullptr); + m_pClipboardContent = nullptr; #else gtk_clipboard_clear(clipboard); #endif @@ -1423,97 +1413,13 @@ void VclGtkClipboard::SyncGtkClipboard() } } -#if GTK_CHECK_VERSION(4, 0, 0) - -G_BEGIN_DECLS - -#define CLIPBOARD_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), clipboard_content_get_type(), ClipboardContent)) - -struct _ClipboardContent -{ - GdkContentProvider parent; - VclGtkClipboard* clipboard; -}; - -struct _ClipboardContentClass -{ - GdkContentProviderClass parent_class; -}; - -G_DEFINE_TYPE(ClipboardContent, clipboard_content, GDK_TYPE_CONTENT_PROVIDER) - -static void clipboard_content_write_mime_type_async(GdkContentProvider* provider, - const char* mime_type, - GOutputStream* stream, - int io_priority, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - ClipboardContent *content = CLIPBOARD_CONTENT(provider); - content->clipboard->write_mime_type_async(provider, mime_type, stream, io_priority, - cancellable, callback, user_data); -} - -static gboolean clipboard_content_write_mime_type_finish(GdkContentProvider*, - GAsyncResult* result, - GError** error) -{ - return g_task_propagate_boolean(G_TASK(result), error); -} - -static GdkContentFormats* clipboard_content_ref_formats(GdkContentProvider *provider) -{ - ClipboardContent *content = CLIPBOARD_CONTENT(provider); - return content->clipboard->ref_formats(); -} - -static void clipboard_content_detach_clipboard(GdkContentProvider *provider, GdkClipboard*) -{ - ClipboardContent *content = CLIPBOARD_CONTENT(provider); - return content->clipboard->ClipboardClear(); -} - -static void clipboard_content_class_init(ClipboardContentClass* klass) -{ - GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS(klass); - - provider_class->ref_formats = clipboard_content_ref_formats; - provider_class->detach_clipboard = clipboard_content_detach_clipboard; - provider_class->write_mime_type_async = clipboard_content_write_mime_type_async; - provider_class->write_mime_type_finish = clipboard_content_write_mime_type_finish; -} - -static void clipboard_content_init(ClipboardContent*) -{ -} - -static GdkContentProvider* clipboard_content_new(VclGtkClipboard* pClipboard) -{ - ClipboardContent *content = CLIPBOARD_CONTENT(g_object_new(clipboard_content_get_type(), nullptr)); - content->clipboard = pClipboard; - return GDK_CONTENT_PROVIDER(content); -} - -G_END_DECLS - -#endif - -#if GTK_CHECK_VERSION(4, 0, 0) -GdkContentFormats* VclGtkClipboard::ref_formats() -{ - GdkContentFormatsBuilder* pBuilder = gdk_content_formats_builder_new(); - for (const auto& rFormat : m_aGtkTargets) - gdk_content_formats_builder_add_mime_type(pBuilder, rFormat.getStr()); - return gdk_content_formats_builder_free_to_formats(pBuilder); -} -#endif - void VclGtkClipboard::SetGtkClipboard() { GdkClipboard* clipboard = clipboard_get(m_eSelection); #if GTK_CHECK_VERSION(4, 0, 0) - gdk_clipboard_set_content(clipboard, clipboard_content_new(this)); + m_pClipboardContent = TRANSFERABLE_CONTENT(transerable_content_new(&m_aConversionHelper, m_aContents.get())); + transerable_content_set_detach_clipboard_link(m_pClipboardContent, LINK(this, VclGtkClipboard, DetachClipboard)); + gdk_clipboard_set_content(clipboard, GDK_CONTENT_PROVIDER(m_pClipboardContent)); #else gtk_clipboard_set_with_data(clipboard, m_aGtkTargets.data(), m_aGtkTargets.size(), ClipboardGetFunc, ClipboardClearFunc, this); @@ -1535,6 +1441,10 @@ void VclGtkClipboard::setContents( Reference< datatransfer::clipboard::XClipboardOwner > xOldOwner( m_aOwner ); Reference< datatransfer::XTransferable > xOldContents( m_aContents ); m_aContents = xTrans; +#if GTK_CHECK_VERSION(4, 0, 0) + if (m_pClipboardContent) + transerable_content_set_transferable(m_pClipboardContent, m_aContents.get()); +#endif m_aOwner = xClipboardOwner; std::vector< Reference< datatransfer::clipboard::XClipboardListener > > aListeners( m_aListeners ); @@ -1545,6 +1455,7 @@ void VclGtkClipboard::setContents( { #if GTK_CHECK_VERSION(4, 0, 0) gdk_clipboard_set_content(clipboard, nullptr); + m_pClipboardContent = nullptr; #else gtk_clipboard_clear(clipboard); #endif diff --git a/vcl/unx/gtk4/contentprovider.hxx b/vcl/unx/gtk4/contentprovider.hxx deleted file mode 100644 index ffb7b99f0ffb..000000000000 --- a/vcl/unx/gtk4/contentprovider.hxx +++ /dev/null @@ -1,20 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#pragma once - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(ClipboardContent, clipboard_content, CLIPBOARD, CONTENT, GdkContentProvider) - -G_END_DECLS - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/gtk4/gtkframe.cxx b/vcl/unx/gtk4/gtkframe.cxx index 9133b06ad6b3..e446ba8a55d4 100644 --- a/vcl/unx/gtk4/gtkframe.cxx +++ b/vcl/unx/gtk4/gtkframe.cxx @@ -7,6 +7,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "transferableprovider.hxx" + #include "../gtk3/gtkframe.cxx" /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/gtk4/gtkinst.cxx b/vcl/unx/gtk4/gtkinst.cxx index c1f3e310b8e3..502eed2aa246 100644 --- a/vcl/unx/gtk4/gtkinst.cxx +++ b/vcl/unx/gtk4/gtkinst.cxx @@ -10,10 +10,10 @@ // make gtk4 plug advertise correctly as gtk4 #define GTK_TOOLKIT_NAME "gtk4" -#include "contentprovider.hxx" #include "convert3to4.hxx" #include "notifyinglayout.hxx" #include "surfacepaintable.hxx" +#include "transferableprovider.hxx" #include "../gtk3/gtkinst.cxx" diff --git a/vcl/unx/gtk4/transferableprovider.cxx b/vcl/unx/gtk4/transferableprovider.cxx new file mode 100644 index 000000000000..554b80c0d4a6 --- /dev/null +++ b/vcl/unx/gtk4/transferableprovider.cxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <unx/gtk/gtkinst.hxx> +#include "transferableprovider.hxx" + +#define TRANSFERABLE_CONTENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), transerable_content_get_type(), TransferableContent)) + +struct _TransferableContent +{ + GdkContentProvider parent; + VclToGtkHelper* m_pConversionHelper; + css::datatransfer::XTransferable* m_pContents; + Link<void*, void> m_aDetachClipboardLink; +}; + +namespace +{ +struct _TransferableContentClass : public GdkContentProviderClass +{ +}; +} + +G_DEFINE_TYPE(TransferableContent, transerable_content, GDK_TYPE_CONTENT_PROVIDER) + +static void transerable_content_write_mime_type_async(GdkContentProvider* provider, + const char* mime_type, GOutputStream* stream, + int io_priority, GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TransferableContent* self = TRANSFERABLE_CONTENT(provider); + if (!self->m_pContents) + return; + // tdf#129809 take a reference in case m_aContents is replaced during this + // call + css::uno::Reference<css::datatransfer::XTransferable> xCurrentContents(self->m_pContents); + self->m_pConversionHelper->setSelectionData(xCurrentContents, provider, mime_type, stream, + io_priority, cancellable, callback, user_data); +} + +static gboolean transerable_content_write_mime_type_finish(GdkContentProvider*, + GAsyncResult* result, GError** error) +{ + return g_task_propagate_boolean(G_TASK(result), error); +} + +static GdkContentFormats* transerable_content_ref_formats(GdkContentProvider* provider) +{ + TransferableContent* self = TRANSFERABLE_CONTENT(provider); + css::uno::Reference<css::datatransfer::XTransferable> xCurrentContents(self->m_pContents); + if (!xCurrentContents) + return nullptr; + + auto aFormats = xCurrentContents->getTransferDataFlavors(); + std::vector<OString> aGtkTargets(self->m_pConversionHelper->FormatsToGtk(aFormats)); + + GdkContentFormatsBuilder* pBuilder = gdk_content_formats_builder_new(); + for (const auto& rFormat : aGtkTargets) + gdk_content_formats_builder_add_mime_type(pBuilder, rFormat.getStr()); + return gdk_content_formats_builder_free_to_formats(pBuilder); +} + +static void transerable_content_detach_clipboard(GdkContentProvider* provider, GdkClipboard*) +{ + TransferableContent* self = TRANSFERABLE_CONTENT(provider); + self->m_aDetachClipboardLink.Call(nullptr); +} + +static void transerable_content_class_init(TransferableContentClass* klass) +{ + GdkContentProviderClass* provider_class = GDK_CONTENT_PROVIDER_CLASS(klass); + + provider_class->ref_formats = transerable_content_ref_formats; + provider_class->detach_clipboard = transerable_content_detach_clipboard; + provider_class->write_mime_type_async = transerable_content_write_mime_type_async; + provider_class->write_mime_type_finish = transerable_content_write_mime_type_finish; +} + +static void transerable_content_init(TransferableContent* self) +{ + self->m_pConversionHelper = nullptr; + self->m_pContents = nullptr; + // prevent loplugin:unreffun firing on macro generated function + (void)transerable_content_get_instance_private(self); +} + +void transerable_content_set_transferable(TransferableContent* pContent, + css::datatransfer::XTransferable* pTransferable) +{ + pContent->m_pContents = pTransferable; +} + +void transerable_content_set_detach_clipboard_link(TransferableContent* pContent, + const Link<void*, void>& rDetachClipboardLink) +{ + pContent->m_aDetachClipboardLink = rDetachClipboardLink; +} + +GdkContentProvider* transerable_content_new(VclToGtkHelper* pConversionHelper, + css::datatransfer::XTransferable* pTransferable) +{ + TransferableContent* content + = TRANSFERABLE_CONTENT(g_object_new(transerable_content_get_type(), nullptr)); + content->m_pConversionHelper = pConversionHelper; + content->m_pContents = pTransferable; + return GDK_CONTENT_PROVIDER(content); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/gtk4/transferableprovider.hxx b/vcl/unx/gtk4/transferableprovider.hxx new file mode 100644 index 000000000000..df4d643d9f0f --- /dev/null +++ b/vcl/unx/gtk4/transferableprovider.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <tools/link.hxx> + +#include <gtk/gtk.h> + +struct VclToGtkHelper; + +namespace com::sun::star::datatransfer +{ +class XTransferable; +} + +G_BEGIN_DECLS + +/* + Provide a mechanism to provide data from a LibreOffice XTransferable via a + GdkContentProvider for gtk clipboard or dnd +*/ + +G_DECLARE_FINAL_TYPE(TransferableContent, transerable_content, TRANSFERABLE, CONTENT, + GdkContentProvider) + +GdkContentProvider* transerable_content_new(VclToGtkHelper* pConversionHelper, + css::datatransfer::XTransferable* pTransferable); + +/* + Change to a new XTransferable + */ +void transerable_content_set_transferable(TransferableContent* pContent, + css::datatransfer::XTransferable* pTransferable); + +/* + If the GdkContentProvider is used by a clipboard call rDetachClipboardLink on losing + ownership of the clipboard +*/ +void transerable_content_set_detach_clipboard_link(TransferableContent* pContent, + const Link<void*, void>& rDetachClipboardLink); + +G_END_DECLS + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |