You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
559 lines
23 KiB
559 lines
23 KiB
From d76d6ff0761d47df938f1dab0daeeecac2feb56e Mon Sep 17 00:00:00 2001 |
|
From: Ray Strode <rstrode@redhat.com> |
|
Date: Mon, 6 Sep 2021 08:43:28 -0400 |
|
Subject: [PATCH 4/5] daemon: Consolidate session-type and |
|
supported-session-types list |
|
|
|
There's currently a bug in computing the session-type to use. |
|
|
|
The `i > 0` check means wayland will overwrite x11 in the |
|
transient session type list. |
|
|
|
Morever, the separation between "session-type" and |
|
"supported-session-types" is a little redundant. Since |
|
supported-session-types is a sorted list, the first item should |
|
always be the same as "session-type". |
|
|
|
This commit addresses the bug and the redundant logic, by computing |
|
the supported session types early in the function and indexing into |
|
it to get the session-type. |
|
|
|
A future cleanup could probably get rid of session-type entirely. |
|
|
|
https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/153 |
|
--- |
|
daemon/gdm-local-display-factory.c | 193 +++++++++++++++++------------ |
|
1 file changed, 116 insertions(+), 77 deletions(-) |
|
|
|
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c |
|
index 141d64c6..eba38671 100644 |
|
--- a/daemon/gdm-local-display-factory.c |
|
+++ b/daemon/gdm-local-display-factory.c |
|
@@ -197,164 +197,226 @@ get_preferred_display_server (GdmLocalDisplayFactory *factory) |
|
} |
|
|
|
if (!wayland_enabled && !xorg_enabled) { |
|
return g_strdup ("none"); |
|
} |
|
|
|
gdm_settings_direct_get_string (GDM_KEY_PREFERRED_DISPLAY_SERVER, &preferred_display_server); |
|
|
|
if (g_strcmp0 (preferred_display_server, "wayland") == 0) { |
|
if (wayland_enabled) |
|
return g_strdup (preferred_display_server); |
|
else |
|
return g_strdup ("xorg"); |
|
} |
|
|
|
if (g_strcmp0 (preferred_display_server, "xorg") == 0) { |
|
if (xorg_enabled) |
|
return g_strdup (preferred_display_server); |
|
else |
|
return g_strdup ("wayland"); |
|
} |
|
|
|
if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0) { |
|
if (xorg_enabled) |
|
return g_strdup (preferred_display_server); |
|
} |
|
|
|
return g_strdup ("none"); |
|
} |
|
|
|
+struct GdmDisplayServerConfiguration { |
|
+ const char *display_server; |
|
+ const char *key; |
|
+ const char *binary; |
|
+ const char *session_type; |
|
+} display_server_configuration[] = { |
|
+#ifdef ENABLE_WAYLAND_SUPPORT |
|
+ { "wayland", GDM_KEY_WAYLAND_ENABLE, "/usr/bin/Xwayland", "wayland" }, |
|
+#endif |
|
+ { "xorg", GDM_KEY_XORG_ENABLE, "/usr/bin/Xorg", "x11" }, |
|
+ { NULL, NULL, NULL }, |
|
+}; |
|
+ |
|
+static gboolean |
|
+display_server_enabled (GdmLocalDisplayFactory *factory, |
|
+ const char *display_server) |
|
+{ |
|
+ size_t i; |
|
+ |
|
+ for (i = 0; display_server_configuration[i].display_server != NULL; i++) { |
|
+ const char *key = display_server_configuration[i].key; |
|
+ const char *binary = display_server_configuration[i].binary; |
|
+ gboolean enabled = FALSE; |
|
+ |
|
+ if (!g_str_equal (display_server_configuration[i].display_server, |
|
+ display_server)) |
|
+ continue; |
|
+ |
|
+ if (!gdm_settings_direct_get_boolean (key, &enabled) || !enabled) |
|
+ return FALSE; |
|
+ |
|
+ if (!g_file_test (binary, G_FILE_TEST_IS_EXECUTABLE)) |
|
+ return FALSE; |
|
+ |
|
+ return TRUE; |
|
+ } |
|
+ |
|
+ return FALSE; |
|
+} |
|
+ |
|
static const char * |
|
-gdm_local_display_factory_get_session_type (GdmLocalDisplayFactory *factory, |
|
- gboolean should_fall_back) |
|
+get_session_type_for_display_server (GdmLocalDisplayFactory *factory, |
|
+ const char *display_server) |
|
+{ |
|
+ size_t i; |
|
+ |
|
+ for (i = 0; display_server_configuration[i].display_server != NULL; i++) { |
|
+ if (!g_str_equal (display_server_configuration[i].display_server, |
|
+ display_server)) |
|
+ continue; |
|
+ |
|
+ return display_server_configuration[i].session_type; |
|
+ } |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+static char ** |
|
+gdm_local_display_factory_get_session_types (GdmLocalDisplayFactory *factory, |
|
+ gboolean should_fall_back) |
|
{ |
|
- const char *session_types[3] = { NULL }; |
|
- gsize i, session_type_index = 0; |
|
g_autofree gchar *preferred_display_server = NULL; |
|
+ const char *fallback_display_server = NULL; |
|
+ gboolean wayland_preferred = FALSE; |
|
+ gboolean xorg_preferred = FALSE; |
|
+ g_autoptr (GPtrArray) session_types_array = NULL; |
|
+ char **session_types; |
|
+ |
|
+ session_types_array = g_ptr_array_new (); |
|
|
|
preferred_display_server = get_preferred_display_server (factory); |
|
|
|
- if (g_strcmp0 (preferred_display_server, "wayland") != 0 && |
|
- g_strcmp0 (preferred_display_server, "xorg") != 0) |
|
- return NULL; |
|
+ g_debug ("GdmLocalDisplayFactory: Getting session type (prefers %s, falling back: %s)", |
|
+ preferred_display_server, should_fall_back? "yes" : "no"); |
|
|
|
- for (i = 0; i < G_N_ELEMENTS (session_types) - 1; i++) { |
|
-#ifdef ENABLE_WAYLAND_SUPPORT |
|
- if (i > 0 || |
|
- g_strcmp0 (preferred_display_server, "wayland") == 0) { |
|
- gboolean wayland_enabled = FALSE; |
|
- if (gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled)) { |
|
- if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE)) { |
|
- session_types[i] = "wayland"; |
|
- continue; |
|
- } |
|
- } |
|
- } |
|
-#endif |
|
+ wayland_preferred = g_str_equal (preferred_display_server, "wayland"); |
|
+ xorg_preferred = g_str_equal (preferred_display_server, "xorg"); |
|
+ |
|
+ if (wayland_preferred) |
|
+ fallback_display_server = "xorg"; |
|
+ else if (xorg_preferred) |
|
+ fallback_display_server = "wayland"; |
|
+ else |
|
+ return NULL; |
|
|
|
- if (i > 0 || |
|
- g_strcmp0 (preferred_display_server, "xorg") == 0) { |
|
- gboolean xorg_enabled = FALSE; |
|
- if (gdm_settings_direct_get_boolean (GDM_KEY_XORG_ENABLE, &xorg_enabled)) { |
|
- if (xorg_enabled && g_file_test ("/usr/bin/Xorg", G_FILE_TEST_IS_EXECUTABLE)) { |
|
- session_types[i] = "x11"; |
|
- continue; |
|
- } |
|
- } |
|
- } |
|
+ if (!should_fall_back) { |
|
+ if (display_server_enabled (factory, preferred_display_server)) |
|
+ g_ptr_array_add (session_types_array, (gpointer) get_session_type_for_display_server (factory, preferred_display_server)); |
|
} |
|
|
|
- if (should_fall_back) |
|
- session_type_index++; |
|
+ if (display_server_enabled (factory, fallback_display_server)) |
|
+ g_ptr_array_add (session_types_array, (gpointer) get_session_type_for_display_server (factory, fallback_display_server)); |
|
|
|
- return session_types[session_type_index]; |
|
+ if (session_types_array->len == 0) |
|
+ return NULL; |
|
+ |
|
+ g_ptr_array_add (session_types_array, NULL); |
|
+ |
|
+ session_types = g_strdupv ((char **) session_types_array->pdata); |
|
+ |
|
+ return session_types; |
|
} |
|
|
|
static void |
|
on_display_disposed (GdmLocalDisplayFactory *factory, |
|
GdmDisplay *display) |
|
{ |
|
g_debug ("GdmLocalDisplayFactory: Display %p disposed", display); |
|
} |
|
|
|
static void |
|
store_display (GdmLocalDisplayFactory *factory, |
|
GdmDisplay *display) |
|
{ |
|
GdmDisplayStore *store; |
|
|
|
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); |
|
gdm_display_store_add (store, display); |
|
} |
|
|
|
/* |
|
Example: |
|
dbus-send --system --dest=org.gnome.DisplayManager \ |
|
--type=method_call --print-reply --reply-timeout=2000 \ |
|
/org/gnome/DisplayManager/Manager \ |
|
org.gnome.DisplayManager.Manager.GetDisplays |
|
*/ |
|
gboolean |
|
gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory, |
|
char **id, |
|
GError **error) |
|
{ |
|
gboolean ret; |
|
GdmDisplay *display = NULL; |
|
gboolean is_initial = FALSE; |
|
const char *session_type; |
|
g_autofree gchar *preferred_display_server = NULL; |
|
|
|
g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE); |
|
|
|
ret = FALSE; |
|
|
|
g_debug ("GdmLocalDisplayFactory: Creating transient display"); |
|
|
|
preferred_display_server = get_preferred_display_server (factory); |
|
|
|
#ifdef ENABLE_USER_DISPLAY_SERVER |
|
if (g_strcmp0 (preferred_display_server, "wayland") == 0 || |
|
g_strcmp0 (preferred_display_server, "xorg") == 0) { |
|
- session_type = gdm_local_display_factory_get_session_type (factory, FALSE); |
|
+ g_auto(GStrv) session_types = NULL; |
|
|
|
- if (session_type == NULL) { |
|
+ session_types = gdm_local_display_factory_get_session_types (factory, FALSE); |
|
+ |
|
+ if (session_types == NULL) { |
|
g_set_error_literal (error, |
|
GDM_DISPLAY_ERROR, |
|
GDM_DISPLAY_ERROR_GENERAL, |
|
"Both Wayland and Xorg are unavailable"); |
|
return FALSE; |
|
} |
|
|
|
display = gdm_local_display_new (); |
|
- g_object_set (G_OBJECT (display), "session-type", session_type, NULL); |
|
+ g_object_set (G_OBJECT (display), |
|
+ "session-type", session_types[0], |
|
+ "supported-session-types", session_types, |
|
+ NULL); |
|
is_initial = TRUE; |
|
} |
|
#endif |
|
if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0) { |
|
if (display == NULL) { |
|
guint32 num; |
|
|
|
num = take_next_display_number (factory); |
|
|
|
display = gdm_legacy_display_new (num); |
|
} |
|
} |
|
|
|
if (display == NULL) { |
|
g_set_error_literal (error, |
|
GDM_DISPLAY_ERROR, |
|
GDM_DISPLAY_ERROR_GENERAL, |
|
"Invalid preferred display server configured"); |
|
return FALSE; |
|
} |
|
|
|
g_object_set (display, |
|
"seat-id", "seat0", |
|
"allow-timed-login", FALSE, |
|
"is-initial", is_initial, |
|
NULL); |
|
|
|
store_display (factory, display); |
|
|
|
if (! gdm_display_manage (display)) { |
|
@@ -549,243 +611,220 @@ lookup_prepared_display_by_seat_id (const char *id, |
|
|
|
if (status != GDM_DISPLAY_PREPARED) |
|
return FALSE; |
|
|
|
return lookup_by_seat_id (id, display, user_data); |
|
} |
|
|
|
static int |
|
on_seat0_graphics_check_timeout (gpointer user_data) |
|
{ |
|
GdmLocalDisplayFactory *factory = user_data; |
|
|
|
factory->seat0_graphics_check_timeout_id = 0; |
|
|
|
/* Simply try to re-add seat0. If it is there already (i.e. CanGraphical |
|
* turned TRUE, then we'll find it and it will not be created again). |
|
*/ |
|
factory->seat0_graphics_check_timed_out = TRUE; |
|
ensure_display_for_seat (factory, "seat0"); |
|
|
|
return G_SOURCE_REMOVE; |
|
} |
|
|
|
static void |
|
ensure_display_for_seat (GdmLocalDisplayFactory *factory, |
|
const char *seat_id) |
|
{ |
|
int ret; |
|
gboolean seat_supports_graphics; |
|
gboolean is_seat0; |
|
- const char *session_type = "wayland"; |
|
+ g_auto (GStrv) session_types = NULL; |
|
+ const char *legacy_session_types[] = { "x11", NULL }; |
|
GdmDisplayStore *store; |
|
GdmDisplay *display = NULL; |
|
g_autofree char *login_session_id = NULL; |
|
gboolean wayland_enabled = FALSE, xorg_enabled = FALSE; |
|
g_autofree gchar *preferred_display_server = NULL; |
|
- gboolean falling_back; |
|
+ gboolean falling_back = FALSE; |
|
|
|
gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled); |
|
gdm_settings_direct_get_boolean (GDM_KEY_XORG_ENABLE, &xorg_enabled); |
|
|
|
preferred_display_server = get_preferred_display_server (factory); |
|
|
|
if (g_strcmp0 (preferred_display_server, "none") == 0) { |
|
g_debug ("GdmLocalDisplayFactory: Preferred display server is none, so not creating display"); |
|
return; |
|
} |
|
|
|
ret = sd_seat_can_graphical (seat_id); |
|
|
|
if (ret < 0) { |
|
g_critical ("Failed to query CanGraphical information for seat %s", seat_id); |
|
return; |
|
} |
|
|
|
if (ret == 0) { |
|
g_debug ("GdmLocalDisplayFactory: System doesn't currently support graphics"); |
|
seat_supports_graphics = FALSE; |
|
} else { |
|
g_debug ("GdmLocalDisplayFactory: System supports graphics"); |
|
seat_supports_graphics = TRUE; |
|
} |
|
|
|
if (g_strcmp0 (seat_id, "seat0") == 0) { |
|
is_seat0 = TRUE; |
|
|
|
falling_back = factory->num_failures > 0; |
|
- session_type = gdm_local_display_factory_get_session_type (factory, falling_back); |
|
+ session_types = gdm_local_display_factory_get_session_types (factory, falling_back); |
|
|
|
g_debug ("GdmLocalDisplayFactory: New displays on seat0 will use %s%s", |
|
- session_type, falling_back? " fallback" : ""); |
|
+ session_types[0], falling_back? " fallback" : ""); |
|
} else { |
|
is_seat0 = FALSE; |
|
|
|
g_debug ("GdmLocalDisplayFactory: New displays on seat %s will use X11 fallback", seat_id); |
|
/* Force legacy X11 for all auxiliary seats */ |
|
seat_supports_graphics = TRUE; |
|
- session_type = "x11"; |
|
+ session_types = g_strdupv ((char **) legacy_session_types); |
|
} |
|
|
|
/* For seat0, we have a fallback logic to still try starting it after |
|
* SEAT0_GRAPHICS_CHECK_TIMEOUT seconds. i.e. we simply continue even if |
|
* CanGraphical is unset. |
|
* This is ugly, but it means we'll come up eventually in some |
|
* scenarios where no master device is present. |
|
* Note that we'll force an X11 fallback even though there might be |
|
* cases where an wayland capable device is present and simply not marked as |
|
* master-of-seat. In these cases, this should likely be fixed in the |
|
* udev rules. |
|
* |
|
* At the moment, systemd always sets CanGraphical for non-seat0 seats. |
|
* This is because non-seat0 seats are defined by having master-of-seat |
|
* set. This means we can avoid the fallback check for non-seat0 seats, |
|
* which simplifies the code. |
|
*/ |
|
if (is_seat0) { |
|
if (!seat_supports_graphics) { |
|
if (!factory->seat0_graphics_check_timed_out) { |
|
if (factory->seat0_graphics_check_timeout_id == 0) { |
|
g_debug ("GdmLocalDisplayFactory: seat0 doesn't yet support graphics. Waiting %d seconds to try again.", SEAT0_GRAPHICS_CHECK_TIMEOUT); |
|
factory->seat0_graphics_check_timeout_id = g_timeout_add_seconds (SEAT0_GRAPHICS_CHECK_TIMEOUT, |
|
on_seat0_graphics_check_timeout, |
|
factory); |
|
|
|
} else { |
|
/* It is not yet time to force X11 fallback. */ |
|
g_debug ("GdmLocalDisplayFactory: seat0 display requested when there is no graphics support before graphics check timeout."); |
|
} |
|
|
|
return; |
|
} |
|
|
|
g_debug ("GdmLocalDisplayFactory: Assuming we can use seat0 for X11 even though system says it doesn't support graphics!"); |
|
g_debug ("GdmLocalDisplayFactory: This might indicate an issue where the framebuffer device is not tagged as master-of-seat in udev."); |
|
seat_supports_graphics = TRUE; |
|
- session_type = "x11"; |
|
wayland_enabled = FALSE; |
|
+ g_strfreev (session_types); |
|
+ session_types = g_strdupv ((char **) legacy_session_types); |
|
} else { |
|
g_clear_handle_id (&factory->seat0_graphics_check_timeout_id, g_source_remove); |
|
} |
|
} |
|
|
|
if (!seat_supports_graphics) |
|
return; |
|
|
|
- if (session_type != NULL) |
|
+ if (session_types != NULL) |
|
g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested", |
|
- session_type, seat_id); |
|
+ session_types[0], seat_id); |
|
else if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0) |
|
g_debug ("GdmLocalDisplayFactory: Legacy Xorg login display for seat %s requested", |
|
seat_id); |
|
|
|
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); |
|
|
|
if (is_seat0) |
|
display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id); |
|
else |
|
display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id); |
|
|
|
/* Ensure we don't create the same display more than once */ |
|
if (display != NULL) { |
|
g_debug ("GdmLocalDisplayFactory: display already created"); |
|
return; |
|
} |
|
|
|
/* If we already have a login window, switch to it */ |
|
if (gdm_get_login_window_session_id (seat_id, &login_session_id)) { |
|
GdmDisplay *display; |
|
|
|
display = gdm_display_store_find (store, |
|
lookup_by_session_id, |
|
(gpointer) login_session_id); |
|
if (display != NULL && |
|
(gdm_display_get_status (display) == GDM_DISPLAY_MANAGED || |
|
gdm_display_get_status (display) == GDM_DISPLAY_WAITING_TO_FINISH)) { |
|
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_MANAGED, NULL); |
|
g_debug ("GdmLocalDisplayFactory: session %s found, activating.", |
|
login_session_id); |
|
gdm_activate_session_by_id (factory->connection, seat_id, login_session_id); |
|
return; |
|
} |
|
} |
|
|
|
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id); |
|
|
|
#ifdef ENABLE_USER_DISPLAY_SERVER |
|
if (g_strcmp0 (preferred_display_server, "wayland") == 0 || |
|
g_strcmp0 (preferred_display_server, "xorg") == 0) { |
|
if (is_seat0) { |
|
- g_autoptr (GPtrArray) supported_session_types = NULL; |
|
- |
|
- if (session_type == NULL) { |
|
- g_warning ("GdmLocalDisplayFactory: Both Wayland and Xorg sessions are unavailable"); |
|
- return; |
|
- } |
|
- |
|
- supported_session_types = g_ptr_array_new (); |
|
- |
|
- if (g_strcmp0 (preferred_display_server, "wayland") == 0) { |
|
- if (wayland_enabled) |
|
- g_ptr_array_add (supported_session_types, "wayland"); |
|
- } else { |
|
- if (xorg_enabled) |
|
- g_ptr_array_add (supported_session_types, "x11"); |
|
- } |
|
- |
|
- if (!falling_back) { |
|
- if (g_strcmp0 (preferred_display_server, "wayland") == 0) { |
|
- if (xorg_enabled) |
|
- g_ptr_array_add (supported_session_types, "x11"); |
|
- } else { |
|
- if (wayland_enabled) |
|
- g_ptr_array_add (supported_session_types, "wayland"); |
|
- } |
|
- } |
|
- |
|
- g_ptr_array_add (supported_session_types, NULL); |
|
- |
|
display = gdm_local_display_new (); |
|
- g_object_set (G_OBJECT (display), "session-type", session_type, NULL); |
|
- g_object_set (G_OBJECT (display), "supported-session-types", supported_session_types->pdata, NULL); |
|
+ g_object_set (G_OBJECT (display), |
|
+ "session-type", session_types[0], |
|
+ "supported-session-types", session_types, |
|
+ NULL); |
|
} |
|
} |
|
#endif |
|
|
|
if (display == NULL) { |
|
guint32 num; |
|
- const char *supported_session_types[] = { "x11", NULL }; |
|
|
|
num = take_next_display_number (factory); |
|
|
|
display = gdm_legacy_display_new (num); |
|
- g_object_set (G_OBJECT (display), "supported-session-types", supported_session_types, NULL); |
|
+ g_object_set (G_OBJECT (display), |
|
+ "session-type", legacy_session_types[0], |
|
+ "supported-session-types", legacy_session_types, |
|
+ NULL); |
|
} |
|
|
|
g_object_set (display, "seat-id", seat_id, NULL); |
|
g_object_set (display, "is-initial", is_seat0, NULL); |
|
|
|
store_display (factory, display); |
|
|
|
/* let store own the ref */ |
|
g_object_unref (display); |
|
|
|
if (! gdm_display_manage (display)) { |
|
gdm_display_unmanage (display); |
|
} |
|
|
|
return; |
|
} |
|
|
|
static void |
|
delete_display (GdmLocalDisplayFactory *factory, |
|
const char *seat_id) { |
|
|
|
GdmDisplayStore *store; |
|
|
|
g_debug ("GdmLocalDisplayFactory: Removing used_display_numbers on seat %s", seat_id); |
|
|
|
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); |
|
gdm_display_store_foreach_remove (store, lookup_by_seat_id, (gpointer) seat_id); |
|
} |
|
|
|
static gboolean |
|
-- |
|
2.34.1 |
|
|
|
|