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 update_property (Login1Seat *seat, const gchar *name, GVariant *value)
87 if (strcmp (name, "CanGraphical") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
89 seat->priv->can_graphical = g_variant_get_boolean (value);
90 g_signal_emit (seat, seat_signals[CAN_GRAPHICAL_CHANGED], 0);
95 seat_properties_changed_cb (GDBusConnection *connection,
96 const gchar *sender_name,
97 const gchar *object_path,
98 const gchar *interface_name,
99 const gchar *signal_name,
100 GVariant *parameters,
103 Login1Seat *seat = user_data;
105 GVariantIter *invalidated_properties;
109 g_variant_get (parameters, "(sa{sv}as)", NULL, &iter, &invalidated_properties);
110 while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
111 update_property (seat, name, value);
112 g_variant_iter_free (iter);
113 while (g_variant_iter_loop (invalidated_properties, "&s", &name))
116 GError *error = NULL;
118 result = g_dbus_connection_call_sync (connection,
121 "org.freedesktop.DBus.Properties",
123 g_variant_new ("(ss)", "org.freedesktop.login1.Seat", name),
124 G_VARIANT_TYPE ("(v)"),
125 G_DBUS_CALL_FLAGS_NONE,
130 g_warning ("Error updating seat property %s: %s", name, error->message);
131 g_clear_error (&error);
134 g_variant_get (result, "(v)", &value);
135 update_property (seat, name, value);
136 g_variant_unref (result);
139 g_variant_iter_free (invalidated_properties);
143 add_seat (Login1Service *service, const gchar *id, const gchar *path)
147 GError *error = NULL;
149 seat = g_object_new (LOGIN1_SEAT_TYPE, NULL);
150 seat->priv->connection = g_object_ref (service->priv->connection);
151 seat->priv->id = g_strdup (id);
152 seat->priv->path = g_strdup (path);
154 seat->priv->signal_id = g_dbus_connection_signal_subscribe (seat->priv->connection,
156 "org.freedesktop.DBus.Properties",
159 "org.freedesktop.login1.Seat",
160 G_DBUS_SIGNAL_FLAGS_NONE,
161 seat_properties_changed_cb,
165 /* Get properties for this seat */
166 result = g_dbus_connection_call_sync (seat->priv->connection,
169 "org.freedesktop.DBus.Properties",
171 g_variant_new ("(s)", "org.freedesktop.login1.Seat"),
172 G_VARIANT_TYPE ("(a{sv})"),
173 G_DBUS_CALL_FLAGS_NONE,
178 g_warning ("Failed to get seat properties: %s", error->message);
179 g_clear_error (&error);
182 GVariantIter *properties;
186 g_variant_get (result, "(a{sv})", &properties);
187 while (g_variant_iter_loop (properties, "{&sv}", &name, &value))
189 if (strcmp (name, "CanGraphical") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
190 seat->priv->can_graphical = g_variant_get_boolean (value);
191 else if (strcmp (name, "CanMultiSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
192 seat->priv->can_multi_session = g_variant_get_boolean (value);
194 g_variant_iter_free (properties);
195 g_variant_unref (result);
198 service->priv->seats = g_list_append (service->priv->seats, seat);
204 signal_cb (GDBusConnection *connection,
205 const gchar *sender_name,
206 const gchar *object_path,
207 const gchar *interface_name,
208 const gchar *signal_name,
209 GVariant *parameters,
212 Login1Service *service = user_data;
214 if (strcmp (signal_name, "SeatNew") == 0)
216 const gchar *id, *path;
219 g_variant_get (parameters, "(&s&o)", &id, &path);
220 seat = login1_service_get_seat (service, id);
223 seat = add_seat (service, id, path);
224 g_signal_emit (service, service_signals[SEAT_ADDED], 0, seat);
227 else if (strcmp (signal_name, "SeatRemoved") == 0)
229 const gchar *id, *path;
232 g_variant_get (parameters, "(&s&o)", &id, &path);
233 seat = login1_service_get_seat (service, id);
236 service->priv->seats = g_list_remove (service->priv->seats, seat);
237 g_signal_emit (service, service_signals[SEAT_REMOVED], 0, seat);
238 g_object_unref (seat);
244 login1_service_connect (Login1Service *service)
247 GVariantIter *seat_iter;
248 const gchar *id, *path;
249 GError *error = NULL;
251 g_return_val_if_fail (service != NULL, FALSE);
253 if (service->priv->connected)
256 service->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
258 g_warning ("Failed to get system bus: %s", error->message);
259 g_clear_error (&error);
260 if (!service->priv->connection)
263 service->priv->signal_id = g_dbus_connection_signal_subscribe (service->priv->connection,
265 LOGIN1_MANAGER_INTERFACE_NAME,
269 G_DBUS_SIGNAL_FLAGS_NONE,
271 g_object_ref (service),
274 result = g_dbus_connection_call_sync (service->priv->connection,
277 LOGIN1_MANAGER_INTERFACE_NAME,
279 g_variant_new ("()"),
280 G_VARIANT_TYPE ("(a(so))"),
281 G_DBUS_CALL_FLAGS_NONE,
286 g_warning ("Failed to get list of logind seats: %s", error->message);
287 g_clear_error (&error);
291 g_variant_get (result, "(a(so))", &seat_iter);
292 while (g_variant_iter_loop (seat_iter, "(&s&o)", &id, &path))
293 add_seat (service, id, path);
294 g_variant_iter_free (seat_iter);
295 g_variant_unref (result);
297 service->priv->connected = TRUE;
303 login1_service_get_is_connected (Login1Service *service)
305 g_return_val_if_fail (service != NULL, FALSE);
306 return service->priv->connected;
310 login1_service_get_seats (Login1Service *service)
312 g_return_val_if_fail (service != NULL, NULL);
313 return service->priv->seats;
317 login1_service_get_seat (Login1Service *service, const gchar *id)
321 g_return_val_if_fail (service != NULL, NULL);
323 for (link = service->priv->seats; link; link = link->next)
325 Login1Seat *seat = link->data;
326 if (strcmp (seat->priv->id, id) == 0)
334 login1_service_lock_session (Login1Service *service, const gchar *session_id)
336 GError *error = NULL;
338 g_return_if_fail (service != NULL);
339 g_return_if_fail (session_id != NULL);
341 g_debug ("Locking login1 session %s", session_id);
347 result = g_dbus_connection_call_sync (service->priv->connection,
350 LOGIN1_MANAGER_INTERFACE_NAME,
352 g_variant_new ("(s)", session_id),
353 G_VARIANT_TYPE ("()"),
354 G_DBUS_CALL_FLAGS_NONE,
359 g_warning ("Error locking login1 session: %s", error->message);
360 g_clear_error (&error);
362 g_variant_unref (result);
367 login1_service_unlock_session (Login1Service *service, const gchar *session_id)
369 GError *error = NULL;
371 g_return_if_fail (service != NULL);
372 g_return_if_fail (session_id != NULL);
374 g_debug ("Unlocking login1 session %s", session_id);
380 result = g_dbus_connection_call_sync (service->priv->connection,
383 LOGIN1_MANAGER_INTERFACE_NAME,
385 g_variant_new ("(s)", session_id),
386 G_VARIANT_TYPE ("()"),
387 G_DBUS_CALL_FLAGS_NONE,
392 g_warning ("Error unlocking login1 session: %s", error->message);
393 g_clear_error (&error);
395 g_variant_unref (result);
400 login1_service_activate_session (Login1Service *service, const gchar *session_id)
402 GError *error = NULL;
404 g_return_if_fail (service != NULL);
405 g_return_if_fail (session_id != NULL);
407 g_debug ("Activating login1 session %s", session_id);
413 result = g_dbus_connection_call_sync (service->priv->connection,
416 LOGIN1_MANAGER_INTERFACE_NAME,
418 g_variant_new ("(s)", session_id),
419 G_VARIANT_TYPE ("()"),
420 G_DBUS_CALL_FLAGS_NONE,
425 g_warning ("Error activating login1 session: %s", error->message);
426 g_clear_error (&error);
428 g_variant_unref (result);
433 login1_service_init (Login1Service *service)
435 service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, LOGIN1_SERVICE_TYPE, Login1ServicePrivate);
439 login1_service_finalize (GObject *object)
441 Login1Service *self = LOGIN1_SERVICE (object);
443 g_list_free_full (self->priv->seats, g_object_unref);
444 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
445 g_object_unref (self->priv->connection);
447 G_OBJECT_CLASS (login1_service_parent_class)->finalize (object);
451 login1_service_class_init (Login1ServiceClass *klass)
453 GObjectClass *object_class = G_OBJECT_CLASS (klass);
455 object_class->finalize = login1_service_finalize;
457 g_type_class_add_private (klass, sizeof (Login1ServicePrivate));
459 service_signals[SEAT_ADDED] =
460 g_signal_new ("seat-added",
461 G_TYPE_FROM_CLASS (klass),
463 G_STRUCT_OFFSET (Login1ServiceClass, seat_added),
466 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
467 service_signals[SEAT_REMOVED] =
468 g_signal_new ("seat-removed",
469 G_TYPE_FROM_CLASS (klass),
471 G_STRUCT_OFFSET (Login1ServiceClass, seat_removed),
474 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
478 login1_seat_get_id (Login1Seat *seat)
480 g_return_val_if_fail (seat != NULL, NULL);
481 return seat->priv->id;
485 login1_seat_get_can_graphical (Login1Seat *seat)
487 g_return_val_if_fail (seat != NULL, FALSE);
488 return seat->priv->can_graphical;
492 login1_seat_get_can_multi_session (Login1Seat *seat)
494 g_return_val_if_fail (seat != NULL, FALSE);
495 return seat->priv->can_multi_session;
499 login1_seat_init (Login1Seat *seat)
501 seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, LOGIN1_SEAT_TYPE, Login1SeatPrivate);
505 login1_seat_finalize (GObject *object)
507 Login1Seat *self = LOGIN1_SEAT (object);
509 g_free (self->priv->id);
510 g_free (self->priv->path);
511 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
512 g_object_unref (self->priv->connection);
514 G_OBJECT_CLASS (login1_seat_parent_class)->finalize (object);
518 login1_seat_class_init (Login1SeatClass *klass)
520 GObjectClass *object_class = G_OBJECT_CLASS (klass);
522 object_class->finalize = login1_seat_finalize;
524 g_type_class_add_private (klass, sizeof (Login1SeatPrivate));
526 seat_signals[CAN_GRAPHICAL_CHANGED] =
527 g_signal_new ("can-graphical-changed",
528 G_TYPE_FROM_CLASS (klass),
530 G_STRUCT_OFFSET (Login1SeatClass, can_graphical_changed),