[Libreoffice-commits] core.git: Branch 'libreoffice-5-2' - 2 commits - vcl/inc vcl/unx

Caolán McNamara caolanm at redhat.com
Tue Oct 25 07:37:20 UTC 2016


 vcl/inc/unx/gtk/gtkinst.hxx  |    3 
 vcl/unx/gtk3/gtk3gtkinst.cxx |  200 ++++++++++++++++++++++++-------------------
 2 files changed, 115 insertions(+), 88 deletions(-)

New commits:
commit 92b5045a2895eeaddc839a2b40b7c9da625ef4af
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Fri Jun 24 15:06:36 2016 +0100

    Related: tdf#98831 backport gtk3 clipboard fixes
    
    Resolves: rhbz#1326304 cannot detect loss of wayland clipboard ownership
    
    gtk_clipboard_get_owner always returns what you set with
    gtk_clipboard_set_with_owner and that doesn't change if some other
    application takes over the clipboard
    
    The "owner-change" signal doesn't contain any useful data under wayland,
    and doesn't fire when you'd expect either, just when the app becomes
    active or gets focus or something like that. So you get it when you
    do have the clipboard and when you don't, so that's no use either to
    detect loss of clipboard ownership
    
    So, forget about clipboard ownership, and always take the data to
    be pasted from the system clipboard, so when we are pasting from ourselves
    its "paste"->m_aSystemContents->gtk->"copy"->m_aOurContents
    
    Resolves: rhbz#1350478 identify that we own the selection with a unique target
    
    so we can tell that we own the selection in the absence of reliable selection
    ownership notifications under wayland
    
    Note that gnome#768177 means that requests for CLIPBOARD targets after
    requests for PRIMARY targets can time out, which is why my attempts at
    doing this before giving up with
    
    commit 88cd9dd591d7921e5bce33c170b457ae5aa871bb
    Author: Caolán McNamara <caolanm at redhat.com>
    Date:   Fri Jun 24 15:06:36 2016 +0100
    
        Resolves: rhbz#1326304 cannot detect loss of wayland clipboard ownership
    
    didn't work.
    
    (cherry picked from commit 88f7aae022bedd61588424a11bbc033217ba4e43)
    
    Resolves: rhbz#1352965 gtk3 infinite clipboard recursion with clipit installed
    
    Related: rhbz#1351369 gtk3 clipboards have to live to end once created
    
    like the other platforms do
    
    Change-Id: I32f2e1a2cc3310687f61a094fdfa940fa0cfcc39
    1154899e478b6e0cc6f70aa0c90c26663299072c
    b67afaf532b8409e05fffbf1b8312d664460567d
    31340254573d13dc808d1e3038e3a36ae97f6c22
    d9c12b7ce6458348890d7c7ff7fdb2cd37c4601c
    Related: rhbz#1362451 avoid recursive ownerchanged handling during ownerchange
    Reviewed-on: https://gerrit.libreoffice.org/30019
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index bf8fde0..7202b468 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 )
commit 3284234de21c65f58bbad6bef8d40ae5bc5a8ea5
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Jul 12 20:31:52 2016 +0100

    Resolves: tdf#101457 gtk3 clipboards have to live to end once created
    
    was Related: rhbz#1351369 gtk3 clipboards have to live to end once created
    
    like the other platforms do
    
    (cherry picked from commit 962e0bb4b31265b046fe4fb57d3087e20f5fe4ef)
    
    Change-Id: I31340254573d13dc808d1e3038e3a36ae97f6c22
    Reviewed-on: https://gerrit.libreoffice.org/30010
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
index f1ee273..941fa4a 100644
--- a/vcl/inc/unx/gtk/gtkinst.hxx
+++ b/vcl/inc/unx/gtk/gtkinst.hxx
@@ -248,6 +248,9 @@ public:
 
 private:
     std::vector<GtkSalTimer *>  m_aTimers;
+#if GTK_CHECK_VERSION(3,0,0)
+    std::unordered_map< GdkAtom, css::uno::Reference<css::uno::XInterface> > m_aClipboards;
+#endif
     bool                        IsTimerExpired();
     bool                        bNeedsInit;
     cairo_font_options_t*       m_pLastCairoFontOptions;
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index ed64ded..bf8fde0 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -669,7 +669,14 @@ Reference< XInterface > GtkInstance::CreateClipboard(const Sequence< Any >& argu
 
     GdkAtom nSelection = (sel == "CLIPBOARD") ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY;
 
-    return Reference< XInterface >( static_cast<cppu::OWeakObject *>(new VclGtkClipboard(nSelection)) );
+    auto it = m_aClipboards.find(nSelection);
+    if (it != m_aClipboards.end())
+        return it->second;
+
+    Reference<XInterface> xClipboard(static_cast<cppu::OWeakObject *>(new VclGtkClipboard(nSelection)));
+    m_aClipboards[nSelection] = xClipboard;
+
+    return xClipboard;
 }
 
 GtkDropTarget::GtkDropTarget()


More information about the Libreoffice-commits mailing list