diff options
author | Robert Ancell <robert.ancell@canonical.com> | 2016-12-06 14:41:05 +1300 |
---|---|---|
committer | Robert Ancell <robert.ancell@canonical.com> | 2016-12-06 14:41:05 +1300 |
commit | 91e5fd37ee8dc2180f741e1e18155f0096fd51d6 (patch) | |
tree | 445c1a2514c79416401f5ef34a9e69204c334a7e | |
parent | ce8011ae61acd90079e774e8910384fe41679c11 (diff) | |
download | lightdm-git-91e5fd37ee8dc2180f741e1e18155f0096fd51d6.tar.gz |
Refator D-Bus service into its own class
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/display-manager-service.c | 746 | ||||
-rw-r--r-- | src/display-manager-service.h | 52 | ||||
-rw-r--r-- | src/lightdm.c | 675 |
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; } |