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

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