Blame SOURCES/0001-local-display-factory-Stall-startup-until-main-graph.patch

4e44f9
From e5b3467412874d27c311253e3d5d7e65a61d12a4 Mon Sep 17 00:00:00 2001
4e44f9
From: Ray Strode <rstrode@redhat.com>
4e44f9
Date: Tue, 1 Mar 2022 13:25:02 -0500
4e44f9
Subject: [PATCH 1/4] local-display-factory: Stall startup until main graphics
4e44f9
 card is ready
4e44f9
4e44f9
At the moment, GDM waits until systemd says the system supports
4e44f9
graphics (via the CanGraphical logind property).
4e44f9
4e44f9
Unfortunately, this property isn't really what we need, since it flips
4e44f9
to true when *any* graphics are available, not when the main graphics
4e44f9
for the system are ready.
4e44f9
4e44f9
This is a problem on hybrid graphics systems, if one card is slower to
4e44f9
load than another. In particular, the vendor nvidia driver can be slow
4e44f9
to load because it has multiple kernel modules it loads in series.
4e44f9
4e44f9
Indeed on fast systems, that use the vendor nvidia driver, it's not
4e44f9
unusual for boot to get to a point where all of userspace up to and
4e44f9
including GDM is executed before the graphics are ready to go.
4e44f9
4e44f9
This commit tries to mitigate the situation by adding an additional,
4e44f9
check aside from CanGraphical to test if the system is ready.
4e44f9
4e44f9
This check waits for the graphics card associated with boot to be fully
4e44f9
up and running before proceeding to start a login screen.
4e44f9
4e44f9
Closes: https://gitlab.gnome.org/GNOME/gdm/-/issues/763
4e44f9
---
4e44f9
 daemon/gdm-local-display-factory.c | 164 ++++++++++++++++++++++++++---
4e44f9
 daemon/meson.build                 |   4 +
4e44f9
 meson.build                        |   2 +
4e44f9
 4 files changed, 159 insertions(+), 12 deletions(-)
4e44f9
4e44f9
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
4e44f9
index c00e1c47..0b1d3482 100644
4e44f9
--- a/daemon/gdm-local-display-factory.c
4e44f9
+++ b/daemon/gdm-local-display-factory.c
4e44f9
@@ -1,100 +1,112 @@
4e44f9
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4e44f9
  *
4e44f9
  * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4e44f9
  *
4e44f9
  * This program is free software; you can redistribute it and/or modify
4e44f9
  * it under the terms of the GNU General Public License as published by
4e44f9
  * the Free Software Foundation; either version 2 of the License, or
4e44f9
  * (at your option) any later version.
4e44f9
  *
4e44f9
  * This program is distributed in the hope that it will be useful,
4e44f9
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
4e44f9
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4e44f9
  * GNU General Public License for more details.
4e44f9
  *
4e44f9
  * You should have received a copy of the GNU General Public License
4e44f9
  * along with this program; if not, write to the Free Software
4e44f9
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
4e44f9
  *
4e44f9
  */
4e44f9
 
4e44f9
 #include "config.h"
4e44f9
 
4e44f9
 #include <stdlib.h>
4e44f9
 #include <stdio.h>
4e44f9
 
4e44f9
 #include <glib.h>
4e44f9
 #include <glib/gi18n.h>
4e44f9
 #include <glib-object.h>
4e44f9
 #include <gio/gio.h>
4e44f9
 
4e44f9
+#ifdef HAVE_UDEV
4e44f9
+#include <gudev/gudev.h>
4e44f9
+#endif
4e44f9
+
4e44f9
 #include <systemd/sd-login.h>
4e44f9
 
4e44f9
 #include "gdm-common.h"
4e44f9
 #include "gdm-manager.h"
4e44f9
 #include "gdm-display-factory.h"
4e44f9
 #include "gdm-local-display-factory.h"
4e44f9
 #include "gdm-local-display-factory-glue.h"
4e44f9
 
4e44f9
 #include "gdm-settings-keys.h"
4e44f9
 #include "gdm-settings-direct.h"
4e44f9
 #include "gdm-display-store.h"
4e44f9
 #include "gdm-local-display.h"
4e44f9
 #include "gdm-legacy-display.h"
4e44f9
 
4e44f9
 #define GDM_DBUS_PATH                       "/org/gnome/DisplayManager"
4e44f9
 #define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory"
4e44f9
 #define GDM_MANAGER_DBUS_NAME               "org.gnome.DisplayManager.LocalDisplayFactory"
4e44f9
 
4e44f9
 #define MAX_DISPLAY_FAILURES 5
4e44f9
 #define WAIT_TO_FINISH_TIMEOUT 10 /* seconds */
4e44f9
 #define SEAT0_GRAPHICS_CHECK_TIMEOUT 10 /* seconds */
4e44f9
 
4e44f9
 struct _GdmLocalDisplayFactory
4e44f9
 {
4e44f9
-        GdmDisplayFactory              parent;
4e44f9
+        GdmDisplayFactory  parent;
4e44f9
+#ifdef HAVE_UDEV
4e44f9
+        GUdevClient       *gudev_client;
4e44f9
+#endif
4e44f9
 
4e44f9
         GdmDBusLocalDisplayFactory *skeleton;
4e44f9
         GDBusConnection *connection;
4e44f9
         GHashTable      *used_display_numbers;
4e44f9
 
4e44f9
         /* FIXME: this needs to be per seat? */
4e44f9
         guint            num_failures;
4e44f9
 
4e44f9
         guint            seat_new_id;
4e44f9
         guint            seat_removed_id;
4e44f9
         guint            seat_properties_changed_id;
4e44f9
 
4e44f9
+        gboolean         seat0_has_platform_graphics;
4e44f9
+        gboolean         seat0_has_boot_up_graphics;
4e44f9
+
4e44f9
         gboolean         seat0_graphics_check_timed_out;
4e44f9
         guint            seat0_graphics_check_timeout_id;
4e44f9
 
4e44f9
+        gulong           uevent_handler_id;
4e44f9
+
4e44f9
 #if defined(ENABLE_USER_DISPLAY_SERVER)
4e44f9
         unsigned int     active_vt;
4e44f9
         guint            active_vt_watch_id;
4e44f9
         guint            wait_to_finish_timeout_id;
4e44f9
 #endif
4e44f9
 
4e44f9
         gboolean         is_started;
4e44f9
 };
4e44f9
 
4e44f9
 enum {
4e44f9
         PROP_0,
4e44f9
 };
4e44f9
 
4e44f9
 static void     gdm_local_display_factory_class_init    (GdmLocalDisplayFactoryClass *klass);
4e44f9
 static void     gdm_local_display_factory_init          (GdmLocalDisplayFactory      *factory);
4e44f9
 static void     gdm_local_display_factory_finalize      (GObject                     *object);
4e44f9
 
4e44f9
 static void     ensure_display_for_seat                 (GdmLocalDisplayFactory      *factory,
4e44f9
                                                          const char                  *seat_id);
4e44f9
 
4e44f9
 static void     on_display_status_changed               (GdmDisplay                  *display,
4e44f9
                                                          GParamSpec                  *arg1,
4e44f9
                                                          GdmLocalDisplayFactory      *factory);
4e44f9
 
4e44f9
 static gboolean gdm_local_display_factory_sync_seats    (GdmLocalDisplayFactory *factory);
4e44f9
 static gpointer local_display_factory_object = NULL;
4e44f9
 static gboolean lookup_by_session_id (const char *id,
4e44f9
                                       GdmDisplay *display,
4e44f9
                                       gpointer    user_data);
4e44f9
 
4e44f9
@@ -594,142 +606,236 @@ lookup_by_seat_id (const char *id,
4e44f9
                    gpointer    user_data)
4e44f9
 {
4e44f9
         const char *looking_for = user_data;
4e44f9
         char *current;
4e44f9
         gboolean res;
4e44f9
 
4e44f9
         g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
4e44f9
 
4e44f9
         res = g_strcmp0 (current, looking_for) == 0;
4e44f9
 
4e44f9
         g_free(current);
4e44f9
 
4e44f9
         return res;
4e44f9
 }
4e44f9
 
4e44f9
 static gboolean
4e44f9
 lookup_prepared_display_by_seat_id (const char *id,
4e44f9
                                     GdmDisplay *display,
4e44f9
                                     gpointer    user_data)
4e44f9
 {
4e44f9
         int status;
4e44f9
 
4e44f9
         status = gdm_display_get_status (display);
4e44f9
 
4e44f9
         if (status != GDM_DISPLAY_PREPARED)
4e44f9
                 return FALSE;
4e44f9
 
4e44f9
         return lookup_by_seat_id (id, display, user_data);
4e44f9
 }
4e44f9
 
4e44f9
+#ifdef HAVE_UDEV
4e44f9
+static gboolean
4e44f9
+udev_is_settled (GdmLocalDisplayFactory *factory)
4e44f9
+{
4e44f9
+        g_autoptr (GUdevEnumerator) enumerator = NULL;
4e44f9
+        GList *devices;
4e44f9
+        GList *node;
4e44f9
+
4e44f9
+        gboolean is_settled = FALSE;
4e44f9
+
4e44f9
+        if (factory->seat0_has_platform_graphics) {
4e44f9
+                g_debug ("GdmLocalDisplayFactory: udev settled, platform graphics enabled.");
4e44f9
+                return TRUE;
4e44f9
+        }
4e44f9
+
4e44f9
+        if (factory->seat0_has_boot_up_graphics) {
4e44f9
+                g_debug ("GdmLocalDisplayFactory: udev settled, boot up graphics available.");
4e44f9
+                return TRUE;
4e44f9
+        }
4e44f9
+
4e44f9
+        if (factory->seat0_graphics_check_timed_out) {
4e44f9
+                g_debug ("GdmLocalDisplayFactory: udev timed out, proceeding anyway.");
4e44f9
+                return TRUE;
4e44f9
+        }
4e44f9
+
4e44f9
+        g_debug ("GdmLocalDisplayFactory: Checking if udev has settled enough to support graphics.");
4e44f9
+
4e44f9
+        enumerator = g_udev_enumerator_new (factory->gudev_client);
4e44f9
+
4e44f9
+        g_udev_enumerator_add_match_name (enumerator, "card*");
4e44f9
+        g_udev_enumerator_add_match_tag (enumerator, "master-of-seat");
4e44f9
+        g_udev_enumerator_add_match_subsystem (enumerator, "drm");
4e44f9
+
4e44f9
+        devices = g_udev_enumerator_execute (enumerator);
4e44f9
+        if (!devices) {
4e44f9
+                g_debug ("GdmLocalDisplayFactory: udev has no candidate graphics devices available yet.");
4e44f9
+                return FALSE;
4e44f9
+        }
4e44f9
+
4e44f9
+        node = devices;
4e44f9
+        while (node != NULL) {
4e44f9
+                GUdevDevice *device = node->data;
4e44f9
+                GList *next_node = node->next;
4e44f9
+                g_autoptr (GUdevDevice) platform_device = NULL;
4e44f9
+                g_autoptr (GUdevDevice) pci_device = NULL;
4e44f9
+
4e44f9
+                platform_device = g_udev_device_get_parent_with_subsystem (device, "platform", NULL);
4e44f9
+
4e44f9
+                if (platform_device != NULL) {
4e44f9
+                        g_debug ("GdmLocalDisplayFactory: Found embedded platform graphics, proceeding.");
4e44f9
+                        factory->seat0_has_platform_graphics = TRUE;
4e44f9
+                        is_settled = TRUE;
4e44f9
+                        break;
4e44f9
+                }
4e44f9
+
4e44f9
+                pci_device = g_udev_device_get_parent_with_subsystem (device, "pci", NULL);
4e44f9
+
4e44f9
+                if (pci_device != NULL) {
4e44f9
+                        gboolean boot_vga;
4e44f9
+
4e44f9
+                        boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga");
4e44f9
+
4e44f9
+                        if (boot_vga == 1) {
4e44f9
+                                 g_debug ("GdmLocalDisplayFactory: Found primary PCI graphics adapter, proceeding.");
4e44f9
+                                 factory->seat0_has_boot_up_graphics = TRUE;
4e44f9
+                                 is_settled = TRUE;
4e44f9
+                                 break;
4e44f9
+                        } else {
4e44f9
+                                 g_debug ("GdmLocalDisplayFactory: Found secondary PCI graphics adapter, not proceeding yet.");
4e44f9
+                        }
4e44f9
+                }
4e44f9
+                node = next_node;
4e44f9
+        }
4e44f9
+
4e44f9
+        g_debug ("GdmLocalDisplayFactory: udev has %ssettled enough for graphics.", is_settled? "" : "not ");
4e44f9
+        g_list_free_full (devices, g_object_unref);
4e44f9
+
4e44f9
+        if (is_settled)
4e44f9
+                g_clear_signal_handler (&factory->uevent_handler_id, factory->gudev_client);
4e44f9
+
4e44f9
+        return is_settled;
4e44f9
+}
4e44f9
+#endif
4e44f9
+
4e44f9
 static int
4e44f9
 on_seat0_graphics_check_timeout (gpointer user_data)
4e44f9
 {
4e44f9
         GdmLocalDisplayFactory *factory = user_data;
4e44f9
 
4e44f9
         factory->seat0_graphics_check_timeout_id = 0;
4e44f9
 
4e44f9
         /* Simply try to re-add seat0. If it is there already (i.e. CanGraphical
4e44f9
          * turned TRUE, then we'll find it and it will not be created again).
4e44f9
          */
4e44f9
         factory->seat0_graphics_check_timed_out = TRUE;
4e44f9
         ensure_display_for_seat (factory, "seat0");
4e44f9
 
4e44f9
         return G_SOURCE_REMOVE;
4e44f9
 }
4e44f9
 
4e44f9
 static void
4e44f9
 ensure_display_for_seat (GdmLocalDisplayFactory *factory,
4e44f9
                          const char             *seat_id)
4e44f9
 {
4e44f9
         int ret;
4e44f9
         gboolean seat_supports_graphics;
4e44f9
         gboolean is_seat0;
4e44f9
         g_auto (GStrv) session_types = NULL;
4e44f9
         const char *legacy_session_types[] = { "x11", NULL };
4e44f9
         GdmDisplayStore *store;
4e44f9
         GdmDisplay      *display = NULL;
4e44f9
         g_autofree char *login_session_id = NULL;
4e44f9
         gboolean wayland_enabled = FALSE, xorg_enabled = FALSE;
4e44f9
         g_autofree gchar *preferred_display_server = NULL;
4e44f9
         gboolean falling_back = FALSE;
4e44f9
+        gboolean waiting_on_udev = FALSE;
4e44f9
 
4e44f9
         gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled);
4e44f9
         gdm_settings_direct_get_boolean (GDM_KEY_XORG_ENABLE, &xorg_enabled);
4e44f9
 
4e44f9
         preferred_display_server = get_preferred_display_server (factory);
4e44f9
 
4e44f9
         if (g_strcmp0 (preferred_display_server, "none") == 0) {
4e44f9
                g_debug ("GdmLocalDisplayFactory: Preferred display server is none, so not creating display");
4e44f9
                return;
4e44f9
         }
4e44f9
 
4e44f9
-        ret = sd_seat_can_graphical (seat_id);
4e44f9
+#ifdef HAVE_UDEV
4e44f9
+        waiting_on_udev = !udev_is_settled (factory);
4e44f9
+#endif
4e44f9
 
4e44f9
-        if (ret < 0) {
4e44f9
-                g_critical ("Failed to query CanGraphical information for seat %s", seat_id);
4e44f9
-                return;
4e44f9
-        }
4e44f9
+        if (!waiting_on_udev) {
4e44f9
+                ret = sd_seat_can_graphical (seat_id);
4e44f9
 
4e44f9
-        if (ret == 0) {
4e44f9
-                g_debug ("GdmLocalDisplayFactory: System doesn't currently support graphics");
4e44f9
-                seat_supports_graphics = FALSE;
4e44f9
+                if (ret < 0) {
4e44f9
+                        g_critical ("Failed to query CanGraphical information for seat %s", seat_id);
4e44f9
+                        return;
4e44f9
+                }
4e44f9
+
4e44f9
+                if (ret == 0) {
4e44f9
+                        g_debug ("GdmLocalDisplayFactory: System doesn't currently support graphics");
4e44f9
+                        seat_supports_graphics = FALSE;
4e44f9
+                } else {
4e44f9
+                        g_debug ("GdmLocalDisplayFactory: System supports graphics");
4e44f9
+                        seat_supports_graphics = TRUE;
4e44f9
+                }
4e44f9
         } else {
4e44f9
-                g_debug ("GdmLocalDisplayFactory: System supports graphics");
4e44f9
-                seat_supports_graphics = TRUE;
4e44f9
+               g_debug ("GdmLocalDisplayFactory: udev is still settling, so not creating display yet");
4e44f9
+               seat_supports_graphics = FALSE;
4e44f9
         }
4e44f9
 
4e44f9
         if (g_strcmp0 (seat_id, "seat0") == 0) {
4e44f9
                 is_seat0 = TRUE;
4e44f9
 
4e44f9
                 falling_back = factory->num_failures > 0;
4e44f9
                 session_types = gdm_local_display_factory_get_session_types (factory, falling_back);
4e44f9
 
4e44f9
                 if (session_types == NULL) {
4e44f9
                         g_debug ("GdmLocalDisplayFactory: Both Wayland and Xorg are unavailable");
4e44f9
                         seat_supports_graphics = FALSE;
4e44f9
                 } else {
4e44f9
                         g_debug ("GdmLocalDisplayFactory: New displays on seat0 will use %s%s",
4e44f9
                                  session_types[0], falling_back? " fallback" : "");
4e44f9
                 }
4e44f9
         } else {
4e44f9
                 is_seat0 = FALSE;
4e44f9
 
4e44f9
                 g_debug ("GdmLocalDisplayFactory: New displays on seat %s will use X11 fallback", seat_id);
4e44f9
                 /* Force legacy X11 for all auxiliary seats */
4e44f9
                 seat_supports_graphics = TRUE;
4e44f9
                 session_types = g_strdupv ((char **) legacy_session_types);
4e44f9
         }
4e44f9
 
4e44f9
         /* For seat0, we have a fallback logic to still try starting it after
4e44f9
          * SEAT0_GRAPHICS_CHECK_TIMEOUT seconds. i.e. we simply continue even if
4e44f9
-         * CanGraphical is unset.
4e44f9
+         * CanGraphical is unset or udev otherwise never finds a suitable graphics card.
4e44f9
          * This is ugly, but it means we'll come up eventually in some
4e44f9
          * scenarios where no master device is present.
4e44f9
          * Note that we'll force an X11 fallback even though there might be
4e44f9
          * cases where an wayland capable device is present and simply not marked as
4e44f9
          * master-of-seat. In these cases, this should likely be fixed in the
4e44f9
          * udev rules.
4e44f9
          *
4e44f9
          * At the moment, systemd always sets CanGraphical for non-seat0 seats.
4e44f9
          * This is because non-seat0 seats are defined by having master-of-seat
4e44f9
          * set. This means we can avoid the fallback check for non-seat0 seats,
4e44f9
          * which simplifies the code.
4e44f9
          */
4e44f9
         if (is_seat0) {
4e44f9
                 if (!seat_supports_graphics) {
4e44f9
                         if (!factory->seat0_graphics_check_timed_out) {
4e44f9
                                 if (factory->seat0_graphics_check_timeout_id == 0) {
4e44f9
                                         g_debug ("GdmLocalDisplayFactory: seat0 doesn't yet support graphics.  Waiting %d seconds to try again.", SEAT0_GRAPHICS_CHECK_TIMEOUT);
4e44f9
                                         factory->seat0_graphics_check_timeout_id = g_timeout_add_seconds (SEAT0_GRAPHICS_CHECK_TIMEOUT,
4e44f9
                                                                                                           on_seat0_graphics_check_timeout,
4e44f9
                                                                                                           factory);
4e44f9
 
4e44f9
                                 } else {
4e44f9
                                         /* It is not yet time to force X11 fallback. */
4e44f9
                                         g_debug ("GdmLocalDisplayFactory: seat0 display requested when there is no graphics support before graphics check timeout.");
4e44f9
                                 }
4e44f9
 
4e44f9
                                 return;
4e44f9
                         }
4e44f9
 
4e44f9
                         g_debug ("GdmLocalDisplayFactory: Assuming we can use seat0 for X11 even though system says it doesn't support graphics!");
4e44f9
@@ -1138,113 +1240,151 @@ on_vt_changed (GIOChannel    *source,
4e44f9
                                 if (factory->wait_to_finish_timeout_id != 0) {
4e44f9
                                          g_debug ("GdmLocalDisplayFactory: deferring previous login screen clean up operation");
4e44f9
                                          g_source_remove (factory->wait_to_finish_timeout_id);
4e44f9
                                 }
4e44f9
 
4e44f9
                                 factory->wait_to_finish_timeout_id = g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT,
4e44f9
                                                                                             (GSourceFunc)
4e44f9
                                                                                             on_finish_waiting_for_seat0_displays_timeout,
4e44f9
                                                                                             factory);
4e44f9
                         }
4e44f9
                 }
4e44f9
         }
4e44f9
 
4e44f9
         /* if user jumped back to initial vt and it's empty put a login screen
4e44f9
          * on it (unless a login screen is already running elsewhere, then
4e44f9
          * jump to that login screen)
4e44f9
          */
4e44f9
         if (factory->active_vt != GDM_INITIAL_VT) {
4e44f9
                 g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
4e44f9
                 return G_SOURCE_CONTINUE;
4e44f9
         }
4e44f9
 
4e44f9
         g_debug ("GdmLocalDisplayFactory: creating new display on seat0 because of VT change");
4e44f9
 
4e44f9
         ensure_display_for_seat (factory, "seat0");
4e44f9
 
4e44f9
         return G_SOURCE_CONTINUE;
4e44f9
 }
4e44f9
 #endif
4e44f9
 
4e44f9
+#ifdef HAVE_UDEV
4e44f9
+static void
4e44f9
+on_uevent (GUdevClient *client,
4e44f9
+           const char  *action,
4e44f9
+           GUdevDevice *device,
4e44f9
+           GdmLocalDisplayFactory *factory)
4e44f9
+{
4e44f9
+        if (!g_udev_device_get_device_file (device))
4e44f9
+                return;
4e44f9
+
4e44f9
+        if (g_strcmp0 (action, "add") != 0 &&
4e44f9
+            g_strcmp0 (action, "change") != 0)
4e44f9
+                return;
4e44f9
+
4e44f9
+        if (!udev_is_settled (factory))
4e44f9
+                return;
4e44f9
+
4e44f9
+        g_signal_handler_disconnect (factory->gudev_client, factory->uevent_handler_id);
4e44f9
+        factory->uevent_handler_id = 0;
4e44f9
+
4e44f9
+        ensure_display_for_seat (factory, "seat0");
4e44f9
+}
4e44f9
+#endif
4e44f9
+
4e44f9
 static void
4e44f9
 gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
4e44f9
 {
4e44f9
         g_autoptr (GIOChannel) io_channel = NULL;
4e44f9
+        const char *subsystems[] = { "drm", NULL };
4e44f9
 
4e44f9
         factory->seat_new_id = g_dbus_connection_signal_subscribe (factory->connection,
4e44f9
                                                                          "org.freedesktop.login1",
4e44f9
                                                                          "org.freedesktop.login1.Manager",
4e44f9
                                                                          "SeatNew",
4e44f9
                                                                          "/org/freedesktop/login1",
4e44f9
                                                                          NULL,
4e44f9
                                                                          G_DBUS_SIGNAL_FLAGS_NONE,
4e44f9
                                                                          on_seat_new,
4e44f9
                                                                          g_object_ref (factory),
4e44f9
                                                                          g_object_unref);
4e44f9
         factory->seat_removed_id = g_dbus_connection_signal_subscribe (factory->connection,
4e44f9
                                                                              "org.freedesktop.login1",
4e44f9
                                                                              "org.freedesktop.login1.Manager",
4e44f9
                                                                              "SeatRemoved",
4e44f9
                                                                              "/org/freedesktop/login1",
4e44f9
                                                                              NULL,
4e44f9
                                                                              G_DBUS_SIGNAL_FLAGS_NONE,
4e44f9
                                                                              on_seat_removed,
4e44f9
                                                                              g_object_ref (factory),
4e44f9
                                                                              g_object_unref);
4e44f9
         factory->seat_properties_changed_id = g_dbus_connection_signal_subscribe (factory->connection,
4e44f9
                                                                                   "org.freedesktop.login1",
4e44f9
                                                                                   "org.freedesktop.DBus.Properties",
4e44f9
                                                                                   "PropertiesChanged",
4e44f9
                                                                                   NULL,
4e44f9
                                                                                   "org.freedesktop.login1.Seat",
4e44f9
                                                                                   G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE,
4e44f9
                                                                                   on_seat_properties_changed,
4e44f9
                                                                                   g_object_ref (factory),
4e44f9
                                                                                   g_object_unref);
4e44f9
+#ifdef HAVE_UDEV
4e44f9
+        factory->gudev_client = g_udev_client_new (subsystems);
4e44f9
+        factory->uevent_handler_id = g_signal_connect (factory->gudev_client,
4e44f9
+                                                       "uevent",
4e44f9
+                                                       G_CALLBACK (on_uevent),
4e44f9
+                                                       factory);
4e44f9
+#endif
4e44f9
 
4e44f9
 #if defined(ENABLE_USER_DISPLAY_SERVER)
4e44f9
         io_channel = g_io_channel_new_file ("/sys/class/tty/tty0/active", "r", NULL);
4e44f9
 
4e44f9
         if (io_channel != NULL) {
4e44f9
                 factory->active_vt_watch_id =
4e44f9
                         g_io_add_watch (io_channel,
4e44f9
                                         G_IO_PRI,
4e44f9
                                         (GIOFunc)
4e44f9
                                         on_vt_changed,
4e44f9
                                         factory);
4e44f9
         }
4e44f9
 #endif
4e44f9
 }
4e44f9
 
4e44f9
 static void
4e44f9
 gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
4e44f9
 {
4e44f9
+        if (factory->uevent_handler_id) {
4e44f9
+                g_signal_handler_disconnect (factory->gudev_client, factory->uevent_handler_id);
4e44f9
+                factory->uevent_handler_id = 0;
4e44f9
+        }
4e44f9
+        g_clear_object (&factory->gudev_client);
4e44f9
+
4e44f9
         if (factory->seat_new_id) {
4e44f9
                 g_dbus_connection_signal_unsubscribe (factory->connection,
4e44f9
                                                       factory->seat_new_id);
4e44f9
                 factory->seat_new_id = 0;
4e44f9
         }
4e44f9
         if (factory->seat_removed_id) {
4e44f9
                 g_dbus_connection_signal_unsubscribe (factory->connection,
4e44f9
                                                       factory->seat_removed_id);
4e44f9
                 factory->seat_removed_id = 0;
4e44f9
         }
4e44f9
         if (factory->seat_properties_changed_id) {
4e44f9
                 g_dbus_connection_signal_unsubscribe (factory->connection,
4e44f9
                                                       factory->seat_properties_changed_id);
4e44f9
                 factory->seat_properties_changed_id = 0;
4e44f9
         }
4e44f9
 #if defined(ENABLE_USER_DISPLAY_SERVER)
4e44f9
         if (factory->active_vt_watch_id) {
4e44f9
                 g_source_remove (factory->active_vt_watch_id);
4e44f9
                 factory->active_vt_watch_id = 0;
4e44f9
         }
4e44f9
         if (factory->wait_to_finish_timeout_id != 0) {
4e44f9
                 g_source_remove (factory->wait_to_finish_timeout_id);
4e44f9
                 factory->wait_to_finish_timeout_id = 0;
4e44f9
         }
4e44f9
 #endif
4e44f9
 }
4e44f9
 
4e44f9
 static void
4e44f9
 on_display_added (GdmDisplayStore        *display_store,
4e44f9
                   const char             *id,
4e44f9
diff --git a/daemon/meson.build b/daemon/meson.build
4e44f9
index 2e61b644..41f30abe 100644
4e44f9
--- a/daemon/meson.build
4e44f9
+++ b/daemon/meson.build
4e44f9
@@ -177,37 +177,41 @@ gdm_daemon_sources = files(
4e44f9
   'gdm-session-record.c',
4e44f9
   'gdm-session-worker-common.c',
4e44f9
   'gdm-session-worker-job.c',
4e44f9
   'gdm-session.c',
4e44f9
   'main.c',
4e44f9
 )
4e44f9
 
4e44f9
 gdm_daemon_gen_sources = [
4e44f9
   display_dbus_gen,
4e44f9
   local_display_factory_dbus_gen,
4e44f9
   manager_dbus_gen,
4e44f9
   local_display_dbus_gen,
4e44f9
   session_dbus_gen,
4e44f9
   session_worker_dbus_gen,
4e44f9
   gdm_session_enums,
4e44f9
 ]
4e44f9
 
4e44f9
 if xdmcp_dep.found()
4e44f9
   gdm_daemon_deps += xdmcp_dep
4e44f9
 
4e44f9
   gdm_daemon_sources = [
4e44f9
     gdm_daemon_sources,
4e44f9
     files(
4e44f9
       'gdm-xdmcp-display-factory.c',
4e44f9
       'gdm-xdmcp-display.c',
4e44f9
       'gdm-xdmcp-chooser-display.c',
4e44f9
     ),
4e44f9
   ]
4e44f9
 endif
4e44f9
 
4e44f9
+if gudev_dep.found()
4e44f9
+  gdm_daemon_deps += gudev_dep
4e44f9
+endif
4e44f9
+
4e44f9
 gdm_daemon = executable('gdm',
4e44f9
   [ gdm_daemon_sources, gdm_daemon_gen_sources ],
4e44f9
   dependencies: gdm_daemon_deps,
4e44f9
   include_directories: config_h_dir,
4e44f9
   install: true,
4e44f9
   install_dir: get_option('sbindir')
4e44f9
 )
4e44f9
diff --git a/meson.build b/meson.build
4e44f9
index 02d609dc..05d8da41 100644
4e44f9
--- a/meson.build
4e44f9
+++ b/meson.build
4e44f9
@@ -11,60 +11,61 @@ i18n = import('i18n')
4e44f9
 
4e44f9
 # Compiler
4e44f9
 cc = meson.get_compiler('c')
4e44f9
 
4e44f9
 # Options
4e44f9
 gdm_prefix = get_option('prefix')
4e44f9
 
4e44f9
 gdmconfdir = (get_option('sysconfsubdir') == '')? gdm_prefix / get_option('sysconfdir') : gdm_prefix / get_option('sysconfdir') / get_option('sysconfsubdir')
4e44f9
 dmconfdir = (get_option('dmconfdir') != '')? get_option('dmconfdir') : gdm_prefix / get_option('sysconfdir') / 'dm'
4e44f9
 udev_dir = get_option('udev-dir')
4e44f9
 at_spi_registryd_dir = (get_option('at-spi-registryd-dir') != '')? get_option('at-spi-registryd-dir') : gdm_prefix / get_option('libexecdir')
4e44f9
 lang_config_file = (get_option('lang-file') != '')? get_option('lang-file') : gdm_prefix / get_option('sysconfdir') / 'locale.conf'
4e44f9
 pam_mod_dir = (get_option('pam-mod-dir') != '')? get_option('pam-mod-dir') : gdm_prefix / get_option('libdir') / 'security'
4e44f9
 dbus_sys_dir = (get_option('dbus-sys') != '')? get_option('dbus-sys') : get_option('sysconfdir') / 'dbus-1' / 'system.d'
4e44f9
 gdm_defaults_conf = (get_option('defaults-conf') != '')? get_option('defaults-conf') : gdm_prefix / get_option('datadir') / 'gdm' / 'defaults.conf'
4e44f9
 gdm_custom_conf = (get_option('custom-conf') != '')? get_option('custom-conf') : gdmconfdir / 'custom.conf'
4e44f9
 gnome_settings_daemon_dir = (get_option('gnome-settings-daemon-dir') != '')? get_option('gnome-settings-daemon-dir') : gdm_prefix / get_option('libexecdir')
4e44f9
 gdm_run_dir = (get_option('run-dir') != '')? get_option('run-dir') : gdm_prefix / get_option('localstatedir') / 'run' / 'gdm'
4e44f9
 gdm_runtime_conf = (get_option('runtime-conf') != '')? get_option('runtime-conf') : gdm_run_dir / 'custom.conf'
4e44f9
 gdm_pid_file = (get_option('pid-file') != '')? get_option('pid-file') : gdm_run_dir / 'gdm.pid'
4e44f9
 ran_once_marker_dir = (get_option('ran-once-marker-dir') != '')? get_option('ran-once-marker-dir') : gdm_run_dir
4e44f9
 working_dir = (get_option('working-dir') != '')? get_option('working-dir') : gdm_prefix / get_option('localstatedir') / 'lib' / 'gdm'
4e44f9
 gdm_xauth_dir = (get_option('xauth-dir') != '')? get_option('xauth-dir') : gdm_run_dir
4e44f9
 gdm_screenshot_dir = (get_option('screenshot-dir') != '')? get_option('screenshot-dir') : gdm_run_dir / 'greeter'
4e44f9
 
4e44f9
 # Common variables
4e44f9
 config_h_dir = include_directories('.')
4e44f9
 
4e44f9
 # Dependencies
4e44f9
 udev_dep = dependency('udev')
4e44f9
+gudev_dep = dependency('gudev-1.0', version: '>= 232')
4e44f9
 
4e44f9
 glib_min_version = '2.56.0'
4e44f9
 
4e44f9
 glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version)
4e44f9
 gobject_dep = dependency('gobject-2.0', version: '>=' + glib_min_version)
4e44f9
 gio_dep = dependency('gio-2.0', version: '>=' + glib_min_version)
4e44f9
 gio_unix_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version)
4e44f9
 gtk_dep = dependency('gtk+-3.0', version: '>= 2.91.1')
4e44f9
 libcanberra_gtk_dep = dependency('libcanberra-gtk3', version: '>= 0.4')
4e44f9
 accountsservice_dep = dependency('accountsservice', version: '>= 0.6.35')
4e44f9
 xcb_dep = dependency('xcb')
4e44f9
 keyutils_dep = dependency('libkeyutils', required: false)
4e44f9
 libselinux_dep = dependency('libselinux', required: get_option('selinux'))
4e44f9
 
4e44f9
 # udev
4e44f9
 if udev_dir == ''
4e44f9
   if udev_dep.found()
4e44f9
     udev_prefix = udev_dep.get_pkgconfig_variable('udevdir')
4e44f9
   else
4e44f9
     udev_prefix = gdm_prefix / 'lib' / 'udev'
4e44f9
   endif
4e44f9
   udev_dir = udev_prefix / 'rules.d'
4e44f9
 endif
4e44f9
 
4e44f9
 # X11
4e44f9
 x_deps = declare_dependency(
4e44f9
   dependencies: [
4e44f9
     dependency('x11'),
4e44f9
     dependency('xau'),
4e44f9
   ],
4e44f9
@@ -217,60 +218,61 @@ conf.set('HAVE_UTMP_H', have_utmp_header)
4e44f9
 conf.set('HAVE_UTMPX_H', have_utmpx_header)
4e44f9
 conf.set('HAVE_POSIX_GETPWNAM_R', have_posix_getpwnam_r)
4e44f9
 conf.set('UTMP', utmp_struct)
4e44f9
 conf.set('HAVE_GETUTXENT', cc.has_function('getutxent'))
4e44f9
 conf.set('HAVE_UPDWTMP', cc.has_function('updwtmp'))
4e44f9
 conf.set('HAVE_UPDWTMPX', cc.has_function('updwtmpx'))
4e44f9
 conf.set('HAVE_LOGIN', cc.has_function('login', args: '-lutil'))
4e44f9
 conf.set('HAVE_LOGOUT', cc.has_function('logout', args: '-lutil'))
4e44f9
 conf.set('HAVE_LOGWTMP', cc.has_function('logwtmp', args: '-lutil'))
4e44f9
 conf.set('HAVE_PAM_SYSLOG', have_pam_syslog)
4e44f9
 conf.set('HAVE_KEYUTILS', keyutils_dep.found())
4e44f9
 conf.set('SUPPORTS_PAM_EXTENSIONS', pam_extensions_supported)
4e44f9
 conf.set('HAVE_SELINUX', libselinux_dep.found())
4e44f9
 conf.set('HAVE_XSERVER_WITH_LISTEN', xserver_has_listen)
4e44f9
 conf.set('ENABLE_USER_DISPLAY_SERVER', get_option('user-display-server'))
4e44f9
 conf.set('ENABLE_SYSTEMD_JOURNAL', get_option('systemd-journal'))
4e44f9
 conf.set('ENABLE_WAYLAND_SUPPORT', get_option('wayland-support'))
4e44f9
 conf.set('ENABLE_PROFILING', get_option('profiling'))
4e44f9
 conf.set('GDM_INITIAL_VT', get_option('initial-vt'))
4e44f9
 conf.set_quoted('GDM_DEFAULTS_CONF', gdm_defaults_conf)
4e44f9
 conf.set_quoted('GDM_CUSTOM_CONF', gdm_custom_conf)
4e44f9
 conf.set_quoted('GDM_RUNTIME_CONF', gdm_runtime_conf)
4e44f9
 conf.set_quoted('GDM_SESSION_DEFAULT_PATH', get_option('default-path'))
4e44f9
 conf.set_quoted('GDM_USERNAME', get_option('user'))
4e44f9
 conf.set_quoted('GDM_GROUPNAME', get_option('group'))
4e44f9
 conf.set('HAVE_LIBXDMCP', xdmcp_dep.found())
4e44f9
 conf.set_quoted('SYSTEMD_X_SERVER', systemd_x_server)
4e44f9
 conf.set('WITH_PLYMOUTH', plymouth_dep.found())
4e44f9
 conf.set_quoted('X_SERVER', x_bin)
4e44f9
 conf.set_quoted('X_PATH', x_path)
4e44f9
+conf.set('HAVE_UDEV', gudev_dep.found())
4e44f9
 conf.set('HAVE_UT_UT_HOST', utmp_has_host_field)
4e44f9
 conf.set('HAVE_UT_UT_PID', utmp_has_pid_field)
4e44f9
 conf.set('HAVE_UT_UT_ID', utmp_has_id_field)
4e44f9
 conf.set('HAVE_UT_UT_NAME', utmp_has_name_field)
4e44f9
 conf.set('HAVE_UT_UT_TYPE', utmp_has_type_field)
4e44f9
 conf.set('HAVE_UT_UT_EXIT_E_TERMINATION', utmp_has_exit_e_termination_field)
4e44f9
 conf.set('HAVE_UT_UT_USER', utmp_has_user_field)
4e44f9
 conf.set('HAVE_UT_UT_TIME', utmp_has_time_field)
4e44f9
 conf.set('HAVE_UT_UT_TV', utmp_has_tv_field)
4e44f9
 conf.set('HAVE_UT_UT_SYSLEN', utmp_has_syslen_field)
4e44f9
 conf.set('ENABLE_IPV6', get_option('ipv6'))
4e44f9
 configure_file(output: 'config.h', configuration: conf)
4e44f9
 
4e44f9
 # Subdirs
4e44f9
 subdir('data')
4e44f9
 subdir('common')
4e44f9
 if pam_extensions_supported
4e44f9
   subdir('pam-extensions')
4e44f9
 endif
4e44f9
 subdir('daemon')
4e44f9
 subdir('libgdm')
4e44f9
 subdir('utils')
4e44f9
 subdir('pam_gdm')
4e44f9
 subdir('po')
4e44f9
 if libcheck_dep.found()
4e44f9
   subdir('tests')
4e44f9
 endif
4e44f9
 if xdmcp_dep.found()
4e44f9
   subdir('chooser')
4e44f9
 endif
4e44f9
-- 
4e44f9
2.34.1
4e44f9