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);
}