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

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