diff options
author | Ray Strode <halfline@gmail.com> | 2018-08-03 21:27:31 +0000 |
---|---|---|
committer | Ray Strode <halfline@gmail.com> | 2018-08-03 21:27:31 +0000 |
commit | 904b254f819f5a1efb2c9ac96ba4712ed9dc6ef3 (patch) | |
tree | ad3b99de29a26e937b2b5f0369a2113e6f02621a | |
parent | c22145194b7153253743c94d95c7e1f1a056b7d3 (diff) | |
parent | c0188a7030f2e629eefc47eeae1aa8313b7fda1b (diff) | |
download | gdm-904b254f819f5a1efb2c9ac96ba4712ed9dc6ef3.tar.gz |
Merge branch 'wip/reap-greeter-on-login' into 'master'
kill and restart greeter on demand under wayland
Closes #222
See merge request GNOME/gdm!26
-rw-r--r-- | daemon/gdm-local-display-factory.c | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index f214185f..8bf92b64 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -61,6 +61,11 @@ struct GdmLocalDisplayFactoryPrivate guint seat_new_id; guint seat_removed_id; + +#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) + char *tty_of_active_vt; + guint active_vt_watch_id; +#endif }; enum { @@ -395,7 +400,7 @@ create_display (GdmLocalDisplayFactory *factory, return NULL; } g_clear_pointer (&active_session_id, g_free); - } else { + } else if (!sd_seat_can_multi_session (seat_id)) { /* Ensure we don't create the same display more than once */ display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id); @@ -529,9 +534,150 @@ on_seat_removed (GDBusConnection *connection, 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 void +maybe_stop_greeter_display (GdmDisplay *display) +{ + g_autofree char *display_session_type = NULL; + + if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) + return; + + g_object_get (G_OBJECT (display), + "session-type", &display_session_type, + NULL); + + /* we can only stop greeter for wayland sessions, since + * X server would jump back on exit */ + if (g_strcmp0 (display_session_type, "wayland") != 0) + return; + + gdm_display_stop_greeter_session (display); + gdm_display_unmanage (display); + gdm_display_finish (display); +} + +static gboolean +on_vt_changed (GIOChannel *source, + GIOCondition condition, + GdmLocalDisplayFactory *factory) +{ + GIOStatus status; + static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT; + g_autofree char *tty_of_previous_vt = NULL; + g_autofree char *tty_of_active_vt = NULL; + g_autofree char *login_session_id = NULL; + g_autofree char *active_session_id = NULL; + const char *session_type = NULL; + int ret; + + 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; + case G_IO_STATUS_AGAIN: + return G_SOURCE_CONTINUE; + case G_IO_STATUS_NORMAL: + break; + } + } + + if ((condition & G_IO_ERR) || (condition & G_IO_HUP)) + return G_SOURCE_REMOVE; + + if (tty_of_active_vt == NULL) + return G_SOURCE_CONTINUE; + + g_strchomp (tty_of_active_vt); + + /* don't do anything if we're on the same VT we were before */ + if (g_strcmp0 (tty_of_active_vt, factory->priv->tty_of_active_vt) == 0) + return G_SOURCE_CONTINUE; + + tty_of_previous_vt = g_steal_pointer (&factory->priv->tty_of_active_vt); + factory->priv->tty_of_active_vt = g_steal_pointer (&tty_of_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 vt; + + ret = sd_session_get_vt (login_session_id, &vt); + if (ret == 0 && vt != 0) { + g_autofree char *tty_of_login_window_vt = NULL; + + tty_of_login_window_vt = g_strdup_printf ("tty%u", vt); + + if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) { + GdmDisplayStore *store; + GdmDisplay *display; + + 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_display (display); + } + } + } + + /* 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 (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) { + return G_SOURCE_CONTINUE; + } + + ret = sd_seat_get_active ("seat0", &active_session_id, NULL); + + if (ret == 0) { + g_autofree char *state = NULL; + ret = sd_session_get_state (active_session_id, &state); + + /* if there's something already running on the active VT then bail */ + if (ret == 0 && g_strcmp0 (state, "closing") != 0) + return G_SOURCE_CONTINUE; + } + + if (gdm_local_display_factory_use_wayland ()) + session_type = "wayland"; + + create_display (factory, "seat0", session_type, TRUE); + + return G_SOURCE_CONTINUE; +} +#endif + static void gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory) { + g_autoptr (GIOChannel) io_channel = NULL; + factory->priv->seat_new_id = g_dbus_connection_signal_subscribe (factory->priv->connection, "org.freedesktop.login1", "org.freedesktop.login1.Manager", @@ -552,6 +698,19 @@ gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory) on_seat_removed, g_object_ref (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 @@ -567,6 +726,14 @@ gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory) factory->priv->seat_removed_id); factory->priv->seat_removed_id = 0; } +#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) + if (factory->priv->active_vt_watch_id) { + g_source_remove (factory->priv->active_vt_watch_id); + factory->priv->active_vt_watch_id = 0; + } + + g_clear_pointer (&factory->priv->tty_of_active_vt, g_free); +#endif } static void |