summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-07-27 01:32:54 +0200
committerLennart Poettering <lennart@poettering.net>2012-02-07 22:57:11 +0100
commit6e9fb3fb4df7d05c803cc01fe638eb9cf88c4beb (patch)
treef972abb7e7af79d24f589a08296fa29f4bc230b6
parent69a8b09c993669e324c785be463136313be2cdb4 (diff)
downloadgdm-6e9fb3fb4df7d05c803cc01fe638eb9cf88c4beb.tar.gz
local-display-factory: subscribe to new seats being created and removed
logind will notify us when ever a new seat becomes available in the system, or an existing seat is removed. We simply create a new display for each seat showing up and remove a display when a seat goes away.
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/gdm-local-display-factory.c239
2 files changed, 224 insertions, 16 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 8f8eedfe..ffbaf9b0 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -363,6 +363,7 @@ gdm_binary_LDADD = \
$(DAEMON_LIBS) \
$(XDMCP_LIBS) \
$(LIBWRAP_LIBS) \
+ $(SYSTEMD_LIBS) \
$(NULL)
if WITH_CONSOLE_KIT
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 349c7b2c..988b2ff9 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -27,6 +27,13 @@
#include <glib/gi18n.h>
#include <glib-object.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#ifdef WITH_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
#include "gdm-display-factory.h"
#include "gdm-local-display-factory.h"
#include "gdm-local-display-factory-glue.h"
@@ -64,7 +71,8 @@ static void gdm_local_display_factory_class_init (GdmLocalDisplayFactoryC
static void gdm_local_display_factory_init (GdmLocalDisplayFactory *factory);
static void gdm_local_display_factory_finalize (GObject *object);
-static GdmDisplay *create_display (GdmLocalDisplayFactory *factory);
+static GdmDisplay *create_display (GdmLocalDisplayFactory *factory,
+ const char *seat_id);
static gpointer local_display_factory_object = NULL;
@@ -282,6 +290,7 @@ on_static_display_status_changed (GdmDisplay *display,
int status;
GdmDisplayStore *store;
int num;
+ char *seat_id = NULL;
num = -1;
gdm_display_get_x11_display_number (display, &num, NULL);
@@ -289,6 +298,8 @@ on_static_display_status_changed (GdmDisplay *display,
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+ g_object_get (display, "seat-id", &seat_id, NULL);
+
status = gdm_display_get_status (display);
g_debug ("GdmLocalDisplayFactory: static display status changed: %d", status);
@@ -300,7 +311,7 @@ on_static_display_status_changed (GdmDisplay *display,
gdm_display_store_remove (store, display);
/* reset num failures */
factory->priv->num_failures = 0;
- create_display (factory);
+ create_display (factory, seat_id);
break;
case GDM_DISPLAY_FAILED:
/* leave the display number in factory->priv->displays
@@ -313,7 +324,7 @@ on_static_display_status_changed (GdmDisplay *display,
/* FIXME: should monitor hardware changes to
try again when seats change */
} else {
- create_display (factory);
+ create_display (factory, seat_id);
}
break;
case GDM_DISPLAY_UNMANAGED:
@@ -326,13 +337,44 @@ on_static_display_status_changed (GdmDisplay *display,
g_assert_not_reached ();
break;
}
+
+ g_free (seat_id);
+}
+
+static gboolean
+lookup_by_seat_id (const char *id,
+ GdmDisplay *display,
+ gpointer user_data)
+{
+ const char *looking_for = user_data;
+ char *current;
+ gboolean res;
+
+ g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
+
+ res = g_strcmp0 (current, looking_for) == 0;
+
+ g_free(current);
+
+ return res;
}
static GdmDisplay *
-create_display (GdmLocalDisplayFactory *factory)
+create_display (GdmLocalDisplayFactory *factory,
+ const char *seat_id)
{
- GdmDisplay *display;
- guint32 num;
+ GdmDisplayStore *store;
+ GdmDisplay *display;
+ guint32 num;
+
+ /* Ensure we don't create the same display more than once */
+ store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+ display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
+ if (display != NULL) {
+ return NULL;
+ }
+
+ g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
num = take_next_display_number (factory);
@@ -342,8 +384,7 @@ create_display (GdmLocalDisplayFactory *factory)
display = gdm_static_display_new (num);
#endif
- /* FIXME: don't hardcode seat1? */
- g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
+ g_object_set (display, "seat-id", seat_id, NULL);
g_signal_connect (display,
"notify::status",
@@ -362,24 +403,182 @@ create_display (GdmLocalDisplayFactory *factory)
return display;
}
+#ifdef WITH_SYSTEMD
+
+static void
+delete_display (GdmLocalDisplayFactory *factory,
+ const char *seat_id) {
+
+ GdmDisplayStore *store;
+
+ g_debug ("GdmLocalDisplayFactory: Removing displays on seat %s", seat_id);
+
+ store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+ gdm_display_store_foreach_remove (store, lookup_by_seat_id, (gpointer) seat_id);
+}
+
+static gboolean gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory)
+{
+ DBusError error;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, sub, sub2;
+
+ dbus_error_init (&error);
+
+ message = dbus_message_new_method_call (
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "ListSeats");
+ if (message == NULL) {
+ g_warning ("GdmLocalDisplayFactory: Failed to allocate message");
+ return FALSE;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (factory->priv->connection), message, -1, &error);
+ dbus_message_unref (message);
+
+ if (reply == NULL) {
+ g_warning ("GdmLocalDisplayFactory: Failed to issue method call: %s", error.message);
+ dbus_error_free (&error);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_init (reply, &iter) ||
+ dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRUCT) {
+ g_warning ("GdmLocalDisplayFactory: Failed to parse reply.");
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse (&iter, &sub);
+
+ while (dbus_message_iter_get_arg_type (&sub) != DBUS_TYPE_INVALID) {
+ const char *seat;
+
+ if (dbus_message_iter_get_arg_type (&sub) != DBUS_TYPE_STRUCT) {
+ g_warning ("GdmLocalDisplayFactory: Failed to parse reply.");
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse (&sub, &sub2);
+
+ if (dbus_message_iter_get_arg_type (&sub2) != DBUS_TYPE_STRING) {
+ g_warning ("GdmLocalDisplayFactory: Failed to parse reply.");
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic (&sub2, &seat);
+ create_display (factory, seat);
+
+ dbus_message_iter_next (&sub);
+ }
+
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+static DBusHandlerResult
+on_seat_signal (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GdmLocalDisplayFactory *factory = user_data;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ if (dbus_message_is_signal (message, "org.freedesktop.login1.Manager", "SeatNew") ||
+ dbus_message_is_signal (message, "org.freedesktop.login1.Manager", "SeatRemoved")) {
+ const char *seat;
+
+ dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &seat,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_error_is_set (&error)) {
+ g_warning ("GdmLocalDisplayFactory: Failed to decode seat message: %s", error.message);
+ dbus_error_free (&error);
+ } else {
+
+ if (strcmp (dbus_message_get_member (message), "SeatNew") == 0) {
+ create_display (factory, seat);
+ } else {
+ delete_display (factory, seat);
+ }
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
+{
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ dbus_bus_add_match (dbus_g_connection_get_connection (factory->priv->connection),
+ "type='signal',"
+ "sender='org.freedesktop.login1',"
+ "path='/org/freedesktop/login1',"
+ "interface='org.freedesktop.login1.Manager',"
+ "member='SeatNew'",
+ &error);
+
+ if (dbus_error_is_set (&error)) {
+ g_warning ("GdmLocalDisplayFactory: Failed to add match for SeatNew: %s", error.message);
+ dbus_error_free (&error);
+ }
+
+ dbus_bus_add_match (dbus_g_connection_get_connection (factory->priv->connection),
+ "type='signal',"
+ "sender='org.freedesktop.login1',"
+ "path='/org/freedesktop/login1',"
+ "interface='org.freedesktop.login1.Manager',"
+ "member='SeatRemoved'",
+ &error);
+
+ if (dbus_error_is_set (&error)) {
+ g_warning ("GdmLocalDisplayFactory: Failed to add match for SeatNew: %s", error.message);
+ dbus_error_free (&error);
+ }
+
+ dbus_connection_add_filter (dbus_g_connection_get_connection (factory->priv->connection), on_seat_signal, factory, NULL);
+}
+
+static void
+gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
+{
+ dbus_connection_remove_filter (dbus_g_connection_get_connection (factory->priv->connection), on_seat_signal, factory);
+}
+
+#endif
+
static gboolean
gdm_local_display_factory_start (GdmDisplayFactory *base_factory)
{
- gboolean ret;
GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (base_factory);
GdmDisplay *display;
g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
- ret = TRUE;
-
- /* FIXME: use seat configuration */
- display = create_display (factory);
- if (display == NULL) {
- ret = FALSE;
+#ifdef WITH_SYSTEMD
+ if (sd_booted () > 0) {
+ gdm_local_display_factory_start_monitor (factory);
+ return gdm_local_display_factory_sync_seats (factory);
}
+#endif
- return ret;
+ /* On ConsoleKit just create Seat1, and that's it. */
+ display = create_display (factory, CK_SEAT1_PATH);
+
+ return display != NULL;
}
static gboolean
@@ -389,6 +588,10 @@ gdm_local_display_factory_stop (GdmDisplayFactory *base_factory)
g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
+#ifdef WITH_SYSTEMD
+ gdm_local_display_factory_stop_monitor (factory);
+#endif
+
return TRUE;
}
@@ -499,6 +702,10 @@ gdm_local_display_factory_finalize (GObject *object)
g_hash_table_destroy (factory->priv->displays);
+#ifdef WITH_SYSTEMD
+ gdm_local_display_factory_stop_monitor (factory);
+#endif
+
G_OBJECT_CLASS (gdm_local_display_factory_parent_class)->finalize (object);
}