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 signals[LAST_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 */
42 struct Login1SeatPrivate
47 /* D-Bus path for this seat */
50 /* TRUE if can run a graphical display on this seat */
51 gboolean can_graphical;
53 /* TRUE if can do session switching */
54 gboolean can_multi_session;
57 G_DEFINE_TYPE (Login1Service, login1_service, G_TYPE_OBJECT);
58 G_DEFINE_TYPE (Login1Seat, login1_seat, G_TYPE_OBJECT);
60 static Login1Service *singleton = NULL;
63 login1_get_session_id (void)
70 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
72 g_warning ("Failed to get system bus: %s", error->message);
73 g_clear_error (&error);
76 result = g_dbus_connection_call_sync (bus,
78 "/org/freedesktop/login1",
79 "org.freedesktop.login1.Manager",
81 g_variant_new ("(u)", getpid()),
82 G_VARIANT_TYPE ("(o)"),
83 G_DBUS_CALL_FLAGS_NONE,
90 g_warning ("Failed to open login1 session: %s", error->message);
91 g_clear_error (&error);
95 g_variant_get (result, "(o)", &session_path);
96 g_variant_unref (result);
97 g_debug ("Got login1 session id: %s", session_path);
103 login1_lock_session (const gchar *session_path)
105 GDBusConnection *bus;
106 GError *error = NULL;
108 g_return_if_fail (session_path != NULL);
110 g_debug ("Locking login1 session %s", session_path);
112 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
114 g_warning ("Failed to get system bus: %s", error->message);
115 g_clear_error (&error);
123 result = g_dbus_connection_call_sync (bus,
126 "org.freedesktop.login1.Session",
128 g_variant_new ("()"),
129 G_VARIANT_TYPE ("()"),
130 G_DBUS_CALL_FLAGS_NONE,
135 g_warning ("Error locking login1 session: %s", error->message);
136 g_clear_error (&error);
138 g_variant_unref (result);
140 g_object_unref (bus);
144 login1_unlock_session (const gchar *session_path)
146 GDBusConnection *bus;
147 GError *error = NULL;
149 g_return_if_fail (session_path != NULL);
151 g_debug ("Unlocking login1 session %s", session_path);
153 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
155 g_warning ("Failed to get system bus: %s", error->message);
156 g_clear_error (&error);
164 result = g_dbus_connection_call_sync (bus,
167 "org.freedesktop.login1.Session",
169 g_variant_new ("()"),
170 G_VARIANT_TYPE ("()"),
171 G_DBUS_CALL_FLAGS_NONE,
176 g_warning ("Error unlocking login1 session: %s", error->message);
177 g_clear_error (&error);
179 g_variant_unref (result);
181 g_object_unref (bus);
185 login1_activate_session (const gchar *session_path)
187 GDBusConnection *bus;
188 GError *error = NULL;
190 g_return_if_fail (session_path != NULL);
192 g_debug ("Activating login1 session %s", session_path);
194 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
196 g_warning ("Failed to get system bus: %s", error->message);
197 g_clear_error (&error);
205 result = g_dbus_connection_call_sync (bus,
208 "org.freedesktop.login1.Session",
210 g_variant_new ("()"),
211 G_VARIANT_TYPE ("()"),
212 G_DBUS_CALL_FLAGS_NONE,
217 g_warning ("Error activating login1 session: %s", error->message);
218 g_clear_error (&error);
220 g_variant_unref (result);
222 g_object_unref (bus);
226 login1_service_get_instance (void)
229 singleton = g_object_new (LOGIN1_SERVICE_TYPE, NULL);
234 add_seat (Login1Service *service, const gchar *id, const gchar *path)
238 GError *error = NULL;
240 seat = g_object_new (LOGIN1_SEAT_TYPE, NULL);
241 seat->priv->id = g_strdup (id);
242 seat->priv->path = g_strdup (path);
244 /* Get properties for this seat */
245 result = g_dbus_connection_call_sync (service->priv->connection,
248 "org.freedesktop.DBus.Properties",
250 g_variant_new ("(s)", "org.freedesktop.login1.Seat"),
251 G_VARIANT_TYPE ("(a{sv})"),
252 G_DBUS_CALL_FLAGS_NONE,
257 g_warning ("Failed to get seat properties: %s", error->message);
258 g_clear_error (&error);
261 GVariantIter *properties;
265 g_variant_get (result, "(a{sv})", &properties);
266 while (g_variant_iter_loop (properties, "{&sv}", &name, &value))
268 if (strcmp (name, "CanGraphical") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
269 seat->priv->can_graphical = g_variant_get_boolean (value);
270 else if (strcmp (name, "CanMultiSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
271 seat->priv->can_multi_session = g_variant_get_boolean (value);
272 g_variant_unref (value);
274 g_variant_iter_free (properties);
275 g_variant_unref (result);
278 service->priv->seats = g_list_append (service->priv->seats, seat);
284 signal_cb (GDBusConnection *connection,
285 const gchar *sender_name,
286 const gchar *object_path,
287 const gchar *interface_name,
288 const gchar *signal_name,
289 GVariant *parameters,
292 Login1Service *service = user_data;
294 if (strcmp (signal_name, "SeatNew") == 0)
296 const gchar *id, *path;
299 g_variant_get (parameters, "(&s&o)", &id, &path);
300 seat = login1_service_get_seat (service, id);
303 seat = add_seat (service, id, path);
304 g_signal_emit (service, signals[SEAT_ADDED], 0, seat);
307 else if (strcmp (signal_name, "SeatRemoved") == 0)
309 const gchar *id, *path;
312 g_variant_get (parameters, "(&s&o)", &id, &path);
313 seat = login1_service_get_seat (service, id);
316 service->priv->seats = g_list_remove (service->priv->seats, seat);
317 g_signal_emit (service, signals[SEAT_REMOVED], 0, seat);
318 g_object_unref (seat);
324 login1_service_connect (Login1Service *service)
327 GVariantIter *seat_iter;
328 const gchar *id, *path;
329 GError *error = NULL;
331 g_return_val_if_fail (service != NULL, FALSE);
333 if (service->priv->connected)
336 service->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
338 g_warning ("Failed to get system bus: %s", error->message);
339 g_clear_error (&error);
340 if (!service->priv->connection)
343 service->priv->signal_id = g_dbus_connection_signal_subscribe (service->priv->connection,
345 "org.freedesktop.login1.Manager",
347 "/org/freedesktop/login1",
349 G_DBUS_SIGNAL_FLAGS_NONE,
354 result = g_dbus_connection_call_sync (service->priv->connection,
356 "/org/freedesktop/login1",
357 "org.freedesktop.login1.Manager",
359 g_variant_new ("()"),
360 G_VARIANT_TYPE ("(a(so))"),
361 G_DBUS_CALL_FLAGS_NONE,
366 g_warning ("Failed to get list of logind seats: %s", error->message);
367 g_clear_error (&error);
371 g_variant_get (result, "(a(so))", &seat_iter);
372 while (g_variant_iter_loop (seat_iter, "(&s&o)", &id, &path))
373 add_seat (service, id, path);
374 g_variant_iter_free (seat_iter);
375 g_variant_unref (result);
377 service->priv->connected = TRUE;
383 login1_service_get_is_connected (Login1Service *service)
385 g_return_val_if_fail (service != NULL, FALSE);
386 return service->priv->connected;
390 login1_service_get_seats (Login1Service *service)
392 g_return_val_if_fail (service != NULL, NULL);
393 return service->priv->seats;
397 login1_service_get_seat (Login1Service *service, const gchar *id)
401 g_return_val_if_fail (service != NULL, NULL);
403 for (link = service->priv->seats; link; link = link->next)
405 Login1Seat *seat = link->data;
406 if (strcmp (seat->priv->id, id) == 0)
414 login1_service_init (Login1Service *service)
416 service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, LOGIN1_SERVICE_TYPE, Login1ServicePrivate);
420 login1_service_finalize (GObject *object)
422 Login1Service *self = LOGIN1_SERVICE (object);
424 g_list_free_full (self->priv->seats, g_object_unref);
425 g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
426 g_object_unref (self->priv->connection);
428 G_OBJECT_CLASS (login1_service_parent_class)->finalize (object);
432 login1_service_class_init (Login1ServiceClass *klass)
434 GObjectClass *object_class = G_OBJECT_CLASS (klass);
436 object_class->finalize = login1_service_finalize;
438 g_type_class_add_private (klass, sizeof (Login1ServicePrivate));
440 signals[SEAT_ADDED] =
441 g_signal_new ("seat-added",
442 G_TYPE_FROM_CLASS (klass),
444 G_STRUCT_OFFSET (Login1ServiceClass, seat_added),
447 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
448 signals[SEAT_REMOVED] =
449 g_signal_new ("seat-removed",
450 G_TYPE_FROM_CLASS (klass),
452 G_STRUCT_OFFSET (Login1ServiceClass, seat_removed),
455 G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
459 login1_seat_get_id (Login1Seat *seat)
461 g_return_val_if_fail (seat != NULL, NULL);
462 return seat->priv->id;
466 login1_seat_get_can_graphical (Login1Seat *seat)
468 g_return_val_if_fail (seat != NULL, FALSE);
469 return seat->priv->can_graphical;
473 login1_seat_get_can_multi_session (Login1Seat *seat)
475 g_return_val_if_fail (seat != NULL, FALSE);
476 return seat->priv->can_multi_session;
480 login1_seat_init (Login1Seat *seat)
482 seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, LOGIN1_SEAT_TYPE, Login1SeatPrivate);
486 login1_seat_finalize (GObject *object)
488 Login1Seat *self = LOGIN1_SEAT (object);
490 g_free (self->priv->id);
491 g_free (self->priv->path);
493 G_OBJECT_CLASS (login1_seat_parent_class)->finalize (object);
497 login1_seat_class_init (Login1SeatClass *klass)
499 GObjectClass *object_class = G_OBJECT_CLASS (klass);
501 object_class->finalize = login1_seat_finalize;
503 g_type_class_add_private (klass, sizeof (Login1SeatPrivate));