diff options
-rw-r--r-- | daemon/gdm-local-display-factory.c | 132 |
1 files changed, 126 insertions, 6 deletions
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 891c2537..5430085e 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -56,6 +56,7 @@ struct GdmLocalDisplayFactoryPrivate GdmDBusLocalDisplayFactory *skeleton; GDBusConnection *connection; GHashTable *used_display_numbers; + GHashTable *seat_proxies; /* FIXME: this needs to be per seat? */ guint num_failures; @@ -88,6 +89,11 @@ static void on_display_status_changed (GdmDisplay GdmLocalDisplayFactory *factory); static gboolean gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory); + +static gboolean create_seat_proxy (GdmLocalDisplayFactory *self, + const char *seat_id, + const char *seat_path); + static gpointer local_display_factory_object = NULL; static gboolean lookup_by_session_id (const char *id, GdmDisplay *display, @@ -436,6 +442,7 @@ create_display (GdmLocalDisplayFactory *factory, g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested", session_type? : "X11", seat_id); + store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); if (sd_seat_can_multi_session (seat_id)) @@ -520,7 +527,7 @@ gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory) GVariant *result; GVariant *array; GVariantIter iter; - const char *seat; + const char *seat, *path; g_debug ("GdmLocalDisplayFactory: enumerating seats from logind"); result = g_dbus_connection_call_sync (factory->priv->connection, @@ -543,7 +550,7 @@ gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory) array = g_variant_get_child_value (result, 0); g_variant_iter_init (&iter, array); - while (g_variant_iter_loop (&iter, "(&so)", &seat, NULL)) { + while (g_variant_iter_loop (&iter, "(&s&o)", &seat, &path)) { gboolean is_initial; const char *session_type = NULL; @@ -555,6 +562,14 @@ gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory) is_initial = FALSE; } + if (!create_seat_proxy (factory, seat, path)) + continue; + + if (!sd_seat_can_graphical (seat)) { + g_debug ("GdmLocalDisplayFactory: seat %s not ready for graphical displays", seat); + continue; + } + create_display (factory, seat, session_type, is_initial); } @@ -564,6 +579,86 @@ gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory) } static void +on_seat_proxy_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + char **invalidated_properties, + gpointer user_data) +{ + GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (user_data); + g_autoptr (GVariant) value = NULL; + const char *seat; + + value = g_variant_lookup_value (changed_properties, "CanGraphical", G_VARIANT_TYPE_BOOLEAN); + + if (!value) + return; + + g_debug ("GdmLocalDisplayFactory: CanGraphical changed"); + + seat = g_object_get_data (G_OBJECT (proxy), "seat-id"); + + if (!seat) + return; + + if (g_variant_get_boolean (value)) { + gboolean is_initial; + const char *session_type = NULL; + + g_debug ("GdmLocalDisplayFactory: seat '%s' now graphical", seat); + + if (g_strcmp0 (seat, "seat0") == 0) { + is_initial = TRUE; + if (gdm_local_display_factory_use_wayland ()) + session_type = "wayland"; + } else { + is_initial = FALSE; + } + + create_display (factory, seat, session_type, is_initial); + } else { + g_debug ("GdmLocalDisplayFactory: seat '%s' no longer graphical", seat); + delete_display (factory, seat); + } +} + +static gboolean +create_seat_proxy (GdmLocalDisplayFactory *self, + const char *seat, + const char *path) +{ + g_autoptr (GDBusProxy) proxy = NULL; + g_autoptr (GError) error = NULL; + + g_debug ("GdmLocalDisplayFactory: creating seat proxy for seat '%s' with path '%s'", + seat, path); + + proxy = g_dbus_proxy_new_sync (self->priv->connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.login1", + path, + "org.freedesktop.login1.Seat", + NULL, + &error); + + if (proxy == NULL) { + g_debug ("GdmLocalDisplayFactory: failed to get proxy to seat '%s' from logind: %s", + seat, error->message); + return FALSE; + } + + g_hash_table_insert (self->priv->seat_proxies, g_strdup (seat), g_object_ref (proxy)); + g_object_set_data_full (G_OBJECT (proxy), "seat-id", g_strdup (seat), (GDestroyNotify) g_free); + g_signal_connect_object (G_OBJECT (proxy), + "g-properties-changed", + G_CALLBACK (on_seat_proxy_properties_changed), + self, + 0); + + return TRUE; +} + +static void on_seat_new (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, @@ -572,10 +667,22 @@ on_seat_new (GDBusConnection *connection, GVariant *parameters, gpointer user_data) { - const char *seat; + GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (user_data); + const char *seat, *path; - g_variant_get (parameters, "(&s&o)", &seat, NULL); - create_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat, NULL, FALSE); + g_variant_get (parameters, "(&s&o)", &seat, &path); + + g_debug ("GdmLocalDisplayFactory: new seat '%s' available", seat); + + if (!create_seat_proxy (factory, seat, path)) + return; + + if (!sd_seat_can_graphical (seat)) { + g_debug ("GdmLocalDisplayFactory: but not yet ready for graphical displays"); + return; + } + + create_display (factory, seat, NULL, FALSE); } static void @@ -587,10 +694,15 @@ on_seat_removed (GDBusConnection *connection, GVariant *parameters, gpointer user_data) { + GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (user_data); const char *seat; g_variant_get (parameters, "(&s&o)", &seat, NULL); - delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat); + + g_debug ("GdmLocalDisplayFactory: seat '%s' no longer available", seat); + + g_hash_table_remove (factory->priv->seat_proxies, (gpointer) seat); + delete_display (factory, seat); } static gboolean @@ -764,6 +876,11 @@ on_vt_changed (GIOChannel *source, return G_SOURCE_CONTINUE; } + if (!sd_seat_can_graphical ("seat0")) { + g_debug ("GdmLocalDisplayFactory: seat0 not yet ready for graphical displays"); + return G_SOURCE_CONTINUE; + } + if (gdm_local_display_factory_use_wayland ()) session_type = "wayland"; @@ -1041,6 +1158,7 @@ gdm_local_display_factory_init (GdmLocalDisplayFactory *factory) factory->priv = GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE (factory); factory->priv->used_display_numbers = g_hash_table_new (NULL, NULL); + factory->priv->seat_proxies = g_hash_table_new_full (NULL, NULL, g_free, g_object_unref); } static void @@ -1055,6 +1173,8 @@ gdm_local_display_factory_finalize (GObject *object) g_return_if_fail (factory->priv != NULL); + g_hash_table_destroy (factory->priv->seat_proxies); + g_clear_object (&factory->priv->connection); g_clear_object (&factory->priv->skeleton); |