diff options
Diffstat (limited to 'daemon/gdm-local-display-factory.c')
-rw-r--r-- | daemon/gdm-local-display-factory.c | 858 |
1 files changed, 824 insertions, 34 deletions
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 7ad27bec..f88f4e1c 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -27,18 +27,30 @@ #include <glib/gi18n.h> #include <glib-object.h> +#include <dbus/dbus-glib-lowlevel.h> + #include "gdm-display-factory.h" #include "gdm-local-display-factory.h" #include "gdm-local-display-factory-glue.h" +#include "gdm-marshal.h" #include "gdm-display-store.h" #include "gdm-static-display.h" +#include "gdm-dynamic-display.h" #include "gdm-transient-display.h" #include "gdm-static-factory-display.h" #include "gdm-product-display.h" #define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate)) +#define CK_NAME "org.freedesktop.ConsoleKit" +#define CK_PATH "/org/freedesktop/ConsoleKit" +#define CK_INTERFACE "org.freedesktop.ConsoleKit" +#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" +#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" +#define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" +#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" + #define CK_SEAT1_PATH "/org/freedesktop/ConsoleKit/Seat1" #define GDM_DBUS_PATH "/org/gnome/DisplayManager" @@ -47,11 +59,17 @@ #define MAX_DISPLAY_FAILURES 5 +#define IS_STR_SET(x) (x != NULL && x[0] != '\0') + +#define GDM_DBUS_TYPE_G_STRING_STRING_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)) + struct GdmLocalDisplayFactoryPrivate { DBusGConnection *connection; DBusGProxy *proxy; + DBusGProxy *proxy_ck; GHashTable *displays; + GHashTable *managed_seat_proxies; /* FIXME: this needs to be per seat? */ guint num_failures; @@ -65,7 +83,14 @@ static void gdm_local_display_factory_class_init (GdmLocalDisplayFactoryC static void gdm_local_display_factory_init (GdmLocalDisplayFactory *factory); static void gdm_local_display_factory_finalize (GObject *object); -static GdmDisplay *create_display (GdmLocalDisplayFactory *factory); +static gboolean create_static_displays (GdmLocalDisplayFactory *factory); +static void on_display_status_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmLocalDisplayFactory *factory); +static void on_block_console_session_requests_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmLocalDisplayFactory *factory); +static gboolean connect_to_ck (GdmLocalDisplayFactory *factory); static gpointer local_display_factory_object = NULL; @@ -179,6 +204,100 @@ store_display (GdmLocalDisplayFactory *factory, g_hash_table_insert (factory->priv->displays, GUINT_TO_POINTER (num), NULL); } +static void +store_remove_display (GdmLocalDisplayFactory *factory, + guint32 num, + GdmDisplay *display) +{ + GdmDisplayStore *store; + + store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); + gdm_display_store_remove (store, display); + + g_debug ("GdmLocalDisplayFactory: Remove display %d from store", num); + + /* remove from our reserved spot */ + g_hash_table_remove (factory->priv->displays, GUINT_TO_POINTER (num)); +} + +static gboolean +lookup_by_session (const char *id, + GdmDisplay *display, + gpointer user_data) +{ + char *key1 = user_data; + char *key2; + + if (!GDM_IS_DISPLAY (display)) { + return FALSE; + } + + gdm_display_get_session_id (display, &key2, NULL); + + if (strcmp (key1, key2) == 0) { + g_free (key2); + return TRUE; + } + g_free (key2); + + return FALSE; +} + +static gboolean +lookup_by_x11_display (const char *id, + GdmDisplay *display, + gpointer user_data) +{ + char *key1 = user_data; + char *key2; + + if (! GDM_IS_DISPLAY (display)) { + return FALSE; + } + + gdm_display_get_x11_display_name (display, &key2, NULL); + + if (strcmp (key1, key2) == 0) { + g_free (key2); + return TRUE; + } + g_free (key2); + + return FALSE; +} + +static gboolean +lookup_by_x11_display_num (const char *id, + GdmDisplay *display, + gpointer user_data) +{ + guint32 key1 = GPOINTER_TO_UINT (user_data); + int key2; + + if (! GDM_IS_DISPLAY (display)) { + return FALSE; + } + + gdm_display_get_x11_display_number (display, &key2, NULL); + + if (key1 == key2) { + return TRUE; + } + + return FALSE; +} + +static GdmDisplay * +factory_find_display (GdmLocalDisplayFactory *factory, + GdmDisplayStoreFunc predicate, + gpointer user_data) +{ + GdmDisplayStore *store; + + store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); + return gdm_display_store_find (store, predicate, user_data); +} + /* Example: dbus-send --system --dest=org.gnome.DisplayManager \ @@ -275,14 +394,113 @@ gdm_local_display_factory_create_product_display (GdmLocalDisplayFactory *factor return ret; } +static gboolean +display_has_pending_sessions (GdmLocalDisplayFactory *factory, + GdmDisplay *display) +{ + return g_object_get_data (G_OBJECT (display), + "gdm-local-display-factory-console-session-requests") != NULL; +} + static void -on_static_display_status_changed (GdmDisplay *display, - GParamSpec *arg1, - GdmLocalDisplayFactory *factory) +manage_next_pending_session_on_display (GdmLocalDisplayFactory *factory, + GdmDisplay *display) +{ + GList *pending_sessions; + GList *next_session; + char *ssid; + + g_debug ("GdmLocalDisplayFactory: Manage next pending session on display"); + + pending_sessions = g_object_get_data (G_OBJECT (display), + "gdm-local-display-factory-console-session-requests"); + next_session = g_list_last (pending_sessions); + + if (next_session == NULL) { + return; + } + + ssid = next_session->data; + pending_sessions = g_list_delete_link (pending_sessions, next_session); + g_object_set_data (G_OBJECT (display), + "gdm-local-display-factory-console-session-requests", + pending_sessions); + + g_object_set (display, "session-id", ssid, NULL); + g_free (ssid); + + gdm_display_manage (display); +} + +static void +discard_pending_session_on_display (GdmLocalDisplayFactory *factory, + GdmDisplay *display, + const char *ssid) +{ + GList *pending_sessions; + GList *node; + + pending_sessions = g_object_get_data (G_OBJECT (display), + "gdm-local-display-factory-console-session-requests"); + node = g_list_last (pending_sessions); + + while (node != NULL) { + GList *prev_node; + char *node_ssid; + + prev_node = node->prev; + node_ssid = node->data; + + if (strcmp (node_ssid, ssid) == 0) { + pending_sessions = g_list_delete_link (pending_sessions, node); + break; + } + + node = prev_node; + } + + g_object_set_data (G_OBJECT (display), + "gdm-local-display-factory-console-session-requests", + pending_sessions); +} + +static void +on_block_console_session_requests_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmLocalDisplayFactory *factory) +{ + gboolean display_is_blocked; + int status; + + g_object_get (G_OBJECT (display), + "status", &status, + "block-console-session-requests", + &display_is_blocked, NULL); + + if (display_is_blocked) { + int number; + + gdm_display_get_x11_display_number (display, &number, NULL); + g_debug ("GdmLocalDisplayFactory: display :%d is blocked", number); + return; + } + + if (status == GDM_DISPLAY_UNMANAGED) { + manage_next_pending_session_on_display (factory, display); + } +} + +static void +on_display_status_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmLocalDisplayFactory *factory) { int status; GdmDisplayStore *store; int num; + gboolean display_is_blocked; + + g_debug ("GdmLocalDisplayFactory: Display Status Changed"); num = -1; gdm_display_get_x11_display_number (display, &num, NULL); @@ -292,16 +510,17 @@ on_static_display_status_changed (GdmDisplay *display, status = gdm_display_get_status (display); + g_object_get (G_OBJECT (display), + "block-console-session-requests", + &display_is_blocked, NULL); + g_debug ("GdmLocalDisplayFactory: static display status changed: %d", status); switch (status) { case GDM_DISPLAY_FINISHED: - /* remove the display number from factory->priv->displays - so that it may be reused */ - g_hash_table_remove (factory->priv->displays, GUINT_TO_POINTER (num)); - gdm_display_store_remove (store, display); - /* reset num failures */ + /* Do not remove the display number from factory->priv->displays + here because it should be remove under signal "SessionRemoved" + */ factory->priv->num_failures = 0; - create_display (factory); break; case GDM_DISPLAY_FAILED: /* leave the display number in factory->priv->displays @@ -313,11 +532,13 @@ on_static_display_status_changed (GdmDisplay *display, g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors"); /* FIXME: should monitor hardware changes to try again when seats change */ - } else { - create_display (factory); } break; case GDM_DISPLAY_UNMANAGED: + if (display_has_pending_sessions (factory, display) && !display_is_blocked) { + store_display (factory, num, display); + manage_next_pending_session_on_display (factory, display); + } break; case GDM_DISPLAY_PREPARED: break; @@ -329,38 +550,535 @@ on_static_display_status_changed (GdmDisplay *display, } } -static GdmDisplay * -create_display (GdmLocalDisplayFactory *factory) +static void +seat_open_session_request (DBusGProxy *seat_proxy, + const char *ssid, + const char *session_type, + const char *display_template_name, + GHashTable *display_variables, + const char *display_type, + GHashTable *parameters, + GdmLocalDisplayFactory *factory) { GdmDisplay *display; - guint32 num; + gint argc; + gchar **argv; + GError *error; + char *comm = NULL; + const char *sid = NULL; + gint32 display_number; + gboolean is_chooser = FALSE; + gboolean use_auth = FALSE; + int i; + char *xserver_command; + gboolean display_is_blocked; + GList *pending_sessions; + + g_return_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory)); + + g_debug ("GdmLocalDisplayFactory: Open Session Request"); + + display_is_blocked = FALSE; + + display = factory_find_display (factory, lookup_by_session, (gpointer)ssid); + + if (display != NULL) { + g_object_get (G_OBJECT (display), + "block-console-session-requests", + &display_is_blocked, NULL); + } - num = take_next_display_number (factory); + if (strcmp (display_type, "X11") != 0) { + g_warning ("Unknown display type '%s' requested", display_type); + return; + } -#if 0 - display = gdm_static_factory_display_new (num); -#else - display = gdm_static_display_new (num); -#endif + xserver_command = g_hash_table_lookup (parameters, "Exec"); - /* FIXME: don't hardcode seat1? */ - g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL); + if (! g_shell_parse_argv (xserver_command, &argc, &argv, &error)) { + g_warning ("Could not parse command %s: %s", xserver_command, error->message); + g_error_free (error); + return; + } - g_signal_connect (display, - "notify::status", - G_CALLBACK (on_static_display_status_changed), - factory); + g_debug("GdmLocalDisplayFactory: X11 server cmd pre-mangle: %s", + xserver_command); + for (i = 0; i < argc; i++) { + /* replase $display in case of not specified */ + if (g_str_equal (argv[i], "$display")) { + display_number = take_next_display_number (factory); + argv[i][0] = '\0'; + continue; + } - store_display (factory, num, display); + /* get display_number in case of specified */ + if (g_str_has_prefix (argv[i], ":")) { + display_number = atoi (argv[i]+1); + argv[i][0] = '\0'; + continue; + } - /* let store own the ref */ - g_object_unref (display); + if (! g_strcmp0 (argv[i], "-indirect")) { + is_chooser = TRUE; + continue; + } - if (! gdm_display_manage (display)) { - gdm_display_unmanage (display); + /* + * -auth is added by gdm_server_resolve_command_line() + * in gdm-server.c + */ + if (! g_strcmp0 (argv[i], "-auth") && + ! g_strcmp0 (argv[i+1], "$auth")) { + use_auth = TRUE; + argv[i][0] = '\0'; + argv[++i][0] = '\0'; + continue; + } + + if (!g_strcmp0 (argv[i], "$vt")) { + argv[i][0] = '\0'; + continue; + } } + comm = g_strjoinv (" ", argv); + g_debug ("GdmLocalDisplayFactory: X11 server cmd post-mangle: %s", + comm); + g_strfreev (argv); + + if (display == NULL) { + if (is_chooser) { + /* TODO: Start a xdmcp chooser as request */ + + /* display = gdm_xdmcp_chooser_display_new (display_number); */ + } else { + display = gdm_dynamic_display_new (display_number); + } + + if (display == NULL) { + g_warning ("Unable to create display: %d", display_number); + g_free (comm); + return; + } + + g_object_set (display, "session-id", ssid, NULL); + + sid = dbus_g_proxy_get_path (seat_proxy); + if (IS_STR_SET (sid)) + g_object_set (display, "seat-id", sid, NULL); + if (IS_STR_SET (comm)) + g_object_set (display, "x11-command", comm, NULL); + g_free (comm); + if (IS_STR_SET (display_template_name)) + g_object_set (display, "x11-display-type", display_template_name, NULL); + g_object_set (display, "use-auth", use_auth, NULL); + + g_signal_connect (display, + "notify::status", + G_CALLBACK (on_display_status_changed), + factory); + + g_signal_connect (display, + "notify::block-console-session-requests", + G_CALLBACK (on_block_console_session_requests_changed), + factory); + + store_display (factory, display_number, display); + + g_object_unref (display); + + if (! gdm_display_manage (display)) { + gdm_display_unmanage (display); + } + + return; + } + + /* FIXME: Make sure the display returned is compatible + */ + + if (!display_is_blocked) { + /* FIXME: What do we do here? + */ + g_debug ("Got console request to add display for session that " + "already has a display, and display is already in " + "use"); + return; + } + + pending_sessions = g_object_get_data (G_OBJECT (display), + "gdm-local-display-factory-console-session-requests"); + pending_sessions = g_list_prepend (pending_sessions, g_strdup (ssid)); + + g_object_set_data (G_OBJECT (display), + "gdm-local-display-factory-console-session-requests", + pending_sessions); +} + +static void +seat_close_session_request (DBusGProxy *seat_proxy, + const char *ssid, + GdmLocalDisplayFactory *factory) +{ + GdmDisplay *display; + int display_number; + char *display_ssid; + + g_debug ("GdmLocalDisplayFactory: Close session request"); + + g_return_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory)); + + display = factory_find_display (factory, lookup_by_session, (gpointer)ssid); + + if (display == NULL) { + g_debug ("GdmLocalDisplayFactory: display for session '%s' doesn't exists", ssid); + return; + } + + g_object_get (G_OBJECT (display), "session-id", &display_ssid, NULL); + + if (display_ssid == NULL || strcmp (ssid, display_ssid) != 0) { + g_free (display_ssid); + discard_pending_session_on_display (factory, display, ssid); + return; + } + g_free (display_ssid); + + if (! gdm_display_unmanage (display)) { + display = NULL; + return; + } + + gdm_display_get_x11_display_number (display, &display_number, NULL); + store_remove_display (factory, display_number, display); +} + +static void +seat_session_no_respawn (DBusGProxy *seat_proxy, + const char *ssid, + GdmLocalDisplayFactory *factory) +{ + GdmDisplay *display; + int display_number; + char *display_ssid; + + g_debug ("GdmLocalDisplayFactory: No Respawn"); + + g_return_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory)); + + display = factory_find_display (factory, lookup_by_session, (gpointer)ssid); + + if (display == NULL) { + g_debug ("GdmLocalDisplayFactory: display for session '%s' doesn't exists", ssid); + return; + } + + if (GDM_IS_DYNAMIC_DISPLAY (display)) { + gdm_dynamic_display_removed (GDM_DYNAMIC_DISPLAY (display)); + } +} + +static gboolean +get_session_x11_display (GdmLocalDisplayFactory *factory, + const char *ssid, + char **x11_display) +{ + DBusGProxy *proxy; + gboolean res; + + if (!x11_display) + return FALSE; + + proxy = dbus_g_proxy_new_for_name (factory->priv->connection, + CK_NAME, + ssid, + CK_SESSION_INTERFACE); + if (proxy == NULL) { + return FALSE; + } + + res = dbus_g_proxy_call (proxy, + "GetX11Display", + NULL, + G_TYPE_INVALID, + G_TYPE_STRING, x11_display, + G_TYPE_INVALID); + if (!res) { + return FALSE; + } + + return TRUE; +} + +static void +seat_session_added (DBusGProxy *seat_proxy, + const char *ssid, + GdmLocalDisplayFactory *factory) +{ + GdmDisplay *display; + char *x11_display; + gboolean res; + + g_debug ("GdmLocalDisplayFactory: Adding Seat Session"); + + res = get_session_x11_display (factory, ssid, &x11_display); + if (!res) { + g_warning ("Failed to get X11 display number for %s", ssid); + return; + } + + display = factory_find_display (factory, lookup_by_x11_display, +x11_display); + if (display) { + gdm_display_set_session_id (display, ssid, NULL); + g_debug ("Update session id for display %s to %s", + x11_display, ssid); + } + g_free (x11_display); +} + + +static void +seat_session_removed (DBusGProxy *seat_proxy, + const char *ssid, + GdmLocalDisplayFactory *factory) +{ + GdmDisplay *display = NULL; + gboolean res; + int status; + int num; + + g_debug ("GdmLocalDisplayFactory: Removed Seat Session"); + + display = factory_find_display (factory, lookup_by_session, +(gpointer)ssid); + if (display) { + num = -1; + gdm_display_get_x11_display_number (display, &num, NULL); + g_assert (num != -1); + store_remove_display (factory, num, display); + } +} + +static void +seat_remove_request (DBusGProxy *seat_proxy, + GdmLocalDisplayFactory *factory) +{ + GHashTableIter iter; + gpointer key, value; + const char *sid_to_remove; + GQueue ssids_to_remove; + + g_debug ("GdmLocalDisplayFactory: Seat Remove Request"); + + sid_to_remove = dbus_g_proxy_get_path (seat_proxy); + + g_queue_init (&ssids_to_remove); + g_hash_table_iter_init (&iter, factory->priv->displays); + while (g_hash_table_iter_next (&iter, &key, &value)) { + GdmDisplay *display; + char *sid; + guint32 x11_display_num; + + x11_display_num = GPOINTER_TO_UINT (key); + display = factory_find_display (factory, + lookup_by_x11_display_num, + GUINT_TO_POINTER (x11_display_num)); + + gdm_display_get_seat_id (display, &sid, NULL); + + if (strcmp (sid, sid_to_remove) == 0) { + char *ssid; + + gdm_display_get_session_id (display, &ssid, NULL); + + g_queue_push_tail (&ssids_to_remove, ssid); + } + + g_free (sid); + } + + while (!g_queue_is_empty (&ssids_to_remove)) { + char *ssid; + + ssid = g_queue_pop_head (&ssids_to_remove); + + seat_close_session_request (seat_proxy, ssid, factory); + + g_free (ssid); + } + + g_hash_table_remove (factory->priv->managed_seat_proxies, sid_to_remove); + + dbus_g_proxy_call_no_reply (seat_proxy, + "Unmanage", + G_TYPE_INVALID, + G_TYPE_INVALID); + + if (factory->priv->proxy_ck == NULL) { + connect_to_ck (factory); + } + + dbus_g_proxy_call_no_reply (factory->priv->proxy_ck, + "RemoveSeat", + DBUS_TYPE_G_OBJECT_PATH, sid_to_remove, + G_TYPE_INVALID, + G_TYPE_INVALID); +} + +static void +manage_static_sessions_per_seat (GdmLocalDisplayFactory *factory, + const char *sid) +{ + DBusGProxy *proxy; + + g_debug ("GdmLocalDisplayFactory: Manage Static Sessions Per Seat"); + + proxy = dbus_g_proxy_new_for_name (factory->priv->connection, + CK_NAME, + sid, + CK_SEAT_INTERFACE); + + if (proxy == NULL) { + g_warning ("Failed to connect to the ConsoleKit seat object"); + return; + } + + dbus_g_object_register_marshaller (gdm_marshal_VOID__STRING_STRING_STRING_POINTER_STRING_POINTER, + G_TYPE_NONE, + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_STRING, + G_TYPE_STRING, + GDM_DBUS_TYPE_G_STRING_STRING_HASHTABLE, + G_TYPE_STRING, + GDM_DBUS_TYPE_G_STRING_STRING_HASHTABLE, + G_TYPE_INVALID); + + dbus_g_proxy_add_signal (proxy, + "OpenSessionRequest", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_STRING, + G_TYPE_STRING, + GDM_DBUS_TYPE_G_STRING_STRING_HASHTABLE, + G_TYPE_STRING, + GDM_DBUS_TYPE_G_STRING_STRING_HASHTABLE, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxy, + "CloseSessionRequest", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxy, + "NoRespawn", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxy, + "SessionAdded", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxy, + "SessionRemoved", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxy, + "RemoveRequest", + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (proxy, + "OpenSessionRequest", + G_CALLBACK (seat_open_session_request), + factory, + NULL); + dbus_g_proxy_connect_signal (proxy, + "CloseSessionRequest", + G_CALLBACK (seat_close_session_request), + factory, + NULL); + dbus_g_proxy_connect_signal (proxy, + "NoRespawn", + G_CALLBACK (seat_session_no_respawn), + factory, + NULL); + dbus_g_proxy_connect_signal (proxy, + "SessionAdded", + G_CALLBACK (seat_session_added), + factory, + NULL); + dbus_g_proxy_connect_signal (proxy, + "SessionRemoved", + G_CALLBACK (seat_session_removed), + factory, + NULL); + dbus_g_proxy_connect_signal (proxy, + "RemoveRequest", + G_CALLBACK (seat_remove_request), + factory, + NULL); + + dbus_g_proxy_call_no_reply (proxy, + "Manage", + G_TYPE_INVALID, + G_TYPE_INVALID); + + g_hash_table_insert (factory->priv->managed_seat_proxies, + g_strdup (dbus_g_proxy_get_path (proxy)), + proxy); +} + +static void +seat_added (DBusGProxy *mgr_proxy, + const char *sid, + const char *type, + GdmLocalDisplayFactory *factory) +{ + g_debug ("GdmLocalDisplayFactory: Seat Added"); + + if (strcmp (type, "Default") == 0) { + manage_static_sessions_per_seat (factory, sid); + } +} + +static gboolean +create_static_displays (GdmLocalDisplayFactory *factory) +{ + GError *error; + gboolean res; + GPtrArray *seats; + int i; + + g_debug ("GdmLocalDisplayFactory: Create Static Display"); + + seats = NULL; + + if (factory->priv->proxy_ck == NULL) { + connect_to_ck (factory); + } + + error = NULL; + res = dbus_g_proxy_call (factory->priv->proxy_ck, + "GetUnmanagedSeats", + &error, + G_TYPE_INVALID, + dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), + &seats, + G_TYPE_INVALID); + if (! res) { + if (error != NULL) { + g_warning ("Failed to get list of unmanaged seats: %s", error->message); + g_error_free (error); + } + return FALSE; + } + + for (i = 0; i < seats->len; i++) { + char *sid; + + sid = g_ptr_array_index (seats, i); + + manage_static_sessions_per_seat (factory, sid); + + g_free (sid); + } + + return TRUE; - return display; } static gboolean @@ -375,7 +1093,7 @@ gdm_local_display_factory_start (GdmDisplayFactory *base_factory) ret = TRUE; /* FIXME: use seat configuration */ - display = create_display (factory); + display = create_static_displays (factory); if (display == NULL) { ret = FALSE; } @@ -439,6 +1157,68 @@ register_factory (GdmLocalDisplayFactory *factory) return TRUE; } +static void +bus_proxy_destroyed_cb (DBusGProxy *bus_proxy, + GdmLocalDisplayFactoryPrivate *priv) +{ + g_debug ("Local Display Factory - Disconnected from D-Bus"); + + if (priv == NULL) { + /* probably shutting down or something */ + return; + } + + priv->proxy_ck = NULL; +} + +static gboolean +connect_to_ck (GdmLocalDisplayFactory *factory) +{ + GdmLocalDisplayFactoryPrivate *priv; + + g_debug ("GdmLocalDisplayFactory: Connect To ConsoleKit"); + + priv = factory->priv; + + priv->proxy_ck = dbus_g_proxy_new_for_name (priv->connection, + CK_NAME, + CK_MANAGER_PATH, + CK_MANAGER_INTERFACE); + + if (priv->proxy_ck == NULL) { + g_warning ("Couldn't create proxy for ConsoleKit Manager"); + return FALSE; + } + + dbus_g_object_register_marshaller (gdm_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + + dbus_g_proxy_add_signal (priv->proxy_ck, + "SeatAdded", + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy_ck, + "SeatAdded", + G_CALLBACK (seat_added), + factory, + NULL); + g_signal_connect (priv->proxy_ck, + "destroy", + G_CALLBACK (bus_proxy_destroyed_cb), + priv); +} + +static void +disconnect_from_ck (GdmLocalDisplayFactory *factory) +{ + if (factory->priv->proxy_ck == NULL) { + g_object_unref (factory->priv->proxy_ck); + } +} + static GObject * gdm_local_display_factory_constructor (GType type, guint n_construct_properties, @@ -456,6 +1236,8 @@ gdm_local_display_factory_constructor (GType type, g_warning ("Unable to register local display factory with system bus"); } + connect_to_ck (factory); + return G_OBJECT (factory); } @@ -484,6 +1266,11 @@ gdm_local_display_factory_init (GdmLocalDisplayFactory *factory) factory->priv = GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE (factory); factory->priv->displays = g_hash_table_new (NULL, NULL); + factory->priv->proxy_ck = NULL; + + factory->priv->managed_seat_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); } static void @@ -499,6 +1286,9 @@ gdm_local_display_factory_finalize (GObject *object) g_return_if_fail (factory->priv != NULL); g_hash_table_destroy (factory->priv->displays); + g_hash_table_destroy (factory->priv->managed_seat_proxies); + + disconnect_from_ck (factory); G_OBJECT_CLASS (gdm_local_display_factory_parent_class)->finalize (object); } |