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
This commit is contained in:
Jonas Ådahl 2017-12-26 15:58:54 +08:00
parent 1caaf0cd1e
commit f635876eac
3 changed files with 97 additions and 53 deletions

View File

@ -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);
}
}
/**

View File

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

View File

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