10161a6
From 3af38da4f0cb6b6341efad280c73a7733de42bea Mon Sep 17 00:00:00 2001
5f3bcc9
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
5f3bcc9
Date: Fri, 24 Jun 2016 15:06:36 +0100
5f3bcc9
Subject: [PATCH] Resolves: rhbz#1326304 cannot detect loss of wayland
5f3bcc9
 clipboard ownership
4b3e37c
MIME-Version: 1.0
4b3e37c
Content-Type: text/plain; charset=UTF-8
4b3e37c
Content-Transfer-Encoding: 8bit
5f3bcc9
5f3bcc9
gtk_clipboard_get_owner always returns what you set with
5f3bcc9
gtk_clipboard_set_with_owner and that doesn't change if some other
5f3bcc9
application takes over the clipboard
5f3bcc9
5f3bcc9
The "owner-change" signal doesn't contain any useful data under wayland,
5f3bcc9
and doesn't fire when you'd expect either, just when the app becomes
5f3bcc9
active or gets focus or something like that. So you get it when you
5f3bcc9
do have the clipboard and when you don't, so that's no use either to
5f3bcc9
detect loss of clipboard ownership
5f3bcc9
5f3bcc9
So, forget about clipboard ownership, and always take the data to
5f3bcc9
be pasted from the system clipboard, so when we are pasting from ourselves
5f3bcc9
its "paste"->m_aSystemContents->gtk->"copy"->m_aOurContents
5f3bcc9
5f3bcc9
Undoubtedly something else will break now
5f3bcc9
5f3bcc9
Change-Id: I32f2e1a2cc3310687f61a094fdfa940fa0cfcc39
4b3e37c
4b3e37c
Resolves: rhbz#1350478 identify that we own the selection with a unique target
4b3e37c
4b3e37c
so we can tell that we own the selection in the absence of reliable selection
4b3e37c
ownership notifications under wayland
4b3e37c
4b3e37c
Note that gnome#768177 means that requests for CLIPBOARD targets after
4b3e37c
requests for PRIMARY targets can time out, which is why my attempts at
4b3e37c
doing this before giving up with
4b3e37c
4b3e37c
commit 88cd9dd591d7921e5bce33c170b457ae5aa871bb
4b3e37c
Author: Caolán McNamara <caolanm@redhat.com>
4b3e37c
Date:   Fri Jun 24 15:06:36 2016 +0100
4b3e37c
4b3e37c
    Resolves: rhbz#1326304 cannot detect loss of wayland clipboard ownership
4b3e37c
4b3e37c
didn't work.
4b3e37c
4b3e37c
Change-Id: I1154899e478b6e0cc6f70aa0c90c26663299072c
4b3e37c
(cherry picked from commit 88f7aae022bedd61588424a11bbc033217ba4e43)
5f3bcc9
---
10161a6
 vcl/unx/gtk3/gtk3gtkinst.cxx | 124 ++++++++++++++++++++++---------------------
10161a6
 1 file changed, 63 insertions(+), 61 deletions(-)
5f3bcc9
5f3bcc9
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
10161a6
index ed64ded..8b01166 100644
5f3bcc9
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
5f3bcc9
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
10161a6
@@ -238,47 +238,6 @@ public:
5f3bcc9
     }
5f3bcc9
 };
5f3bcc9
 
5f3bcc9
-//We want to use gtk_clipboard_get_owner own owner-change to distinguish between
5f3bcc9
-//us gaining the clipboard ownership vs losing it. To do that we need to use
5f3bcc9
-//gtk_clipboard_set_with_owner and to do that we need a GObject, so define
5f3bcc9
-//one here for that purpose and just give it a VclGtkClipboard* member
5f3bcc9
-class VclGtkClipboard;
5f3bcc9
-
10161a6
-struct ClipboardOwner
5f3bcc9
-{
5f3bcc9
-    GObject parent_instance;
5f3bcc9
-
5f3bcc9
-    /* instance members */
5f3bcc9
-    VclGtkClipboard* m_pThis;
5f3bcc9
-};
5f3bcc9
-
10161a6
-struct ClipboardOwnerClass
5f3bcc9
-{
5f3bcc9
-  GObjectClass parent_class;
5f3bcc9
-
5f3bcc9
-  /* class members */
5f3bcc9
-};
5f3bcc9
-
5f3bcc9
-#define CLIPBOARD_OWNER_OBJECT           (clipboard_owner_get_type ())
5f3bcc9
-#define CLIPBOARD_OWNER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLIPBOARD_OWNER_OBJECT, ClipboardOwner))
5f3bcc9
-
5f3bcc9
-#ifdef __GNUC__
5f3bcc9
-#pragma GCC diagnostic push
5f3bcc9
-#pragma GCC diagnostic ignored "-Wunused-function"
5f3bcc9
-#endif
5f3bcc9
-G_DEFINE_TYPE(ClipboardOwner, clipboard_owner, G_TYPE_OBJECT);
5f3bcc9
-#ifdef __GNUC__
5f3bcc9
-#pragma GCC diagnostic pop
5f3bcc9
-#endif
5f3bcc9
-
5f3bcc9
-static void clipboard_owner_class_init (ClipboardOwnerClass *)
5f3bcc9
-{
5f3bcc9
-}
5f3bcc9
-
5f3bcc9
-static void clipboard_owner_init(ClipboardOwner *)
5f3bcc9
-{
5f3bcc9
-}
5f3bcc9
-
5f3bcc9
 class VclGtkClipboard :
5f3bcc9
         public cppu::WeakComponentImplHelper<
5f3bcc9
         datatransfer::clipboard::XSystemClipboard,
10161a6
@@ -287,7 +246,6 @@ class VclGtkClipboard :
5f3bcc9
 {
5f3bcc9
     GdkAtom                                                  m_nSelection;
5f3bcc9
     osl::Mutex                                               m_aMutex;
5f3bcc9
-    ClipboardOwner*                                          m_pOwner;
4b3e37c
     gulong                                                   m_nOwnerChangedSignalId;
4b3e37c
     Reference<css::datatransfer::XTransferable>              m_aContents;
5f3bcc9
     Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
10161a6
@@ -349,7 +307,7 @@ public:
5f3bcc9
 
5f3bcc9
     void ClipboardGet(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info);
5f3bcc9
     void ClipboardClear(GtkClipboard *clipboard);
5f3bcc9
-    void OwnerChanged(GtkClipboard *clipboard, GdkEvent *event);
4b3e37c
+    void OwnerPossiblyChanged(GtkClipboard *clipboard, GdkEvent *event);
5f3bcc9
 };
5f3bcc9
 
5f3bcc9
 OUString VclGtkClipboard::getImplementationName() throw( RuntimeException, std::exception )
10161a6
@@ -370,13 +328,13 @@ sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName ) throw(
5f3bcc9
 
5f3bcc9
 Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents() throw( RuntimeException, std::exception )
5f3bcc9
 {
5f3bcc9
-    if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(gtk_clipboard_get(m_nSelection)) &&
5f3bcc9
-        !m_aContents.is())
4b3e37c
+    if (!m_aContents.is())
4b3e37c
     {
4b3e37c
         //tdf#93887 This is the system clipboard/selection. We fetch it when we are not
4b3e37c
         //the owner of the clipboard and have not already fetched it.
4b3e37c
         m_aContents = new GtkClipboardTransferable(m_nSelection);
4b3e37c
     }
4b3e37c
+
4b3e37c
     return m_aContents;
5f3bcc9
 }
5f3bcc9
 
10161a6
@@ -388,9 +346,55 @@ void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData
4b3e37c
     m_aConversionHelper.setSelectionData(m_aContents, selection_data, info);
5f3bcc9
 }
5f3bcc9
 
4b3e37c
-void VclGtkClipboard::OwnerChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
4b3e37c
+namespace
10161a6
+{
4b3e37c
+    const OString& getPID()
4b3e37c
+    {
4b3e37c
+        static OString sPID;
4b3e37c
+        if (!sPID.getLength())
4b3e37c
+        {
4b3e37c
+            oslProcessIdentifier aProcessId = 0;
4b3e37c
+            oslProcessInfo info;
4b3e37c
+            info.Size = sizeof (oslProcessInfo);
4b3e37c
+            if (osl_getProcessInfo(nullptr, osl_Process_IDENTIFIER, &info) == osl_Process_E_None)
4b3e37c
+                aProcessId = info.Ident;
4b3e37c
+            sPID = OString::number(aProcessId);
4b3e37c
+        }
4b3e37c
+        return sPID;
4b3e37c
+    }
4b3e37c
+}
4b3e37c
+
4b3e37c
+void VclGtkClipboard::OwnerPossiblyChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
10161a6
 {
10161a6
-    if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(clipboard))
4b3e37c
+    if (!m_aContents.is())
4b3e37c
+        return;
4b3e37c
+
4b3e37c
+    //if gdk_display_supports_selection_notification is not supported, e.g. like
4b3e37c
+    //right now under wayland, then you only get owner-changed nofications at
4b3e37c
+    //opportune times when the selection might have changed. So here
4b3e37c
+    //we see if the selection supports a dummy selection type identifying
4b3e37c
+    //our pid, in which case it's us.
4b3e37c
+    bool bSelf = false;
4b3e37c
+
4b3e37c
+    OString sTunnel = "application/x-libreoffice-internal-id-" + getPID();
4b3e37c
+    GdkAtom *targets;
4b3e37c
+    gint n_targets;
4b3e37c
+    if (gtk_clipboard_wait_for_targets(clipboard, &targets, &n_targets))
4b3e37c
+    {
4b3e37c
+        for (gint i = 0; i < n_targets && !bSelf; ++i)
4b3e37c
+        {
4b3e37c
+            gchar* pName = gdk_atom_name(targets[i]);
4b3e37c
+            if (strcmp(pName, sTunnel.getStr()) == 0)
4b3e37c
+            {
4b3e37c
+                bSelf = true;
4b3e37c
+            }
4b3e37c
+            g_free(pName);
4b3e37c
+        }
4b3e37c
+
4b3e37c
+        g_free(targets);
4b3e37c
+    }
4b3e37c
+
4b3e37c
+    if (!bSelf)
4b3e37c
     {
4b3e37c
         //null out m_aContents to return control to the system-one which
4b3e37c
         //will be retrieved if getContents is called again
10161a6
@@ -488,20 +492,20 @@ namespace
5f3bcc9
                           guint info,
5f3bcc9
                           gpointer user_data_or_owner)
5f3bcc9
     {
5f3bcc9
-        VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
5f3bcc9
+        VclGtkClipboard* pThis = reinterpret_cast<VclGtkClipboard*>(user_data_or_owner);
5f3bcc9
         pThis->ClipboardGet(clipboard, selection_data, info);
5f3bcc9
     }
5f3bcc9
 
5f3bcc9
     void ClipboardClearFunc(GtkClipboard *clipboard, gpointer user_data_or_owner)
5f3bcc9
     {
5f3bcc9
-        VclGtkClipboard* pThis = CLIPBOARD_OWNER(user_data_or_owner)->m_pThis;
5f3bcc9
+        VclGtkClipboard* pThis = reinterpret_cast<VclGtkClipboard*>(user_data_or_owner);
5f3bcc9
         pThis->ClipboardClear(clipboard);
5f3bcc9
     }
4b3e37c
 
4b3e37c
     void handle_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer user_data)
4b3e37c
     {
4b3e37c
         VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data);
5f3bcc9
-        pThis->OwnerChanged(clipboard, event);
4b3e37c
+        pThis->OwnerPossiblyChanged(clipboard, event);
4b3e37c
     }
5f3bcc9
 }
5f3bcc9
 
10161a6
@@ -514,8 +518,6 @@ VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
4b3e37c
     GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
4b3e37c
     m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",
4b3e37c
                                                G_CALLBACK(handle_owner_change), this);
5f3bcc9
-    m_pOwner = CLIPBOARD_OWNER(g_object_new(CLIPBOARD_OWNER_OBJECT, nullptr));
5f3bcc9
-    m_pOwner->m_pThis = this;
5f3bcc9
 }
5f3bcc9
 
5f3bcc9
 void VclGtkClipboard::flushClipboard()
10161a6
@@ -534,7 +536,6 @@ VclGtkClipboard::~VclGtkClipboard()
5f3bcc9
 {
4b3e37c
     GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
4b3e37c
     g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
5f3bcc9
-    g_object_unref(m_pOwner);
5f3bcc9
     ClipboardClear(nullptr);
5f3bcc9
 }
5f3bcc9
 
10161a6
@@ -599,15 +600,16 @@ void VclGtkClipboard::setContents(
5f3bcc9
         std::vector<GtkTargetEntry> aGtkTargets(m_aConversionHelper.FormatsToGtk(aFormats));
5f3bcc9
         if (!aGtkTargets.empty())
5f3bcc9
         {
5f3bcc9
-            //if there was a previous gtk_clipboard_set_with_data call then
5f3bcc9
-            //ClipboardClearFunc will be called now
4b3e37c
+            GtkTargetEntry aEntry;
4b3e37c
+            OString sTunnel = "application/x-libreoffice-internal-id-" + getPID();
4b3e37c
+            aEntry.target = g_strdup(sTunnel.getStr());
4b3e37c
+            aEntry.flags = 0;
4b3e37c
+            aEntry.info = 0;
4b3e37c
+            aGtkTargets.push_back(aEntry);
4b3e37c
+
4b3e37c
             GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
5f3bcc9
-            if(G_OBJECT(m_pOwner) == gtk_clipboard_get_owner(clipboard))
5f3bcc9
-                gtk_clipboard_clear(clipboard);
5f3bcc9
-            //use with_owner with m_pOwner so we can distinguish in handle_owner_change
5f3bcc9
-            //if we have gained or lost ownership of the clipboard
5f3bcc9
-            gtk_clipboard_set_with_owner(clipboard, aGtkTargets.data(), aGtkTargets.size(),
5f3bcc9
-                                        ClipboardGetFunc, ClipboardClearFunc, G_OBJECT(m_pOwner));
5f3bcc9
+            gtk_clipboard_set_with_data(clipboard, aGtkTargets.data(), aGtkTargets.size(),
5f3bcc9
+                                        ClipboardGetFunc, ClipboardClearFunc, this);
5f3bcc9
             gtk_clipboard_set_can_store(clipboard, aGtkTargets.data(), aGtkTargets.size());
5f3bcc9
         }
5f3bcc9
 
5f3bcc9
-- 
5f3bcc9
2.7.4
5f3bcc9