diff --git a/0001-manager-Schedule-deferred-plymouth-quit-on-session-r.patch b/0001-manager-Schedule-deferred-plymouth-quit-on-session-r.patch new file mode 100644 index 0000000..c411168 --- /dev/null +++ b/0001-manager-Schedule-deferred-plymouth-quit-on-session-r.patch @@ -0,0 +1,127 @@ +From 46642cb36d63687fdd52b7161b192a3ac9e18393 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Mon, 13 Apr 2026 17:06:05 +0200 +Subject: [PATCH] manager: Schedule deferred plymouth quit on session + registration + +On headless or no-monitor systems, gnome-shell can register the session +but won't register the display, leaving plymouth running indefinitely. +That makes the system unusable because it didn't reach graphical.target. + +Schedule a deferred plymouth quit when RegisterSession is called on a +local display, using the same REGISTER_DISPLAY_TIMEOUT (10s) as the +session wrappers. If RegisterDisplay arrives first, the timeout is +cancelled and plymouth is quit immediately with transition as before. + +Part-of: +--- + daemon/gdm-manager.c | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index dde2819..d83ba10 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -96,6 +96,7 @@ struct _GdmManager + + #ifdef WITH_PLYMOUTH + guint plymouth_is_running : 1; ++ guint plymouth_quit_timeout_id; + #endif + guint did_automatic_login : 1; + }; +@@ -204,6 +205,19 @@ plymouth_quit_without_transition (void) + g_error_free (error); + } + } ++ ++static void ++plymouth_quit_timeout_cb (gpointer user_data) ++{ ++ GdmManager *manager = user_data; ++ ++ manager->plymouth_quit_timeout_id = 0; ++ ++ if (manager->plymouth_is_running) { ++ plymouth_quit_without_transition (); ++ manager->plymouth_is_running = FALSE; ++ } ++} + #endif + + static char * +@@ -828,6 +842,23 @@ gdm_manager_handle_register_session (GdmDBusManager *manager, + "session-registered", TRUE, + NULL); + ++#ifdef WITH_PLYMOUTH ++ if (self->plymouth_is_running) { ++ gboolean display_is_local = FALSE; ++ ++ g_object_get (G_OBJECT (display), ++ "is-local", &display_is_local, ++ NULL); ++ ++ if (display_is_local && self->plymouth_quit_timeout_id == 0) { ++ self->plymouth_quit_timeout_id = ++ g_timeout_add_seconds_once (REGISTER_DISPLAY_TIMEOUT, ++ plymouth_quit_timeout_cb, ++ self); ++ } ++ } ++#endif ++ + gdm_dbus_manager_complete_register_session (GDM_DBUS_MANAGER (manager), + invocation); + +@@ -1579,6 +1610,7 @@ on_display_status_changed (GdmDisplay *display, + if (status == GDM_DISPLAY_MANAGED && quit_plymouth) { + plymouth_quit_with_transition (); + manager->plymouth_is_running = FALSE; ++ g_clear_handle_id (&manager->plymouth_quit_timeout_id, g_source_remove); + } + #endif + break; +@@ -1589,6 +1621,7 @@ on_display_status_changed (GdmDisplay *display, + if (quit_plymouth) { + plymouth_quit_without_transition (); + manager->plymouth_is_running = FALSE; ++ g_clear_handle_id (&manager->plymouth_quit_timeout_id, g_source_remove); + } + #endif + +@@ -2613,6 +2646,7 @@ on_graphics_unsupported (GdmLocalDisplayFactory *factory, + if (manager->plymouth_is_running) { + plymouth_quit_without_transition (); + manager->plymouth_is_running = FALSE; ++ g_clear_handle_id (&manager->plymouth_quit_timeout_id, g_source_remove); + } + } + +@@ -2636,6 +2670,10 @@ gdm_manager_stop (GdmManager *manager) + } + #endif + ++#ifdef WITH_PLYMOUTH ++ g_clear_handle_id (&manager->plymouth_quit_timeout_id, g_source_remove); ++#endif ++ + manager->started = FALSE; + } + +@@ -2670,6 +2708,7 @@ gdm_manager_start (GdmManager *manager) + if (!manager->show_local_greeter && manager->plymouth_is_running) { + plymouth_quit_without_transition (); + manager->plymouth_is_running = FALSE; ++ g_clear_handle_id (&manager->plymouth_quit_timeout_id, g_source_remove); + } + #endif + } +@@ -2682,6 +2721,7 @@ gdm_manager_start (GdmManager *manager) + if (!manager->show_local_greeter && manager->plymouth_is_running) { + plymouth_quit_without_transition (); + manager->plymouth_is_running = FALSE; ++ g_clear_handle_id (&manager->plymouth_quit_timeout_id, g_source_remove); + } + #endif + if (manager->xdmcp_factory != NULL) { diff --git a/0001-manager-Update-RegisterSession-dbus-method.patch b/0001-manager-Update-RegisterSession-dbus-method.patch new file mode 100644 index 0000000..444bcdb --- /dev/null +++ b/0001-manager-Update-RegisterSession-dbus-method.patch @@ -0,0 +1,448 @@ +From ecc9ab663cd698faa2eef596789f43df50976534 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Tue, 3 Feb 2026 14:29:18 +0100 +Subject: [PATCH 1/2] manager: Add RegisterDisplay again + +1. RegisterSession is used to record a session login. It should be + called when the new session is started. +2. RegisterDisplay is used to terminate pending greeters and plymouth + to reach graphical.target. It should be called once the new session + completes its graphics startup. + +RegisterSession was trying to do both before new session startup was completed. +This had a potential issue: the new session is setting up while the greeter +session is tearing down leading to configuration conflicts. + +Fixes: deeb4b8aba46e37a1f6dcb85252ed713183cb170 ("manager: Combine register +display with register session") +--- + daemon/gdm-local-display-factory.c | 8 +------ + daemon/gdm-manager.c | 38 +++++++++++++++++++++++++++--- + daemon/gdm-manager.xml | 2 ++ + 3 files changed, 38 insertions(+), 10 deletions(-) + +diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c +index 63117e1..69b6ddb 100644 +--- a/daemon/gdm-local-display-factory.c ++++ b/daemon/gdm-local-display-factory.c +@@ -529,8 +529,6 @@ on_display_status_changed (GdmDisplay *display, + char *session_id = NULL; + gboolean is_initial = TRUE; + gboolean is_local = TRUE; +- gboolean registered = FALSE; +- + + if (!factory->is_started) + return; +@@ -600,11 +598,7 @@ on_display_status_changed (GdmDisplay *display, + break; + case GDM_DISPLAY_MANAGED: + #if defined(ENABLE_USER_DISPLAY_SERVER) +- g_object_get (display, "session-registered", ®istered, NULL); +- if (registered) { +- g_debug ("GdmLocalDisplayFactory: session registered on display, looking for any background displays to kill"); +- finish_waiting_displays_on_seat (factory, "seat0"); +- } ++ finish_waiting_displays_on_seat (factory, "seat0"); + #endif + break; + case GDM_DISPLAY_WAITING_TO_FINISH: +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index ff04203..24a7242 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -731,6 +731,39 @@ find_user_session_for_display (GdmManager *self, + return NULL; + } + ++static gboolean ++gdm_manager_handle_register_display (GdmDBusManager *manager, ++ GDBusMethodInvocation *invocation, ++ GVariant *details) ++{ ++ GdmManager *self = GDM_MANAGER (manager); ++ const char *sender; ++ GDBusConnection *connection; ++ GdmDisplay *display = NULL; ++ ++ sender = g_dbus_method_invocation_get_sender (invocation); ++ connection = g_dbus_method_invocation_get_connection (invocation); ++ get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, NULL, NULL, NULL, NULL, NULL); ++ ++ if (display == NULL) { ++ g_dbus_method_invocation_return_error_literal (invocation, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_ACCESS_DENIED, ++ _("No display available")); ++ ++ return G_DBUS_METHOD_INVOCATION_HANDLED; ++ } ++ ++ g_object_set (G_OBJECT (display), ++ "status", GDM_DISPLAY_MANAGED, ++ NULL); ++ ++ gdm_dbus_manager_complete_register_display (GDM_DBUS_MANAGER (manager), ++ invocation); ++ ++ return G_DBUS_METHOD_INVOCATION_HANDLED; ++} ++ + static gboolean + gdm_manager_handle_register_session (GdmDBusManager *manager, + GDBusMethodInvocation *invocation, +@@ -759,7 +792,7 @@ gdm_manager_handle_register_session (GdmDBusManager *manager, + G_DBUS_ERROR_ACCESS_DENIED, + _("No display available")); + +- return TRUE; ++ return G_DBUS_METHOD_INVOCATION_HANDLED; + } + + g_variant_iter_init (&iter, details); +@@ -793,14 +826,13 @@ gdm_manager_handle_register_session (GdmDBusManager *manager, + } + + g_object_set (G_OBJECT (display), +- "status", GDM_DISPLAY_MANAGED, + "session-registered", TRUE, + NULL); + + gdm_dbus_manager_complete_register_session (GDM_DBUS_MANAGER (manager), + invocation); + +- return TRUE; ++ return G_DBUS_METHOD_INVOCATION_HANDLED; + } + + static gboolean +@@ -1214,6 +1246,7 @@ gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager + static void + manager_interface_init (GdmDBusManagerIface *interface) + { ++ interface->handle_register_display = gdm_manager_handle_register_display; + interface->handle_register_session = gdm_manager_handle_register_session; + interface->handle_open_session = gdm_manager_handle_open_session; + interface->handle_open_reauthentication_channel = gdm_manager_handle_open_reauthentication_channel; +diff --git a/daemon/gdm-manager.xml b/daemon/gdm-manager.xml +index aba079a..92ef1d0 100644 +--- a/daemon/gdm-manager.xml ++++ b/daemon/gdm-manager.xml +@@ -1,6 +1,9 @@ + + + ++ ++ ++ + + + +From d8e9406bfd6ebe3b395476ba0460f08d1db536c1 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Tue, 3 Feb 2026 14:31:39 +0100 +Subject: [PATCH 2/2] session: Call RegisterSession and RegisterDisplay from + session launchers + +RegisterSession is called when the session starts to record the login. +RegisterDisplay is called after a delay to terminate pending greeters +and plymouth once graphics have settled. + +This follows the workflow established in the previous commit where +RegisterSession and RegisterDisplay serve distinct purposes. +--- + common/gdm-common.h | 2 +- + daemon/gdm-session.c | 4 +-- + daemon/gdm-wayland-session.c | 63 ++++++++++++++++++++++-------------- + daemon/gdm-x-session.c | 47 +++++++++++++++++---------- + 4 files changed, 71 insertions(+), 45 deletions(-) + +diff --git a/common/gdm-common.h b/common/gdm-common.h +index 37e7e00..247c3a3 100644 +--- a/common/gdm-common.h ++++ b/common/gdm-common.h +@@ -27,7 +27,7 @@ + #include + #include + +-#define REGISTER_SESSION_TIMEOUT 10 ++#define REGISTER_DISPLAY_TIMEOUT 10 + + #define VE_IGNORE_EINTR(expr) \ + do { \ +diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c +index 08ba39c..15f19f9 100644 +--- a/daemon/gdm-session.c ++++ b/daemon/gdm-session.c +@@ -3120,7 +3120,7 @@ gdm_session_start_session (GdmSession *self, + gboolean allow_remote_connections = FALSE; + char *command; + char *program; +- gboolean register_session; ++ gboolean needs_registration; + + g_return_if_fail (GDM_IS_SESSION (self)); + g_return_if_fail (service_name != NULL); +@@ -3147,7 +3147,7 @@ gdm_session_start_session (GdmSession *self, + run_launcher = TRUE; + } + +- register_session = !gdm_session_session_registers (self); ++ needs_registration = !gdm_session_session_registers (self); + + if (self->selected_program == NULL) { + gboolean run_xsession_script; +@@ -3167,13 +3167,13 @@ gdm_session_start_session (GdmSession *self, + if (run_launcher) { + if (is_x11) { + program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s%s %s\"%s\"", +- register_session ? "--register-session " : "", ++ needs_registration ? "--handle-registration " : "", + run_xsession_script? "--run-script " : "", + allow_remote_connections? "--allow-remote-connections " : "", + command); + } else { + program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"%s\"", +- register_session ? "--register-session " : "", ++ needs_registration ? "--handle-registration " : "", + command); + } + } else if (run_xsession_script) { +@@ -3201,11 +3201,11 @@ gdm_session_start_session (GdmSession *self, + if (run_launcher) { + if (is_x11) { + program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s\"dbus-run-session -- %s\"", +- register_session ? "--register-session " : "", ++ needs_registration ? "--handle-registration " : "", + self->selected_program); + } else { + program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"dbus-run-session -- %s\"", +- register_session ? "--register-session " : "", ++ needs_registration ? "--handle-registration " : "", + self->selected_program); + } + } else { +diff --git a/daemon/gdm-wayland-session.c b/daemon/gdm-wayland-session.c +index d4d1edd..1d6bf28 100644 +--- a/daemon/gdm-wayland-session.c ++++ b/daemon/gdm-wayland-session.c +@@ -54,7 +54,7 @@ typedef struct + char *session_command; + int session_exit_status; + +- guint register_session_id; ++ guint register_display_id; + + GMainLoop *main_loop; + +@@ -404,6 +404,22 @@ wait_on_subprocesses (State *state) + } + } + ++static gboolean ++register_session (State *state) ++{ ++ g_autoptr(GError) error = NULL; ++ ++ if (!gdm_dbus_manager_call_register_session_sync (state->display_manager_proxy, ++ g_variant_new ("a{sv}", NULL), ++ state->cancellable, ++ &error)) { ++ g_warning ("Could not register session: %s", error->message); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + static void + init_state (State **state) + { +@@ -422,7 +438,7 @@ clear_state (State **out_state) + g_clear_object (&state->session_subprocess); + g_clear_pointer (&state->environment, g_strfreev); + g_clear_pointer (&state->main_loop, g_main_loop_unref); +- g_clear_handle_id (&state->register_session_id, g_source_remove); ++ g_clear_handle_id (&state->register_display_id, g_source_remove); + *out_state = NULL; + } + +@@ -438,25 +454,17 @@ on_sigterm (State *state) + return G_SOURCE_CONTINUE; + } + +-static gboolean +-register_session_timeout_cb (gpointer user_data) ++static void ++register_display_timeout_cb (gpointer user_data) + { +- State *state; +- GError *error = NULL; +- +- state = (State *) user_data; +- +- gdm_dbus_manager_call_register_session_sync (state->display_manager_proxy, +- g_variant_new ("a{sv}", NULL), +- state->cancellable, +- &error); +- +- if (error != NULL) { +- g_warning ("Could not register session: %s", error->message); +- g_error_free (error); +- } +- +- return G_SOURCE_REMOVE; ++ State *state = (State *) user_data; ++ g_autoptr(GError) error = NULL; ++ ++ if (!gdm_dbus_manager_call_register_display_sync (state->display_manager_proxy, ++ g_variant_new ("a{ss}", NULL), ++ state->cancellable, ++ &error)) ++ g_warning ("Could not display session: %s", error->message); + } + + static gboolean +@@ -491,10 +499,10 @@ main (int argc, + gboolean debug = FALSE; + gboolean ret; + int exit_status = EX_OK; +- static gboolean register_session = FALSE; ++ static gboolean handle_registration = FALSE; + + static GOptionEntry entries [] = { +- { "register-session", 0, 0, G_OPTION_ARG_NONE, ®ister_session, "Register session after a delay", NULL }, ++ { "handle-registration", 0, 0, G_OPTION_ARG_NONE, &handle_registration, "Handle session and display registration (fallback for non-GNOME sessions)", NULL }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" }, + { NULL } + }; +@@ -561,11 +569,17 @@ main (int argc, + if (!connect_to_display_manager (state)) + goto out; + +- if (register_session) { +- g_debug ("gdm-wayland-session: Will register session in %d seconds", REGISTER_SESSION_TIMEOUT); +- state->register_session_id = g_timeout_add_seconds (REGISTER_SESSION_TIMEOUT, +- register_session_timeout_cb, +- state); ++ if (handle_registration) { ++ if (!register_session (state)) { ++ g_printerr ("Unable to register session with display manager\n"); ++ exit_status = EX_SOFTWARE; ++ goto out; ++ } ++ ++ g_debug ("gdm-wayland-session: Will register display in %d seconds", REGISTER_DISPLAY_TIMEOUT); ++ state->register_display_id = g_timeout_add_seconds_once (REGISTER_DISPLAY_TIMEOUT, ++ register_display_timeout_cb, ++ state); + } else { + g_debug ("gdm-wayland-session: Session will register itself"); + } +diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c +index 36b3975..f756706 100644 +--- a/daemon/gdm-x-session.c ++++ b/daemon/gdm-x-session.c +@@ -60,7 +60,7 @@ typedef struct + char *session_command; + int session_exit_status; + +- guint register_session_id; ++ guint register_display_id; + + GMainLoop *main_loop; + +@@ -778,7 +778,7 @@ clear_state (State **out_state) + g_clear_pointer (&state->auth_file, g_free); + g_clear_pointer (&state->display_name, g_free); + g_clear_pointer (&state->main_loop, g_main_loop_unref); +- g_clear_handle_id (&state->register_session_id, g_source_remove); ++ g_clear_handle_id (&state->register_display_id, g_source_remove); + *out_state = NULL; + } + +@@ -794,25 +794,33 @@ on_sigterm (State *state) + return G_SOURCE_CONTINUE; + } + +-static gboolean +-register_session_timeout_cb (gpointer user_data) ++static void ++register_display_timeout_cb (gpointer user_data) + { +- State *state; +- GError *error = NULL; +- +- state = (State *) user_data; ++ State *state = (State *) user_data; ++ g_autoptr(GError) error = NULL; ++ ++ if (!gdm_dbus_manager_call_register_display_sync (state->display_manager_proxy, ++ g_variant_new ("a{ss}", NULL), ++ state->cancellable, ++ &error)) ++ g_warning ("Could not register display: %s", error->message); ++} + +- gdm_dbus_manager_call_register_session_sync (state->display_manager_proxy, +- g_variant_new ("a{sv}", NULL), +- state->cancellable, +- &error); ++static gboolean ++register_session (State *state) ++{ ++ g_autoptr(GError) error = NULL; + +- if (error != NULL) { ++ if (!gdm_dbus_manager_call_register_session_sync (state->display_manager_proxy, ++ g_variant_new ("a{sv}", NULL), ++ state->cancellable, ++ &error)) { + g_warning ("Could not register session: %s", error->message); +- g_error_free (error); ++ return FALSE; + } + +- return G_SOURCE_REMOVE; ++ return TRUE; + } + + static gboolean +@@ -849,12 +857,12 @@ main (int argc, + gboolean debug = FALSE; + gboolean ret; + int exit_status = EX_OK; +- static gboolean register_session = FALSE; ++ static gboolean handle_registration = FALSE; + + static GOptionEntry entries [] = { + { "run-script", 'r', 0, G_OPTION_ARG_NONE, &run_script, N_("Run program through /etc/gdm/Xsession wrapper script"), NULL }, + { "allow-remote-connections", 'a', 0, G_OPTION_ARG_NONE, &allow_remote_connections, N_("Listen on TCP socket"), NULL }, +- { "register-session", 0, 0, G_OPTION_ARG_NONE, ®ister_session, "Register session after a delay", NULL }, ++ { "register-session", 0, 0, G_OPTION_ARG_NONE, &handle_registration, "Register session after a delay", NULL }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" }, + { NULL } + }; +@@ -937,11 +945,17 @@ main (int argc, + goto out; + } + +- if (register_session) { +- g_debug ("gdm-x-session: Will register session in %d seconds", REGISTER_SESSION_TIMEOUT); +- state->register_session_id = g_timeout_add_seconds (REGISTER_SESSION_TIMEOUT, +- register_session_timeout_cb, +- state); ++ if (handle_registration) { ++ if (!register_session (state)) { ++ g_printerr ("Unable to register session with display manager\n"); ++ exit_status = EX_SOFTWARE; ++ goto out; ++ } ++ ++ g_debug ("gdm-x-session: Will register display in %d seconds", REGISTER_DISPLAY_TIMEOUT); ++ state->register_display_id = g_timeout_add_seconds_once (REGISTER_DISPLAY_TIMEOUT, ++ register_display_timeout_cb, ++ state); + } else { + g_debug ("gdm-x-session: Session will register itself"); + } diff --git a/gdm.spec b/gdm.spec index 8fb6e37..92abdf6 100644 --- a/gdm.spec +++ b/gdm.spec @@ -48,7 +48,12 @@ Patch: 0001-Introduce-gdm-new-session-tool.patch # RHEL-86140 # https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/285 Patch: 0001-Revert-hack-that-quits-plymouth-late.patch -Patch: 0001-manager-Keep-register-display-method.patch + +# RHEL-178659 +# https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/350 +Patch: 0001-manager-Update-RegisterSession-dbus-method.patch +# https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/360 +Patch: 0001-manager-Schedule-deferred-plymouth-quit-on-session-r.patch # RHEL-4147 # https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/335