summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Azzarone <azzaronea@gmail.com>2018-10-31 14:21:40 +0000
committerAndrea Azzarone <andrea.azzarone@canonical.com>2018-11-08 10:30:13 +0000
commit1d863f4d3e102c3100ca879224a2d0c6dcb45674 (patch)
treeb209a4be52fee620a015e79407e718f3f2a8e982
parent1abab3fe2ed2d07bafc9f3aabe188c4d1c05ee43 (diff)
downloadmutter-1d863f4d3e102c3100ca879224a2d0c6dcb45674.tar.gz
x11: close display in an idle function
Closing a GdkDisplay during an event handler is not currently supported by Gdk and it will result in a crash when doing e.g. 'mutter --replace'. Using an idle function will close it safely in a subsequent main loop iteration. Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/595
-rw-r--r--src/x11/events.c28
-rw-r--r--src/x11/meta-x11-display-private.h3
-rw-r--r--src/x11/meta-x11-display.c9
3 files changed, 33 insertions, 7 deletions
diff --git a/src/x11/events.c b/src/x11/events.c
index 59caeb4b9..1e77538db 100644
--- a/src/x11/events.c
+++ b/src/x11/events.c
@@ -1139,6 +1139,18 @@ process_selection_request (MetaX11Display *x11_display,
}
static gboolean
+close_display_idle_cb (gpointer user_data)
+{
+ MetaX11Display *x11_display = META_X11_DISPLAY (user_data);
+
+ meta_display_close (x11_display->display,
+ x11_display->xselectionclear_timestamp);
+ x11_display->display_close_idle = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
process_selection_clear (MetaX11Display *x11_display,
XEvent *event)
{
@@ -1163,8 +1175,13 @@ process_selection_clear (MetaX11Display *x11_display,
meta_verbose ("Got selection clear for on display %s\n",
x11_display->name);
- meta_display_close (x11_display->display,
- event->xselectionclear.time);
+ /* We can't close a GdkDisplay in an even handler. */
+ if (!x11_display->display_close_idle)
+ {
+ x11_display->xselectionclear_timestamp = event->xselectionclear.time;
+ x11_display->display_close_idle = g_idle_add (close_display_idle_cb, x11_display);
+ }
+
return TRUE;
}
@@ -1818,11 +1835,8 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
{
if (process_selection_clear (x11_display, event))
{
- /* This means we called meta_display_unmanage_screen, which
- * means the MetaDisplay is effectively dead. We don't want
- * to poke into display->current_time below, since that would
- * crash, so just directly return. */
- return TRUE;
+ bypass_gtk = TRUE;
+ goto out;
}
}
diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h
index 05019e8cf..fdd642bbc 100644
--- a/src/x11/meta-x11-display-private.h
+++ b/src/x11/meta-x11-display-private.h
@@ -92,6 +92,9 @@ struct _MetaX11Display
Atom wm_sn_atom;
guint32 wm_sn_timestamp;
+ guint display_close_idle;
+ guint32 xselectionclear_timestamp;
+
Window wm_cm_selection_window;
Window composite_overlay_window;
diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c
index 83f7dfbae..4a6d64e08 100644
--- a/src/x11/meta-x11-display.c
+++ b/src/x11/meta-x11-display.c
@@ -215,6 +215,12 @@ meta_x11_display_dispose (GObject *object)
x11_display->gdk_display = NULL;
}
+ if (x11_display->display_close_idle)
+ {
+ g_source_remove (x11_display->display_close_idle);
+ x11_display->display_close_idle = 0;
+ }
+
g_free (x11_display->name);
x11_display->name = NULL;
@@ -1186,6 +1192,9 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
x11_display->timestamp_pinging_window = None;
x11_display->wm_sn_selection_window = None;
+ x11_display->display_close_idle = 0;
+ x11_display->xselectionclear_timestamp = 0;
+
x11_display->last_bell_time = 0;
x11_display->focus_serial = 0;
x11_display->server_focus_window = None;