From d6aca6da3ab9c16e907c7f46cf6d7bc2abbc2890 Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Tue, 7 May 2019 16:00:14 +0100 Subject: [PATCH 50/51] Allow sessions to register with GDM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recording when sessions start, for Wayland → Xorg fallback or transitioning to the user session, is currently done with timeouts. This isn't ideal, because on some very slow machines the timeout can be hit before the session has had a chance to fail: if gnome-session takes more than 3 seconds to fail then the session will be considered to have exited rather than failed, and so we don't do Xorg fallback. We can do this more reliably if we allow sessions to optionally register themselves with GDM. Then we will know when they've started, so can shut down the greeter or fall back to Xorg as appropriate. The mechanism is that they specify X-GDM-SessionRegisters=true in their file, and then call RegsterSession on the DisplayManager interface on the bus (added in the previous commit) to say that they've started up. If X-GDM-SessionRegisters is missing or false, GDM will call the same method for them after 10 seconds. Closes: #483 --- common/gdm-common.h | 2 + daemon/gdm-display.c | 19 ++----- daemon/gdm-local-display-factory.c | 49 +++++++++--------- daemon/gdm-session.c | 47 +++++++++++++++-- daemon/gdm-session.h | 1 + daemon/gdm-wayland-session.c | 81 +++++++++++++++++++++++------- daemon/gdm-x-session.c | 81 +++++++++++++++++++++++------- 7 files changed, 201 insertions(+), 79 deletions(-) diff --git a/common/gdm-common.h b/common/gdm-common.h index 3fbf07653..7fd6458d7 100644 --- a/common/gdm-common.h +++ b/common/gdm-common.h @@ -1,59 +1,61 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _GDM_COMMON_H #define _GDM_COMMON_H #include #include #include #include +#define REGISTER_SESSION_TIMEOUT 10 + #define VE_IGNORE_EINTR(expr) \ do { \ errno = 0; \ expr; \ } while G_UNLIKELY (errno == EINTR); GQuark gdm_common_error_quark (void); #define GDM_COMMON_ERROR gdm_common_error_quark() typedef char * (*GdmExpandVarFunc) (const char *var, gpointer user_data); G_BEGIN_DECLS int gdm_wait_on_pid (int pid); int gdm_wait_on_and_disown_pid (int pid, int timeout); int gdm_signal_pid (int pid, int signal); gboolean gdm_get_pwent_for_name (const char *name, struct passwd **pwentp); gboolean gdm_clear_close_on_exec_flag (int fd); const char * gdm_make_temp_dir (char *template); char *gdm_generate_random_bytes (gsize size, GError **error); gboolean gdm_get_login_window_session_id (const char *seat_id, char **session_id); diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c index 09cc2e116..ae20491cd 100644 --- a/daemon/gdm-display.c +++ b/daemon/gdm-display.c @@ -39,61 +39,60 @@ #include "gdm-common.h" #include "gdm-display.h" #include "gdm-display-glue.h" #include "gdm-display-access-file.h" #include "gdm-launch-environment.h" #include "gdm-settings-direct.h" #include "gdm-settings-keys.h" #include "gdm-launch-environment.h" #include "gdm-dbus-util.h" #define GNOME_SESSION_SESSIONS_PATH DATADIR "/gnome-session/sessions" #define GDM_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY, GdmDisplayPrivate)) struct GdmDisplayPrivate { char *id; char *seat_id; char *session_id; char *session_class; char *session_type; char *remote_hostname; int x11_display_number; char *x11_display_name; int status; time_t creation_time; - GTimer *server_timer; char *x11_cookie; gsize x11_cookie_size; GdmDisplayAccessFile *access_file; guint finish_idle_id; xcb_connection_t *xcb_connection; int xcb_screen_number; GDBusConnection *connection; GdmDisplayAccessFile *user_access_file; GdmDBusDisplay *display_skeleton; GDBusObjectSkeleton *object_skeleton; /* this spawns and controls the greeter session */ GdmLaunchEnvironment *launch_environment; guint is_local : 1; guint is_initial : 1; guint allow_timed_login : 1; guint have_existing_user_accounts : 1; guint doing_initial_setup : 1; guint session_registered : 1; }; enum { PROP_0, PROP_ID, @@ -510,62 +509,60 @@ gdm_display_prepare (GdmDisplay *self) * asynchronously */ look_for_existing_users_sync (self); self->priv->doing_initial_setup = wants_initial_setup (self); g_object_ref (self); ret = GDM_DISPLAY_GET_CLASS (self)->prepare (self); g_object_unref (self); return ret; } gboolean gdm_display_manage (GdmDisplay *self) { gboolean res; g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE); g_debug ("GdmDisplay: Managing display: %s", self->priv->id); /* If not explicitly prepared, do it now */ if (self->priv->status == GDM_DISPLAY_UNMANAGED) { res = gdm_display_prepare (self); if (! res) { return FALSE; } } - g_timer_start (self->priv->server_timer); - if (g_strcmp0 (self->priv->session_class, "greeter") == 0) { if (GDM_DISPLAY_GET_CLASS (self)->manage != NULL) { GDM_DISPLAY_GET_CLASS (self)->manage (self); } } return TRUE; } gboolean gdm_display_finish (GdmDisplay *self) { g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE); if (self->priv->finish_idle_id != 0) { g_source_remove (self->priv->finish_idle_id); self->priv->finish_idle_id = 0; } _gdm_display_set_status (self, GDM_DISPLAY_FINISHED); g_debug ("GdmDisplay: finish display"); return TRUE; } static void gdm_display_disconnect (GdmDisplay *self) { /* These 3 bits are reserved/unused by the X protocol */ @@ -576,85 +573,80 @@ gdm_display_disconnect (GdmDisplay *self) if (self->priv->xcb_connection == NULL) { return; } setup = xcb_get_setup (self->priv->xcb_connection); /* resource_id_mask is the bits given to each client for * addressing resources */ highest_client = (XID) ~unused_bits & ~setup->resource_id_mask; client_increment = setup->resource_id_mask + 1; /* Kill every client but ourselves, then close our own connection */ for (client = 0; client <= highest_client; client += client_increment) { if (client != setup->resource_id_base) xcb_kill_client (self->priv->xcb_connection, client); } xcb_flush (self->priv->xcb_connection); g_clear_pointer (&self->priv->xcb_connection, xcb_disconnect); } gboolean gdm_display_unmanage (GdmDisplay *self) { - gdouble elapsed; - g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE); g_debug ("GdmDisplay: unmanage display"); gdm_display_disconnect (self); - g_timer_stop (self->priv->server_timer); - if (self->priv->user_access_file != NULL) { gdm_display_access_file_close (self->priv->user_access_file); g_object_unref (self->priv->user_access_file); self->priv->user_access_file = NULL; } if (self->priv->access_file != NULL) { gdm_display_access_file_close (self->priv->access_file); g_object_unref (self->priv->access_file); self->priv->access_file = NULL; } - elapsed = g_timer_elapsed (self->priv->server_timer, NULL); - if (elapsed < 3) { - g_warning ("GdmDisplay: display lasted %lf seconds", elapsed); + if (!self->priv->session_registered) { + g_warning ("GdmDisplay: Session never registered, failing"); _gdm_display_set_status (self, GDM_DISPLAY_FAILED); } else { _gdm_display_set_status (self, GDM_DISPLAY_UNMANAGED); } return TRUE; } gboolean gdm_display_get_id (GdmDisplay *self, char **id, GError **error) { g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE); if (id != NULL) { *id = g_strdup (self->priv->id); } return TRUE; } gboolean gdm_display_get_x11_display_name (GdmDisplay *self, char **x11_display, GError **error) { g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE); if (x11_display != NULL) { @@ -898,61 +890,61 @@ gdm_display_get_property (GObject *object, case PROP_X11_DISPLAY_NAME: g_value_set_string (value, self->priv->x11_display_name); break; case PROP_X11_COOKIE: g_value_set_string (value, self->priv->x11_cookie); break; case PROP_X11_AUTHORITY_FILE: g_value_take_string (value, self->priv->access_file? gdm_display_access_file_get_path (self->priv->access_file) : NULL); break; case PROP_IS_LOCAL: g_value_set_boolean (value, self->priv->is_local); break; case PROP_IS_CONNECTED: g_value_set_boolean (value, self->priv->xcb_connection != NULL); break; case PROP_LAUNCH_ENVIRONMENT: g_value_set_object (value, self->priv->launch_environment); break; case PROP_IS_INITIAL: g_value_set_boolean (value, self->priv->is_initial); break; case PROP_HAVE_EXISTING_USER_ACCOUNTS: g_value_set_boolean (value, self->priv->have_existing_user_accounts); break; case PROP_DOING_INITIAL_SETUP: g_value_set_boolean (value, self->priv->doing_initial_setup); break; case PROP_SESSION_REGISTERED: - g_value_set_boolean (value, priv->session_registered); + g_value_set_boolean (value, self->priv->session_registered); break; case PROP_ALLOW_TIMED_LOGIN: g_value_set_boolean (value, self->priv->allow_timed_login); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean handle_get_id (GdmDBusDisplay *skeleton, GDBusMethodInvocation *invocation, GdmDisplay *self) { char *id; gdm_display_get_id (self, &id, NULL); gdm_dbus_display_complete_get_id (skeleton, invocation, id); g_free (id); return TRUE; } static gboolean handle_get_remote_hostname (GdmDBusDisplay *skeleton, GDBusMethodInvocation *invocation, GdmDisplay *self) { @@ -1251,99 +1243,94 @@ gdm_display_class_init (GdmDisplayClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_LAUNCH_ENVIRONMENT, g_param_spec_object ("launch-environment", NULL, NULL, GDM_TYPE_LAUNCH_ENVIRONMENT, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_STATUS, g_param_spec_int ("status", "status", "status", -1, G_MAXINT, GDM_DISPLAY_UNMANAGED, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GdmDisplayPrivate)); } static void gdm_display_init (GdmDisplay *self) { self->priv = GDM_DISPLAY_GET_PRIVATE (self); self->priv->creation_time = time (NULL); - self->priv->server_timer = g_timer_new (); } static void gdm_display_finalize (GObject *object) { GdmDisplay *self; g_return_if_fail (object != NULL); g_return_if_fail (GDM_IS_DISPLAY (object)); self = GDM_DISPLAY (object); g_return_if_fail (self->priv != NULL); g_debug ("GdmDisplay: Finalizing display: %s", self->priv->id); g_free (self->priv->id); g_free (self->priv->seat_id); g_free (self->priv->session_class); g_free (self->priv->remote_hostname); g_free (self->priv->x11_display_name); g_free (self->priv->x11_cookie); g_clear_object (&self->priv->display_skeleton); g_clear_object (&self->priv->object_skeleton); g_clear_object (&self->priv->connection); if (self->priv->access_file != NULL) { g_object_unref (self->priv->access_file); } if (self->priv->user_access_file != NULL) { g_object_unref (self->priv->user_access_file); } - if (self->priv->server_timer != NULL) { - g_timer_destroy (self->priv->server_timer); - } - G_OBJECT_CLASS (gdm_display_parent_class)->finalize (object); } GDBusObjectSkeleton * gdm_display_get_object_skeleton (GdmDisplay *self) { return self->priv->object_skeleton; } static void on_launch_environment_session_opened (GdmLaunchEnvironment *launch_environment, GdmDisplay *self) { char *session_id; g_debug ("GdmDisplay: Greeter session opened"); session_id = gdm_launch_environment_get_session_id (launch_environment); _gdm_display_set_session_id (self, session_id); g_free (session_id); } static void on_launch_environment_session_started (GdmLaunchEnvironment *launch_environment, GdmDisplay *self) { g_debug ("GdmDisplay: Greeter started"); } static void self_destruct (GdmDisplay *self) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index aae226750..35880563d 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -39,61 +39,60 @@ #include "gdm-settings-keys.h" #include "gdm-settings-direct.h" #include "gdm-display-store.h" #include "gdm-local-display.h" #include "gdm-legacy-display.h" #define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate)) #define GDM_DBUS_PATH "/org/gnome/DisplayManager" #define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory" #define GDM_MANAGER_DBUS_NAME "org.gnome.DisplayManager.LocalDisplayFactory" #define MAX_DISPLAY_FAILURES 5 #define WAIT_TO_FINISH_TIMEOUT 10 /* seconds */ struct GdmLocalDisplayFactoryPrivate { GdmDBusLocalDisplayFactory *skeleton; GDBusConnection *connection; GHashTable *used_display_numbers; /* FIXME: this needs to be per seat? */ guint num_failures; guint seat_new_id; guint seat_removed_id; #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) unsigned int active_vt; guint active_vt_watch_id; - guint wait_to_finish_timeout_id; #endif }; enum { PROP_0, }; static void gdm_local_display_factory_class_init (GdmLocalDisplayFactoryClass *klass); static void gdm_local_display_factory_init (GdmLocalDisplayFactory *factory); static void gdm_local_display_factory_finalize (GObject *object); static GdmDisplay *create_display (GdmLocalDisplayFactory *factory, const char *seat_id, const char *session_type, gboolean initial_display); static void on_display_status_changed (GdmDisplay *display, GParamSpec *arg1, GdmLocalDisplayFactory *factory); static gboolean gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory); static gpointer local_display_factory_object = NULL; static gboolean lookup_by_session_id (const char *id, GdmDisplay *display, gpointer user_data); G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY) GQuark gdm_local_display_factory_error_quark (void) @@ -276,60 +275,79 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact static gboolean finish_display_on_seat_if_waiting (GdmDisplayStore *display_store, GdmDisplay *display, const char *seat_id) { if (gdm_display_get_status (display) != GDM_DISPLAY_WAITING_TO_FINISH) return FALSE; g_debug ("GdmLocalDisplayFactory: finish background display\n"); gdm_display_stop_greeter_session (display); gdm_display_unmanage (display); gdm_display_finish (display); return FALSE; } static void finish_waiting_displays_on_seat (GdmLocalDisplayFactory *factory, const char *seat_id) { GdmDisplayStore *store; store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); gdm_display_store_foreach (store, (GdmDisplayStoreFunc) finish_display_on_seat_if_waiting, (gpointer) seat_id); } +static void +on_session_registered_cb (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + GdmDisplay *display = GDM_DISPLAY (gobject); + GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (user_data); + gboolean registered; + + g_object_get (display, "session-registered", ®istered, NULL); + + if (!registered) + return; + + g_debug ("GdmLocalDisplayFactory: session registered on display, looking for any background displays to kill"); + + finish_waiting_displays_on_seat (factory, "seat0"); +} + static void on_display_status_changed (GdmDisplay *display, GParamSpec *arg1, GdmLocalDisplayFactory *factory) { int status; int num; char *seat_id = NULL; char *session_type = NULL; char *session_class = NULL; gboolean is_initial = TRUE; gboolean is_local = TRUE; num = -1; gdm_display_get_x11_display_number (display, &num, NULL); g_object_get (display, "seat-id", &seat_id, "is-initial", &is_initial, "is-local", &is_local, "session-type", &session_type, "session-class", &session_class, NULL); status = gdm_display_get_status (display); g_debug ("GdmLocalDisplayFactory: display status changed: %d", status); switch (status) { case GDM_DISPLAY_FINISHED: /* remove the display number from factory->priv->used_display_numbers @@ -359,60 +377,67 @@ on_display_status_changed (GdmDisplay *display, /* Create a new equivalent display if it was static */ if (is_local) { factory->priv->num_failures++; if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) { /* oh shit */ g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors"); } else { #ifdef ENABLE_WAYLAND_SUPPORT if (g_strcmp0 (session_type, "wayland") == 0) { g_free (session_type); session_type = NULL; /* workaround logind race for now * bug 1643874 */ g_usleep (2 * G_USEC_PER_SEC); } #endif create_display (factory, seat_id, session_type, is_initial); } } break; case GDM_DISPLAY_UNMANAGED: break; case GDM_DISPLAY_PREPARED: break; case GDM_DISPLAY_MANAGED: +#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) + g_signal_connect_object (display, + "notify::session-registered", + G_CALLBACK (on_session_registered_cb), + factory, + 0); +#endif break; case GDM_DISPLAY_WAITING_TO_FINISH: break; default: g_assert_not_reached (); break; } g_free (seat_id); g_free (session_type); g_free (session_class); } static gboolean lookup_by_seat_id (const char *id, GdmDisplay *display, gpointer user_data) { const char *looking_for = user_data; char *current; gboolean res; g_object_get (G_OBJECT (display), "seat-id", ¤t, NULL); res = g_strcmp0 (current, looking_for) == 0; g_free(current); return res; } @@ -587,100 +612,83 @@ on_seat_new (GDBusConnection *connection, } static void on_seat_removed (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { const char *seat; g_variant_get (parameters, "(&s&o)", &seat, NULL); delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat); } #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) static gboolean lookup_by_session_id (const char *id, GdmDisplay *display, gpointer user_data) { const char *looking_for = user_data; const char *current; current = gdm_display_get_session_id (display); return g_strcmp0 (current, looking_for) == 0; } -static gboolean -wait_to_finish_timeout (GdmLocalDisplayFactory *factory) -{ - finish_waiting_displays_on_seat (factory, "seat0"); - factory->priv->wait_to_finish_timeout_id = 0; - return G_SOURCE_REMOVE; -} - static void maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory, GdmDisplay *display) { gboolean doing_initial_setup = FALSE; if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) { g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring"); return; } g_object_get (G_OBJECT (display), "doing-initial-setup", &doing_initial_setup, NULL); /* we don't ever stop initial-setup implicitly */ if (doing_initial_setup) { g_debug ("GdmLocalDisplayFactory: login window is performing initial-setup, so ignoring"); return; } g_debug ("GdmLocalDisplayFactory: killing login window once its unused"); g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL); - - /* We stop the greeter after a timeout to avoid flicker */ - if (factory->priv->wait_to_finish_timeout_id != 0) - g_source_remove (factory->priv->wait_to_finish_timeout_id); - - factory->priv->wait_to_finish_timeout_id = - g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT, - (GSourceFunc)wait_to_finish_timeout, - factory); } static gboolean on_vt_changed (GIOChannel *source, GIOCondition condition, GdmLocalDisplayFactory *factory) { GIOStatus status; g_autofree char *tty_of_active_vt = NULL; g_autofree char *login_session_id = NULL; g_autofree char *active_session_id = NULL; unsigned int previous_vt, new_vt; const char *session_type = NULL; int ret, n_returned; g_debug ("GdmLocalDisplayFactory: received VT change event"); g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL); if (condition & G_IO_PRI) { g_autoptr (GError) error = NULL; status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error); if (error != NULL) { g_warning ("could not read active VT from kernel: %s", error->message); } switch (status) { case G_IO_STATUS_ERROR: return G_SOURCE_REMOVE; case G_IO_STATUS_EOF: return G_SOURCE_REMOVE; @@ -722,61 +730,60 @@ on_vt_changed (GIOChannel *source, factory->priv->active_vt = new_vt; /* don't do anything at start up */ if (previous_vt == 0) { g_debug ("GdmLocalDisplayFactory: VT is %u at startup", factory->priv->active_vt); return G_SOURCE_CONTINUE; } g_debug ("GdmLocalDisplayFactory: VT changed from %u to %u", previous_vt, factory->priv->active_vt); /* if the old VT was running a wayland login screen kill it */ if (gdm_get_login_window_session_id ("seat0", &login_session_id)) { unsigned int login_window_vt; ret = sd_session_get_vt (login_session_id, &login_window_vt); if (ret == 0 && login_window_vt != 0) { g_debug ("GdmLocalDisplayFactory: VT of login window is %u", login_window_vt); if (login_window_vt == previous_vt) { GdmDisplayStore *store; GdmDisplay *display; g_debug ("GdmLocalDisplayFactory: VT switched from login window"); store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); display = gdm_display_store_find (store, lookup_by_session_id, (gpointer) login_session_id); - if (display != NULL) maybe_stop_greeter_in_background (factory, display); } else { g_debug ("GdmLocalDisplayFactory: VT not switched from login window"); } } } /* if user jumped back to initial vt and it's empty put a login screen * on it (unless a login screen is already running elsewhere, then * jump to that login screen) */ if (factory->priv->active_vt != GDM_INITIAL_VT) { g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring"); return G_SOURCE_CONTINUE; } if (gdm_local_display_factory_use_wayland ()) session_type = "wayland"; g_debug ("GdmLocalDisplayFactory: creating new display on seat0 because of VT change"); create_display (factory, "seat0", session_type, TRUE); return G_SOURCE_CONTINUE; } #endif static void gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory) @@ -805,64 +812,60 @@ gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory) g_object_unref); #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) io_channel = g_io_channel_new_file ("/sys/class/tty/tty0/active", "r", NULL); if (io_channel != NULL) { factory->priv->active_vt_watch_id = g_io_add_watch (io_channel, G_IO_PRI, (GIOFunc) on_vt_changed, factory); } #endif } static void gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory) { if (factory->priv->seat_new_id) { g_dbus_connection_signal_unsubscribe (factory->priv->connection, factory->priv->seat_new_id); factory->priv->seat_new_id = 0; } if (factory->priv->seat_removed_id) { g_dbus_connection_signal_unsubscribe (factory->priv->connection, factory->priv->seat_removed_id); factory->priv->seat_removed_id = 0; } #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) - if (factory->priv->wait_to_finish_timeout_id != 0) { - g_source_remove (factory->priv->wait_to_finish_timeout_id); - factory->priv->wait_to_finish_timeout_id = 0; - } if (factory->priv->active_vt_watch_id) { g_source_remove (factory->priv->active_vt_watch_id); factory->priv->active_vt_watch_id = 0; } #endif } static void on_display_added (GdmDisplayStore *display_store, const char *id, GdmLocalDisplayFactory *factory) { GdmDisplay *display; display = gdm_display_store_lookup (display_store, id); if (display != NULL) { g_signal_connect_object (display, "notify::status", G_CALLBACK (on_display_status_changed), factory, 0); g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory); } } static void on_display_removed (GdmDisplayStore *display_store, GdmDisplay *display, GdmLocalDisplayFactory *factory) diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c index 5b76ba129..540a2534d 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -2849,132 +2849,139 @@ on_start_program_cb (GdmDBusWorker *worker, self = conversation->session; service_name = conversation->service_name; if (worked) { self->priv->session_pid = pid; self->priv->session_conversation = conversation; g_debug ("GdmSession: Emitting 'session-started' signal with pid '%d'", pid); g_signal_emit (self, signals[SESSION_STARTED], 0, service_name, pid); } else { gdm_session_stop_conversation (self, service_name); g_debug ("GdmSession: Emitting 'session-start-failed' signal"); g_signal_emit (self, signals[SESSION_START_FAILED], 0, service_name, error->message); } } void gdm_session_start_session (GdmSession *self, const char *service_name) { GdmSessionConversation *conversation; GdmSessionDisplayMode display_mode; gboolean is_x11 = TRUE; gboolean run_launcher = FALSE; gboolean allow_remote_connections = FALSE; gboolean run_separate_bus = FALSE; char *command; char *program; + gboolean register_session; g_return_if_fail (GDM_IS_SESSION (self)); g_return_if_fail (self->priv->session_conversation == NULL); conversation = find_conversation_by_name (self, service_name); if (conversation == NULL) { g_warning ("GdmSession: Tried to start session of " "nonexistent conversation %s", service_name); return; } stop_all_other_conversations (self, conversation, FALSE); display_mode = gdm_session_get_display_mode (self); #ifdef ENABLE_WAYLAND_SUPPORT is_x11 = g_strcmp0 (self->priv->session_type, "wayland") != 0; #endif if (display_mode == GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED || display_mode == GDM_SESSION_DISPLAY_MODE_NEW_VT) { run_launcher = TRUE; } if (g_strcmp0 (self->priv->display_seat_id, "seat0") != 0 && !run_launcher) { run_separate_bus = TRUE; } + register_session = !gdm_session_session_registers (self); + if (self->priv->selected_program == NULL) { gboolean run_xsession_script; command = get_session_command (self); run_xsession_script = !gdm_session_bypasses_xsession (self); if (self->priv->display_is_local) { gboolean disallow_tcp = TRUE; gdm_settings_direct_get_boolean (GDM_KEY_DISALLOW_TCP, &disallow_tcp); allow_remote_connections = !disallow_tcp; } else { allow_remote_connections = TRUE; } if (run_launcher) { if (is_x11) { - program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s %s\"%s\"", + program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s%s %s\"%s\"", + register_session ? "--register-session " : "", run_xsession_script? "--run-script " : "", allow_remote_connections? "--allow-remote-connections " : "", command); } else { - program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session \"%s\"", + program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"%s\"", + register_session ? "--register-session " : "", command); } } else if (run_xsession_script) { if (run_separate_bus) { program = g_strdup_printf ("dbus-run-session -- " GDMCONFDIR "/Xsession \"%s\"", command); } else { program = g_strdup_printf (GDMCONFDIR "/Xsession \"%s\"", command); } } else { program = g_strdup (command); } g_free (command); } else { if (run_launcher) { if (is_x11) { - program = g_strdup_printf (LIBEXECDIR "/gdm-x-session \"%s\"", + program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s\"%s\"", + register_session ? "--register-session " : "", self->priv->selected_program); } else { - program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session \"%s\"", + program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"%s\"", + register_session ? "--register-session " : "", self->priv->selected_program); } } else { if (run_separate_bus) { program = g_strdup_printf ("dbus-run-session -- %s", self->priv->selected_program); } else { program = g_strdup (self->priv->selected_program); } } } set_up_session_environment (self); send_environment (self, conversation); gdm_dbus_worker_call_start_program (conversation->worker_proxy, program, conversation->worker_cancellable, (GAsyncReadyCallback) on_start_program_cb, conversation); g_free (program); } static void stop_all_conversations (GdmSession *self) { stop_all_other_conversations (self, NULL, TRUE); } static void @@ -3199,60 +3206,92 @@ gdm_session_is_wayland_session (GdmSession *self) } if (full_path != NULL && strstr (full_path, "/wayland-sessions/") != NULL) { is_wayland_session = TRUE; } } out: g_debug ("GdmSession: checking if file '%s' is wayland session: %s", filename, is_wayland_session? "yes" : "no"); return is_wayland_session; } #endif static void update_session_type (GdmSession *self) { #ifdef ENABLE_WAYLAND_SUPPORT gboolean is_wayland_session = FALSE; is_wayland_session = gdm_session_is_wayland_session (self); if (is_wayland_session) { set_session_type (self, "wayland"); } else { set_session_type (self, NULL); } #endif } +gboolean +gdm_session_session_registers (GdmSession *self) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GKeyFile) key_file = NULL; + gboolean session_registers = FALSE; + g_autofree char *filename = NULL; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); + + filename = get_session_filename (self); + + key_file = load_key_file_for_file (self, filename, NULL, NULL); + + session_registers = g_key_file_get_boolean (key_file, + G_KEY_FILE_DESKTOP_GROUP, + "X-GDM-SessionRegisters", + &error); + if (!session_registers && + error != NULL && + !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) { + g_warning ("GdmSession: Couldn't read session file '%s'", filename); + return FALSE; + } + + g_debug ("GdmSession: '%s' %s self", filename, + session_registers ? "registers" : "does not register"); + + return session_registers; +} + gboolean gdm_session_bypasses_xsession (GdmSession *self) { GError *error; GKeyFile *key_file; gboolean res; gboolean bypasses_xsession = FALSE; char *filename = NULL; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); #ifdef ENABLE_WAYLAND_SUPPORT if (gdm_session_is_wayland_session (self)) { bypasses_xsession = TRUE; goto out; } #endif filename = get_session_filename (self); key_file = load_key_file_for_file (self, filename, "x11", NULL); error = NULL; res = g_key_file_has_key (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", NULL); if (!res) { goto out; } else { bypasses_xsession = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", &error); if (error) { diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h index a22c09543..682d2c99f 100644 --- a/daemon/gdm-session.h +++ b/daemon/gdm-session.h @@ -108,60 +108,61 @@ typedef struct void (* conversation_started) (GdmSession *session, const char *service_name); void (* conversation_stopped) (GdmSession *session, const char *service_name); void (* setup_complete) (GdmSession *session, const char *service_name); } GdmSessionClass; GType gdm_session_get_type (void); GdmSession *gdm_session_new (GdmSessionVerificationMode verification_mode, uid_t allowed_user, const char *display_name, const char *display_hostname, const char *display_device, const char *display_seat_id, const char *display_x11_authority_file, gboolean display_is_local, const char * const *environment); uid_t gdm_session_get_allowed_user (GdmSession *session); void gdm_session_start_reauthentication (GdmSession *session, GPid pid_of_caller, uid_t uid_of_caller); const char *gdm_session_get_server_address (GdmSession *session); const char *gdm_session_get_username (GdmSession *session); const char *gdm_session_get_display_device (GdmSession *session); const char *gdm_session_get_display_seat_id (GdmSession *session); const char *gdm_session_get_session_id (GdmSession *session); gboolean gdm_session_bypasses_xsession (GdmSession *session); +gboolean gdm_session_session_registers (GdmSession *session); GdmSessionDisplayMode gdm_session_get_display_mode (GdmSession *session); #ifdef ENABLE_WAYLAND_SUPPORT void gdm_session_set_ignore_wayland (GdmSession *session, gboolean ignore_wayland); #endif gboolean gdm_session_start_conversation (GdmSession *session, const char *service_name); void gdm_session_stop_conversation (GdmSession *session, const char *service_name); const char *gdm_session_get_conversation_session_id (GdmSession *session, const char *service_name); void gdm_session_setup (GdmSession *session, const char *service_name); void gdm_session_setup_for_user (GdmSession *session, const char *service_name, const char *username); void gdm_session_setup_for_program (GdmSession *session, const char *service_name, const char *username, const char *log_file); void gdm_session_set_environment_variable (GdmSession *session, const char *key, const char *value); void gdm_session_send_environment (GdmSession *self, const char *service_name); void gdm_session_reset (GdmSession *session); void gdm_session_cancel (GdmSession *session); void gdm_session_authenticate (GdmSession *session, const char *service_name); diff --git a/daemon/gdm-wayland-session.c b/daemon/gdm-wayland-session.c index 94f49e19c..35679b194 100644 --- a/daemon/gdm-wayland-session.c +++ b/daemon/gdm-wayland-session.c @@ -18,68 +18,71 @@ * 02110-1301, USA. */ #include "config.h" #include #include #include "gdm-common.h" #include "gdm-settings-direct.h" #include "gdm-settings-keys.h" #include "gdm-log.h" #include "gdm-manager-glue.h" #include #include #include #include #include #define BUS_ADDRESS_FILENO (STDERR_FILENO + 1) typedef struct { GdmSettings *settings; GCancellable *cancellable; GSubprocess *bus_subprocess; GDBusConnection *bus_connection; + GdmDBusManager *display_manager_proxy; char *bus_address; char **environment; GSubprocess *session_subprocess; char *session_command; int session_exit_status; + guint register_session_id; + GMainLoop *main_loop; guint32 debug_enabled : 1; } State; static void on_bus_finished (GSubprocess *subprocess, GAsyncResult *result, State *state) { gboolean cancelled; cancelled = !g_subprocess_wait_finish (subprocess, result, NULL); if (cancelled) { goto out; } if (g_subprocess_get_if_exited (subprocess)) { int exit_status; exit_status = g_subprocess_get_exit_status (subprocess); g_debug ("message bus exited with status %d", exit_status); } else { int signal_number; signal_number = g_subprocess_get_term_sig (subprocess); g_debug ("message bus was killed with status %d", signal_number); } @@ -358,140 +361,170 @@ out: } static void signal_subprocesses (State *state) { if (state->session_subprocess != NULL) { g_subprocess_send_signal (state->session_subprocess, SIGTERM); } if (state->bus_subprocess != NULL) { g_subprocess_send_signal (state->bus_subprocess, SIGTERM); } } static void wait_on_subprocesses (State *state) { if (state->bus_subprocess != NULL) { g_subprocess_wait (state->bus_subprocess, NULL, NULL); } if (state->session_subprocess != NULL) { g_subprocess_wait (state->session_subprocess, NULL, NULL); } } static gboolean register_display (State *state, GCancellable *cancellable) { - GdmDBusManager *manager = NULL; GError *error = NULL; gboolean registered = FALSE; GVariantBuilder details; - manager = gdm_dbus_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - "org.gnome.DisplayManager", - "/org/gnome/DisplayManager/Manager", - cancellable, - &error); - - if (!manager) { - g_debug ("could not contact display manager: %s", error->message); - g_error_free (error); - goto out; - } - g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}")); g_variant_builder_add (&details, "{ss}", "session-type", "wayland"); - registered = gdm_dbus_manager_call_register_display_sync (manager, + registered = gdm_dbus_manager_call_register_display_sync (state->display_manager_proxy, g_variant_builder_end (&details), cancellable, &error); if (error != NULL) { g_debug ("Could not register display: %s", error->message); g_error_free (error); } -out: - g_clear_object (&manager); return registered; } static void init_state (State **state) { static State state_allocation; *state = &state_allocation; } static void clear_state (State **out_state) { State *state = *out_state; g_clear_object (&state->cancellable); g_clear_object (&state->bus_connection); 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); *out_state = NULL; } static gboolean on_sigterm (State *state) { g_cancellable_cancel (state->cancellable); if (g_main_loop_is_running (state->main_loop)) { g_main_loop_quit (state->main_loop); } return G_SOURCE_CONTINUE; } +static gboolean +register_session_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; +} + +static gboolean +connect_to_display_manager (State *state) +{ + g_autoptr (GError) error = NULL; + + state->display_manager_proxy = gdm_dbus_manager_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + "org.gnome.DisplayManager", + "/org/gnome/DisplayManager/Manager", + state->cancellable, + &error); + + if (state->display_manager_proxy == NULL) { + g_printerr ("gdm-wayland-session: could not contact display manager: %s\n", + error->message); + return FALSE; + } + + return TRUE; +} + int main (int argc, char **argv) { State *state = NULL; GOptionContext *context = NULL; static char **args = NULL; gboolean debug = FALSE; gboolean ret; int exit_status = EX_OK; + static gboolean register_session = FALSE; + static GOptionEntry entries [] = { + { "register-session", 0, 0, G_OPTION_ARG_NONE, ®ister_session, "Register session after a delay", NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" }, { NULL } }; bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); setlocale (LC_ALL, ""); gdm_log_init (); context = g_option_context_new (_("GNOME Display Manager Wayland Session Launcher")); g_option_context_add_main_entries (context, entries, NULL); g_option_context_parse (context, &argc, &argv, NULL); g_option_context_free (context); if (args == NULL || args[0] == NULL || args[1] != NULL) { g_warning ("gdm-wayland-session takes one argument (the session)"); exit_status = EX_USAGE; goto out; } init_state (&state); state->session_command = args[0]; state->settings = gdm_settings_new (); ret = gdm_settings_direct_init (state->settings, DATADIR "/gdm/gdm.schemas", "/"); if (!ret) { @@ -501,55 +534,67 @@ main (int argc, } gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug); state->debug_enabled = debug; gdm_log_set_debug (debug); state->main_loop = g_main_loop_new (NULL, FALSE); state->cancellable = g_cancellable_new (); g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state); ret = spawn_bus (state, state->cancellable); if (!ret) { g_printerr ("Unable to run session message bus\n"); exit_status = EX_SOFTWARE; goto out; } import_environment (state, state->cancellable); ret = spawn_session (state, state->cancellable); if (!ret) { g_printerr ("Unable to run session\n"); exit_status = EX_SOFTWARE; goto out; } + if (!connect_to_display_manager (state)) + goto out; + ret = register_display (state, state->cancellable); if (!ret) { g_printerr ("Unable to register display with display manager\n"); exit_status = EX_SOFTWARE; 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); + } else { + g_debug ("gdm-wayland-session: Session will register itself"); + } + g_main_loop_run (state->main_loop); /* Only use exit status of session if we're here because it exit */ if (state->session_subprocess == NULL) { exit_status = state->session_exit_status; } out: if (state != NULL) { signal_subprocesses (state); wait_on_subprocesses (state); clear_state (&state); } return exit_status; } diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c index d8e3c7d53..f0082fdc6 100644 --- a/daemon/gdm-x-session.c +++ b/daemon/gdm-x-session.c @@ -24,68 +24,71 @@ #include "gdm-common.h" #include "gdm-settings-direct.h" #include "gdm-settings-keys.h" #include "gdm-log.h" #include "gdm-manager-glue.h" #include #include #include #include #include #include #include #define DISPLAY_FILENO (STDERR_FILENO + 1) #define BUS_ADDRESS_FILENO (DISPLAY_FILENO + 1) typedef struct { GdmSettings *settings; GCancellable *cancellable; GSubprocess *x_subprocess; char *auth_file; char *display_name; GSubprocess *bus_subprocess; GDBusConnection *bus_connection; + GdmDBusManager *display_manager_proxy; char *bus_address; char **environment; GSubprocess *session_subprocess; char *session_command; int session_exit_status; + guint register_session_id; + GMainLoop *main_loop; guint32 debug_enabled : 1; } State; static FILE * create_auth_file (char **filename) { char *auth_dir = NULL; char *auth_file = NULL; int fd; FILE *fp = NULL; auth_dir = g_build_filename (g_get_user_runtime_dir (), "gdm", NULL); g_mkdir_with_parents (auth_dir, 0711); auth_file = g_build_filename (auth_dir, "Xauthority", NULL); g_clear_pointer (&auth_dir, g_free); fd = g_open (auth_file, O_RDWR | O_CREAT | O_TRUNC, 0700); if (fd < 0) { g_debug ("could not open %s to store auth cookie: %m", auth_file); g_clear_pointer (&auth_file, g_free); goto out; } @@ -711,148 +714,178 @@ signal_subprocesses (State *state) if (state->bus_subprocess != NULL) { g_subprocess_send_signal (state->bus_subprocess, SIGTERM); } if (state->x_subprocess != NULL) { g_subprocess_send_signal (state->x_subprocess, SIGTERM); } } static void wait_on_subprocesses (State *state) { if (state->x_subprocess != NULL) { g_subprocess_wait (state->x_subprocess, NULL, NULL); } if (state->bus_subprocess != NULL) { g_subprocess_wait (state->bus_subprocess, NULL, NULL); } if (state->session_subprocess != NULL) { g_subprocess_wait (state->session_subprocess, NULL, NULL); } } static gboolean register_display (State *state, GCancellable *cancellable) { - GdmDBusManager *manager = NULL; GError *error = NULL; gboolean registered = FALSE; GVariantBuilder details; - manager = gdm_dbus_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - "org.gnome.DisplayManager", - "/org/gnome/DisplayManager/Manager", - cancellable, - &error); - - if (!manager) { - g_debug ("could not contact display manager: %s", error->message); - g_error_free (error); - goto out; - } - g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}")); g_variant_builder_add (&details, "{ss}", "session-type", "x11"); g_variant_builder_add (&details, "{ss}", "x11-display-name", state->display_name); - registered = gdm_dbus_manager_call_register_display_sync (manager, + registered = gdm_dbus_manager_call_register_display_sync (state->display_manager_proxy, g_variant_builder_end (&details), cancellable, &error); if (error != NULL) { g_debug ("Could not register display: %s", error->message); g_error_free (error); } -out: - g_clear_object (&manager); return registered; } static void init_state (State **state) { static State state_allocation; *state = &state_allocation; } static void clear_state (State **out_state) { State *state = *out_state; g_clear_object (&state->cancellable); g_clear_object (&state->bus_connection); g_clear_object (&state->session_subprocess); g_clear_object (&state->x_subprocess); g_clear_pointer (&state->environment, g_strfreev); 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); *out_state = NULL; } static gboolean on_sigterm (State *state) { g_cancellable_cancel (state->cancellable); if (g_main_loop_is_running (state->main_loop)) { g_main_loop_quit (state->main_loop); } return G_SOURCE_CONTINUE; } +static gboolean +register_session_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; +} + +static gboolean +connect_to_display_manager (State *state) +{ + g_autoptr (GError) error = NULL; + + state->display_manager_proxy = gdm_dbus_manager_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + "org.gnome.DisplayManager", + "/org/gnome/DisplayManager/Manager", + state->cancellable, + &error); + + if (state->display_manager_proxy == NULL) { + g_printerr ("gdm-x-session: could not contact display manager: %s\n", + error->message); + return FALSE; + } + + return TRUE; +} + int main (int argc, char **argv) { State *state = NULL; GOptionContext *context = NULL; static char **args = NULL; static gboolean run_script = FALSE; static gboolean allow_remote_connections = FALSE; gboolean debug = FALSE; gboolean ret; int exit_status = EX_OK; + static gboolean register_session = 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 }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" }, { NULL } }; bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); setlocale (LC_ALL, ""); gdm_log_init (); context = g_option_context_new (_("GNOME Display Manager X Session Launcher")); g_option_context_add_main_entries (context, entries, NULL); g_option_context_parse (context, &argc, &argv, NULL); g_option_context_free (context); if (args == NULL || args[0] == NULL || args[1] != NULL) { g_warning ("gdm-x-session takes one argument (the session)"); exit_status = EX_USAGE; goto out; } init_state (&state); state->session_command = args[0]; state->settings = gdm_settings_new (); ret = gdm_settings_direct_init (state->settings, DATADIR "/gdm/gdm.schemas", "/"); if (!ret) { @@ -870,63 +903,75 @@ main (int argc, state->cancellable = g_cancellable_new (); g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state); ret = spawn_x_server (state, allow_remote_connections, state->cancellable); if (!ret) { g_printerr ("Unable to run X server\n"); exit_status = EX_SOFTWARE; goto out; } ret = spawn_bus (state, state->cancellable); if (!ret) { g_printerr ("Unable to run session message bus\n"); exit_status = EX_SOFTWARE; goto out; } import_environment (state, state->cancellable); ret = update_bus_environment (state, state->cancellable); if (!ret) { g_printerr ("Unable to update bus environment\n"); exit_status = EX_SOFTWARE; goto out; } + if (!connect_to_display_manager (state)) + goto out; + ret = register_display (state, state->cancellable); if (!ret) { g_printerr ("Unable to register display with display manager\n"); exit_status = EX_SOFTWARE; goto out; } ret = spawn_session (state, run_script, state->cancellable); if (!ret) { g_printerr ("Unable to run session\n"); exit_status = EX_SOFTWARE; 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); + } else { + g_debug ("gdm-x-session: Session will register itself"); + } + g_main_loop_run (state->main_loop); /* Only use exit status of session if we're here because it exit */ if (state->session_subprocess == NULL) { exit_status = state->session_exit_status; } out: if (state != NULL) { signal_subprocesses (state); wait_on_subprocesses (state); clear_state (&state); } return exit_status; } -- 2.27.0