]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/login1.c
Make a login1 service object (not currently required, but will be used for automatic...
[sojka/lightdm.git] / src / login1.c
1 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*-
2  *
3  * Copyright (C) 2010-2011 Robert Ancell.
4  * Author: Robert Ancell <robert.ancell@canonical.com>
5  *
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
10  * license.
11  */
12
13 #include <string.h>
14 #include <gio/gio.h>
15
16 #include "login1.h"
17
18 #define LOGIN1_SERVICE_NAME "org.freedesktop.login1"
19
20 enum {
21     SEAT_ADDED,
22     SEAT_REMOVED,
23     LAST_SIGNAL
24 };
25 static guint signals[LAST_SIGNAL] = { 0 };
26
27 struct Login1ServicePrivate
28 {
29     /* Connection to bus service is running on */
30     GDBusConnection *connection;
31
32     /* TRUE if have connected to service */
33     gboolean connected;
34
35     /* Seats the service is reporting */
36     GList *seats;
37
38     /* Handle to signal subscription */
39     guint signal_id;
40 };
41
42 struct Login1SeatPrivate
43 {
44     /* Seat Id */
45     gchar *id;
46
47     /* D-Bus path for this seat */
48     gchar *path;
49 };
50
51 G_DEFINE_TYPE (Login1Service, login1_service, G_TYPE_OBJECT);
52 G_DEFINE_TYPE (Login1Seat, login1_seat, G_TYPE_OBJECT);
53
54 static Login1Service *singleton = NULL;
55
56 gchar *
57 login1_get_session_id (void)
58 {
59     GDBusConnection *bus;
60     GVariant *result;
61     gchar *session_path;
62     GError *error = NULL;
63
64     bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
65     if (error)
66         g_warning ("Failed to get system bus: %s", error->message);
67     g_clear_error (&error);
68     if (!bus)
69         return NULL;
70     result = g_dbus_connection_call_sync (bus,
71                                           LOGIN1_SERVICE_NAME,
72                                           "/org/freedesktop/login1",
73                                           "org.freedesktop.login1.Manager",
74                                           "GetSessionByPID",
75                                           g_variant_new ("(u)", getpid()),
76                                           G_VARIANT_TYPE ("(o)"),
77                                           G_DBUS_CALL_FLAGS_NONE,
78                                           -1,
79                                           NULL,
80                                           &error);
81     g_object_unref (bus);
82
83     if (error)
84         g_warning ("Failed to open login1 session: %s", error->message);
85     g_clear_error (&error);
86     if (!result)
87         return NULL;
88
89     g_variant_get (result, "(o)", &session_path);
90     g_variant_unref (result);
91     g_debug ("Got login1 session id: %s", session_path);
92
93     return session_path;
94 }
95
96 void
97 login1_lock_session (const gchar *session_path)
98 {
99     GDBusConnection *bus;
100     GError *error = NULL;
101
102     g_return_if_fail (session_path != NULL);
103
104     g_debug ("Locking login1 session %s", session_path);
105
106     bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
107     if (error)
108         g_warning ("Failed to get system bus: %s", error->message);
109     g_clear_error (&error);
110     if (!bus)
111         return;
112
113     if (session_path)
114     {
115         GVariant *result;
116
117         result = g_dbus_connection_call_sync (bus,
118                                               LOGIN1_SERVICE_NAME,
119                                               session_path,
120                                               "org.freedesktop.login1.Session",
121                                               "Lock",
122                                               g_variant_new ("()"),
123                                               G_VARIANT_TYPE ("()"),
124                                               G_DBUS_CALL_FLAGS_NONE,
125                                               -1,
126                                               NULL,
127                                               &error);
128         if (error)
129             g_warning ("Error locking login1 session: %s", error->message);
130         g_clear_error (&error);
131         if (result)
132             g_variant_unref (result);
133     }
134     g_object_unref (bus);
135 }
136
137 void
138 login1_unlock_session (const gchar *session_path)
139 {
140     GDBusConnection *bus;
141     GError *error = NULL;
142
143     g_return_if_fail (session_path != NULL);
144
145     g_debug ("Unlocking login1 session %s", session_path);
146
147     bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
148     if (error)
149         g_warning ("Failed to get system bus: %s", error->message);
150     g_clear_error (&error);
151     if (!bus)
152         return;
153
154     if (session_path)
155     {
156         GVariant *result;
157
158         result = g_dbus_connection_call_sync (bus,
159                                               LOGIN1_SERVICE_NAME,
160                                               session_path,
161                                               "org.freedesktop.login1.Session",
162                                               "Unlock",
163                                               g_variant_new ("()"),
164                                               G_VARIANT_TYPE ("()"),
165                                               G_DBUS_CALL_FLAGS_NONE,
166                                               -1,
167                                               NULL,
168                                               &error);
169         if (error)
170             g_warning ("Error unlocking login1 session: %s", error->message);
171         g_clear_error (&error);
172         if (result)
173             g_variant_unref (result);
174     }
175     g_object_unref (bus);
176 }
177
178 void
179 login1_activate_session (const gchar *session_path)
180 {
181     GDBusConnection *bus;
182     GError *error = NULL;
183
184     g_return_if_fail (session_path != NULL);
185
186     g_debug ("Activating login1 session %s", session_path);
187
188     bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
189     if (error)
190         g_warning ("Failed to get system bus: %s", error->message);
191     g_clear_error (&error);
192     if (!bus)
193         return;
194
195     if (session_path)
196     {
197         GVariant *result;
198
199         result = g_dbus_connection_call_sync (bus,
200                                               LOGIN1_SERVICE_NAME,
201                                               session_path,
202                                               "org.freedesktop.login1.Session",
203                                               "Activate",
204                                               g_variant_new ("()"),
205                                               G_VARIANT_TYPE ("()"),
206                                               G_DBUS_CALL_FLAGS_NONE,
207                                               -1,
208                                               NULL,
209                                               &error);
210         if (error)
211             g_warning ("Error activating login1 session: %s", error->message);
212         g_clear_error (&error);
213         if (result)
214             g_variant_unref (result);
215     }
216     g_object_unref (bus);
217 }
218
219 Login1Service *
220 login1_service_get_instance (void)
221 {
222     if (!singleton)
223         singleton = g_object_new (LOGIN1_SERVICE_TYPE, NULL);
224     return singleton;
225 }
226
227 static Login1Seat *
228 add_seat (Login1Service *service, const gchar *id, const gchar *path)
229 {
230     Login1Seat *seat;
231
232     seat = g_object_new (LOGIN1_SEAT_TYPE, NULL);
233     seat->priv->id = g_strdup (id);
234     seat->priv->path = g_strdup (path);
235     service->priv->seats = g_list_append (service->priv->seats, seat);
236
237     return seat;
238 }
239
240 static void
241 signal_cb (GDBusConnection *connection,
242            const gchar *sender_name,
243            const gchar *object_path,
244            const gchar *interface_name,
245            const gchar *signal_name,
246            GVariant *parameters,
247            gpointer user_data)
248 {
249     Login1Service *service = user_data;
250
251     if (strcmp (signal_name, "SeatNew") == 0)
252     {
253         const gchar *id, *path;
254         Login1Seat *seat;
255
256         g_variant_get (parameters, "(&s&o)", &id, &path);
257         seat = login1_service_get_seat (service, id);
258         if (!seat)
259         {
260             seat = add_seat (service, id, path);
261             g_signal_emit (service, signals[SEAT_ADDED], 0, seat);
262         }
263     }
264     else if (strcmp (signal_name, "SeatRemoved") == 0)
265     {
266         const gchar *id, *path;
267         Login1Seat *seat;
268
269         g_variant_get (parameters, "(&s&o)", &id, &path);
270         seat = login1_service_get_seat (service, id);
271         if (seat)
272         {
273             service->priv->seats = g_list_remove (service->priv->seats, seat);            
274             g_signal_emit (service, signals[SEAT_REMOVED], 0, seat);
275             g_object_unref (seat);
276         }                        
277     } 
278 }
279
280 gboolean
281 login1_service_connect (Login1Service *service)
282 {
283     GVariant *result;
284     GVariantIter *seat_iter;
285     const gchar *id, *path;
286     GError *error = NULL;
287
288     g_return_val_if_fail (service != NULL, FALSE);
289
290     if (service->priv->connected)
291         return TRUE;
292
293     service->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
294     if (error)
295         g_warning ("Failed to get system bus: %s", error->message);
296     g_clear_error (&error);
297     if (!service->priv->connection)
298         return FALSE;
299
300     service->priv->signal_id = g_dbus_connection_signal_subscribe (service->priv->connection,
301                                                                    LOGIN1_SERVICE_NAME,
302                                                                    "org.freedesktop.login1.Manager",
303                                                                    NULL,
304                                                                    "/org/freedesktop/login1",
305                                                                    NULL,
306                                                                    G_DBUS_SIGNAL_FLAGS_NONE,
307                                                                    signal_cb,
308                                                                    service,
309                                                                    NULL);
310
311     result = g_dbus_connection_call_sync (service->priv->connection,
312                                           LOGIN1_SERVICE_NAME,
313                                           "/org/freedesktop/login1",
314                                           "org.freedesktop.login1.Manager",
315                                           "ListSeats",
316                                           g_variant_new ("()"),
317                                           G_VARIANT_TYPE ("(a(so))"),
318                                           G_DBUS_CALL_FLAGS_NONE,
319                                           -1,
320                                           NULL,
321                                           &error);
322     if (error)
323         g_warning ("Failed to get list of logind seats: %s", error->message);
324     g_clear_error (&error);
325     if (!result)
326         return FALSE;
327
328     g_variant_get (result, "(a(so))", &seat_iter);
329     while (g_variant_iter_loop (seat_iter, "(&s&o)", &id, &path))
330         add_seat (service, id, path);
331     g_variant_iter_free (seat_iter);
332     g_variant_unref (result);
333
334     service->priv->connected = TRUE;
335
336     return TRUE;
337 }
338
339 gboolean
340 login1_service_get_is_connected (Login1Service *service)
341 {
342     g_return_val_if_fail (service != NULL, FALSE);
343     return service->priv->connected;
344 }
345
346 GList *
347 login1_service_get_seats (Login1Service *service)
348 {
349     g_return_val_if_fail (service != NULL, NULL);
350     return service->priv->seats;
351 }
352
353 Login1Seat *
354 login1_service_get_seat (Login1Service *service, const gchar *id)
355 {
356     GList *link;
357
358     g_return_val_if_fail (service != NULL, NULL);
359
360     for (link = service->priv->seats; link; link = link->next)
361     {
362         Login1Seat *seat = link->data;
363         if (strcmp (seat->priv->id, id) == 0)
364             return seat;
365     }
366
367     return NULL;
368 }
369
370 static void
371 login1_service_init (Login1Service *service)
372 {
373     service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service, LOGIN1_SERVICE_TYPE, Login1ServicePrivate);
374 }
375
376 static void
377 login1_service_finalize (GObject *object)
378 {
379     Login1Service *self = LOGIN1_SERVICE (object);
380
381     g_list_free_full (self->priv->seats, g_object_unref);
382     g_dbus_connection_signal_unsubscribe (self->priv->connection, self->priv->signal_id);
383     g_object_unref (self->priv->connection);
384
385     G_OBJECT_CLASS (login1_service_parent_class)->finalize (object);
386 }
387
388 static void
389 login1_service_class_init (Login1ServiceClass *klass)
390 {
391     GObjectClass *object_class = G_OBJECT_CLASS (klass);
392
393     object_class->finalize = login1_service_finalize;
394
395     g_type_class_add_private (klass, sizeof (Login1ServicePrivate));
396
397     signals[SEAT_ADDED] =
398         g_signal_new ("seat-added",
399                       G_TYPE_FROM_CLASS (klass),
400                       G_SIGNAL_RUN_LAST,
401                       G_STRUCT_OFFSET (Login1ServiceClass, seat_added),
402                       NULL, NULL,
403                       NULL,
404                       G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
405     signals[SEAT_REMOVED] =
406         g_signal_new ("seat-removed",
407                       G_TYPE_FROM_CLASS (klass),
408                       G_SIGNAL_RUN_LAST,
409                       G_STRUCT_OFFSET (Login1ServiceClass, seat_removed),
410                       NULL, NULL,
411                       NULL,
412                       G_TYPE_NONE, 1, LOGIN1_SEAT_TYPE);
413 }
414
415 const gchar *
416 login1_seat_get_id (Login1Seat *seat)
417 {
418     g_return_val_if_fail (seat != NULL, NULL);
419     return seat->priv->id;
420 }
421
422 static void
423 login1_seat_init (Login1Seat *seat)
424 {
425     seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, LOGIN1_SEAT_TYPE, Login1SeatPrivate);
426 }
427
428 static void
429 login1_seat_finalize (GObject *object)
430 {
431     Login1Seat *self = LOGIN1_SEAT (object);
432
433     g_free (self->priv->id);
434     g_free (self->priv->path);
435
436     G_OBJECT_CLASS (login1_seat_parent_class)->finalize (object);
437 }
438
439 static void
440 login1_seat_class_init (Login1SeatClass *klass)
441 {
442     GObjectClass *object_class = G_OBJECT_CLASS (klass);
443
444     object_class->finalize = login1_seat_finalize;
445
446     g_type_class_add_private (klass, sizeof (Login1SeatPrivate));
447 }