From d524c8e88f558b9f2aebff39b6fbe77eab51e081 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:43:08 +0200 Subject: Adding upstream version 43.0. Signed-off-by: Daniel Baumann --- libgdm/gdm-user-switching.c | 258 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 libgdm/gdm-user-switching.c (limited to 'libgdm/gdm-user-switching.c') diff --git a/libgdm/gdm-user-switching.c b/libgdm/gdm-user-switching.c new file mode 100644 index 0000000..b39d21d --- /dev/null +++ b/libgdm/gdm-user-switching.c @@ -0,0 +1,258 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 Giovanni Campagna + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "common/gdm-common.h" +#include "gdm-user-switching.h" +#include "gdm-client.h" + +static gboolean +create_transient_display (GDBusConnection *connection, + GCancellable *cancellable, + GError **error) +{ + GVariant *reply; + const char *value; + + reply = g_dbus_connection_call_sync (connection, + "org.gnome.DisplayManager", + "/org/gnome/DisplayManager/LocalDisplayFactory", + "org.gnome.DisplayManager.LocalDisplayFactory", + "CreateTransientDisplay", + NULL, /* parameters */ + G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, error); + if (reply == NULL) { + g_prefix_error (error, _("Unable to create transient display: ")); + return FALSE; + } + + g_variant_get (reply, "(&o)", &value); + g_debug ("Started %s", value); + + g_variant_unref (reply); + return TRUE; +} + +static gboolean +activate_session_id (GDBusConnection *connection, + GCancellable *cancellable, + const char *seat_id, + const char *session_id, + GError **error) +{ + GVariant *reply; + + reply = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ActivateSessionOnSeat", + g_variant_new ("(ss)", session_id, seat_id), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, error); + if (reply == NULL) { + g_prefix_error (error, _("Unable to activate session: ")); + return FALSE; + } + + g_variant_unref (reply); + + return TRUE; +} + +static gboolean +get_login_window_session_id (const char *seat_id, + char **session_id) +{ + gboolean ret; + int res, i; + char **sessions; + char *service_id; + char *service_class; + char *state; + + res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL); + if (res < 0) { + g_debug ("Failed to determine sessions: %s", strerror (-res)); + return FALSE; + } + + if (sessions == NULL || sessions[0] == NULL) { + *session_id = NULL; + ret = TRUE; + goto out; + } + + for (i = 0; sessions[i]; i ++) { + + res = sd_session_get_class (sessions[i], &service_class); + if (res < 0) { + g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res)); + ret = FALSE; + goto out; + } + + if (strcmp (service_class, "greeter") != 0) { + free (service_class); + continue; + } + + free (service_class); + + ret = sd_session_get_state (sessions[i], &state); + if (ret < 0) { + g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res)); + ret = FALSE; + goto out; + } + + if (g_strcmp0 (state, "closing") == 0) { + free (state); + continue; + } + free (state); + + res = sd_session_get_service (sessions[i], &service_id); + if (res < 0) { + g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res)); + ret = FALSE; + goto out; + } + + if (strcmp (service_id, "gdm-launch-environment") == 0) { + *session_id = g_strdup (sessions[i]); + ret = TRUE; + + free (service_id); + goto out; + } + + free (service_id); + } + + *session_id = NULL; + ret = TRUE; + +out: + if (sessions) { + for (i = 0; sessions[i]; i ++) { + free (sessions[i]); + } + + free (sessions); + } + + return ret; +} + +static gboolean +goto_login_session (GDBusConnection *connection, + GCancellable *cancellable, + GError **error) +{ + gboolean ret; + int res; + char *our_session; + char *session_id; + char *seat_id; + GError *local_error = NULL; + + ret = FALSE; + session_id = NULL; + seat_id = NULL; + + /* First look for any existing LoginWindow sessions on the seat. + If none are found, create a new one. */ + + /* Note that we mostly use free () here, instead of g_free () + * since the data allocated is from libsystemd-logind, which + * does not use GLib's g_malloc (). */ + if (!gdm_find_display_session (0, getuid (), &our_session, &local_error)) { + g_propagate_prefixed_error (error, local_error, _("Could not identify the current session: ")); + + return FALSE; + } + + res = sd_session_get_seat (our_session, &seat_id); + free (our_session); + if (res < 0) { + g_debug ("failed to determine own seat: %s", strerror (-res)); + g_set_error (error, GDM_CLIENT_ERROR, 0, _("Could not identify the current seat.")); + + return FALSE; + } + + res = get_login_window_session_id (seat_id, &session_id); + if (res && session_id != NULL) { + res = activate_session_id (connection, cancellable, seat_id, session_id, error); + + if (res) { + ret = TRUE; + } + } + + if (! ret && g_strcmp0 (seat_id, "seat0") == 0) { + res = create_transient_display (connection, cancellable, error); + if (res) { + ret = TRUE; + } + } + + free (seat_id); + g_free (session_id); + + return ret; +} + +gboolean +gdm_goto_login_session_sync (GCancellable *cancellable, + GError **error) +{ + GDBusConnection *connection; + gboolean retval; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error); + if (!connection) + return FALSE; + + retval = goto_login_session (connection, cancellable, error); + + g_object_unref (connection); + return retval; +} -- cgit v1.2.3