1 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*-
3 * Copyright (C) 2010-2011 Robert Ancell.
4 * Author: Robert Ancell <robert.ancell@canonical.com>
6 * This program is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
9 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
18 #define LOGIN1_SERVICE_NAME "org.freedesktop.login1"
19 #define LOGIN1_OBJECT_NAME "/org/freedesktop/login1"
20 #define LOGIN1_MANAGER_INTERFACE_NAME "org.freedesktop.login1.Manager"
27 static guint service_signals[LAST_SERVICE_SIGNAL] = { 0 };
29 struct Login1ServicePrivate
31 /* Connection to bus service is running on */
32 GDBusConnection *connection;
34 /* TRUE if have connected to service */
37 /* Seats the service is reporting */
40 /* Handle to signal subscription */
45 CAN_GRAPHICAL_CHANGED,
48 static guint seat_signals[LAST_SEAT_SIGNAL] = { 0 };
50 struct Login1SeatPrivate
52 /* Connection to bus seat is running on */
53 GDBusConnection *connection;
58 /* D-Bus path for this seat */
61 /* Handle to signal subscription */
64 /* TRUE if can run a graphical display on this seat */
65 gboolean can_graphical;
67 /* TRUE if can do session switching */
68 gboolean can_multi_session;
71 G_DEFINE_TYPE (Login1Service, login1_service, G_TYPE_OBJECT);
72 G_DEFINE_TYPE (Login1Seat, login1_seat, G_TYPE_OBJECT);
74 static Login1Service *singleton = NULL;
77 login1_lock_session (const gchar *session_id)
82 g_return_if_fail (session_id != NULL);
84 g_debug ("Locking login1 session %s", session_id);
86 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
88 g_warning ("Failed to get system bus: %s", error->message);
89 g_clear_error (&error);
97 result = g_dbus_connection_call_sync (bus,
100 LOGIN1_MANAGER_INTERFACE_NAME,
102 g_variant_new ("(s)", session_id),
103 G_VARIANT_TYPE ("()"),
104 G_DBUS_CALL_FLAGS_NONE,
109 g_warning ("Error locking login1 session: %s", error->message);
110 g_clear_error (&error);
112 g_variant_unref (result);
114 g_object_unref (bus);
118 login1_unlock_session (const gchar *session_id)
120 GDBusConnection *bus;
121 GError *error = NULL;
123 g_return_if_fail (session_id != NULL);
125 g_debug ("Unlocking login1 session %s", session_id);
127 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
129 g_warning ("Failed to get system bus: %s", error->message);
130 g_clear_error (&error);
138 result = g_dbus_connection_call_sync (bus,
141 LOGIN1_MANAGER_INTERFACE_NAME,
143 g_variant_new ("(s)", session_id),
144 G_VARIANT_TYPE ("()"),
145 G_DBUS_CALL_FLAGS_NONE,
150 g_warning ("Error unlocking login1 session: %s", error->message);
151 g_clear_error (&error);
153 g_variant_unref (result);
155 g_object_unref (bus);
159 login1_activate_session (const gchar *session_id)
161 GDBusConnection *bus;
162 GError *error = NULL;
164 g_return_if_fail (session_id != NULL);
166 g_debug ("Activating login1 session %s", session_id);
168 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
170 g_warning ("Failed to get system bus: %s", error->message);
171 g_clear_error (&error);
179 result = g_dbus_connection_call_sync (bus,
182 LOGIN1_MANAGER_INTERFACE_NAME,
184 g_variant_new ("(s)", session_id),
185 G_VARIANT_TYPE ("()"),
186 G_DBUS_CALL_FLAGS_NONE,
191 g_warning ("Error activating login1 session: %s", error->message);
192 g_clear_error (&error);
194 g_variant_unref (result);
196 g_object_unref (bus);
200 login1_service_get_instance (void)
203 singleton = g_object_new (LOGIN1_SERVICE_TYPE, NULL);
208 seat_properties_changed_cb (GDBusConnection *connection,
209 const gchar *sender_name,
210 const gchar *object_path,
211 const gchar *interface_name,
212 const gchar *signal_name,
213 GVariant *parameters,
216 Login1Seat *seat = user_data;
217 GVariantIter *invalidated_properties;
218 const gchar *property_name;
220 g_variant_get (parameters, "(sa{sv}as)", NULL, NULL, &invalidated_properties);
221 while (g_variant_iter_loop (invalidated_properties, "&s", &property_name))
223 if (strcmp (property_name, "CanGraphical") == 0)
226 GError *error = NULL;
228 result = g_dbus_connection_call_sync (connection,
231 "org.freedesktop.DBus.Properties",
233 g_variant_new ("(ss)", "org.freedesktop.login1.Seat", property_name),
234 G_VARIANT_TYPE ("(v)"),
235 G_DBUS_CALL_FLAGS_NONE,
240 g_warning ("Error updating CanGraphical: %s", error->message);
241 g_clear_error (&error);
246 g_variant_get (result, "(v)", &value);
247 seat->priv->can_graphical = g_variant_get_boolean (value);
248 g_variant_unref (value);
250 g_signal_emit (seat, seat_signals[CAN_GRAPHICAL_CHANGED], 0);
252 g_variant_unref (result);
256 g_variant_iter_free (invalidated_properties);
260 add_seat (Login1Service *service, const gchar *id, const gchar *path)
264 GError *error = NULL;
266 seat = g_object_new (LOGIN1_SEAT_TYPE, NULL);
267 seat->priv->connection = g_object_ref (service->priv->connection);
268 seat->priv->id = g_strdup (id);
269 seat->priv->path = g_strdup (path);
271 seat->priv->signal_id = g_dbus_connection_signal_subscribe (seat->priv->connection,
273 "org.freedesktop.DBus.Properties",
276 "org.freedesktop.login1.Seat",
277 G_DBUS_SIGNAL_FLAGS_NONE,
278 seat_properties_changed_cb,
282 /* Get properties for this seat */
283 result = g_dbus_connection_call_sync (seat->priv->connection,
286 "org.freedesktop.DBus.Properties",
288 g_variant_new ("(s)", "org.freedesktop.login1.Seat"),
289 G_VARIANT_TYPE ("(a{sv})"),
290 G_DBUS_CALL_FLAGS_NONE,
295 g_warning ("Failed to get seat properties: %s", error->message);
296 g_clear_error (&error);
299 GVariantIter *properties;
303 g_variant_get (result, "(a{sv})", &properties);
304 while (g_variant_iter_loop (properties, "{&sv}", &name, &value))
306 if (strcmp (name, "CanGraphical") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
307 seat->priv->can_graphical = g_variant_get_boolean (value);
308 else if (strcmp (name, "CanMultiSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
309 seat->priv->can_multi_session = g_variant_get_boolean (value);
311 g_variant_iter_free (properties);
312 g_variant_unref (result);
315 service->priv->seats = g_list_append (service->priv->seats, seat);
321 signal_cb (GDBusConnection *connection,
322 const gchar *sender_name,
323 const gchar *object_path,
324 const gchar *interface_name,
325 const gchar *signal_name,
326 GVariant *parameters,
329 Login1Service *service = user_data;
331 if (strcmp (signal_name, "SeatNew") == 0)
333 const gchar *id, *path;
336 g_variant_get (parameters, "(&s&o)", &id, &path);
337 seat = login1_service_get_seat (service, id);
340 seat = add_seat (service, id, path);
341 g_signal_emit (service, service_signals[SEAT_ADDED], 0, seat);
344 else if (strcmp (signal_name, "SeatRemoved") == 0)
346 const gchar *id, *path;
349 g_variant_get (parameters, "(&s&o)", &id, &path);
350 seat = login1_service_get_seat (service, id);
353 service->priv->seats = g_list_remove (service->priv->seats, seat);
354 g_signal_emit (service, service_signals[SEAT_REMOVED], 0, seat);
355 g_object_unref (seat);
361 login1_service_connect (Login1Service *service)
364 GVariantIter *seat_iter;
365 const gchar *id, *path;
366 GError *error = NULL;
368 g_return_val_if_fail (service != NULL, FALSE);
370 if (service->priv->connected)
373 service->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
375 g_warning ("Failed to get system bus: %s", error->message);
376 g_clear_error (&error);
377 if (!service->priv->connection)
380 service->priv->signal_id = g_dbus_connection_signal_subscribe (service->priv->connection,
382 LOGIN1_MANAGER_INTERFACE_NAME,
386 G_DBUS_SIGNAL_FLAGS_NONE,
388 g_object_ref (service),
391 result = g_dbus_connection_call_sync (service->priv->connection,
394 LOGIN1_MANAGER_INTERFACE_NAME,
396 g_variant_new ("()"),
397 G_VARIANT_TYPE ("(a(so))"),
398 G_DBUS_CALL_FLAGS_NONE,
403 g_warning ("Failed to get list of logind seats: %s", error->message);
404 g_clear_error (&error);
408 g_variant_get (result, "(a(so))", &seat_iter);
409 while (g_variant_iter_loop (seat_iter, "(&s&o)", &id, &path))
410 add_seat (service, id, path);
411 g_variant_iter_free (seat_iter);
412 g_variant_unref (result);
414 service->priv->connected = TRUE;
420 login1_service_get_is_connected (Login1Service *service)
422 g_return_val_if_fail (service != NULL, FALSE);
423 return service->priv->connected;
427 login1_service_get_seats (Login1Service *service)
429 g_return_val_if_fail (service != NULL, NULL);
430 return service->priv->seats;
434 login1_service_get_seat (Login1Service *service, const gchar *id)
438 g_return_val_if_fail (service != NULL, NULL);
440 for (link = service->priv->seats; link; link = link->next)
442 Login1Seat *seat = link->data;
443 if (strcmp (seat->priv->id, id) == 0)
451 login1_service_init (Login1Service *service)
453 service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, LOGIN1_SERVICE_TYPE, Login1ServicePrivate);
457 login1_service_finalize (GObject *object)
459 Login1Service *self = LOGIN1_SERVICE (object);
461 g_list_free_full (self->priv->seats, g_object_unref);
462 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
463 g_object_unref (self->priv->connection);
465 G_OBJECT_CLASS (login1_service_parent_class)->finalize (object);
469 login1_service_class_init (Login1ServiceClass *klass)
471 GObjectClass *object_class = G_OBJECT_CLASS (klass);
473 object_class->finalize = login1_service_finalize;
475 g_type_class_add_private (klass, sizeof (Login1ServicePrivate));
477 service_signals[SEAT_ADDED] =
478 g_signal_new ("seat-added",
479 G_TYPE_FROM_CLASS (klass),
481 G_STRUCT_OFFSET (Login1ServiceClass, seat_added),
484 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
485 service_signals[SEAT_REMOVED] =
486 g_signal_new ("seat-removed",
487 G_TYPE_FROM_CLASS (klass),
489 G_STRUCT_OFFSET (Login1ServiceClass, seat_removed),
492 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
496 login1_seat_get_id (Login1Seat *seat)
498 g_return_val_if_fail (seat != NULL, NULL);
499 return seat->priv->id;
503 login1_seat_get_can_graphical (Login1Seat *seat)
505 g_return_val_if_fail (seat != NULL, FALSE);
506 return seat->priv->can_graphical;
510 login1_seat_get_can_multi_session (Login1Seat *seat)
512 g_return_val_if_fail (seat != NULL, FALSE);
513 return seat->priv->can_multi_session;
517 login1_seat_init (Login1Seat *seat)
519 seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, LOGIN1_SEAT_TYPE, Login1SeatPrivate);
523 login1_seat_finalize (GObject *object)
525 Login1Seat *self = LOGIN1_SEAT (object);
527 g_free (self->priv->id);
528 g_free (self->priv->path);
529 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
530 g_object_unref (self->priv->connection);
532 G_OBJECT_CLASS (login1_seat_parent_class)->finalize (object);
536 login1_seat_class_init (Login1SeatClass *klass)
538 GObjectClass *object_class = G_OBJECT_CLASS (klass);
540 object_class->finalize = login1_seat_finalize;
542 g_type_class_add_private (klass, sizeof (Login1SeatPrivate));
544 seat_signals[CAN_GRAPHICAL_CHANGED] =
545 g_signal_new ("can-graphical-changed",
546 G_TYPE_FROM_CLASS (klass),
548 G_STRUCT_OFFSET (Login1SeatClass, can_graphical_changed),