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
This commit is contained in:
parent
7b79fcee45
commit
e1c4e55880
@ -127,6 +127,7 @@ struct _MetaX11Display
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
Window xwindow;
|
Window xwindow;
|
||||||
|
guint timeout_id;
|
||||||
MetaSelectionSource *owners[META_N_SELECTION_TYPES];
|
MetaSelectionSource *owners[META_N_SELECTION_TYPES];
|
||||||
GCancellable *cancellables[META_N_SELECTION_TYPES];
|
GCancellable *cancellables[META_N_SELECTION_TYPES];
|
||||||
|
|
||||||
|
@ -311,6 +311,22 @@ source_new_cb (GObject *object,
|
|||||||
g_free (data);
|
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
|
static gboolean
|
||||||
meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
|
meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
|
||||||
XEvent *xevent)
|
XEvent *xevent)
|
||||||
@ -325,6 +341,9 @@ meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
|
|||||||
|
|
||||||
selection = meta_display_get_selection (meta_get_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])
|
if (x11_display->selection.cancellables[selection_type])
|
||||||
{
|
{
|
||||||
g_cancellable_cancel (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);
|
meta_selection_set_owner (selection, selection_type, source);
|
||||||
g_object_unref (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
|
else
|
||||||
{
|
{
|
||||||
/* An X client went away, clear the selection */
|
/* 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.event_mask = PropertyChangeMask | SubstructureNotifyMask;
|
||||||
attributes.override_redirect = True;
|
attributes.override_redirect = True;
|
||||||
|
|
||||||
|
x11_display->selection.timeout_id = 0;
|
||||||
x11_display->selection.xwindow =
|
x11_display->selection.xwindow =
|
||||||
XCreateWindow (x11_display->xdisplay,
|
XCreateWindow (x11_display->xdisplay,
|
||||||
x11_display->xroot,
|
x11_display->xroot,
|
||||||
@ -482,4 +515,6 @@ meta_x11_selection_shutdown (MetaX11Display *x11_display)
|
|||||||
XDestroyWindow (x11_display->xdisplay, x11_display->selection.xwindow);
|
XDestroyWindow (x11_display->xdisplay, x11_display->selection.xwindow);
|
||||||
x11_display->selection.xwindow = None;
|
x11_display->selection.xwindow = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_clear_handle_id (&x11_display->selection.timeout_id, g_source_remove);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user