[Libreoffice-commits] core.git: vcl/unx

Caolán McNamara caolanm at redhat.com
Wed Jun 29 13:30:10 UTC 2016


 vcl/unx/gtk3/gtk3gtkinst.cxx |  107 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 92 insertions(+), 15 deletions(-)

New commits:
commit 88f7aae022bedd61588424a11bbc033217ba4e43
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 29 13:43:39 2016 +0100

    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.
    
    Change-Id: I1154899e478b6e0cc6f70aa0c90c26663299072c

diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 6be4438..363de3d 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -246,8 +246,8 @@ class VclGtkClipboard :
 {
     GdkAtom                                                  m_nSelection;
     osl::Mutex                                               m_aMutex;
-    Reference<css::datatransfer::XTransferable>              m_aOurContents;
-    Reference<css::datatransfer::XTransferable>              m_aSystemContents;
+    gulong                                                   m_nOwnerChangedSignalId;
+    Reference<css::datatransfer::XTransferable>              m_aContents;
     Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
     std::list< Reference<css::datatransfer::clipboard::XClipboardListener> > m_aListeners;
     std::vector<GtkTargetEntry> m_aGtkTargets;
@@ -307,6 +307,7 @@ public:
 
     void ClipboardGet(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info);
     void ClipboardClear(GtkClipboard *clipboard);
+    void OwnerPossiblyChanged(GtkClipboard *clipboard, GdkEvent *event);
 };
 
 OUString VclGtkClipboard::getImplementationName() throw( RuntimeException, std::exception )
@@ -327,17 +328,79 @@ sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName ) throw(
 
 Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents() throw( RuntimeException, std::exception )
 {
-    if (!m_aSystemContents.is())
-        m_aSystemContents= new GtkClipboardTransferable(m_nSelection);
-    return m_aSystemContents;
+    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;
 }
 
 void VclGtkClipboard::ClipboardGet(GtkClipboard* /*clipboard*/, GtkSelectionData *selection_data,
                                    guint info)
 {
-    if (!m_aOurContents.is())
+    if (!m_aContents.is())
         return;
-    m_aConversionHelper.setSelectionData(m_aOurContents, selection_data, info);
+    m_aConversionHelper.setSelectionData(m_aContents, selection_data, info);
+}
+
+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;
+    }
+}
+
+void VclGtkClipboard::OwnerPossiblyChanged(GtkClipboard* clipboard, GdkEvent* /*event*/)
+{
+    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;
+
+    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);
+    }
+
+    if (!bSelf)
+    {
+        //null out m_aContents to return control to the system-one which
+        //will be retrieved if getContents is called again
+        setContents(Reference<css::datatransfer::XTransferable>(),
+                    Reference<css::datatransfer::clipboard::XClipboardOwner>());
+    }
 }
 
 void VclGtkClipboard::ClipboardClear(GtkClipboard * /*clipboard*/)
@@ -438,6 +501,12 @@ namespace
         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);
+    }
 }
 
 VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
@@ -446,6 +515,9 @@ VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
         (m_aMutex)
     , m_nSelection(nSelection)
 {
+    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+    m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",
+                                               G_CALLBACK(handle_owner_change), this);
 }
 
 void VclGtkClipboard::flushClipboard()
@@ -462,6 +534,8 @@ void VclGtkClipboard::flushClipboard()
 
 VclGtkClipboard::~VclGtkClipboard()
 {
+    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
+    g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
     ClipboardClear(nullptr);
 }
 
@@ -513,24 +587,27 @@ void VclGtkClipboard::setContents(
 {
     osl::ClearableMutexGuard aGuard( m_aMutex );
     Reference< datatransfer::clipboard::XClipboardOwner > xOldOwner( m_aOwner );
-    Reference< datatransfer::XTransferable > xOldContents(m_aOurContents);
-    m_aOurContents = xTrans;
+    Reference< datatransfer::XTransferable > xOldContents( m_aContents );
+    m_aContents = xTrans;
     m_aOwner = xClipboardOwner;
 
     std::list< Reference< datatransfer::clipboard::XClipboardListener > > aListeners( m_aListeners );
     datatransfer::clipboard::ClipboardEvent aEv;
 
-    //if there was a previous gtk_clipboard_set_with_data call then
-    //ClipboardClearFunc will be called now
-    GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
-    gtk_clipboard_clear(clipboard);
-
-    if (m_aOurContents.is())
+    if (m_aContents.is())
     {
         css::uno::Sequence<css::datatransfer::DataFlavor> aFormats = xTrans->getTransferDataFlavors();
         std::vector<GtkTargetEntry> aGtkTargets(m_aConversionHelper.FormatsToGtk(aFormats));
         if (!aGtkTargets.empty())
         {
+            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);
+
+            GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
             gtk_clipboard_set_with_data(clipboard, aGtkTargets.data(), aGtkTargets.size(),
                                         ClipboardGetFunc, ClipboardClearFunc, this);
             gtk_clipboard_set_can_store(clipboard, aGtkTargets.data(), aGtkTargets.size());


More information about the Libreoffice-commits mailing list