# Ported from gnome-session git commit 53cb8b5d6deb2f6425a388e46c58f097fe126904 # (30.6.2019) - " gsm-systemd: Find user's graphical session, not the current pid's session" # (https://github.com/GNOME/gnome-session/commit/53cb8b5): # ============================================================================= # If we're started by systemd --user, we won't be in the XDG session of # the user. The session will still exist, and we want to monitor when it # closes so that we know when to die ourselves. # diff -up mate-session-manager-f56f8cd63d330e576aeabd09a0600a8da2e02392/mate-session/gsm-systemd.c~ mate-session-manager-f56f8cd63d330e576aeabd09a0600a8da2e02392/mate-session/gsm-systemd.c --- mate-session-manager-f56f8cd63d330e576aeabd09a0600a8da2e02392/mate-session/gsm-systemd.c~ 2021-05-17 10:22:07.111952069 +0200 +++ mate-session-manager-f56f8cd63d330e576aeabd09a0600a8da2e02392/mate-session/gsm-systemd.c 2021-05-17 10:22:07.193952605 +0200 @@ -44,6 +44,8 @@ #define SD_SEAT_INTERFACE "org.freedesktop.login1.Seat" #define SD_SESSION_INTERFACE "org.freedesktop.login1.Session" +#define SYSTEMD_SESSION_REQUIRE_ONLINE 0 /* active or online sessions only */ + typedef struct { DBusGConnection *dbus_connection; @@ -292,6 +294,104 @@ gsm_systemd_on_name_owner_changed (DBusG gsm_systemd_ensure_sd_connection (manager, NULL); } +static gboolean +_systemd_session_is_graphical (const char *session_id) +{ + const gchar * const graphical_session_types[] = { "wayland", "x11", "mir", NULL }; + int saved_errno; + g_autofree gchar *type = NULL; + + saved_errno = sd_session_get_type (session_id, &type); + if (saved_errno < 0) { + g_warning ("Couldn't get type for session '%s': %s", + session_id, + g_strerror (-saved_errno)); + return FALSE; + } + + if (!g_strv_contains (graphical_session_types, type)) { + g_debug ("Session '%s' is not a graphical session (type: '%s')", + session_id, + type); + return FALSE; + } + + return TRUE; +} + +static gboolean +_systemd_session_is_active (const char *session_id) +{ + const gchar * const active_states[] = { "active", "online", NULL }; + int saved_errno; + g_autofree gchar *state = NULL; + + /* + * display sessions can be 'closing' if they are logged out but some + * processes are lingering; we shouldn't consider these (this is + * checking for a race condition since we specified + * SYSTEMD_SESSION_REQUIRE_ONLINE) + */ + saved_errno = sd_session_get_state (session_id, &state); + if (saved_errno < 0) { + g_warning ("Couldn't get state for session '%s': %s", + session_id, + g_strerror (-saved_errno)); + return FALSE; + } + + if (!g_strv_contains (active_states, state)) { + g_debug ("Session '%s' is not active or online", session_id); + return FALSE; + } + + return TRUE; +} + +static gboolean +gsm_systemd_find_session (char **session_id) +{ + char *local_session_id = NULL; + g_auto(GStrv) sessions = NULL; + int n_sessions; + + g_return_val_if_fail (session_id != NULL, FALSE); + + g_debug ("Finding a graphical session for user %d", getuid ()); + + n_sessions = sd_uid_get_sessions (getuid (), + SYSTEMD_SESSION_REQUIRE_ONLINE, + &sessions); + + if (n_sessions < 0) { + g_critical ("Failed to get sessions for user %d", getuid ()); + return FALSE; + } + + for (int i = 0; i < n_sessions; ++i) { + g_debug ("Considering session '%s'", sessions[i]); + + if (!_systemd_session_is_graphical (sessions[i])) + continue; + + if (!_systemd_session_is_active (sessions[i])) + continue; + + /* + * We get the sessions from newest to oldest, so take the last + * one we find that's good + */ + local_session_id = sessions[i]; + } + + if (local_session_id == NULL) + return FALSE; + + *session_id = g_strdup (local_session_id); + + return TRUE; +} + static void gsm_systemd_init (GsmSystemd *manager) { @@ -428,13 +528,15 @@ gsm_systemd_is_last_session_for_user (Gs int ret, i; #ifdef HAVE_SYSTEMD - ret = sd_pid_get_session (getpid (), &session); + ret = gsm_systemd_find_session (&session); #endif if (session == NULL) { return FALSE; } + g_debug ("Found session ID: %s", session); + if (ret != 0) { free (session); return FALSE; @@ -584,12 +686,14 @@ gsm_systemd_get_session_path (DBusConnec gchar *session_id = NULL; #ifdef HAVE_SYSTEMD - sd_pid_get_session (getpid (), &session_id); + gsm_systemd_find_session (&session_id); #endif if (session_id == NULL) return; + g_debug ("Found session ID: %s", session_id); + reply = NULL; dbus_error_init (&local_error); @@ -710,12 +814,14 @@ gsm_systemd_can_switch_user (GsmSystemd } #ifdef HAVE_SYSTEMD - sd_pid_get_session (getpid (), &session_id); + gsm_systemd_find_session (&session_id); #endif if (session_id == NULL) return FALSE; + g_debug ("Found session ID: %s", session_id); + #ifdef HAVE_SYSTEMD sd_session_get_seat (session_id, &seat_id); ret = sd_seat_can_multi_session (seat_id); @@ -989,12 +1095,14 @@ gsm_systemd_get_current_session_type (Gs } #ifdef HAVE_SYSTEMD - sd_pid_get_session (getpid (), &session_id); + gsm_systemd_find_session (&session_id); #endif if (session_id == NULL) return NULL; + g_debug ("Found session ID: %s", session_id); + #ifdef HAVE_SYSTEMD res = sd_session_get_class (session_id, &session_class); if (res < 0) {