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"
25 static guint service_signals[LAST_SERVICE_SIGNAL] = { 0 };
27 struct Login1ServicePrivate
29 /* Connection to bus service is running on */
30 GDBusConnection *connection;
32 /* TRUE if have connected to service */
35 /* Seats the service is reporting */
38 /* Handle to signal subscription */
43 CAN_GRAPHICAL_CHANGED,
46 static guint seat_signals[LAST_SEAT_SIGNAL] = { 0 };
48 struct Login1SeatPrivate
50 /* Connection to bus seat is running on */
51 GDBusConnection *connection;
56 /* D-Bus path for this seat */
59 /* Handle to signal subscription */
62 /* TRUE if can run a graphical display on this seat */
63 gboolean can_graphical;
65 /* TRUE if can do session switching */
66 gboolean can_multi_session;
69 G_DEFINE_TYPE (Login1Service, login1_service, G_TYPE_OBJECT);
70 G_DEFINE_TYPE (Login1Seat, login1_seat, G_TYPE_OBJECT);
72 static Login1Service *singleton = NULL;
75 login1_get_session_id (void)
82 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
84 g_warning ("Failed to get system bus: %s", error->message);
85 g_clear_error (&error);
88 result = g_dbus_connection_call_sync (bus,
90 "/org/freedesktop/login1",
91 "org.freedesktop.login1.Manager",
93 g_variant_new ("(u)", getpid()),
94 G_VARIANT_TYPE ("(o)"),
95 G_DBUS_CALL_FLAGS_NONE,
102 g_warning ("Failed to open login1 session: %s", error->message);
103 g_clear_error (&error);
107 g_variant_get (result, "(o)", &session_path);
108 g_variant_unref (result);
109 g_debug ("Got login1 session id: %s", session_path);
115 login1_lock_session (const gchar *session_path)
117 GDBusConnection *bus;
118 GError *error = NULL;
120 g_return_if_fail (session_path != NULL);
122 g_debug ("Locking login1 session %s", session_path);
124 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
126 g_warning ("Failed to get system bus: %s", error->message);
127 g_clear_error (&error);
135 result = g_dbus_connection_call_sync (bus,
138 "org.freedesktop.login1.Session",
140 g_variant_new ("()"),
141 G_VARIANT_TYPE ("()"),
142 G_DBUS_CALL_FLAGS_NONE,
147 g_warning ("Error locking login1 session: %s", error->message);
148 g_clear_error (&error);
150 g_variant_unref (result);
152 g_object_unref (bus);
156 login1_unlock_session (const gchar *session_path)
158 GDBusConnection *bus;
159 GError *error = NULL;
161 g_return_if_fail (session_path != NULL);
163 g_debug ("Unlocking login1 session %s", session_path);
165 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
167 g_warning ("Failed to get system bus: %s", error->message);
168 g_clear_error (&error);
176 result = g_dbus_connection_call_sync (bus,
179 "org.freedesktop.login1.Session",
181 g_variant_new ("()"),
182 G_VARIANT_TYPE ("()"),
183 G_DBUS_CALL_FLAGS_NONE,
188 g_warning ("Error unlocking login1 session: %s", error->message);
189 g_clear_error (&error);
191 g_variant_unref (result);
193 g_object_unref (bus);
197 login1_activate_session (const gchar *session_path)
199 GDBusConnection *bus;
200 GError *error = NULL;
202 g_return_if_fail (session_path != NULL);
204 g_debug ("Activating login1 session %s", session_path);
206 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
208 g_warning ("Failed to get system bus: %s", error->message);
209 g_clear_error (&error);
217 result = g_dbus_connection_call_sync (bus,
220 "org.freedesktop.login1.Session",
222 g_variant_new ("()"),
223 G_VARIANT_TYPE ("()"),
224 G_DBUS_CALL_FLAGS_NONE,
229 g_warning ("Error activating login1 session: %s", error->message);
230 g_clear_error (&error);
232 g_variant_unref (result);
234 g_object_unref (bus);
238 login1_service_get_instance (void)
241 singleton = g_object_new (LOGIN1_SERVICE_TYPE, NULL);
246 seat_properties_changed_cb (GDBusConnection *connection,
247 const gchar *sender_name,
248 const gchar *object_path,
249 const gchar *interface_name,
250 const gchar *signal_name,
251 GVariant *parameters,
254 Login1Seat *seat = user_data;
255 GVariantIter *invalidated_properties;
256 const gchar *property_name;
258 g_variant_get (parameters, "(sa{sv}as)", NULL, NULL, &invalidated_properties);
259 while (g_variant_iter_loop (invalidated_properties, "&s", &property_name))
261 if (strcmp (property_name, "CanGraphical") == 0)
264 GError *error = NULL;
266 result = g_dbus_connection_call_sync (connection,
269 "org.freedesktop.DBus.Properties",
271 g_variant_new ("(ss)", "org.freedesktop.login1.Seat", property_name),
272 G_VARIANT_TYPE ("(v)"),
273 G_DBUS_CALL_FLAGS_NONE,
278 g_warning ("Error updating CanGraphical: %s", error->message);
279 g_clear_error (&error);
284 g_variant_get (result, "(v)", &value);
285 seat->priv->can_graphical = g_variant_get_boolean (value);
286 g_variant_unref (value);
288 g_signal_emit (seat, seat_signals[CAN_GRAPHICAL_CHANGED], 0);
290 g_variant_unref (result);
294 g_variant_iter_free (invalidated_properties);
298 add_seat (Login1Service *service, const gchar *id, const gchar *path)
302 GError *error = NULL;
304 seat = g_object_new (LOGIN1_SEAT_TYPE, NULL);
305 seat->priv->connection = g_object_ref (service->priv->connection);
306 seat->priv->id = g_strdup (id);
307 seat->priv->path = g_strdup (path);
309 seat->priv->signal_id = g_dbus_connection_signal_subscribe (seat->priv->connection,
311 "org.freedesktop.DBus.Properties",
314 "org.freedesktop.login1.Seat",
315 G_DBUS_SIGNAL_FLAGS_NONE,
316 seat_properties_changed_cb,
320 /* Get properties for this seat */
321 result = g_dbus_connection_call_sync (seat->priv->connection,
324 "org.freedesktop.DBus.Properties",
326 g_variant_new ("(s)", "org.freedesktop.login1.Seat"),
327 G_VARIANT_TYPE ("(a{sv})"),
328 G_DBUS_CALL_FLAGS_NONE,
333 g_warning ("Failed to get seat properties: %s", error->message);
334 g_clear_error (&error);
337 GVariantIter *properties;
341 g_variant_get (result, "(a{sv})", &properties);
342 while (g_variant_iter_loop (properties, "{&sv}", &name, &value))
344 if (strcmp (name, "CanGraphical") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
345 seat->priv->can_graphical = g_variant_get_boolean (value);
346 else if (strcmp (name, "CanMultiSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
347 seat->priv->can_multi_session = g_variant_get_boolean (value);
349 g_variant_iter_free (properties);
350 g_variant_unref (result);
353 service->priv->seats = g_list_append (service->priv->seats, seat);
359 signal_cb (GDBusConnection *connection,
360 const gchar *sender_name,
361 const gchar *object_path,
362 const gchar *interface_name,
363 const gchar *signal_name,
364 GVariant *parameters,
367 Login1Service *service = user_data;
369 if (strcmp (signal_name, "SeatNew") == 0)
371 const gchar *id, *path;
374 g_variant_get (parameters, "(&s&o)", &id, &path);
375 seat = login1_service_get_seat (service, id);
378 seat = add_seat (service, id, path);
379 g_signal_emit (service, service_signals[SEAT_ADDED], 0, seat);
382 else if (strcmp (signal_name, "SeatRemoved") == 0)
384 const gchar *id, *path;
387 g_variant_get (parameters, "(&s&o)", &id, &path);
388 seat = login1_service_get_seat (service, id);
391 service->priv->seats = g_list_remove (service->priv->seats, seat);
392 g_signal_emit (service, service_signals[SEAT_REMOVED], 0, seat);
393 g_object_unref (seat);
399 login1_service_connect (Login1Service *service)
402 GVariantIter *seat_iter;
403 const gchar *id, *path;
404 GError *error = NULL;
406 g_return_val_if_fail (service != NULL, FALSE);
408 if (service->priv->connected)
411 service->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
413 g_warning ("Failed to get system bus: %s", error->message);
414 g_clear_error (&error);
415 if (!service->priv->connection)
418 service->priv->signal_id = g_dbus_connection_signal_subscribe (service->priv->connection,
420 "org.freedesktop.login1.Manager",
422 "/org/freedesktop/login1",
424 G_DBUS_SIGNAL_FLAGS_NONE,
426 g_object_ref (service),
429 result = g_dbus_connection_call_sync (service->priv->connection,
431 "/org/freedesktop/login1",
432 "org.freedesktop.login1.Manager",
434 g_variant_new ("()"),
435 G_VARIANT_TYPE ("(a(so))"),
436 G_DBUS_CALL_FLAGS_NONE,
441 g_warning ("Failed to get list of logind seats: %s", error->message);
442 g_clear_error (&error);
446 g_variant_get (result, "(a(so))", &seat_iter);
447 while (g_variant_iter_loop (seat_iter, "(&s&o)", &id, &path))
448 add_seat (service, id, path);
449 g_variant_iter_free (seat_iter);
450 g_variant_unref (result);
452 service->priv->connected = TRUE;
458 login1_service_get_is_connected (Login1Service *service)
460 g_return_val_if_fail (service != NULL, FALSE);
461 return service->priv->connected;
465 login1_service_get_seats (Login1Service *service)
467 g_return_val_if_fail (service != NULL, NULL);
468 return service->priv->seats;
472 login1_service_get_seat (Login1Service *service, const gchar *id)
476 g_return_val_if_fail (service != NULL, NULL);
478 for (link = service->priv->seats; link; link = link->next)
480 Login1Seat *seat = link->data;
481 if (strcmp (seat->priv->id, id) == 0)
489 login1_service_init (Login1Service *service)
491 service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, LOGIN1_SERVICE_TYPE, Login1ServicePrivate);
495 login1_service_finalize (GObject *object)
497 Login1Service *self = LOGIN1_SERVICE (object);
499 g_list_free_full (self->priv->seats, g_object_unref);
500 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
501 g_object_unref (self->priv->connection);
503 G_OBJECT_CLASS (login1_service_parent_class)->finalize (object);
507 login1_service_class_init (Login1ServiceClass *klass)
509 GObjectClass *object_class = G_OBJECT_CLASS (klass);
511 object_class->finalize = login1_service_finalize;
513 g_type_class_add_private (klass, sizeof (Login1ServicePrivate));
515 service_signals[SEAT_ADDED] =
516 g_signal_new ("seat-added",
517 G_TYPE_FROM_CLASS (klass),
519 G_STRUCT_OFFSET (Login1ServiceClass, seat_added),
522 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
523 service_signals[SEAT_REMOVED] =
524 g_signal_new ("seat-removed",
525 G_TYPE_FROM_CLASS (klass),
527 G_STRUCT_OFFSET (Login1ServiceClass, seat_removed),
530 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
534 login1_seat_get_id (Login1Seat *seat)
536 g_return_val_if_fail (seat != NULL, NULL);
537 return seat->priv->id;
541 login1_seat_get_can_graphical (Login1Seat *seat)
543 g_return_val_if_fail (seat != NULL, FALSE);
544 return seat->priv->can_graphical;
548 login1_seat_get_can_multi_session (Login1Seat *seat)
550 g_return_val_if_fail (seat != NULL, FALSE);
551 return seat->priv->can_multi_session;
555 login1_seat_init (Login1Seat *seat)
557 seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, LOGIN1_SEAT_TYPE, Login1SeatPrivate);
561 login1_seat_finalize (GObject *object)
563 Login1Seat *self = LOGIN1_SEAT (object);
565 g_free (self->priv->id);
566 g_free (self->priv->path);
567 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
568 g_object_unref (self->priv->connection);
570 G_OBJECT_CLASS (login1_seat_parent_class)->finalize (object);
574 login1_seat_class_init (Login1SeatClass *klass)
576 GObjectClass *object_class = G_OBJECT_CLASS (klass);
578 object_class->finalize = login1_seat_finalize;
580 g_type_class_add_private (klass, sizeof (Login1SeatPrivate));
582 seat_signals[CAN_GRAPHICAL_CHANGED] =
583 g_signal_new ("can-graphical-changed",
584 G_TYPE_FROM_CLASS (klass),
586 G_STRUCT_OFFSET (Login1SeatClass, can_graphical_changed),