summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compilerplugins/clang/reservedid.cxx4
-rw-r--r--vcl/Library_vclplug_gtk4.mk7
-rw-r--r--vcl/inc/unx/gtk/gtkframe.hxx14
-rw-r--r--vcl/inc/unx/gtk/gtkinst.hxx6
-rw-r--r--vcl/unx/gtk3/gtkframe.cxx127
-rw-r--r--vcl/unx/gtk3/gtkinst.cxx147
-rw-r--r--vcl/unx/gtk4/contentprovider.hxx20
-rw-r--r--vcl/unx/gtk4/gtkframe.cxx2
-rw-r--r--vcl/unx/gtk4/gtkinst.cxx2
-rw-r--r--vcl/unx/gtk4/transferableprovider.cxx118
-rw-r--r--vcl/unx/gtk4/transferableprovider.hxx51
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: */