summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Ancell <robert.ancell@canonical.com>2016-12-06 14:41:05 +1300
committerRobert Ancell <robert.ancell@canonical.com>2016-12-06 14:41:05 +1300
commit91e5fd37ee8dc2180f741e1e18155f0096fd51d6 (patch)
tree445c1a2514c79416401f5ef34a9e69204c334a7e
parentce8011ae61acd90079e774e8910384fe41679c11 (diff)
downloadlightdm-git-91e5fd37ee8dc2180f741e1e18155f0096fd51d6.tar.gz
Refator D-Bus service into its own class
-rw-r--r--src/Makefile.am2
-rw-r--r--src/display-manager-service.c746
-rw-r--r--src/display-manager-service.h52
-rw-r--r--src/lightdm.c675
4 files changed, 839 insertions, 636 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index edee5bf8..e4501975 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,8 @@ lightdm_SOURCES = \
console-kit.h \
display-manager.c \
display-manager.h \
+ display-manager-service.c \
+ display-manager-service.h \
display-server.c \
display-server.h \
greeter.c \
diff --git a/src/display-manager-service.c b/src/display-manager-service.c
new file mode 100644
index 00000000..796b676e
--- /dev/null
+++ b/src/display-manager-service.c
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+#include <config.h>
+
+#include "display-manager-service.h"
+
+enum {
+ READY,
+ ADD_XLOCAL_SEAT,
+ NAME_LOST,
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct DisplayManagerServicePrivate
+{
+ /* Display manager being exposed on D-Bus */
+ DisplayManager *manager;
+
+ /* Bus connected to */
+ GDBusConnection *bus;
+
+ /* Handle for D-Bus name */
+ guint bus_id;
+
+ /* Handle for display manager D-Bus object */
+ guint reg_id;
+
+ /* D-Bus interface information */
+ GDBusNodeInfo *seat_info;
+ GDBusNodeInfo *session_info;
+
+ /* Next index to use for seat / session entries */
+ guint seat_index;
+ guint session_index;
+
+ /* Bus entries for seats / session */
+ GHashTable *seat_bus_entries;
+ GHashTable *session_bus_entries;
+};
+
+G_DEFINE_TYPE (DisplayManagerService, display_manager_service, G_TYPE_OBJECT);
+
+typedef struct
+{
+ DisplayManagerService *service;
+ Seat *seat;
+ gchar *path;
+ guint bus_id;
+} SeatBusEntry;
+typedef struct
+{
+ DisplayManagerService *service;
+ Session *session;
+ gchar *path;
+ gchar *seat_path;
+ guint bus_id;
+} SessionBusEntry;
+
+#define LIGHTDM_BUS_NAME "org.freedesktop.DisplayManager"
+
+DisplayManagerService *
+display_manager_service_new (DisplayManager *manager)
+{
+ DisplayManagerService *service;
+
+ service = g_object_new (DISPLAY_MANAGER_SERVICE_TYPE, NULL);
+ service->priv->manager = g_object_ref (manager);
+
+ return service;
+}
+
+static SeatBusEntry *
+seat_bus_entry_new (DisplayManagerService *service, Seat *seat, const gchar *path)
+{
+ SeatBusEntry *entry;
+
+ entry = g_malloc0 (sizeof (SeatBusEntry));
+ entry->service = service;
+ entry->seat = seat;
+ entry->path = g_strdup (path);
+
+ return entry;
+}
+
+static SessionBusEntry *
+session_bus_entry_new (DisplayManagerService *service, Session *session, const gchar *path, const gchar *seat_path)
+{
+ SessionBusEntry *entry;
+
+ entry = g_malloc0 (sizeof (SessionBusEntry));
+ entry->service = service;
+ entry->session = session;
+ entry->path = g_strdup (path);
+ entry->seat_path = g_strdup (seat_path);
+
+ return entry;
+}
+
+static void
+emit_object_value_changed (GDBusConnection *bus, const gchar *path, const gchar *interface_name, const gchar *property_name, GVariant *property_value)
+{
+ GVariantBuilder builder;
+ GError *error = NULL;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (&builder, "{sv}", property_name, property_value);
+
+ if (!g_dbus_connection_emit_signal (bus,
+ NULL,
+ path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new ("(sa{sv}as)", interface_name, &builder, NULL),
+ &error))
+ g_warning ("Failed to emit PropertiesChanged signal: %s", error->message);
+ g_clear_error (&error);
+}
+
+static void
+emit_object_signal (GDBusConnection *bus, const gchar *path, const gchar *signal_name, const gchar *object_path)
+{
+ GError *error = NULL;
+
+ if (!g_dbus_connection_emit_signal (bus,
+ NULL,
+ path,
+ "org.freedesktop.DisplayManager",
+ signal_name,
+ g_variant_new ("(o)", object_path),
+ &error))
+ g_warning ("Failed to emit %s signal on %s: %s", signal_name, path, error->message);
+ g_clear_error (&error);
+}
+
+static void
+seat_bus_entry_free (gpointer data)
+{
+ SeatBusEntry *entry = data;
+
+ g_free (entry->path);
+ g_free (entry);
+}
+
+static void
+session_bus_entry_free (gpointer data)
+{
+ SessionBusEntry *entry = data;
+
+ g_free (entry->path);
+ g_free (entry->seat_path);
+ g_free (entry);
+}
+
+static GVariant *
+get_seat_list (DisplayManagerService *service)
+{
+ GVariantBuilder builder;
+ GHashTableIter iter;
+ gpointer value;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
+ g_hash_table_iter_init (&iter, service->priv->seat_bus_entries);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ SeatBusEntry *entry = value;
+ g_variant_builder_add_value (&builder, g_variant_new_object_path (entry->path));
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+get_session_list (DisplayManagerService *service, const gchar *seat_path)
+{
+ GVariantBuilder builder;
+ GHashTableIter iter;
+ gpointer value;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
+
+ g_hash_table_iter_init (&iter, service->priv->session_bus_entries);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ SessionBusEntry *entry = value;
+ if (seat_path == NULL || g_strcmp0 (entry->seat_path, seat_path) == 0)
+ g_variant_builder_add_value (&builder, g_variant_new_object_path (entry->path));
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+handle_display_manager_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ DisplayManagerService *service = user_data;
+
+ if (g_strcmp0 (property_name, "Seats") == 0)
+ return get_seat_list (service);
+ else if (g_strcmp0 (property_name, "Sessions") == 0)
+ return get_session_list (service, NULL);
+
+ return NULL;
+}
+
+static void
+handle_display_manager_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ DisplayManagerService *service = user_data;
+
+ if (g_strcmp0 (method_name, "AddSeat") == 0)
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "AddSeat is deprecated");
+ else if (g_strcmp0 (method_name, "AddLocalXSeat") == 0)
+ {
+ gint display_number;
+ Seat *seat;
+ SeatBusEntry *entry;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(i)")))
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
+ return;
+ }
+
+ g_variant_get (parameters, "(i)", &display_number);
+
+ g_signal_emit (service, signals[ADD_XLOCAL_SEAT], 0, display_number, &seat);
+
+ if (!seat)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to create local X seat");
+ return;
+ }
+ entry = g_hash_table_lookup (service->priv->seat_bus_entries, seat);
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", entry->path));
+ g_object_unref (seat);
+ }
+ else
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
+}
+
+static GVariant *
+handle_seat_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ SeatBusEntry *entry = user_data;
+
+ if (g_strcmp0 (property_name, "CanSwitch") == 0)
+ return g_variant_new_boolean (seat_get_can_switch (entry->seat));
+ if (g_strcmp0 (property_name, "HasGuestAccount") == 0)
+ return g_variant_new_boolean (seat_get_allow_guest (entry->seat));
+ else if (g_strcmp0 (property_name, "Sessions") == 0)
+ return get_session_list (entry->service, entry->path);
+
+ return NULL;
+}
+
+static void
+handle_seat_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ SeatBusEntry *entry = user_data;
+
+ if (g_strcmp0 (method_name, "SwitchToGreeter") == 0)
+ {
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
+
+ if (seat_switch_to_greeter (entry->seat))
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ else// FIXME: Need to make proper error
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to switch to greeter");
+ }
+ else if (g_strcmp0 (method_name, "SwitchToUser") == 0)
+ {
+ const gchar *username, *session_name;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(ss)")))
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
+
+ g_variant_get (parameters, "(&s&s)", &username, &session_name);
+ if (g_strcmp0 (session_name, "") == 0)
+ session_name = NULL;
+
+ if (seat_switch_to_user (entry->seat, username, session_name))
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ else// FIXME: Need to make proper error
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to switch to user");
+ }
+ else if (g_strcmp0 (method_name, "SwitchToGuest") == 0)
+ {
+ const gchar *session_name;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")))
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
+
+ g_variant_get (parameters, "(&s)", &session_name);
+ if (g_strcmp0 (session_name, "") == 0)
+ session_name = NULL;
+
+ if (seat_switch_to_guest (entry->seat, session_name))
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ else// FIXME: Need to make proper error
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to switch to guest");
+ }
+ else if (g_strcmp0 (method_name, "Lock") == 0)
+ {
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
+
+ /* FIXME: Should only allow locks if have a session on this seat */
+ if (seat_lock (entry->seat, NULL))
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ else// FIXME: Need to make proper error
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to lock seat");
+ }
+ else
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
+}
+
+static Seat *
+get_seat_for_session (DisplayManagerService *service, Session *session)
+{
+ GList *seat_link;
+
+ for (seat_link = display_manager_get_seats (service->priv->manager); seat_link; seat_link = seat_link->next)
+ {
+ Seat *seat = seat_link->data;
+ GList *session_link;
+
+ for (session_link = seat_get_sessions (seat); session_link; session_link = session_link->next)
+ {
+ Session *s = session_link->data;
+
+ if (s == session)
+ return seat;
+ }
+ }
+
+ return NULL;
+}
+
+static GVariant *
+handle_session_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ SessionBusEntry *entry = user_data;
+
+ if (g_strcmp0 (property_name, "Seat") == 0)
+ return g_variant_new_object_path (entry->seat_path);
+ else if (g_strcmp0 (property_name, "UserName") == 0)
+ return g_variant_new_string (session_get_username (entry->session));
+
+ return NULL;
+}
+
+static void
+handle_session_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ SessionBusEntry *entry = user_data;
+
+ if (g_strcmp0 (method_name, "Lock") == 0)
+ {
+ Seat *seat;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
+
+ seat = get_seat_for_session (entry->service, entry->session);
+ /* FIXME: Should only allow locks if have a session on this seat */
+ seat_lock (seat, session_get_username (entry->session));
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ else
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
+}
+
+static void
+running_user_session_cb (Seat *seat, Session *session, DisplayManagerService *service)
+{
+ static const GDBusInterfaceVTable session_vtable =
+ {
+ handle_session_call,
+ handle_session_get_property
+ };
+ SeatBusEntry *seat_entry;
+ SessionBusEntry *session_entry;
+ gchar *path;
+ GError *error = NULL;
+
+ /* Set environment variables when session runs */
+ seat_entry = g_hash_table_lookup (service->priv->seat_bus_entries, seat);
+ session_set_env (session, "XDG_SEAT_PATH", seat_entry->path);
+ path = g_strdup_printf ("/org/freedesktop/DisplayManager/Session%d", service->priv->session_index);
+ service->priv->session_index++;
+ session_set_env (session, "XDG_SESSION_PATH", path);
+ g_object_set_data_full (G_OBJECT (session), "XDG_SESSION_PATH", path, g_free);
+
+ session_entry = session_bus_entry_new (service, session, g_object_get_data (G_OBJECT (session), "XDG_SESSION_PATH"), seat_entry ? seat_entry->path : NULL);
+ g_hash_table_insert (service->priv->session_bus_entries, g_object_ref (session), session_entry);
+
+ g_debug ("Registering session with bus path %s", session_entry->path);
+
+ session_entry->bus_id = g_dbus_connection_register_object (service->priv->bus,
+ session_entry->path,
+ service->priv->session_info->interfaces[0],
+ &session_vtable,
+ session_entry, NULL,
+ &error);
+ if (session_entry->bus_id == 0)
+ g_warning ("Failed to register user session: %s", error->message);
+ g_clear_error (&error);
+
+ emit_object_value_changed (service->priv->bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Sessions", get_session_list (service, NULL));
+ emit_object_signal (service->priv->bus, "/org/freedesktop/DisplayManager", "SessionAdded", session_entry->path);
+
+ emit_object_value_changed (service->priv->bus, seat_entry->path, "org.freedesktop.DisplayManager.Seat", "Sessions", get_session_list (service, session_entry->seat_path));
+ emit_object_signal (service->priv->bus, seat_entry->path, "SessionAdded", session_entry->path);
+}
+
+static void
+session_removed_cb (Seat *seat, Session *session, DisplayManagerService *service)
+{
+ SessionBusEntry *entry;
+ gchar *seat_path = NULL;
+
+ g_signal_handlers_disconnect_matched (session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
+
+ entry = g_hash_table_lookup (service->priv->session_bus_entries, session);
+ if (entry)
+ {
+ g_dbus_connection_unregister_object (service->priv->bus, entry->bus_id);
+ emit_object_signal (service->priv->bus, "/org/freedesktop/DisplayManager", "SessionRemoved", entry->path);
+ emit_object_signal (service->priv->bus, entry->seat_path, "SessionRemoved", entry->path);
+ seat_path = g_strdup (entry->seat_path);
+ }
+
+ g_hash_table_remove (service->priv->session_bus_entries, session);
+
+ if (seat_path)
+ {
+ emit_object_value_changed (service->priv->bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Sessions", get_session_list (service, NULL));
+ emit_object_value_changed (service->priv->bus, seat_path, "org.freedesktop.DisplayManager.Seat", "Sessions", get_session_list (service, seat_path));
+ g_free (seat_path);
+ }
+}
+
+static void
+seat_added_cb (DisplayManager *display_manager, Seat *seat, DisplayManagerService *service)
+{
+ static const GDBusInterfaceVTable seat_vtable =
+ {
+ handle_seat_call,
+ handle_seat_get_property
+ };
+ gchar *path;
+ SeatBusEntry *entry;
+ GError *error = NULL;
+
+ path = g_strdup_printf ("/org/freedesktop/DisplayManager/Seat%d", service->priv->seat_index);
+ service->priv->seat_index++;
+
+ entry = seat_bus_entry_new (service, seat, path);
+ g_free (path);
+ g_hash_table_insert (service->priv->seat_bus_entries, g_object_ref (seat), entry);
+
+ g_debug ("Registering seat with bus path %s", entry->path);
+
+ entry->bus_id = g_dbus_connection_register_object (service->priv->bus,
+ entry->path,
+ service->priv->seat_info->interfaces[0],
+ &seat_vtable,
+ entry, NULL,
+ &error);
+ if (entry->bus_id == 0)
+ g_warning ("Failed to register seat: %s", error->message);
+ g_clear_error (&error);
+
+ emit_object_value_changed (service->priv->bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Seats", get_seat_list (service));
+ emit_object_signal (service->priv->bus, "/org/freedesktop/DisplayManager", "SeatAdded", entry->path);
+
+ g_signal_connect (seat, SEAT_SIGNAL_RUNNING_USER_SESSION, G_CALLBACK (running_user_session_cb), service);
+ g_signal_connect (seat, SEAT_SIGNAL_SESSION_REMOVED, G_CALLBACK (session_removed_cb), service);
+}
+
+static void
+seat_removed_cb (DisplayManager *display_manager, Seat *seat, DisplayManagerService *service)
+{
+ SeatBusEntry *entry;
+
+ entry = g_hash_table_lookup (service->priv->seat_bus_entries, seat);
+ if (entry)
+ {
+ g_dbus_connection_unregister_object (service->priv->bus, entry->bus_id);
+ emit_object_signal (service->priv->bus, "/org/freedesktop/DisplayManager", "SeatRemoved", entry->path);
+ }
+
+ g_hash_table_remove (service->priv->seat_bus_entries, seat);
+
+ emit_object_value_changed (service->priv->bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Seats", get_seat_list (service));
+}
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ const gchar *display_manager_interface =
+ "<node>"
+ " <interface name='org.freedesktop.DisplayManager'>"
+ " <property name='Seats' type='ao' access='read'/>"
+ " <property name='Sessions' type='ao' access='read'/>"
+ " <method name='AddSeat'>"
+ " <arg name='type' direction='in' type='s'/>"
+ " <arg name='properties' direction='in' type='a(ss)'/>"
+ " <arg name='seat' direction='out' type='o'/>"
+ " </method>"
+ " <method name='AddLocalXSeat'>"
+ " <arg name='display-number' direction='in' type='i'/>"
+ " <arg name='seat' direction='out' type='o'/>"
+ " </method>"
+ " <signal name='SeatAdded'>"
+ " <arg name='seat' type='o'/>"
+ " </signal>"
+ " <signal name='SeatRemoved'>"
+ " <arg name='seat' type='o'/>"
+ " </signal>"
+ " <signal name='SessionAdded'>"
+ " <arg name='session' type='o'/>"
+ " </signal>"
+ " <signal name='SessionRemoved'>"
+ " <arg name='session' type='o'/>"
+ " </signal>"
+ " </interface>"
+ "</node>";
+ static const GDBusInterfaceVTable display_manager_vtable =
+ {
+ handle_display_manager_call,
+ handle_display_manager_get_property
+ };
+ const gchar *seat_interface =
+ "<node>"
+ " <interface name='org.freedesktop.DisplayManager.Seat'>"
+ " <property name='CanSwitch' type='b' access='read'/>"
+ " <property name='HasGuestAccount' type='b' access='read'/>"
+ " <property name='Sessions' type='ao' access='read'/>"
+ " <method name='SwitchToGreeter'/>"
+ " <method name='SwitchToUser'>"
+ " <arg name='username' direction='in' type='s'/>"
+ " <arg name='session-name' direction='in' type='s'/>"
+ " </method>"
+ " <method name='SwitchToGuest'>"
+ " <arg name='session-name' direction='in' type='s'/>"
+ " </method>"
+ " <method name='Lock'/>"
+ " <signal name='SessionAdded'>"
+ " <arg name='session' type='o'/>"
+ " </signal>"
+ " <signal name='SessionRemoved'>"
+ " <arg name='session' type='o'/>"
+ " </signal>"
+ " </interface>"
+ "</node>";
+ const gchar *session_interface =
+ "<node>"
+ " <interface name='org.freedesktop.DisplayManager.Session'>"
+ " <property name='Seat' type='o' access='read'/>"
+ " <property name='UserName' type='s' access='read'/>"
+ " <method name='Lock'/>"
+ " </interface>"
+ "</node>";
+ DisplayManagerService *service = user_data;
+ GDBusNodeInfo *display_manager_info;
+ GList *link;
+ GError *error = NULL;
+
+ g_debug ("Acquired bus name %s", name);
+
+ service->priv->bus = g_object_ref (connection);
+
+ display_manager_info = g_dbus_node_info_new_for_xml (display_manager_interface, NULL);
+ g_assert (display_manager_info != NULL);
+ service->priv->seat_info = g_dbus_node_info_new_for_xml (seat_interface, NULL);
+ g_assert (service->priv->seat_info != NULL);
+ service->priv->session_info = g_dbus_node_info_new_for_xml (session_interface, NULL);
+ g_assert (service->priv->session_info != NULL);
+
+ service->priv->reg_id = g_dbus_connection_register_object (connection,
+ "/org/freedesktop/DisplayManager",
+ display_manager_info->interfaces[0],
+ &display_manager_vtable,
+ service, NULL,
+ &error);
+ if (service->priv->reg_id == 0)
+ g_warning ("Failed to register display manager: %s", error->message);
+ g_clear_error (&error);
+ g_dbus_node_info_unref (display_manager_info);
+
+ /* Add objects for existing seats and listen to new ones */
+ g_signal_connect (service->priv->manager, DISPLAY_MANAGER_SIGNAL_SEAT_ADDED, G_CALLBACK (seat_added_cb), service);
+ g_signal_connect (service->priv->manager, DISPLAY_MANAGER_SIGNAL_SEAT_REMOVED, G_CALLBACK (seat_removed_cb), service);
+ for (link = display_manager_get_seats (service->priv->manager); link; link = link->next)
+ seat_added_cb (service->priv->manager, (Seat *) link->data, service);
+
+ g_signal_emit (service, signals[READY], 0);
+}
+
+static void
+name_lost_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ DisplayManagerService *service = user_data;
+
+ if (connection)
+ g_printerr ("Failed to use bus name " LIGHTDM_BUS_NAME ", do you have appropriate permissions?\n");
+ else
+ g_printerr ("Failed to get D-Bus connection\n");
+
+ g_signal_emit (service, signals[NAME_LOST], 0);
+}
+
+void
+display_manager_service_start (DisplayManagerService *service)
+{
+ g_return_if_fail (service != NULL);
+
+ g_debug ("Using D-Bus name %s", LIGHTDM_BUS_NAME);
+ service->priv->bus_id = g_bus_own_name (getuid () == 0 ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION,
+ LIGHTDM_BUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ bus_acquired_cb,
+ NULL,
+ name_lost_cb,
+ service,
+ NULL);
+}
+
+static void
+display_manager_service_init (DisplayManagerService *service)
+{
+ service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, DISPLAY_MANAGER_SERVICE_TYPE, DisplayManagerServicePrivate);
+ service->priv->seat_bus_entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, seat_bus_entry_free);
+ service->priv->session_bus_entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, session_bus_entry_free);
+}
+
+static void
+display_manager_service_finalize (GObject *object)
+{
+ DisplayManagerService *self = DISPLAY_MANAGER_SERVICE (object);
+
+ g_dbus_connection_unregister_object (self->priv->bus, self->priv->reg_id);
+ g_bus_unown_name (self->priv->bus_id);
+ if (self->priv->seat_info)
+ g_dbus_node_info_unref (self->priv->seat_info);
+ if (self->priv->session_info)
+ g_dbus_node_info_unref (self->priv->session_info);
+ g_hash_table_unref (self->priv->seat_bus_entries);
+ g_hash_table_unref (self->priv->session_bus_entries);
+ g_object_unref (self->priv->bus);
+ g_clear_object (&self->priv->manager);
+
+ G_OBJECT_CLASS (display_manager_service_parent_class)->finalize (object);
+}
+
+static void
+display_manager_service_class_init (DisplayManagerServiceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = display_manager_service_finalize;
+
+ g_type_class_add_private (klass, sizeof (DisplayManagerServicePrivate));
+
+ signals[READY] =
+ g_signal_new (DISPLAY_MANAGER_SERVICE_SIGNAL_READY,
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DisplayManagerServiceClass, ready),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ signals[ADD_XLOCAL_SEAT] =
+ g_signal_new (DISPLAY_MANAGER_SERVICE_SIGNAL_ADD_XLOCAL_SEAT,
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DisplayManagerServiceClass, add_xlocal_seat),
+ g_signal_accumulator_first_wins,
+ NULL,
+ NULL,
+ SEAT_TYPE, 1, G_TYPE_INT);
+
+ signals[NAME_LOST] =
+ g_signal_new (DISPLAY_MANAGER_SERVICE_SIGNAL_NAME_LOST,
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DisplayManagerServiceClass, name_lost),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+}
diff --git a/src/display-manager-service.h b/src/display-manager-service.h
new file mode 100644
index 00000000..65dba65a
--- /dev/null
+++ b/src/display-manager-service.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+#ifndef DISPLAY_MANAGER_SERVICE_H_
+#define DISPLAY_MANAGER_SERVICE_H_
+
+#include <glib-object.h>
+
+#include "display-manager.h"
+
+G_BEGIN_DECLS
+
+#define DISPLAY_MANAGER_SERVICE_TYPE (display_manager_service_get_type())
+#define DISPLAY_MANAGER_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DISPLAY_MANAGER_SERVICE_TYPE, DisplayManagerService));
+
+#define DISPLAY_MANAGER_SERVICE_SIGNAL_READY "ready"
+#define DISPLAY_MANAGER_SERVICE_SIGNAL_ADD_XLOCAL_SEAT "add-xlocal-seat"
+#define DISPLAY_MANAGER_SERVICE_SIGNAL_NAME_LOST "name-lost"
+
+typedef struct DisplayManagerServicePrivate DisplayManagerServicePrivate;
+
+typedef struct
+{
+ GObject parent_instance;
+ DisplayManagerServicePrivate *priv;
+} DisplayManagerService;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (*ready)(DisplayManagerService *service);
+ Seat *(*add_xlocal_seat)(DisplayManagerService *service, gint display_number);
+ void (*name_lost)(DisplayManagerService *service);
+} DisplayManagerServiceClass;
+
+GType display_manager_service_get_type (void);
+
+DisplayManagerService *display_manager_service_new (DisplayManager *manager);
+
+void display_manager_service_start (DisplayManagerService *service);
+
+G_END_DECLS
+
+#endif /* DISPLAY_MANAGER_SERVICE_H_ */
diff --git a/src/lightdm.c b/src/lightdm.c
index 943ec94c..0b45c229 100644
--- a/src/lightdm.c
+++ b/src/lightdm.c
@@ -23,6 +23,7 @@
#include "configuration.h"
#include "display-manager.h"
+#include "display-manager-service.h"
#include "xdmcp-server.h"
#include "vnc-server.h"
#include "seat-xdmcp-session.h"
@@ -42,33 +43,11 @@ static int log_fd = -1;
static gboolean debug = FALSE;
static DisplayManager *display_manager = NULL;
+static DisplayManagerService *display_manager_service = NULL;
static XDMCPServer *xdmcp_server = NULL;
static VNCServer *vnc_server = NULL;
-static guint bus_id = 0;
-static GDBusConnection *bus = NULL;
-static guint reg_id = 0;
-static GDBusNodeInfo *seat_info;
-static GHashTable *seat_bus_entries = NULL;
-static guint seat_index = 0;
-static GDBusNodeInfo *session_info;
-static GHashTable *session_bus_entries = NULL;
-static guint session_index = 0;
static gint exit_code = EXIT_SUCCESS;
-typedef struct
-{
- gchar *path;
- guint bus_id;
-} SeatBusEntry;
-typedef struct
-{
- gchar *path;
- gchar *seat_path;
- guint bus_id;
-} SessionBusEntry;
-
-#define LIGHTDM_BUS_NAME "org.freedesktop.DisplayManager"
-
static gboolean update_login1_seat (Login1Seat *login1_seat);
static void
@@ -229,6 +208,32 @@ create_seat (const gchar *module_name, const gchar *name)
return seat_new (module_name, name);
}
+static Seat *
+service_add_xlocal_seat_cb (DisplayManagerService *service, gint display_number)
+{
+ Seat *seat;
+ gchar *display_number_string;
+
+ g_debug ("Adding local X seat :%d", display_number);
+
+ seat = create_seat ("xremote", "xremote0"); // FIXME: What to use for a name?
+ if (!seat)
+ return NULL;
+
+ set_seat_properties (seat, NULL);
+ display_number_string = g_strdup_printf ("%d", display_number);
+ seat_set_property (seat, "xserver-display-number", display_number_string);
+ g_free (display_number_string);
+
+ if (!display_manager_add_seat (display_manager, seat))
+ {
+ g_object_unref (seat);
+ return NULL;
+ }
+
+ return seat;
+}
+
static void
display_manager_seat_removed_cb (DisplayManager *display_manager, Seat *seat)
{
@@ -283,490 +288,6 @@ display_manager_seat_removed_cb (DisplayManager *display_manager, Seat *seat)
g_string_free (next_types, TRUE);
}
-static GVariant *
-get_seat_list (void)
-{
- GVariantBuilder builder;
- GHashTableIter iter;
- gpointer value;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
- g_hash_table_iter_init (&iter, seat_bus_entries);
- while (g_hash_table_iter_next (&iter, NULL, &value))
- {
- SeatBusEntry *entry = value;
- g_variant_builder_add_value (&builder, g_variant_new_object_path (entry->path));
- }
-
- return g_variant_builder_end (&builder);
-}
-
-static GVariant *
-get_session_list (const gchar *seat_path)
-{
- GVariantBuilder builder;
- GHashTableIter iter;
- gpointer value;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
-
- g_hash_table_iter_init (&iter, session_bus_entries);
- while (g_hash_table_iter_next (&iter, NULL, &value))
- {
- SessionBusEntry *entry = value;
- if (seat_path == NULL || strcmp (entry->seat_path, seat_path) == 0)
- g_variant_builder_add_value (&builder, g_variant_new_object_path (entry->path));
- }
-
- return g_variant_builder_end (&builder);
-}
-
-static GVariant *
-handle_display_manager_get_property (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *property_name,
- GError **error,
- gpointer user_data)
-{
- if (g_strcmp0 (property_name, "Seats") == 0)
- return get_seat_list ();
- else if (g_strcmp0 (property_name, "Sessions") == 0)
- return get_session_list (NULL);
-
- return NULL;
-}
-
-static void
-handle_display_manager_call (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
-{
- if (g_strcmp0 (method_name, "AddSeat") == 0)
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "AddSeat is deprecated");
- else if (g_strcmp0 (method_name, "AddLocalXSeat") == 0)
- {
- gint display_number;
- Seat *seat;
-
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(i)")))
- {
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
- return;
- }
-
- g_variant_get (parameters, "(i)", &display_number);
-
- g_debug ("Adding local X seat :%d", display_number);
-
- seat = create_seat ("xremote", "xremote0"); // FIXME: What to use for a name?
- if (seat)
- {
- gchar *display_number_string;
-
- set_seat_properties (seat, NULL);
- display_number_string = g_strdup_printf ("%d", display_number);
- seat_set_property (seat, "xserver-display-number", display_number_string);
- g_free (display_number_string);
- }
-
- if (!seat)
- {
- // FIXME: Need to make proper error
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to create local X seat");
- return;
- }
-
- if (display_manager_add_seat (display_manager, seat))
- {
- SeatBusEntry *entry;
-
- entry = g_hash_table_lookup (seat_bus_entries, seat);
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", entry->path));
- }
- else// FIXME: Need to make proper error
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to start seat");
- g_object_unref (seat);
- }
- else
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
-}
-
-static GVariant *
-handle_seat_get_property (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *property_name,
- GError **error,
- gpointer user_data)
-{
- Seat *seat = user_data;
-
- if (g_strcmp0 (property_name, "CanSwitch") == 0)
- return g_variant_new_boolean (seat_get_can_switch (seat));
- if (g_strcmp0 (property_name, "HasGuestAccount") == 0)
- return g_variant_new_boolean (seat_get_allow_guest (seat));
- else if (g_strcmp0 (property_name, "Sessions") == 0)
- {
- SeatBusEntry *entry;
-
- entry = g_hash_table_lookup (seat_bus_entries, seat);
- return get_session_list (entry->path);
- }
-
- return NULL;
-}
-
-static void
-handle_seat_call (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
-{
- Seat *seat = user_data;
-
- if (g_strcmp0 (method_name, "SwitchToGreeter") == 0)
- {
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
-
- if (seat_switch_to_greeter (seat))
- g_dbus_method_invocation_return_value (invocation, NULL);
- else// FIXME: Need to make proper error
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to switch to greeter");
- }
- else if (g_strcmp0 (method_name, "SwitchToUser") == 0)
- {
- const gchar *username, *session_name;
-
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(ss)")))
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
-
- g_variant_get (parameters, "(&s&s)", &username, &session_name);
- if (strcmp (session_name, "") == 0)
- session_name = NULL;
-
- if (seat_switch_to_user (seat, username, session_name))
- g_dbus_method_invocation_return_value (invocation, NULL);
- else// FIXME: Need to make proper error
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to switch to user");
- }
- else if (g_strcmp0 (method_name, "SwitchToGuest") == 0)
- {
- const gchar *session_name;
-
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")))
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
-
- g_variant_get (parameters, "(&s)", &session_name);
- if (strcmp (session_name, "") == 0)
- session_name = NULL;
-
- if (seat_switch_to_guest (seat, session_name))
- g_dbus_method_invocation_return_value (invocation, NULL);
- else// FIXME: Need to make proper error
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to switch to guest");
- }
- else if (g_strcmp0 (method_name, "Lock") == 0)
- {
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
-
- /* FIXME: Should only allow locks if have a session on this seat */
- if (seat_lock (seat, NULL))
- g_dbus_method_invocation_return_value (invocation, NULL);
- else// FIXME: Need to make proper error
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to lock seat");
- }
- else
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
-}
-
-static Seat *
-get_seat_for_session (Session *session)
-{
- GList *seat_link;
-
- for (seat_link = display_manager_get_seats (display_manager); seat_link; seat_link = seat_link->next)
- {
- Seat *seat = seat_link->data;
- GList *session_link;
-
- for (session_link = seat_get_sessions (seat); session_link; session_link = session_link->next)
- {
- Session *s = session_link->data;
-
- if (s == session)
- return seat;
- }
- }
-
- return NULL;
-}
-
-static GVariant *
-handle_session_get_property (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *property_name,
- GError **error,
- gpointer user_data)
-{
- Session *session = user_data;
- SessionBusEntry *entry;
-
- entry = g_hash_table_lookup (session_bus_entries, session);
- if (g_strcmp0 (property_name, "Seat") == 0)
- return g_variant_new_object_path (entry ? entry->seat_path : "");
- else if (g_strcmp0 (property_name, "UserName") == 0)
- return g_variant_new_string (session_get_username (session));
-
- return NULL;
-}
-
-static void
-handle_session_call (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
-{
- Session *session = user_data;
-
- if (g_strcmp0 (method_name, "Lock") == 0)
- {
- Seat *seat;
-
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid arguments");
-
- seat = get_seat_for_session (session);
- /* FIXME: Should only allow locks if have a session on this seat */
- seat_lock (seat, session_get_username (session));
- g_dbus_method_invocation_return_value (invocation, NULL);
- }
- else
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
-}
-
-static SeatBusEntry *
-seat_bus_entry_new (const gchar *path)
-{
- SeatBusEntry *entry;
-
- entry = g_malloc0 (sizeof (SeatBusEntry));
- entry->path = g_strdup (path);
-
- return entry;
-}
-
-static SessionBusEntry *
-session_bus_entry_new (const gchar *path, const gchar *seat_path)
-{
- SessionBusEntry *entry;
-
- entry = g_malloc0 (sizeof (SessionBusEntry));
- entry->path = g_strdup (path);
- entry->seat_path = g_strdup (seat_path);
-
- return entry;
-}
-
-static void
-emit_object_value_changed (GDBusConnection *bus, const gchar *path, const gchar *interface_name, const gchar *property_name, GVariant *property_value)
-{
- GVariantBuilder builder;
- GError *error = NULL;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
- g_variant_builder_add (&builder, "{sv}", property_name, property_value);
-
- if (!g_dbus_connection_emit_signal (bus,
- NULL,
- path,
- "org.freedesktop.DBus.Properties",
- "PropertiesChanged",
- g_variant_new ("(sa{sv}as)", interface_name, &builder, NULL),
- &error))
- g_warning ("Failed to emit PropertiesChanged signal: %s", error->message);
- g_clear_error (&error);
-}
-
-static void
-emit_object_signal (GDBusConnection *bus, const gchar *path, const gchar *signal_name, const gchar *object_path)
-{
- GError *error = NULL;
-
- if (!g_dbus_connection_emit_signal (bus,
- NULL,
- path,
- "org.freedesktop.DisplayManager",
- signal_name,
- g_variant_new ("(o)", object_path),
- &error))
- g_warning ("Failed to emit %s signal on %s: %s", signal_name, path, error->message);
- g_clear_error (&error);
-}
-
-static void
-seat_bus_entry_free (gpointer data)
-{
- SeatBusEntry *entry = data;
-
- g_free (entry->path);
- g_free (entry);
-}
-
-static void
-session_bus_entry_free (gpointer data)
-{
- SessionBusEntry *entry = data;
-
- g_free (entry->path);
- g_free (entry->seat_path);
- g_free (entry);
-}
-
-static void
-running_user_session_cb (Seat *seat, Session *session)
-{
- static const GDBusInterfaceVTable session_vtable =
- {
- handle_session_call,
- handle_session_get_property
- };
- SeatBusEntry *seat_entry;
- SessionBusEntry *session_entry;
- gchar *path;
- GError *error = NULL;
-
- /* Set environment variables when session runs */
- seat_entry = g_hash_table_lookup (seat_bus_entries, seat);
- session_set_env (session, "XDG_SEAT_PATH", seat_entry->path);
- path = g_strdup_printf ("/org/freedesktop/DisplayManager/Session%d", session_index);
- session_index++;
- session_set_env (session, "XDG_SESSION_PATH", path);
- g_object_set_data_full (G_OBJECT (session), "XDG_SESSION_PATH", path, g_free);
-
- session_entry = session_bus_entry_new (g_object_get_data (G_OBJECT (session), "XDG_SESSION_PATH"), seat_entry ? seat_entry->path : NULL);
- g_hash_table_insert (session_bus_entries, g_object_ref (session), session_entry);
-
- g_debug ("Registering session with bus path %s", session_entry->path);
-
- session_entry->bus_id = g_dbus_connection_register_object (bus,
- session_entry->path,
- session_info->interfaces[0],
- &session_vtable,
- g_object_ref (session), g_object_unref,
- &error);
- if (session_entry->bus_id == 0)
- g_warning ("Failed to register user session: %s", error->message);
- g_clear_error (&error);
-
- emit_object_value_changed (bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Sessions", get_session_list (NULL));
- emit_object_signal (bus, "/org/freedesktop/DisplayManager", "SessionAdded", session_entry->path);
-
- emit_object_value_changed (bus, seat_entry->path, "org.freedesktop.DisplayManager.Seat", "Sessions", get_session_list (session_entry->seat_path));
- emit_object_signal (bus, seat_entry->path, "SessionAdded", session_entry->path);
-}
-
-static void
-session_removed_cb (Seat *seat, Session *session)
-{
- SessionBusEntry *entry;
- gchar *seat_path = NULL;
-
- g_signal_handlers_disconnect_matched (session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
-
- entry = g_hash_table_lookup (session_bus_entries, session);
- if (entry)
- {
- g_dbus_connection_unregister_object (bus, entry->bus_id);
- emit_object_signal (bus, "/org/freedesktop/DisplayManager", "SessionRemoved", entry->path);
- emit_object_signal (bus, entry->seat_path, "SessionRemoved", entry->path);
- seat_path = g_strdup (entry->seat_path);
- }
-
- g_hash_table_remove (session_bus_entries, session);
-
- if (seat_path)
- {
- emit_object_value_changed (bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Sessions", get_session_list (NULL));
- emit_object_value_changed (bus, seat_path, "org.freedesktop.DisplayManager.Seat", "Sessions", get_session_list (seat_path));
- g_free (seat_path);
- }
-}
-
-static void
-seat_added_cb (DisplayManager *display_manager, Seat *seat)
-{
- static const GDBusInterfaceVTable seat_vtable =
- {
- handle_seat_call,
- handle_seat_get_property
- };
- gchar *path;
- SeatBusEntry *entry;
- GError *error = NULL;
-
- path = g_strdup_printf ("/org/freedesktop/DisplayManager/Seat%d", seat_index);
- seat_index++;
-
- entry = seat_bus_entry_new (path);
- g_free (path);
- g_hash_table_insert (seat_bus_entries, g_object_ref (seat), entry);
-
- g_debug ("Registering seat with bus path %s", entry->path);
-
- entry->bus_id = g_dbus_connection_register_object (bus,
- entry->path,
- seat_info->interfaces[0],
- &seat_vtable,
- g_object_ref (seat), g_object_unref,
- &error);
- if (entry->bus_id == 0)
- g_warning ("Failed to register seat: %s", error->message);
- g_clear_error (&error);
-
- emit_object_value_changed (bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Seats", get_seat_list ());
- emit_object_signal (bus, "/org/freedesktop/DisplayManager", "SeatAdded", entry->path);
-
- g_signal_connect (seat, SEAT_SIGNAL_RUNNING_USER_SESSION, G_CALLBACK (running_user_session_cb), NULL);
- g_signal_connect (seat, SEAT_SIGNAL_SESSION_REMOVED, G_CALLBACK (session_removed_cb), NULL);
-}
-
-static void
-seat_removed_cb (DisplayManager *display_manager, Seat *seat)
-{
- SeatBusEntry *entry;
-
- entry = g_hash_table_lookup (seat_bus_entries, seat);
- if (entry)
- {
- g_dbus_connection_unregister_object (bus, entry->bus_id);
- emit_object_signal (bus, "/org/freedesktop/DisplayManager", "SeatRemoved", entry->path);
- }
-
- g_hash_table_remove (seat_bus_entries, seat);
-
- emit_object_value_changed (bus, "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", "Seats", get_seat_list ());
-}
-
static gboolean
xdmcp_session_cb (XDMCPServer *server, XDMCPSession *session)
{
@@ -894,124 +415,15 @@ start_display_manager (void)
g_warning ("Can't start VNC server, Xvnc is not in the path");
}
}
-
static void
-bus_acquired_cb (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
+service_ready_cb (DisplayManagerService *service)
{
- const gchar *display_manager_interface =
- "<node>"
- " <interface name='org.freedesktop.DisplayManager'>"
- " <property name='Seats' type='ao' access='read'/>"
- " <property name='Sessions' type='ao' access='read'/>"
- " <method name='AddSeat'>"
- " <arg name='type' direction='in' type='s'/>"
- " <arg name='properties' direction='in' type='a(ss)'/>"
- " <arg name='seat' direction='out' type='o'/>"
- " </method>"
- " <method name='AddLocalXSeat'>"
- " <arg name='display-number' direction='in' type='i'/>"
- " <arg name='seat' direction='out' type='o'/>"
- " </method>"
- " <signal name='SeatAdded'>"
- " <arg name='seat' type='o'/>"
- " </signal>"
- " <signal name='SeatRemoved'>"
- " <arg name='seat' type='o'/>"
- " </signal>"
- " <signal name='SessionAdded'>"
- " <arg name='session' type='o'/>"
- " </signal>"
- " <signal name='SessionRemoved'>"
- " <arg name='session' type='o'/>"
- " </signal>"
- " </interface>"
- "</node>";
- static const GDBusInterfaceVTable display_manager_vtable =
- {
- handle_display_manager_call,
- handle_display_manager_get_property
- };
- const gchar *seat_interface =
- "<node>"
- " <interface name='org.freedesktop.DisplayManager.Seat'>"
- " <property name='CanSwitch' type='b' access='read'/>"
- " <property name='HasGuestAccount' type='b' access='read'/>"
- " <property name='Sessions' type='ao' access='read'/>"
- " <method name='SwitchToGreeter'/>"
- " <method name='SwitchToUser'>"
- " <arg name='username' direction='in' type='s'/>"
- " <arg name='session-name' direction='in' type='s'/>"
- " </method>"
- " <method name='SwitchToGuest'>"
- " <arg name='session-name' direction='in' type='s'/>"
- " </method>"
- " <method name='Lock'/>"
- " <signal name='SessionAdded'>"
- " <arg name='session' type='o'/>"
- " </signal>"
- " <signal name='SessionRemoved'>"
- " <arg name='session' type='o'/>"
- " </signal>"
- " </interface>"
- "</node>";
- const gchar *session_interface =
- "<node>"
- " <interface name='org.freedesktop.DisplayManager.Session'>"
- " <property name='Seat' type='o' access='read'/>"
- " <property name='UserName' type='s' access='read'/>"
- " <method name='Lock'/>"
- " </interface>"
- "</node>";
- GDBusNodeInfo *display_manager_info;
- GList *link;
- GError *error = NULL;
-
- g_debug ("Acquired bus name %s", name);
-
- bus = connection;
-
- display_manager_info = g_dbus_node_info_new_for_xml (display_manager_interface, NULL);
- g_assert (display_manager_info != NULL);
- seat_info = g_dbus_node_info_new_for_xml (seat_interface, NULL);
- g_assert (seat_info != NULL);
- session_info = g_dbus_node_info_new_for_xml (session_interface, NULL);
- g_assert (session_info != NULL);
-
- reg_id = g_dbus_connection_register_object (connection,
- "/org/freedesktop/DisplayManager",
- display_manager_info->interfaces[0],
- &display_manager_vtable,
- NULL, NULL,
- &error);
- if (reg_id == 0)
- g_warning ("Failed to register display manager: %s", error->message);
- g_clear_error (&error);
- g_dbus_node_info_unref (display_manager_info);
-
- seat_bus_entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, seat_bus_entry_free);
- session_bus_entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, session_bus_entry_free);
-
- /* Add objects for existing seats and listen to new ones */
- g_signal_connect (display_manager, DISPLAY_MANAGER_SIGNAL_SEAT_ADDED, G_CALLBACK (seat_added_cb), NULL);
- g_signal_connect (display_manager, DISPLAY_MANAGER_SIGNAL_SEAT_REMOVED, G_CALLBACK (seat_removed_cb), NULL);
- for (link = display_manager_get_seats (display_manager); link; link = link->next)
- seat_added_cb (display_manager, (Seat *) link->data);
-
start_display_manager ();
}
static void
-name_lost_cb (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
+service_name_lost_cb (DisplayManagerService *service)
{
- if (connection)
- g_printerr ("Failed to use bus name " LIGHTDM_BUS_NAME ", do you have appropriate permissions?\n");
- else
- g_printerr ("Failed to get D-Bus connection\n");
-
exit (EXIT_FAILURE);
}
@@ -1520,16 +932,6 @@ main (int argc, char **argv)
g_debug ("%s", (gchar *)link->data);
g_list_free_full (messages, g_free);
- g_debug ("Using D-Bus name %s", LIGHTDM_BUS_NAME);
- bus_id = g_bus_own_name (getuid () == 0 ? G_BUS_TYPE_SYSTEM : G_BUS_TYPE_SESSION,
- LIGHTDM_BUS_NAME,
- G_BUS_NAME_OWNER_FLAGS_NONE,
- bus_acquired_cb,
- NULL,
- name_lost_cb,
- NULL,
- NULL);
-
if (getuid () != 0)
g_debug ("Running in user mode");
if (getenv ("DISPLAY"))
@@ -1539,6 +941,12 @@ main (int argc, char **argv)
g_signal_connect (display_manager, DISPLAY_MANAGER_SIGNAL_STOPPED, G_CALLBACK (display_manager_stopped_cb), NULL);
g_signal_connect (display_manager, DISPLAY_MANAGER_SIGNAL_SEAT_REMOVED, G_CALLBACK (display_manager_seat_removed_cb), NULL);
+ display_manager_service = display_manager_service_new (display_manager);
+ g_signal_connect (display_manager_service, DISPLAY_MANAGER_SERVICE_SIGNAL_ADD_XLOCAL_SEAT, G_CALLBACK (service_add_xlocal_seat_cb), NULL);
+ g_signal_connect (display_manager_service, DISPLAY_MANAGER_SERVICE_SIGNAL_READY, G_CALLBACK (service_ready_cb), NULL);
+ g_signal_connect (display_manager_service, DISPLAY_MANAGER_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK (service_name_lost_cb), NULL);
+ display_manager_service_start (display_manager_service);
+
shared_data_manager_start (shared_data_manager_get_instance ());
/* Connect to logind */
@@ -1602,17 +1010,12 @@ main (int argc, char **argv)
/* Clean up user list */
common_user_list_cleanup ();
+ /* Remove D-Bus interface */
+ g_clear_object (&display_manager_service);
+
/* Clean up display manager */
g_clear_object (&display_manager);
- /* Remove D-Bus interface */
- g_dbus_connection_unregister_object (bus, reg_id);
- g_bus_unown_name (bus_id);
- if (seat_bus_entries)
- g_hash_table_unref (seat_bus_entries);
- if (session_bus_entries)
- g_hash_table_unref (session_bus_entries);
-
g_debug ("Exiting with return value %d", exit_code);
return exit_code;
}