summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx191
1 files changed, 104 insertions, 87 deletions
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index bf8fde0e29cc..7202b4681c8d 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -238,47 +238,6 @@ public:
}
};
-//We want to use gtk_clipboard_get_owner own owner-change to distinguish between
-//us gaining the clipboard ownership vs losing it. To do that we need to use
-//gtk_clipboard_set_with_owner and to do that we need a GObject, so define
-//one here for that purpose and just give it a VclGtkClipboard* member
-class VclGtkClipboard;
-
-struct ClipboardOwner
-{
- GObject parent_instance;
-
- /* instance members */
- VclGtkClipboard* m_pThis;
-};
-
-struct ClipboardOwnerClass
-{
- GObjectClass parent_class;
-
- /* class members */
-};
-
-#define CLIPBOARD_OWNER_OBJECT (clipboard_owner_get_type ())
-#define CLIPBOARD_OWNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLIPBOARD_OWNER_OBJECT, ClipboardOwner))
-
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-#endif
-G_DEFINE_TYPE(ClipboardOwner, clipboard_owner, G_TYPE_OBJECT);
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-static void clipboard_owner_class_init (ClipboardOwnerClass *)
-{
-}
-
-static void clipboard_owner_init(ClipboardOwner *)
-{
-}
-
class VclGtkClipboard :
public cppu::WeakComponentImplHelper<
datatransfer::clipboard::XSystemClipboard,
@@ -287,7 +246,6 @@ class VclGtkClipboard :
{
GdkAtom m_nSelection;
osl::Mutex m_aMutex;
- ClipboardOwner* m_pOwner;
gulong m_nOwnerChangedSignalId;
Reference<css::datatransfer::XTransferable> m_aContents;
Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
@@ -349,7 +307,7 @@ public:
void ClipboardGet(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info);
void ClipboardClear(GtkClipboard *clipboard);
- void OwnerChanged(GtkClipboard *clipboard, GdkEvent *event);
+ void OwnerPossiblyChanged(GtkClipboard *clipboard, GdkEvent *event);
};
OUString VclGtkClipboard::getImplementationName() throw( RuntimeException, std::exception )
@@ -370,13 +328,13 @@ sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName ) throw(
Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents() throw( RuntimeException, std::exception )
{
- if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(gtk_clipboard_get(m_nSelection)) &&
- !m_aContents.is())
+ if (!m_aContents.is())
{
//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_nSelection);
}
+
return m_aContents;
}
@@ -388,9 +346,85 @@ void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData
m_aConversionHelper.setSelectionData(m_aContents, selection_data, info);
}
-void VclGtkClipboard::OwnerChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
+namespace
+{
+ const OString& getPID()
+ {
+ static OString sPID;
+ if (!sPID.getLength())
+ {
+ oslProcessIdentifier aProcessId = 0;
+ oslProcessInfo info;
+ info.Size = sizeof (oslProcessInfo);
+ if (osl_getProcessInfo(nullptr, osl_Process_IDENTIFIER, &info) == osl_Process_E_None)
+ aProcessId = info.Ident;
+ sPID = OString::number(aProcessId);
+ }
+ return sPID;
+ }
+}
+
+namespace
+{
+ void ClipboardGetFunc(GtkClipboard *clipboard, GtkSelectionData *selection_data,
+ guint info,
+ gpointer user_data_or_owner)
+ {
+ VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data_or_owner);
+ pThis->ClipboardGet(clipboard, selection_data, info);
+ }
+
+ void ClipboardClearFunc(GtkClipboard *clipboard, gpointer user_data_or_owner)
+ {
+ VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data_or_owner);
+ pThis->ClipboardClear(clipboard);
+ }
+
+ void handle_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer user_data)
+ {
+ VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data);
+ pThis->OwnerPossiblyChanged(clipboard, event);
+ }
+}
+
+void VclGtkClipboard::OwnerPossiblyChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
{
- if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(clipboard))
+ if (!m_aContents.is())
+ return;
+
+ //if gdk_display_supports_selection_notification is not supported, e.g. like
+ //right now under wayland, then you only get owner-changed nofications at
+ //opportune times when the selection might have changed. So here
+ //we see if the selection supports a dummy selection type identifying
+ //our pid, in which case it's us.
+ bool bSelf = false;
+
+ //disconnect and reconnect after gtk_clipboard_wait_for_targets to
+ //avoid possible recursion
+ g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
+
+ OString sTunnel = "application/x-libreoffice-internal-id-" + getPID();
+ GdkAtom *targets;
+ gint n_targets;
+ if (gtk_clipboard_wait_for_targets(clipboard, &targets, &n_targets))
+ {
+ for (gint i = 0; i < n_targets && !bSelf; ++i)
+ {
+ gchar* pName = gdk_atom_name(targets[i]);
+ if (strcmp(pName, sTunnel.getStr()) == 0)
+ {
+ bSelf = true;
+ }
+ g_free(pName);
+ }
+
+ g_free(targets);
+ }
+
+ m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",
+ G_CALLBACK(handle_owner_change), this);
+
+ if (!bSelf)
{
//null out m_aContents to return control to the system-one which
//will be retrieved if getContents is called again
@@ -482,29 +516,6 @@ void VclToGtkHelper::setSelectionData(const Reference<css::datatransfer::XTransf
aData.getLength());
}
-namespace
-{
- void ClipboardGetFunc(GtkClipboard *clipboard, GtkSelectionData *selection_data,
- guint info,
- gpointer user_data_or_owner)
- {
- VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
- pThis->ClipboardGet(clipboard, selection_data, info);
- }
-
- void ClipboardClearFunc(GtkClipboard *clipboard, gpointer user_data_or_owner)
- {
- VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
- pThis->ClipboardClear(clipboard);
- }
-
- void handle_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer user_data)
- {
- VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data);
- pThis->OwnerChanged(clipboard, event);
- }
-}
-
VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
: cppu::WeakComponentImplHelper<datatransfer::clipboard::XSystemClipboard,
datatransfer::clipboard::XFlushableClipboard, XServiceInfo>
@@ -514,8 +525,6 @@ VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",
G_CALLBACK(handle_owner_change), this);
- m_pOwner = CLIPBOARD_OWNER(g_object_new(CLIPBOARD_OWNER_OBJECT, nullptr));
- m_pOwner->m_pThis = this;
}
void VclGtkClipboard::flushClipboard()
@@ -534,8 +543,12 @@ VclGtkClipboard::~VclGtkClipboard()
{
GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
- g_object_unref(m_pOwner);
- ClipboardClear(nullptr);
+ if (!m_aGtkTargets.empty())
+ {
+ gtk_clipboard_clear(clipboard);
+ ClipboardClear(clipboard);
+ }
+ assert(m_aGtkTargets.empty());
}
std::vector<GtkTargetEntry> VclToGtkHelper::FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats)
@@ -593,27 +606,31 @@ void VclGtkClipboard::setContents(
std::list< Reference< datatransfer::clipboard::XClipboardListener > > aListeners( m_aListeners );
datatransfer::clipboard::ClipboardEvent aEv;
+ GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+ if (!m_aGtkTargets.empty())
+ {
+ gtk_clipboard_clear(clipboard);
+ ClipboardClear(clipboard);
+ }
+ assert(m_aGtkTargets.empty());
if (m_aContents.is())
{
css::uno::Sequence<css::datatransfer::DataFlavor> aFormats = xTrans->getTransferDataFlavors();
std::vector<GtkTargetEntry> aGtkTargets(m_aConversionHelper.FormatsToGtk(aFormats));
if (!aGtkTargets.empty())
{
- //if there was a previous gtk_clipboard_set_with_data call then
- //ClipboardClearFunc will be called now
- GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
- if(G_OBJECT(m_pOwner) == gtk_clipboard_get_owner(clipboard))
- gtk_clipboard_clear(clipboard);
- //use with_owner with m_pOwner so we can distinguish in handle_owner_change
- //if we have gained or lost ownership of the clipboard
- gtk_clipboard_set_with_owner(clipboard, aGtkTargets.data(), aGtkTargets.size(),
- ClipboardGetFunc, ClipboardClearFunc, G_OBJECT(m_pOwner));
+ GtkTargetEntry aEntry;
+ OString sTunnel = "application/x-libreoffice-internal-id-" + getPID();
+ aEntry.target = g_strdup(sTunnel.getStr());
+ aEntry.flags = 0;
+ aEntry.info = 0;
+ aGtkTargets.push_back(aEntry);
+
+ gtk_clipboard_set_with_data(clipboard, aGtkTargets.data(), aGtkTargets.size(),
+ ClipboardGetFunc, ClipboardClearFunc, this);
gtk_clipboard_set_can_store(clipboard, aGtkTargets.data(), aGtkTargets.size());
}
- for (auto &a : m_aGtkTargets)
- g_free(a.target);
-
m_aGtkTargets = aGtkTargets;
}
@@ -621,7 +638,7 @@ void VclGtkClipboard::setContents(
aGuard.clear();
- if( xOldOwner.is() && xOldOwner != xClipboardOwner )
+ if (xOldOwner.is() && xOldOwner != xClipboardOwner)
xOldOwner->lostOwnership( this, xOldContents );
for( std::list< Reference< datatransfer::clipboard::XClipboardListener > >::iterator it =
aListeners.begin(); it != aListeners.end() ; ++it )