[mutter/gnome-3-36] x11: Handle selection windows being destroyed before new selection



commit 299569c3b85088b4f6f32a7519328b48e44a81c5
Author: Sebastian Keller <skeller gnome org>
Date:   Tue Jul 14 19:02:06 2020 +0200

    x11: Handle selection windows being destroyed before new selection
    
    Wine destroys its old selection window immediately before creating a new
    selection. This would trigger restoring the clipboard, which would
    overwrite the new selection with the old one. The selection window
    however can also be destroyed as part of the shutdown process of
    applications, such as Chromium for example. In those cases we want the
    clipboard to be restored after the selection window has been destroyed.
    
    Solve this by not immediately restoring the clipboard but instead using
    a timeout which can be canceled by any new selection owner, such as in
    the Wine case.
    
    Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1338
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1369
    
    (cherry picked from commit e1c4e5588061610b5016766253fa2930e0054826)

 src/x11/meta-x11-display-private.h |  1 +
 src/x11/meta-x11-selection.c       | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)
---
diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h
index 36d4bad38e..d53073e111 100644
--- a/src/x11/meta-x11-display-private.h
+++ b/src/x11/meta-x11-display-private.h
@@ -127,6 +127,7 @@ struct _MetaX11Display
 
   struct {
     Window xwindow;
+    guint timeout_id;
     MetaSelectionSource *owners[META_N_SELECTION_TYPES];
     GCancellable *cancellables[META_N_SELECTION_TYPES];
 
diff --git a/src/x11/meta-x11-selection.c b/src/x11/meta-x11-selection.c
index 8f068dedc9..77659fcfaa 100644
--- a/src/x11/meta-x11-selection.c
+++ b/src/x11/meta-x11-selection.c
@@ -311,6 +311,22 @@ source_new_cb (GObject      *object,
   g_free (data);
 }
 
+static gboolean
+unset_clipboard_owner (gpointer data)
+{
+  MetaDisplay *display = meta_get_display ();
+  MetaSelection *selection = meta_display_get_selection (display);
+  MetaX11Display *x11_display = meta_display_get_x11_display (display);
+
+  meta_selection_unset_owner (selection, META_SELECTION_CLIPBOARD,
+                              x11_display->selection.owners[META_SELECTION_CLIPBOARD]);
+  g_clear_object (&x11_display->selection.owners[META_SELECTION_CLIPBOARD]);
+
+  x11_display->selection.timeout_id = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
 static gboolean
 meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
                                                    XEvent         *xevent)
@@ -325,6 +341,9 @@ meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
 
   selection = meta_display_get_selection (meta_get_display ());
 
+  if (selection_type == META_SELECTION_CLIPBOARD)
+    g_clear_handle_id (&x11_display->selection.timeout_id, g_source_remove);
+
   if (x11_display->selection.cancellables[selection_type])
     {
       g_cancellable_cancel (x11_display->selection.cancellables[selection_type]);
@@ -345,6 +364,19 @@ meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
           meta_selection_set_owner (selection, selection_type, source);
           g_object_unref (source);
         }
+      else if (event->subtype == XFixesSelectionWindowDestroyNotify &&
+               selection_type == META_SELECTION_CLIPBOARD)
+        {
+          /* Selection window might have gotten destroyed as part of application
+           * shutdown. Trigger restoring clipboard, but wait a bit, because some
+           * clients, like wine, destroy the old window immediately before a new
+           * selection. Restoring the clipboard in this case would overwrite the
+           * new selection, so this will be cancelled when a new selection
+           * arrives. */
+          x11_display->selection.timeout_id = g_timeout_add (10,
+                                                             unset_clipboard_owner,
+                                                             NULL);
+        }
       else
         {
           /* An X client went away, clear the selection */
@@ -422,6 +454,7 @@ meta_x11_selection_init (MetaX11Display *x11_display)
   attributes.event_mask = PropertyChangeMask | SubstructureNotifyMask;
   attributes.override_redirect = True;
 
+  x11_display->selection.timeout_id = 0;
   x11_display->selection.xwindow =
     XCreateWindow (x11_display->xdisplay,
                    x11_display->xroot,
@@ -482,4 +515,6 @@ meta_x11_selection_shutdown (MetaX11Display *x11_display)
       XDestroyWindow (x11_display->xdisplay, x11_display->selection.xwindow);
       x11_display->selection.xwindow = None;
     }
+
+  g_clear_handle_id (&x11_display->selection.timeout_id, g_source_remove);
 }


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