From f635876eac2b892991a791009ff88d3975cb2c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 26 Dec 2017 15:58:54 +0800 Subject: [PATCH] x11: Open window decoration X11 connection earlier If we wait with opening the X11 window decoration GDK connection, we might end up with a terminated X11 server before we finish initializing, depending on the things happening after spawning Xwayland and before opening the MetaX11Dispaly. In gnome-shell, this involves e.g. creating a couple of temporary X11 connections, and on disconnect, if they happen to be the last client, the X server will terminate itself. https://bugzilla.gnome.org/show_bug.cgi?id=759538 --- src/core/main.c | 16 +++++ src/meta/meta-x11-display.h | 2 + src/x11/meta-x11-display.c | 132 +++++++++++++++++++++--------------- 3 files changed, 97 insertions(+), 53 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index ff2eea195..605290864 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -612,6 +612,22 @@ meta_init (void) meta_fatal ("Can't specify both SM save file and SM client id\n"); meta_main_loop = g_main_loop_new (NULL, FALSE); + + /* + * We need to make sure the first client connecting to the X server + * (e.g. Xwayland started from meta_wayland_init() above) is a permanent one, + * so prepare the GDK X11 connection now already. Without doing this, if + * there are any functionality that relies on X11 after here before + * meta_display_open(), the X server will terminate itself when such a client + * disconnects before the permanent GDK client connects. + */ + if (meta_should_autostart_x11_display ()) + { + GError *error = NULL; + + if (!meta_x11_init_gdk_display (&error)) + g_error ("Failed to open X11 display: %s", error->message); + } } /** diff --git a/src/meta/meta-x11-display.h b/src/meta/meta-x11-display.h index 9aeb60cb6..352ceb675 100644 --- a/src/meta/meta-x11-display.h +++ b/src/meta/meta-x11-display.h @@ -30,6 +30,8 @@ #define META_TYPE_X11_DISPLAY (meta_x11_display_get_type ()) G_DECLARE_FINAL_TYPE (MetaX11Display, meta_x11_display, META, X11_DISPLAY, GObject) +gboolean meta_x11_init_gdk_display (GError **error); + int meta_x11_display_get_screen_number (MetaX11Display *x11_display); Display *meta_x11_display_get_xdisplay (MetaX11Display *x11_display); Window meta_x11_display_get_xroot (MetaX11Display *x11_display); diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index 3dd7f204d..f5bff0da9 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -80,6 +80,8 @@ typedef struct _MetaX11DisplayLogicalMonitorData int xinerama_index; } MetaX11DisplayLogicalMonitorData; +static GdkDisplay *prepared_gdk_display = NULL; + static const char *gnome_wm_keybindings = "Mutter"; static const char *net_wm_name = "Mutter"; @@ -972,6 +974,79 @@ meta_set_gnome_wm_keybindings (const char *wm_keybindings) gnome_wm_keybindings = wm_keybindings; } +gboolean +meta_x11_init_gdk_display (GError **error) +{ + const char *xdisplay_name; + GdkDisplay *gdk_display; + const char *gdk_gl_env = NULL; + Display *xdisplay; + + xdisplay_name = g_getenv ("DISPLAY"); + if (!xdisplay_name) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unable to open display, DISPLAY not set"); + return FALSE; + } + + gdk_set_allowed_backends ("x11"); + + gdk_gl_env = g_getenv ("GDK_GL"); + g_setenv ("GDK_GL", "disable", TRUE); + + gdk_parse_args (NULL, NULL); + if (!gtk_parse_args (NULL, NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to initialize gtk"); + return FALSE; + } + + gdk_display = gdk_display_open (xdisplay_name); + + if (!gdk_display) + { + meta_warning (_("Failed to initialize GDK\n")); + + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to initialize GDK"); + + return FALSE; + } + + if (gdk_gl_env) + g_setenv("GDK_GL", gdk_gl_env, TRUE); + else + unsetenv("GDK_GL"); + + /* We need to be able to fully trust that the window and monitor sizes + that Gdk reports corresponds to the X ones, so we disable the automatic + scale handling */ + gdk_x11_display_set_window_scale (gdk_display, 1); + + meta_verbose ("Opening display '%s'\n", XDisplayName (NULL)); + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display); + + if (xdisplay == NULL) + { + meta_warning (_("Failed to open X Window System display ā€œ%sā€\n"), + XDisplayName (NULL)); + + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to open X11 display"); + + gdk_display_close (gdk_display); + + return FALSE; + } + + prepared_gdk_display = gdk_display; + + return TRUE; +} + /** * meta_x11_display_new: * @@ -1000,47 +1075,10 @@ meta_x11_display_new (MetaDisplay *display, GError **error) Atom atom_restart_helper; Window restart_helper_window = None; GdkDisplay *gdk_display; - const char *gdk_gl_env = NULL; - const char *xdisplay_name; MetaBackend *backend = meta_get_backend (); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - xdisplay_name = g_getenv ("DISPLAY"); - if (!xdisplay_name) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Unable to open display, DISPLAY not set"); - return FALSE; - } - - gdk_set_allowed_backends ("x11"); - - gdk_gl_env = g_getenv ("GDK_GL"); - g_setenv("GDK_GL", "disable", TRUE); - - gdk_display = gdk_display_open (xdisplay_name); - - if (!gdk_display) - { - meta_warning (_("Failed to initialize GDK\n")); - - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to initialize GDK"); - - return NULL; - } - - if (gdk_gl_env) - g_setenv("GDK_GL", gdk_gl_env, TRUE); - else - unsetenv("GDK_GL"); - - /* We need to be able to fully trust that the window and monitor sizes - that Gdk reports corresponds to the X ones, so we disable the automatic - scale handling */ - gdk_x11_display_set_window_scale (gdk_display, 1); - /* A list of all atom names, so that we can intern them in one go. */ const char *atom_names[] = { #define item(x) #x, @@ -1049,28 +1087,16 @@ meta_x11_display_new (MetaDisplay *display, GError **error) }; Atom atoms[G_N_ELEMENTS(atom_names)]; - meta_verbose ("Opening display '%s'\n", XDisplayName (NULL)); - - xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display); - - if (xdisplay == NULL) - { - meta_warning (_("Failed to open X Window System display ā€œ%sā€\n"), - XDisplayName (NULL)); - - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to open X11 display"); - - gdk_display_close (gdk_display); - - return NULL; - } + g_assert (prepared_gdk_display); + gdk_display = g_steal_pointer (&prepared_gdk_display); #ifdef HAVE_WAYLAND if (meta_is_wayland_compositor ()) meta_xwayland_complete_init (display); #endif + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display); + if (meta_is_syncing ()) XSynchronize (xdisplay, True);