[mutter/gnome-3-36] x11: Allow X11 clients to clear the selection



commit e8d9996c9ca009f44593754564d03256a18c139c
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Apr 20 16:49:24 2020 +0200

    x11: Allow X11 clients to clear the selection
    
    According to the XSetSelectionOwner libX11 documentation:
    
      [...] If the owner window it has specified in the request is later
      destroyed, the owner of the selection automatically reverts to None,
      but the last-change time is not affected.
    
    This is indeed visible through the selection_timestamp field in
    XFixesSelectionNotify events.
    
    Use this to check whether the selection time is recent-ish (thus
    likely coming from an explicit XSetSelectionOwner request) and honor
    the client intent by setting a "NULL" owner. If the selection time
    is too old, it's definitely an indication of the owner client being
    closed, the scenario where we do want the clipboard manager to take
    over.
    
    This fixes two usecases:
    - X11 LibreOffice / WPS clear the selection each time before copying
      its own content. Mutter's clipboard manager would see each of those
      as a hint to take over, competing with the client over selection
      ownership. This would simply no longer happen
    - Password managers may want to clear the selection, which would be
      frustrated by our clipboard manager.
    
    There's a slight window of opportunity for the heuristics to fail
    though, if a X11 client sets the selection and closes within 50ms, we
    would miss the clipboard manager taking over.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1206
    
    (cherry picked from commit 5671f0a284a5875f7d964a4d368470c33581ba80)

 src/x11/meta-x11-selection.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)
---
diff --git a/src/x11/meta-x11-selection.c b/src/x11/meta-x11-selection.c
index 4f628d1f7..e55a1995d 100644
--- a/src/x11/meta-x11-selection.c
+++ b/src/x11/meta-x11-selection.c
@@ -24,6 +24,7 @@
 #include <gdk/gdkx.h>
 
 #include "core/meta-selection-private.h"
+#include "meta/meta-selection-source-memory.h"
 #include "x11/meta-selection-source-x11-private.h"
 #include "x11/meta-x11-selection-output-stream-private.h"
 #include "x11/meta-x11-selection-private.h"
@@ -31,6 +32,13 @@
 #define UTF8_STRING_MIMETYPE "text/plain;charset=utf-8"
 #define STRING_MIMETYPE "text/plain"
 
+/* Set an arbitrary (although generous) threshold to determine whether a
+ * XFixesSelectionNotify corresponds to a XSetSelectionOwner from another
+ * client. The selection timestamp is not updated if the owner client is
+ * closed.
+ */
+#define SELECTION_CLEARED_BY_CLIENT(e) (e->timestamp - e->selection_timestamp < 50)
+
 static gboolean
 atom_to_selection_type (Display           *xdisplay,
                         Atom               selection,
@@ -332,9 +340,19 @@ meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
 
   x11_display->selection.cancellables[selection_type] = g_cancellable_new ();
 
-  if (event->owner == None)
+  if (event->owner == None && x11_display->selection.owners[selection_type])
     {
-      if (x11_display->selection.owners[selection_type])
+      if (SELECTION_CLEARED_BY_CLIENT (event))
+        {
+          MetaSelectionSource *source;
+
+          /* Replace with an empty owner */
+          source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
+          g_set_object (&x11_display->selection.owners[selection_type], source);
+          meta_selection_set_owner (selection, selection_type, source);
+          g_object_unref (source);
+        }
+      else
         {
           /* An X client went away, clear the selection */
           meta_selection_unset_owner (selection, selection_type,
@@ -342,7 +360,7 @@ meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
           g_clear_object (&x11_display->selection.owners[selection_type]);
         }
     }
-  else if (event->owner != x11_display->selection.xwindow)
+  else if (event->owner != None && event->owner != x11_display->selection.xwindow)
     {
       SourceNewData *data;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]