Project not found: home:pmmu

File mutter-fix-wine-copy-and-paste.patch of Package mutter.16480

diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h
index 36d4bad38..d53073e11 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 8f068dedc..f9b3607a7 100644
--- a/src/x11/meta-x11-selection.c
+++ b/src/x11/meta-x11-selection.c
@@ -79,18 +79,49 @@ static GBytes *
 mimetypes_to_bytes (GList   *mimetypes,
                     Display *xdisplay)
 {
-  gint i = 0, len = g_list_length (mimetypes) + 2;
-  Atom *atoms = g_new0 (Atom, len);
+  GArray *atoms = g_array_new (FALSE, FALSE, sizeof (Atom));
   GList *l;
+  char *mimetype;
+  Atom atom;
+  gboolean utf8_string_found = FALSE, utf8_string_mimetype_found = FALSE;
+  gboolean string_found = FALSE, string_mimetype_found = FALSE;
+  GBytes *bytes;
 
   for (l = mimetypes; l; l = l->next)
-    atoms[i++] = XInternAtom (xdisplay, l->data, False);
+    {
+      mimetype = l->data;
+      atom = XInternAtom (xdisplay, mimetype, False);
+      g_array_append_val (atoms, atom);
+      utf8_string_mimetype_found |= strcmp (mimetype, UTF8_STRING_MIMETYPE) == 0;
+      utf8_string_found |= strcmp (mimetype, "UTF8_STRING") == 0;
+      string_mimetype_found |= strcmp (mimetype, STRING_MIMETYPE) == 0;
+      string_found |= strcmp (mimetype, "STRING") == 0;
+    }
+
+  /* Some X11 clients can only handle STRING/UTF8_STRING but not the
+   * corresponding mimetypes. */
+  if (utf8_string_mimetype_found && !utf8_string_found)
+    {
+      atom = XInternAtom (xdisplay, "UTF8_STRING", False);
+      g_array_append_val (atoms, atom);
+    }
 
-  atoms[i++] = XInternAtom (xdisplay, "TARGETS", False);
-  atoms[i++] = XInternAtom (xdisplay, "TIMESTAMP", False);
-  g_assert (i == len);
+  if (string_mimetype_found && !string_found)
+    {
+      atom = XInternAtom (xdisplay, "STRING", False);
+      g_array_append_val (atoms, atom);
+    }
+
+  atom = XInternAtom (xdisplay, "TARGETS", False);
+  g_array_append_val (atoms, atom);
 
-  return g_bytes_new_take (atoms, len * sizeof (Atom));
+  atom = XInternAtom (xdisplay, "TIMESTAMP", False);
+  g_array_append_val (atoms, atom);
+
+  bytes = g_bytes_new_take (atoms->data, atoms->len * sizeof (Atom));
+  g_array_free (atoms, FALSE);
+
+  return bytes;
 }
 
 static void
@@ -311,6 +342,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 +372,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 +395,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 +485,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 +546,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);
 }
openSUSE Build Service is sponsored by