Blame SOURCES/0029-local-display-factory-defer-killing-greeter-until-ne.patch

a1b388
From d85448e2e523deb1487e7e405a480e1c4e6a5f6f Mon Sep 17 00:00:00 2001
a1b388
From: Ray Strode <rstrode@redhat.com>
a1b388
Date: Fri, 31 Aug 2018 15:33:00 -0400
a1b388
Subject: [PATCH 29/51] local-display-factory: defer killing greeter until new
a1b388
 session registers
a1b388
a1b388
At the moment we kill the greeter the second the VT change to the new
a1b388
session happens.
a1b388
a1b388
That can cause flicker if the new session doesn't take over the display
a1b388
quickly enough.
a1b388
a1b388
This commit defers killing the greeter until the new display registers.
a1b388
a1b388
Closes https://gitlab.gnome.org/GNOME/gdm/issues/413
a1b388
---
a1b388
 daemon/gdm-display.h               |  1 +
a1b388
 daemon/gdm-local-display-factory.c | 43 +++++++++++++++++++++++++-----
a1b388
 2 files changed, 38 insertions(+), 6 deletions(-)
a1b388
a1b388
diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h
a1b388
index 6d5e88df9..33dc3be41 100644
a1b388
--- a/daemon/gdm-display.h
a1b388
+++ b/daemon/gdm-display.h
a1b388
@@ -13,60 +13,61 @@
a1b388
  * GNU General Public License for more details.
a1b388
  *
a1b388
  * You should have received a copy of the GNU General Public License
a1b388
  * along with this program; if not, write to the Free Software
a1b388
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
a1b388
  *
a1b388
  */
a1b388
 
a1b388
 
a1b388
 #ifndef __GDM_DISPLAY_H
a1b388
 #define __GDM_DISPLAY_H
a1b388
 
a1b388
 #include <glib-object.h>
a1b388
 #include <gio/gio.h>
a1b388
 
a1b388
 G_BEGIN_DECLS
a1b388
 
a1b388
 #define GDM_TYPE_DISPLAY         (gdm_display_get_type ())
a1b388
 #define GDM_DISPLAY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DISPLAY, GdmDisplay))
a1b388
 #define GDM_DISPLAY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DISPLAY, GdmDisplayClass))
a1b388
 #define GDM_IS_DISPLAY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DISPLAY))
a1b388
 #define GDM_IS_DISPLAY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DISPLAY))
a1b388
 #define GDM_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DISPLAY, GdmDisplayClass))
a1b388
 
a1b388
 typedef struct GdmDisplayPrivate GdmDisplayPrivate;
a1b388
 
a1b388
 typedef enum {
a1b388
         GDM_DISPLAY_UNMANAGED = 0,
a1b388
         GDM_DISPLAY_PREPARED,
a1b388
         GDM_DISPLAY_MANAGED,
a1b388
+        GDM_DISPLAY_WAITING_TO_FINISH,
a1b388
         GDM_DISPLAY_FINISHED,
a1b388
         GDM_DISPLAY_FAILED,
a1b388
 } GdmDisplayStatus;
a1b388
 
a1b388
 typedef struct
a1b388
 {
a1b388
         GObject            parent;
a1b388
         GdmDisplayPrivate *priv;
a1b388
 } GdmDisplay;
a1b388
 
a1b388
 typedef struct
a1b388
 {
a1b388
         GObjectClass   parent_class;
a1b388
 
a1b388
         /* methods */
a1b388
         gboolean (*prepare) (GdmDisplay *display);
a1b388
         void     (*manage)  (GdmDisplay *self);
a1b388
 } GdmDisplayClass;
a1b388
 
a1b388
 typedef enum
a1b388
 {
a1b388
          GDM_DISPLAY_ERROR_GENERAL,
a1b388
          GDM_DISPLAY_ERROR_GETTING_USER_INFO,
a1b388
          GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
a1b388
 } GdmDisplayError;
a1b388
 
a1b388
 #define GDM_DISPLAY_ERROR gdm_display_error_quark ()
a1b388
 
a1b388
 GQuark              gdm_display_error_quark                    (void);
a1b388
 GType               gdm_display_get_type                       (void);
a1b388
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
a1b388
index 127127005..bc6ac6855 100644
a1b388
--- a/daemon/gdm-local-display-factory.c
a1b388
+++ b/daemon/gdm-local-display-factory.c
a1b388
@@ -241,60 +241,90 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
a1b388
 
a1b388
                 display = gdm_legacy_display_new (num);
a1b388
         }
a1b388
 #endif
a1b388
 
a1b388
         g_object_set (display,
a1b388
                       "seat-id", "seat0",
a1b388
                       "allow-timed-login", FALSE,
a1b388
                       NULL);
a1b388
 
a1b388
         store_display (factory, display);
a1b388
 
a1b388
         if (! gdm_display_manage (display)) {
a1b388
                 display = NULL;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         if (! gdm_display_get_id (display, id, NULL)) {
a1b388
                 display = NULL;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         ret = TRUE;
a1b388
  out:
a1b388
         /* ref either held by store or not at all */
a1b388
         g_object_unref (display);
a1b388
 
a1b388
         return ret;
a1b388
 }
a1b388
 
a1b388
+static gboolean
a1b388
+finish_display_on_seat_if_waiting (GdmDisplayStore *display_store,
a1b388
+                                   GdmDisplay      *display,
a1b388
+                                   const char      *seat_id)
a1b388
+{
a1b388
+        if (gdm_display_get_status (display) != GDM_DISPLAY_WAITING_TO_FINISH)
a1b388
+                return FALSE;
a1b388
+
a1b388
+        g_debug ("GdmLocalDisplayFactory: finish background display\n");
a1b388
+        gdm_display_stop_greeter_session (display);
a1b388
+        gdm_display_unmanage (display);
a1b388
+        gdm_display_finish (display);
a1b388
+
a1b388
+        return FALSE;
a1b388
+}
a1b388
+
a1b388
+static void
a1b388
+finish_waiting_displays_on_seat (GdmLocalDisplayFactory *factory,
a1b388
+                                 const char             *seat_id)
a1b388
+{
a1b388
+        GdmDisplayStore *store;
a1b388
+
a1b388
+        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
a1b388
+
a1b388
+        gdm_display_store_foreach (store,
a1b388
+                                   (GdmDisplayStoreFunc) finish_display_on_seat_if_waiting,
a1b388
+                                   (gpointer)
a1b388
+                                   seat_id);
a1b388
+}
a1b388
+
a1b388
 static void
a1b388
 on_display_status_changed (GdmDisplay             *display,
a1b388
                            GParamSpec             *arg1,
a1b388
                            GdmLocalDisplayFactory *factory)
a1b388
 {
a1b388
         int              status;
a1b388
         int              num;
a1b388
         char            *seat_id = NULL;
a1b388
         char            *session_type = NULL;
a1b388
         char            *session_class = NULL;
a1b388
         gboolean         is_initial = TRUE;
a1b388
         gboolean         is_local = TRUE;
a1b388
 
a1b388
         num = -1;
a1b388
         gdm_display_get_x11_display_number (display, &num, NULL);
a1b388
 
a1b388
         g_object_get (display,
a1b388
                       "seat-id", &seat_id,
a1b388
                       "is-initial", &is_initial,
a1b388
                       "is-local", &is_local,
a1b388
                       "session-type", &session_type,
a1b388
                       "session-class", &session_class,
a1b388
                       NULL);
a1b388
 
a1b388
         status = gdm_display_get_status (display);
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: display status changed: %d", status);
a1b388
         switch (status) {
a1b388
         case GDM_DISPLAY_FINISHED:
a1b388
                 /* remove the display number from factory->priv->used_display_numbers
a1b388
@@ -324,60 +354,63 @@ on_display_status_changed (GdmDisplay             *display,
a1b388
                 /* Create a new equivalent display if it was static */
a1b388
                 if (is_local) {
a1b388
 
a1b388
                         factory->priv->num_failures++;
a1b388
 
a1b388
                         if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) {
a1b388
                                 /* oh shit */
a1b388
                                 g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors");
a1b388
                         } else {
a1b388
 #ifdef ENABLE_WAYLAND_SUPPORT
a1b388
                                 if (g_strcmp0 (session_type, "wayland") == 0) {
a1b388
                                         g_free (session_type);
a1b388
                                         session_type = NULL;
a1b388
 
a1b388
                                         /* workaround logind race for now
a1b388
                                          * bug 1643874
a1b388
                                          */
a1b388
                                         g_usleep (2 * G_USEC_PER_SEC);
a1b388
                                 }
a1b388
 
a1b388
 #endif
a1b388
                                 create_display (factory, seat_id, session_type, is_initial);
a1b388
                         }
a1b388
                 }
a1b388
                 break;
a1b388
         case GDM_DISPLAY_UNMANAGED:
a1b388
                 break;
a1b388
         case GDM_DISPLAY_PREPARED:
a1b388
                 break;
a1b388
         case GDM_DISPLAY_MANAGED:
a1b388
+                finish_waiting_displays_on_seat (factory, seat_id);
a1b388
+                break;
a1b388
+        case GDM_DISPLAY_WAITING_TO_FINISH:
a1b388
                 break;
a1b388
         default:
a1b388
                 g_assert_not_reached ();
a1b388
                 break;
a1b388
         }
a1b388
 
a1b388
         g_free (seat_id);
a1b388
         g_free (session_type);
a1b388
         g_free (session_class);
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 lookup_by_seat_id (const char *id,
a1b388
                    GdmDisplay *display,
a1b388
                    gpointer    user_data)
a1b388
 {
a1b388
         const char *looking_for = user_data;
a1b388
         char *current;
a1b388
         gboolean res;
a1b388
 
a1b388
         g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
a1b388
 
a1b388
         res = g_strcmp0 (current, looking_for) == 0;
a1b388
 
a1b388
         g_free(current);
a1b388
 
a1b388
         return res;
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
@@ -561,84 +594,82 @@ on_seat_new (GDBusConnection *connection,
a1b388
 
a1b388
 static void
a1b388
 on_seat_removed (GDBusConnection *connection,
a1b388
                  const gchar     *sender_name,
a1b388
                  const gchar     *object_path,
a1b388
                  const gchar     *interface_name,
a1b388
                  const gchar     *signal_name,
a1b388
                  GVariant        *parameters,
a1b388
                  gpointer         user_data)
a1b388
 {
a1b388
         const char *seat;
a1b388
 
a1b388
         g_variant_get (parameters, "(&s&o)", &seat, NULL);
a1b388
         delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
a1b388
 }
a1b388
 
a1b388
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
a1b388
 static gboolean
a1b388
 lookup_by_session_id (const char *id,
a1b388
                       GdmDisplay *display,
a1b388
                       gpointer    user_data)
a1b388
 {
a1b388
         const char *looking_for = user_data;
a1b388
         const char *current;
a1b388
 
a1b388
         current = gdm_display_get_session_id (display);
a1b388
         return g_strcmp0 (current, looking_for) == 0;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
-maybe_stop_greeter_display (GdmDisplay *display)
a1b388
+maybe_stop_greeter_in_background (GdmDisplay *display)
a1b388
 {
a1b388
         g_autofree char *display_session_type = NULL;
a1b388
 
a1b388
         if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) {
a1b388
                 g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring");
a1b388
                 return;
a1b388
         }
a1b388
 
a1b388
         g_object_get (G_OBJECT (display),
a1b388
                       "session-type", &display_session_type,
a1b388
                       NULL);
a1b388
 
a1b388
         /* we can only stop greeter for wayland sessions, since
a1b388
          * X server would jump back on exit */
a1b388
         if (g_strcmp0 (display_session_type, "wayland") != 0) {
a1b388
                 g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
a1b388
                 return;
a1b388
         }
a1b388
 
a1b388
-        g_debug ("GdmLocalDisplayFactory: killing login window since its now unused");
a1b388
-        gdm_display_stop_greeter_session (display);
a1b388
-        gdm_display_unmanage (display);
a1b388
-        gdm_display_finish (display);
a1b388
+        g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
a1b388
+        g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 on_vt_changed (GIOChannel    *source,
a1b388
                GIOCondition   condition,
a1b388
                GdmLocalDisplayFactory *factory)
a1b388
 {
a1b388
         GIOStatus status;
a1b388
         static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
a1b388
         g_autofree char *tty_of_previous_vt = NULL;
a1b388
         g_autofree char *tty_of_active_vt = NULL;
a1b388
         g_autofree char *login_session_id = NULL;
a1b388
         g_autofree char *active_session_id = NULL;
a1b388
         const char *session_type = NULL;
a1b388
         int ret;
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: received VT change event");
a1b388
         g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
a1b388
 
a1b388
         if (condition & G_IO_PRI) {
a1b388
                 g_autoptr (GError) error = NULL;
a1b388
                 status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
a1b388
 
a1b388
                 if (error != NULL) {
a1b388
                         g_warning ("could not read active VT from kernel: %s", error->message);
a1b388
                 }
a1b388
                 switch (status) {
a1b388
                         case G_IO_STATUS_ERROR:
a1b388
                             return G_SOURCE_REMOVE;
a1b388
                         case G_IO_STATUS_EOF:
a1b388
@@ -678,61 +709,61 @@ on_vt_changed (GIOChannel    *source,
a1b388
                 return G_SOURCE_CONTINUE;
a1b388
         }
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: VT changed from %s to %s",
a1b388
                  tty_of_previous_vt, factory->priv->tty_of_active_vt);
a1b388
 
a1b388
         /* if the old VT was running a wayland login screen kill it
a1b388
          */
a1b388
         if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
a1b388
                 unsigned int vt;
a1b388
 
a1b388
                 ret = sd_session_get_vt (login_session_id, &vt;;
a1b388
                 if (ret == 0 && vt != 0) {
a1b388
                         g_autofree char *tty_of_login_window_vt = NULL;
a1b388
 
a1b388
                         tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
a1b388
 
a1b388
                         g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
a1b388
                         if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
a1b388
                                 GdmDisplayStore *store;
a1b388
                                 GdmDisplay *display;
a1b388
 
a1b388
                                 g_debug ("GdmLocalDisplayFactory: VT switched from login window");
a1b388
 
a1b388
                                 store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
a1b388
                                 display = gdm_display_store_find (store,
a1b388
                                                                   lookup_by_session_id,
a1b388
                                                                   (gpointer) login_session_id);
a1b388
 
a1b388
                                 if (display != NULL)
a1b388
-                                        maybe_stop_greeter_display (display);
a1b388
+                                        maybe_stop_greeter_in_background (display);
a1b388
                         } else {
a1b388
                                 g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
a1b388
                         }
a1b388
                 }
a1b388
         }
a1b388
 
a1b388
         /* if user jumped back to initial vt and it's empty put a login screen
a1b388
          * on it (unless a login screen is already running elsewhere, then
a1b388
          * jump to that login screen)
a1b388
          */
a1b388
         if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
a1b388
                 g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
a1b388
                 return G_SOURCE_CONTINUE;
a1b388
         }
a1b388
 
a1b388
         ret = sd_seat_get_active ("seat0", &active_session_id, NULL);
a1b388
 
a1b388
         if (ret == 0) {
a1b388
                 g_autofree char *state = NULL;
a1b388
                 ret = sd_session_get_state (active_session_id, &state);
a1b388
 
a1b388
                 /* if there's something already running on the active VT then bail */
a1b388
                 if (ret == 0 && g_strcmp0 (state, "closing") != 0) {
a1b388
                         g_debug ("GdmLocalDisplayFactory: initial VT is in use, so ignoring");
a1b388
                         return G_SOURCE_CONTINUE;
a1b388
                 }
a1b388
         }
a1b388
 
a1b388
         if (gdm_local_display_factory_use_wayland ())
a1b388
                 session_type = "wayland";
a1b388
-- 
a1b388
2.27.0
a1b388