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_service_get_instance (void)
80 singleton = g_object_new (LOGIN1_SERVICE_TYPE, NULL);
85 seat_properties_changed_cb (GDBusConnection *connection,
86 const gchar *sender_name,
87 const gchar *object_path,
88 const gchar *interface_name,
89 const gchar *signal_name,
93 Login1Seat *seat = user_data;
94 GVariantIter *invalidated_properties;
95 const gchar *property_name;
97 g_variant_get (parameters, "(sa{sv}as)", NULL, NULL, &invalidated_properties);
98 while (g_variant_iter_loop (invalidated_properties, "&s", &property_name))
100 if (strcmp (property_name, "CanGraphical") == 0)
103 GError *error = NULL;
105 result = g_dbus_connection_call_sync (connection,
108 "org.freedesktop.DBus.Properties",
110 g_variant_new ("(ss)", "org.freedesktop.login1.Seat", property_name),
111 G_VARIANT_TYPE ("(v)"),
112 G_DBUS_CALL_FLAGS_NONE,
117 g_warning ("Error updating CanGraphical: %s", error->message);
118 g_clear_error (&error);
123 g_variant_get (result, "(v)", &value);
124 seat->priv->can_graphical = g_variant_get_boolean (value);
125 g_variant_unref (value);
127 g_signal_emit (seat, seat_signals[CAN_GRAPHICAL_CHANGED], 0);
129 g_variant_unref (result);
133 g_variant_iter_free (invalidated_properties);
137 add_seat (Login1Service *service, const gchar *id, const gchar *path)
141 GError *error = NULL;
143 seat = g_object_new (LOGIN1_SEAT_TYPE, NULL);
144 seat->priv->connection = g_object_ref (service->priv->connection);
145 seat->priv->id = g_strdup (id);
146 seat->priv->path = g_strdup (path);
148 seat->priv->signal_id = g_dbus_connection_signal_subscribe (seat->priv->connection,
150 "org.freedesktop.DBus.Properties",
153 "org.freedesktop.login1.Seat",
154 G_DBUS_SIGNAL_FLAGS_NONE,
155 seat_properties_changed_cb,
159 /* Get properties for this seat */
160 result = g_dbus_connection_call_sync (seat->priv->connection,
163 "org.freedesktop.DBus.Properties",
165 g_variant_new ("(s)", "org.freedesktop.login1.Seat"),
166 G_VARIANT_TYPE ("(a{sv})"),
167 G_DBUS_CALL_FLAGS_NONE,
172 g_warning ("Failed to get seat properties: %s", error->message);
173 g_clear_error (&error);
176 GVariantIter *properties;
180 g_variant_get (result, "(a{sv})", &properties);
181 while (g_variant_iter_loop (properties, "{&sv}", &name, &value))
183 if (strcmp (name, "CanGraphical") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
184 seat->priv->can_graphical = g_variant_get_boolean (value);
185 else if (strcmp (name, "CanMultiSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
186 seat->priv->can_multi_session = g_variant_get_boolean (value);
188 g_variant_iter_free (properties);
189 g_variant_unref (result);
192 service->priv->seats = g_list_append (service->priv->seats, seat);
198 signal_cb (GDBusConnection *connection,
199 const gchar *sender_name,
200 const gchar *object_path,
201 const gchar *interface_name,
202 const gchar *signal_name,
203 GVariant *parameters,
206 Login1Service *service = user_data;
208 if (strcmp (signal_name, "SeatNew") == 0)
210 const gchar *id, *path;
213 g_variant_get (parameters, "(&s&o)", &id, &path);
214 seat = login1_service_get_seat (service, id);
217 seat = add_seat (service, id, path);
218 g_signal_emit (service, service_signals[SEAT_ADDED], 0, seat);
221 else if (strcmp (signal_name, "SeatRemoved") == 0)
223 const gchar *id, *path;
226 g_variant_get (parameters, "(&s&o)", &id, &path);
227 seat = login1_service_get_seat (service, id);
230 service->priv->seats = g_list_remove (service->priv->seats, seat);
231 g_signal_emit (service, service_signals[SEAT_REMOVED], 0, seat);
232 g_object_unref (seat);
238 login1_service_connect (Login1Service *service)
241 GVariantIter *seat_iter;
242 const gchar *id, *path;
243 GError *error = NULL;
245 g_return_val_if_fail (service != NULL, FALSE);
247 if (service->priv->connected)
250 service->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
252 g_warning ("Failed to get system bus: %s", error->message);
253 g_clear_error (&error);
254 if (!service->priv->connection)
257 service->priv->signal_id = g_dbus_connection_signal_subscribe (service->priv->connection,
259 LOGIN1_MANAGER_INTERFACE_NAME,
263 G_DBUS_SIGNAL_FLAGS_NONE,
265 g_object_ref (service),
268 result = g_dbus_connection_call_sync (service->priv->connection,
271 LOGIN1_MANAGER_INTERFACE_NAME,
273 g_variant_new ("()"),
274 G_VARIANT_TYPE ("(a(so))"),
275 G_DBUS_CALL_FLAGS_NONE,
280 g_warning ("Failed to get list of logind seats: %s", error->message);
281 g_clear_error (&error);
285 g_variant_get (result, "(a(so))", &seat_iter);
286 while (g_variant_iter_loop (seat_iter, "(&s&o)", &id, &path))
287 add_seat (service, id, path);
288 g_variant_iter_free (seat_iter);
289 g_variant_unref (result);
291 service->priv->connected = TRUE;
297 login1_service_get_is_connected (Login1Service *service)
299 g_return_val_if_fail (service != NULL, FALSE);
300 return service->priv->connected;
304 login1_service_get_seats (Login1Service *service)
306 g_return_val_if_fail (service != NULL, NULL);
307 return service->priv->seats;
311 login1_service_get_seat (Login1Service *service, const gchar *id)
315 g_return_val_if_fail (service != NULL, NULL);
317 for (link = service->priv->seats; link; link = link->next)
319 Login1Seat *seat = link->data;
320 if (strcmp (seat->priv->id, id) == 0)
328 login1_service_lock_session (Login1Service *service, const gchar *session_id)
330 GError *error = NULL;
332 g_return_if_fail (service != NULL);
333 g_return_if_fail (session_id != NULL);
335 g_debug ("Locking login1 session %s", session_id);
341 result = g_dbus_connection_call_sync (service->priv->connection,
344 LOGIN1_MANAGER_INTERFACE_NAME,
346 g_variant_new ("(s)", session_id),
347 G_VARIANT_TYPE ("()"),
348 G_DBUS_CALL_FLAGS_NONE,
353 g_warning ("Error locking login1 session: %s", error->message);
354 g_clear_error (&error);
356 g_variant_unref (result);
361 login1_service_unlock_session (Login1Service *service, const gchar *session_id)
363 GError *error = NULL;
365 g_return_if_fail (service != NULL);
366 g_return_if_fail (session_id != NULL);
368 g_debug ("Unlocking login1 session %s", session_id);
374 result = g_dbus_connection_call_sync (service->priv->connection,
377 LOGIN1_MANAGER_INTERFACE_NAME,
379 g_variant_new ("(s)", session_id),
380 G_VARIANT_TYPE ("()"),
381 G_DBUS_CALL_FLAGS_NONE,
386 g_warning ("Error unlocking login1 session: %s", error->message);
387 g_clear_error (&error);
389 g_variant_unref (result);
394 login1_service_activate_session (Login1Service *service, const gchar *session_id)
396 GError *error = NULL;
398 g_return_if_fail (service != NULL);
399 g_return_if_fail (session_id != NULL);
401 g_debug ("Activating login1 session %s", session_id);
407 result = g_dbus_connection_call_sync (service->priv->connection,
410 LOGIN1_MANAGER_INTERFACE_NAME,
412 g_variant_new ("(s)", session_id),
413 G_VARIANT_TYPE ("()"),
414 G_DBUS_CALL_FLAGS_NONE,
419 g_warning ("Error activating login1 session: %s", error->message);
420 g_clear_error (&error);
422 g_variant_unref (result);
427 login1_service_init (Login1Service *service)
429 service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, LOGIN1_SERVICE_TYPE, Login1ServicePrivate);
433 login1_service_finalize (GObject *object)
435 Login1Service *self = LOGIN1_SERVICE (object);
437 g_list_free_full (self->priv->seats, g_object_unref);
438 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
439 g_object_unref (self->priv->connection);
441 G_OBJECT_CLASS (login1_service_parent_class)->finalize (object);
445 login1_service_class_init (Login1ServiceClass *klass)
447 GObjectClass *object_class = G_OBJECT_CLASS (klass);
449 object_class->finalize = login1_service_finalize;
451 g_type_class_add_private (klass, sizeof (Login1ServicePrivate));
453 service_signals[SEAT_ADDED] =
454 g_signal_new (LOGIN1_SERVICE_SIGNAL_SEAT_ADDED,
455 G_TYPE_FROM_CLASS (klass),
457 G_STRUCT_OFFSET (Login1ServiceClass, seat_added),
460 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
461 service_signals[SEAT_REMOVED] =
462 g_signal_new (LOGIN1_SERVICE_SIGNAL_SEAT_REMOVED,
463 G_TYPE_FROM_CLASS (klass),
465 G_STRUCT_OFFSET (Login1ServiceClass, seat_removed),
468 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
472 login1_seat_get_id (Login1Seat *seat)
474 g_return_val_if_fail (seat != NULL, NULL);
475 return seat->priv->id;
479 login1_seat_get_can_graphical (Login1Seat *seat)
481 g_return_val_if_fail (seat != NULL, FALSE);
482 return seat->priv->can_graphical;
486 login1_seat_get_can_multi_session (Login1Seat *seat)
488 g_return_val_if_fail (seat != NULL, FALSE);
489 return seat->priv->can_multi_session;
493 login1_seat_init (Login1Seat *seat)
495 seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, LOGIN1_SEAT_TYPE, Login1SeatPrivate);
499 login1_seat_finalize (GObject *object)
501 Login1Seat *self = LOGIN1_SEAT (object);
503 g_free (self->priv->id);
504 g_free (self->priv->path);
505 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
506 g_object_unref (self->priv->connection);
508 G_OBJECT_CLASS (login1_seat_parent_class)->finalize (object);
512 login1_seat_class_init (Login1SeatClass *klass)
514 GObjectClass *object_class = G_OBJECT_CLASS (klass);
516 object_class->finalize = login1_seat_finalize;
518 g_type_class_add_private (klass, sizeof (Login1SeatPrivate));
520 seat_signals[CAN_GRAPHICAL_CHANGED] =
521 g_signal_new (LOGIN1_SEAT_SIGNAL_CAN_GRAPHICAL_CHANGED,
522 G_TYPE_FROM_CLASS (klass),
524 G_STRUCT_OFFSET (Login1SeatClass, can_graphical_changed),