VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c@ 64530

最後變更 在這個檔案從64530是 45170,由 vboxsync 提交於 12 年 前

Additions/linux: lightdm-greeter to OSE

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 53.1 KB
 
1/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
2 *
3 * Copyright (C) 2010 Robert Ancell.
4 * Author: Robert Ancell <[email protected]>
5 *
6 * This library is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by the Free
8 * Software Foundation; either version 2 or version 3 of the License.
9 * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
10 */
11
12#include "config.h"
13
14#include <errno.h>
15#include <string.h>
16#include <sys/utsname.h>
17#include <pwd.h>
18#include <gio/gio.h>
19
20#include "lightdm/user.h"
21
22enum
23{
24 LIST_PROP_0,
25 LIST_PROP_NUM_USERS,
26 LIST_PROP_USERS,
27};
28
29enum
30{
31 USER_PROP_0,
32 USER_PROP_NAME,
33 USER_PROP_REAL_NAME,
34 USER_PROP_DISPLAY_NAME,
35 USER_PROP_HOME_DIRECTORY,
36 USER_PROP_IMAGE,
37 USER_PROP_BACKGROUND,
38 USER_PROP_LANGUAGE,
39 USER_PROP_LAYOUT,
40 USER_PROP_LAYOUTS,
41 USER_PROP_SESSION,
42 USER_PROP_LOGGED_IN,
43 USER_PROP_HAS_MESSAGES
44};
45
46enum
47{
48 USER_ADDED,
49 USER_CHANGED,
50 USER_REMOVED,
51 LAST_LIST_SIGNAL
52};
53static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
54
55enum
56{
57 CHANGED,
58 LAST_USER_SIGNAL
59};
60static guint user_signals[LAST_USER_SIGNAL] = { 0 };
61
62typedef struct
63{
64 /* Connection to AccountsService */
65 GDBusProxy *accounts_service_proxy;
66 GList *user_account_objects;
67
68 /* Connection to DisplayManager */
69 GDBusProxy *display_manager_proxy;
70
71 /* File monitor for password file */
72 GFileMonitor *passwd_monitor;
73
74 /* TRUE if have scanned users */
75 gboolean have_users;
76
77 /* List of users */
78 GList *users;
79
80 /* List of sessions */
81 GList *sessions;
82} LightDMUserListPrivate;
83
84typedef struct
85{
86 GDBusProxy *proxy;
87 LightDMUser *user;
88} UserAccountObject;
89
90typedef struct
91{
92 LightDMUserList *user_list;
93
94 gchar *name;
95 gchar *real_name;
96 gchar *home_directory;
97 gchar *image;
98 gchar *background;
99 gboolean has_messages;
100
101 GKeyFile *dmrc_file;
102 gchar *language;
103 gchar **layouts;
104 gchar *session;
105} LightDMUserPrivate;
106
107typedef struct
108{
109 GObject parent_instance;
110 gchar *path;
111 gchar *username;
112} Session;
113
114typedef struct
115{
116 GObjectClass parent_class;
117} SessionClass;
118
119G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
120G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
121#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
122GType session_get_type (void);
123G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
124
125#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
126#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
127
128#define PASSWD_FILE "/etc/passwd"
129#define USER_CONFIG_FILE "/etc/lightdm/users.conf"
130
131static LightDMUserList *singleton = NULL;
132
133/**
134 * lightdm_user_list_get_instance:
135 *
136 * Get the user list.
137 *
138 * Return value: (transfer none): the #LightDMUserList
139 **/
140LightDMUserList *
141lightdm_user_list_get_instance (void)
142{
143 if (!singleton)
144 singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
145 return singleton;
146}
147
148static LightDMUser *
149get_user_by_name (LightDMUserList *user_list, const gchar *username)
150{
151 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
152 GList *link;
153
154 for (link = priv->users; link; link = link->next)
155 {
156 LightDMUser *user = link->data;
157 if (strcmp (lightdm_user_get_name (user), username) == 0)
158 return user;
159 }
160
161 return NULL;
162}
163
164static gint
165compare_user (gconstpointer a, gconstpointer b)
166{
167 LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
168 return strcmp (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
169}
170
171static gboolean
172update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
173{
174 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
175
176 if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
177 g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
178 g_strcmp0 (lightdm_user_get_image (user), image) == 0)
179 return FALSE;
180
181 g_free (priv->real_name);
182 priv->real_name = g_strdup (real_name);
183 g_free (priv->home_directory);
184 priv->home_directory = g_strdup (home_directory);
185 g_free (priv->image);
186 priv->image = g_strdup (image);
187
188 return TRUE;
189}
190
191static void
192user_changed_cb (LightDMUser *user, LightDMUserList *user_list)
193{
194 g_signal_emit (user_list, list_signals[USER_CHANGED], 0, user);
195}
196
197static void
198load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
199{
200 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
201 GKeyFile *config;
202 gchar *value;
203 gint minimum_uid;
204 gchar **hidden_users, **hidden_shells;
205 GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
206 GError *error = NULL;
207
208 g_debug ("Loading user config from %s", USER_CONFIG_FILE);
209
210 config = g_key_file_new ();
211 g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error);
212 if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
213 g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info
214 g_clear_error (&error);
215
216 if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
217 minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
218 else
219 minimum_uid = 500;
220
221 value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
222 if (!value)
223 value = g_strdup ("nobody nobody4 noaccess");
224 hidden_users = g_strsplit (value, " ", -1);
225 g_free (value);
226
227 value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
228 if (!value)
229 value = g_strdup ("/bin/false /usr/sbin/nologin");
230 hidden_shells = g_strsplit (value, " ", -1);
231 g_free (value);
232
233 g_key_file_free (config);
234
235 setpwent ();
236
237 while (TRUE)
238 {
239 struct passwd *entry;
240 LightDMUser *user;
241 LightDMUserPrivate *user_priv;
242 char **tokens;
243 gchar *real_name, *image;
244 int i;
245
246 errno = 0;
247 entry = getpwent ();
248 if (!entry)
249 break;
250
251 /* Ignore system users */
252 if (entry->pw_uid < minimum_uid)
253 continue;
254
255 /* Ignore users disabled by shell */
256 if (entry->pw_shell)
257 {
258 for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
259 if (hidden_shells[i])
260 continue;
261 }
262
263 /* Ignore certain users */
264 for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
265 if (hidden_users[i])
266 continue;
267
268 tokens = g_strsplit (entry->pw_gecos, ",", -1);
269 if (tokens[0] != NULL && tokens[0][0] != '\0')
270 real_name = g_strdup (tokens[0]);
271 else
272 real_name = g_strdup ("");
273 g_strfreev (tokens);
274
275 image = g_build_filename (entry->pw_dir, ".face", NULL);
276 if (!g_file_test (image, G_FILE_TEST_EXISTS))
277 {
278 g_free (image);
279 image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
280 if (!g_file_test (image, G_FILE_TEST_EXISTS))
281 {
282 g_free (image);
283 image = NULL;
284 }
285 }
286
287 user = g_object_new (LIGHTDM_TYPE_USER, NULL);
288 user_priv = GET_USER_PRIVATE (user);
289 user_priv->user_list = user_list;
290 g_free (user_priv->name);
291 user_priv->name = g_strdup (entry->pw_name);
292 g_free (user_priv->real_name);
293 user_priv->real_name = real_name;
294 g_free (user_priv->home_directory);
295 user_priv->home_directory = g_strdup (entry->pw_dir);
296 g_free (user_priv->image);
297 user_priv->image = image;
298
299 /* Update existing users if have them */
300 for (link = priv->users; link; link = link->next)
301 {
302 LightDMUser *info = link->data;
303 if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
304 {
305 if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
306 changed_users = g_list_insert_sorted (changed_users, info, compare_user);
307 g_object_unref (user);
308 user = info;
309 break;
310 }
311 }
312 if (!link)
313 {
314 /* Only notify once we have loaded the user list */
315 if (priv->have_users)
316 new_users = g_list_insert_sorted (new_users, user, compare_user);
317 }
318 users = g_list_insert_sorted (users, user, compare_user);
319 }
320 g_strfreev (hidden_users);
321 g_strfreev (hidden_shells);
322
323 if (errno != 0)
324 g_warning ("Failed to read password database: %s", strerror (errno));
325
326 endpwent ();
327
328 /* Use new user list */
329 old_users = priv->users;
330 priv->users = users;
331
332 /* Notify of changes */
333 for (link = new_users; link; link = link->next)
334 {
335 LightDMUser *info = link->data;
336 g_debug ("User %s added", lightdm_user_get_name (info));
337 g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), user_list);
338 if (emit_add_signal)
339 g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
340 }
341 g_list_free (new_users);
342 for (link = changed_users; link; link = link->next)
343 {
344 LightDMUser *info = link->data;
345 g_debug ("User %s changed", lightdm_user_get_name (info));
346 g_signal_emit (info, user_signals[CHANGED], 0);
347 }
348 g_list_free (changed_users);
349 for (link = old_users; link; link = link->next)
350 {
351 GList *new_link;
352
353 /* See if this user is in the current list */
354 for (new_link = priv->users; new_link; new_link = new_link->next)
355 {
356 if (new_link->data == link->data)
357 break;
358 }
359
360 if (!new_link)
361 {
362 LightDMUser *info = link->data;
363 g_debug ("User %s removed", lightdm_user_get_name (info));
364 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
365 g_object_unref (info);
366 }
367 }
368 g_list_free (old_users);
369}
370
371static void
372passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
373{
374 if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
375 {
376 g_debug ("%s changed, reloading user list", g_file_get_path (file));
377 load_passwd_file (user_list, TRUE);
378 }
379}
380
381static gboolean
382update_user (UserAccountObject *object)
383{
384 LightDMUserPrivate *priv = GET_USER_PRIVATE (object->user);
385 GVariant *result, *value;
386 GVariantIter *iter;
387 gchar *name;
388 GError *error = NULL;
389
390 result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (object->proxy),
391 "org.freedesktop.Accounts",
392 g_dbus_proxy_get_object_path (object->proxy),
393 "org.freedesktop.DBus.Properties",
394 "GetAll",
395 g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
396 G_VARIANT_TYPE ("(a{sv})"),
397 G_DBUS_CALL_FLAGS_NONE,
398 -1,
399 NULL,
400 &error);
401 if (error)
402 g_warning ("Error updating user %s: %s", g_dbus_proxy_get_object_path (object->proxy), error->message);
403 g_clear_error (&error);
404 if (!result)
405 return FALSE;
406
407 g_variant_get (result, "(a{sv})", &iter);
408 while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
409 {
410 if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
411 {
412 gchar *user_name;
413 g_variant_get (value, "&s", &user_name);
414 g_free (priv->name);
415 priv->name = g_strdup (user_name);
416 }
417 else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
418 {
419 gchar *real_name;
420 g_variant_get (value, "&s", &real_name);
421 g_free (priv->real_name);
422 priv->real_name = g_strdup (real_name);
423 }
424 else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
425 {
426 gchar *home_directory;
427 g_variant_get (value, "&s", &home_directory);
428 g_free (priv->home_directory);
429 priv->home_directory = g_strdup (home_directory);
430 }
431 else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
432 {
433 gchar *icon_file;
434 g_variant_get (value, "&s", &icon_file);
435 g_free (priv->image);
436 if (strcmp (icon_file, "") == 0)
437 priv->image = NULL;
438 else
439 priv->image = g_strdup (icon_file);
440 }
441 else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
442 {
443 gchar *background_file;
444 g_variant_get (value, "&s", &background_file);
445 g_free (priv->background);
446 if (strcmp (background_file, "") == 0)
447 priv->background = NULL;
448 else
449 priv->background = g_strdup (background_file);
450 }
451 }
452 g_variant_iter_free (iter);
453
454 g_variant_unref (result);
455
456 return TRUE;
457}
458
459static void
460user_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, UserAccountObject *object)
461{
462 if (strcmp (signal_name, "Changed") == 0)
463 {
464 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
465 {
466 g_debug ("User %s changed", g_dbus_proxy_get_object_path (object->proxy));
467 update_user (object);
468 g_signal_emit (object->user, user_signals[CHANGED], 0);
469 }
470 else
471 g_warning ("Got org.freedesktop.Accounts.User signal Changed with unknown parameters %s", g_variant_get_type_string (parameters));
472 }
473}
474
475static UserAccountObject *
476user_account_object_new (LightDMUserList *user_list, const gchar *path)
477{
478 GDBusProxy *proxy;
479 UserAccountObject *object;
480 GError *error = NULL;
481
482 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
483 G_DBUS_PROXY_FLAGS_NONE,
484 NULL,
485 "org.freedesktop.Accounts",
486 path,
487 "org.freedesktop.Accounts.User",
488 NULL,
489 &error);
490 if (error)
491 g_warning ("Error getting user %s: %s", path, error->message);
492 g_clear_error (&error);
493 if (!proxy)
494 return NULL;
495
496 object = g_malloc0 (sizeof (UserAccountObject));
497 object->user = g_object_new (LIGHTDM_TYPE_USER, NULL);
498 GET_USER_PRIVATE (object->user)->user_list = user_list;
499 object->proxy = proxy;
500 g_signal_connect (proxy, "g-signal", G_CALLBACK (user_signal_cb), object);
501
502 return object;
503}
504
505static void
506user_account_object_free (UserAccountObject *object)
507{
508 if (!object)
509 return;
510 g_object_unref (object->user);
511 g_object_unref (object->proxy);
512 g_free (object);
513}
514
515static UserAccountObject *
516find_user_account_object (LightDMUserList *user_list, const gchar *path)
517{
518 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
519 GList *link;
520
521 for (link = priv->user_account_objects; link; link = link->next)
522 {
523 UserAccountObject *object = link->data;
524 if (strcmp (g_dbus_proxy_get_object_path (object->proxy), path) == 0)
525 return object;
526 }
527
528 return NULL;
529}
530
531static void
532user_accounts_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
533{
534 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
535
536 if (strcmp (signal_name, "UserAdded") == 0)
537 {
538 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
539 {
540 gchar *path;
541 UserAccountObject *object;
542
543 g_variant_get (parameters, "(&o)", &path);
544
545 /* Ignore duplicate requests */
546 object = find_user_account_object (user_list, path);
547 if (object)
548 return;
549
550 object = user_account_object_new (user_list, path);
551 if (object && update_user (object))
552 {
553 g_debug ("User %s added", path);
554 priv->user_account_objects = g_list_append (priv->user_account_objects, object);
555 priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
556 g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
557 g_signal_emit (user_list, list_signals[USER_ADDED], 0, object->user);
558 }
559 else
560 user_account_object_free (object);
561 }
562 else
563 g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
564 }
565 else if (strcmp (signal_name, "UserDeleted") == 0)
566 {
567 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
568 {
569 gchar *path;
570 UserAccountObject *object;
571
572 g_variant_get (parameters, "(&o)", &path);
573
574 object = find_user_account_object (user_list, path);
575 if (!object)
576 return;
577
578 g_debug ("User %s deleted", path);
579 priv->users = g_list_remove (priv->users, object->user);
580 g_object_unref (object->user);
581
582 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, object->user);
583
584 priv->user_account_objects = g_list_remove (priv->user_account_objects, object);
585 user_account_object_free (object);
586 }
587 else
588 g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
589 }
590}
591
592static Session *
593load_session (LightDMUserList *user_list, const gchar *path)
594{
595 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
596 Session *session = NULL;
597 GVariant *result, *username;
598 GError *error = NULL;
599
600 result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
601 "org.freedesktop.DisplayManager",
602 path,
603 "org.freedesktop.DBus.Properties",
604 "Get",
605 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
606 G_VARIANT_TYPE ("(v)"),
607 G_DBUS_CALL_FLAGS_NONE,
608 -1,
609 NULL,
610 &error);
611 if (error)
612 g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
613 g_clear_error (&error);
614 if (!result)
615 return NULL;
616
617 g_variant_get (result, "(v)", &username);
618 if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
619 {
620 gchar *name;
621
622 g_variant_get (username, "&s", &name);
623
624 g_debug ("Loaded session %s (%s)", path, name);
625 session = g_object_new (session_get_type (), NULL);
626 session->username = g_strdup (name);
627 session->path = g_strdup (path);
628 priv->sessions = g_list_append (priv->sessions, session);
629 }
630 g_variant_unref (username);
631 g_variant_unref (result);
632
633 return session;
634}
635
636static void
637display_manager_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
638{
639 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
640
641 if (strcmp (signal_name, "SessionAdded") == 0)
642 {
643 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
644 {
645 gchar *path;
646 Session *session;
647 LightDMUser *user = NULL;
648
649 g_variant_get (parameters, "(&o)", &path);
650 session = load_session (user_list, path);
651 if (session)
652 user = get_user_by_name (user_list, session->username);
653 if (user)
654 g_signal_emit (user, user_signals[CHANGED], 0);
655 }
656 }
657 else if (strcmp (signal_name, "SessionRemoved") == 0)
658 {
659 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
660 {
661 gchar *path;
662 GList *link;
663
664 g_variant_get (parameters, "(&o)", &path);
665
666 for (link = priv->sessions; link; link = link->next)
667 {
668 Session *session = link->data;
669 if (strcmp (session->path, path) == 0)
670 {
671 LightDMUser *user;
672
673 g_debug ("Session %s removed", path);
674 priv->sessions = g_list_remove_link (priv->sessions, link);
675 user = get_user_by_name (user_list, session->username);
676 if (user)
677 g_signal_emit (user, user_signals[CHANGED], 0);
678 g_object_unref (session);
679 break;
680 }
681 }
682 }
683 }
684}
685
686static void
687update_users (LightDMUserList *user_list)
688{
689 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
690 GError *error = NULL;
691
692 if (priv->have_users)
693 return;
694 priv->have_users = TRUE;
695
696 priv->accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
697 G_DBUS_PROXY_FLAGS_NONE,
698 NULL,
699 "org.freedesktop.Accounts",
700 "/org/freedesktop/Accounts",
701 "org.freedesktop.Accounts",
702 NULL,
703 &error);
704 if (error)
705 g_warning ("Error contacting org.freedesktop.Accounts: %s", error->message);
706 g_clear_error (&error);
707
708 /* Check if the service exists */
709 if (priv->accounts_service_proxy)
710 {
711 gchar *name;
712
713 name = g_dbus_proxy_get_name_owner (priv->accounts_service_proxy);
714 if (!name)
715 {
716 g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file");
717 g_object_unref (priv->accounts_service_proxy);
718 priv->accounts_service_proxy = NULL;
719 }
720 g_free (name);
721 }
722
723 if (priv->accounts_service_proxy)
724 {
725 GVariant *result;
726
727 g_signal_connect (priv->accounts_service_proxy, "g-signal", G_CALLBACK (user_accounts_signal_cb), user_list);
728
729 result = g_dbus_proxy_call_sync (priv->accounts_service_proxy,
730 "ListCachedUsers",
731 g_variant_new ("()"),
732 G_DBUS_CALL_FLAGS_NONE,
733 -1,
734 NULL,
735 &error);
736 if (error)
737 g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
738 g_clear_error (&error);
739 if (!result)
740 return;
741
742 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(ao)")))
743 {
744 GVariantIter *iter;
745 const gchar *path;
746
747 g_debug ("Loading users from org.freedesktop.Accounts");
748 g_variant_get (result, "(ao)", &iter);
749 while (g_variant_iter_loop (iter, "&o", &path))
750 {
751 UserAccountObject *object;
752
753 g_debug ("Loading user %s", path);
754
755 object = user_account_object_new (user_list, path);
756 if (object && update_user (object))
757 {
758 priv->user_account_objects = g_list_append (priv->user_account_objects, object);
759 priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
760 g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
761 }
762 else
763 user_account_object_free (object);
764 }
765 g_variant_iter_free (iter);
766 }
767 else
768 g_warning ("Unexpected type from ListCachedUsers: %s", g_variant_get_type_string (result));
769
770 g_variant_unref (result);
771 }
772 else
773 {
774 GFile *passwd_file;
775
776 load_passwd_file (user_list, FALSE);
777
778 /* Watch for changes to user list */
779
780 passwd_file = g_file_new_for_path (PASSWD_FILE);
781 priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
782 g_object_unref (passwd_file);
783 if (error)
784 g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
785 else
786 g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
787 g_clear_error (&error);
788 }
789
790 priv->display_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
791 G_DBUS_PROXY_FLAGS_NONE,
792 NULL,
793 "org.freedesktop.DisplayManager",
794 "/org/freedesktop/DisplayManager",
795 "org.freedesktop.DisplayManager",
796 NULL,
797 &error);
798 if (error)
799 g_warning ("Error contacting org.freedesktop.DisplayManager: %s", error->message);
800 g_clear_error (&error);
801
802 if (priv->display_manager_proxy)
803 {
804 GVariant *result;
805
806 g_signal_connect (priv->display_manager_proxy, "g-signal", G_CALLBACK (display_manager_signal_cb), user_list);
807
808 result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
809 "org.freedesktop.DisplayManager",
810 "/org/freedesktop/DisplayManager",
811 "org.freedesktop.DBus.Properties",
812 "Get",
813 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
814 G_VARIANT_TYPE ("(v)"),
815 G_DBUS_CALL_FLAGS_NONE,
816 -1,
817 NULL,
818 &error);
819 if (error)
820 g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
821 g_clear_error (&error);
822 if (!result)
823 return;
824
825 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
826 {
827 GVariant *value;
828 GVariantIter *iter;
829 const gchar *path;
830
831 g_variant_get (result, "(v)", &value);
832
833 g_debug ("Loading sessions from org.freedesktop.DisplayManager");
834 g_variant_get (value, "ao", &iter);
835 while (g_variant_iter_loop (iter, "&o", &path))
836 load_session (user_list, path);
837 g_variant_iter_free (iter);
838
839 g_variant_unref (value);
840 }
841 else
842 g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
843
844 g_variant_unref (result);
845 }
846}
847
848/**
849 * lightdm_user_list_get_length:
850 * @user_list: a #LightDMUserList
851 *
852 * Return value: The number of users able to log in
853 **/
854gint
855lightdm_user_list_get_length (LightDMUserList *user_list)
856{
857 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
858 update_users (user_list);
859 return g_list_length (GET_LIST_PRIVATE (user_list)->users);
860}
861
862/**
863 * lightdm_user_list_get_users:
864 * @user_list: A #LightDMUserList
865 *
866 * Get a list of users to present to the user. This list may be a subset of the
867 * available users and may be empty depending on the server configuration.
868 *
869 * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user.
870 **/
871GList *
872lightdm_user_list_get_users (LightDMUserList *user_list)
873{
874 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
875 update_users (user_list);
876 return GET_LIST_PRIVATE (user_list)->users;
877}
878
879/**
880 * lightdm_user_list_get_user_by_name:
881 * @user_list: A #LightDMUserList
882 * @username: Name of user to get.
883 *
884 * Get infomation about a given user or #NULL if this user doesn't exist.
885 *
886 * Return value: (transfer none): A #LightDMUser entry for the given user.
887 **/
888LightDMUser *
889lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
890{
891 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
892 g_return_val_if_fail (username != NULL, NULL);
893
894 update_users (user_list);
895
896 return get_user_by_name (user_list, username);
897}
898
899static void
900lightdm_user_list_init (LightDMUserList *user_list)
901{
902}
903
904static void
905lightdm_user_list_set_property (GObject *object,
906 guint prop_id,
907 const GValue *value,
908 GParamSpec *pspec)
909{
910 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
911}
912
913static void
914lightdm_user_list_get_property (GObject *object,
915 guint prop_id,
916 GValue *value,
917 GParamSpec *pspec)
918{
919 LightDMUserList *self;
920
921 self = LIGHTDM_USER_LIST (object);
922
923 switch (prop_id)
924 {
925 case LIST_PROP_NUM_USERS:
926 g_value_set_int (value, lightdm_user_list_get_length (self));
927 break;
928 default:
929 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
930 break;
931 }
932}
933
934static void
935lightdm_user_list_finalize (GObject *object)
936{
937 LightDMUserList *self = LIGHTDM_USER_LIST (object);
938 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
939
940 if (priv->accounts_service_proxy)
941 g_object_unref (priv->accounts_service_proxy);
942 g_list_free_full (priv->user_account_objects, (GDestroyNotify) user_account_object_free);
943 if (priv->passwd_monitor)
944 g_object_unref (priv->passwd_monitor);
945 g_list_free_full (priv->users, g_object_unref);
946 g_list_free_full (priv->sessions, g_object_unref);
947
948 G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
949}
950
951static void
952lightdm_user_list_class_init (LightDMUserListClass *klass)
953{
954 GObjectClass *object_class = G_OBJECT_CLASS (klass);
955
956 g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
957
958 object_class->set_property = lightdm_user_list_set_property;
959 object_class->get_property = lightdm_user_list_get_property;
960 object_class->finalize = lightdm_user_list_finalize;
961
962 g_object_class_install_property (object_class,
963 LIST_PROP_NUM_USERS,
964 g_param_spec_int ("num-users",
965 "num-users",
966 "Number of login users",
967 0, G_MAXINT, 0,
968 G_PARAM_READABLE));
969 /**
970 * LightDMUserList::user-added:
971 * @user_list: A #LightDMUserList
972 * @user: The #LightDM user that has been added.
973 *
974 * The ::user-added signal gets emitted when a user account is created.
975 **/
976 list_signals[USER_ADDED] =
977 g_signal_new ("user-added",
978 G_TYPE_FROM_CLASS (klass),
979 G_SIGNAL_RUN_LAST,
980 G_STRUCT_OFFSET (LightDMUserListClass, user_added),
981 NULL, NULL,
982 g_cclosure_marshal_VOID__OBJECT,
983 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
984
985 /**
986 * LightDMUserList::user-changed:
987 * @user_list: A #LightDMUserList
988 * @user: The #LightDM user that has been changed.
989 *
990 * The ::user-changed signal gets emitted when a user account is modified.
991 **/
992 list_signals[USER_CHANGED] =
993 g_signal_new ("user-changed",
994 G_TYPE_FROM_CLASS (klass),
995 G_SIGNAL_RUN_LAST,
996 G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
997 NULL, NULL,
998 g_cclosure_marshal_VOID__OBJECT,
999 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1000
1001 /**
1002 * LightDMUserList::user-removed:
1003 * @user_list: A #LightDMUserList
1004 * @user: The #LightDM user that has been removed.
1005 *
1006 * The ::user-removed signal gets emitted when a user account is removed.
1007 **/
1008 list_signals[USER_REMOVED] =
1009 g_signal_new ("user-removed",
1010 G_TYPE_FROM_CLASS (klass),
1011 G_SIGNAL_RUN_LAST,
1012 G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
1013 NULL, NULL,
1014 g_cclosure_marshal_VOID__OBJECT,
1015 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1016}
1017
1018/**
1019 * lightdm_user_get_name:
1020 * @user: A #LightDMUser
1021 *
1022 * Get the name of a user.
1023 *
1024 * Return value: The name of the given user
1025 **/
1026const gchar *
1027lightdm_user_get_name (LightDMUser *user)
1028{
1029 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1030 return GET_USER_PRIVATE (user)->name;
1031}
1032
1033/**
1034 * lightdm_user_get_real_name:
1035 * @user: A #LightDMUser
1036 *
1037 * Get the real name of a user.
1038 *
1039 * Return value: The real name of the given user
1040 **/
1041const gchar *
1042lightdm_user_get_real_name (LightDMUser *user)
1043{
1044 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1045 return GET_USER_PRIVATE (user)->real_name;
1046}
1047
1048/**
1049 * lightdm_user_get_display_name:
1050 * @user: A #LightDMUser
1051 *
1052 * Get the display name of a user.
1053 *
1054 * Return value: The display name of the given user
1055 **/
1056const gchar *
1057lightdm_user_get_display_name (LightDMUser *user)
1058{
1059 LightDMUserPrivate *priv;
1060
1061 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1062
1063 priv = GET_USER_PRIVATE (user);
1064 if (strcmp (priv->real_name, ""))
1065 return priv->real_name;
1066 else
1067 return priv->name;
1068}
1069
1070/**
1071 * lightdm_user_get_home_directory:
1072 * @user: A #LightDMUser
1073 *
1074 * Get the home directory for a user.
1075 *
1076 * Return value: The users home directory
1077 */
1078const gchar *
1079lightdm_user_get_home_directory (LightDMUser *user)
1080{
1081 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1082 return GET_USER_PRIVATE (user)->home_directory;
1083}
1084
1085/**
1086 * lightdm_user_get_image:
1087 * @user: A #LightDMUser
1088 *
1089 * Get the image URI for a user.
1090 *
1091 * Return value: The image URI for the given user or #NULL if no URI
1092 **/
1093const gchar *
1094lightdm_user_get_image (LightDMUser *user)
1095{
1096 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1097 return GET_USER_PRIVATE (user)->image;
1098}
1099
1100/**
1101 * lightdm_user_get_background:
1102 * @user: A #LightDMUser
1103 *
1104 * Get the background file path for a user.
1105 *
1106 * Return value: The background file path for the given user or #NULL if no path
1107 **/
1108const gchar *
1109lightdm_user_get_background (LightDMUser *user)
1110{
1111 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1112 return GET_USER_PRIVATE (user)->background;
1113}
1114
1115static void
1116load_dmrc (LightDMUser *user)
1117{
1118 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1119 gchar *path;
1120 //gboolean have_dmrc;
1121
1122 if (!priv->dmrc_file)
1123 priv->dmrc_file = g_key_file_new ();
1124
1125 /* Load from the user directory */
1126 path = g_build_filename (priv->home_directory, ".dmrc", NULL);
1127 /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
1128 g_free (path);
1129
1130 /* If no ~/.dmrc, then load from the cache */
1131 // FIXME
1132
1133 // FIXME: Watch for changes
1134
1135 /* The Language field is actually a locale, strip the codeset off it to get the language */
1136 if (priv->language)
1137 g_free (priv->language);
1138 priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
1139 if (priv->language)
1140 {
1141 gchar *codeset = strchr (priv->language, '.');
1142 if (codeset)
1143 *codeset = '\0';
1144 }
1145
1146 if (priv->layouts)
1147 {
1148 g_strfreev (priv->layouts);
1149 priv->layouts = NULL;
1150 }
1151 if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
1152 {
1153 priv->layouts = g_malloc (sizeof (gchar *) * 2);
1154 priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
1155 priv->layouts[1] = NULL;
1156 }
1157
1158 if (priv->session)
1159 g_free (priv->session);
1160 priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
1161}
1162
1163static GVariant *
1164get_property (GDBusProxy *proxy, const gchar *property)
1165{
1166 GVariant *answer;
1167
1168 if (!proxy)
1169 return NULL;
1170
1171 answer = g_dbus_proxy_get_cached_property (proxy, property);
1172
1173 if (!answer)
1174 {
1175 g_warning ("Could not get accounts property %s", property);
1176 return NULL;
1177 }
1178
1179 return answer;
1180}
1181
1182static gboolean
1183get_boolean_property (GDBusProxy *proxy, const gchar *property)
1184{
1185 GVariant *answer;
1186 gboolean rv;
1187
1188 answer = get_property (proxy, property);
1189 if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_BOOLEAN))
1190 {
1191 g_warning ("Unexpected accounts property type for %s: %s",
1192 property, g_variant_get_type_string (answer));
1193 g_variant_unref (answer);
1194 return FALSE;
1195 }
1196
1197 rv = g_variant_get_boolean (answer);
1198 g_variant_unref (answer);
1199
1200 return rv;
1201}
1202
1203static gchar *
1204get_string_property (GDBusProxy *proxy, const gchar *property)
1205{
1206 GVariant *answer;
1207 gchar *rv;
1208
1209 answer = get_property (proxy, property);
1210 if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_STRING))
1211 {
1212 g_warning ("Unexpected accounts property type for %s: %s",
1213 property, g_variant_get_type_string (answer));
1214 g_variant_unref (answer);
1215 return NULL;
1216 }
1217
1218 rv = g_strdup (g_variant_get_string (answer, NULL));
1219 if (strcmp (rv, "") == 0)
1220 {
1221 g_free (rv);
1222 rv = NULL;
1223 }
1224 g_variant_unref (answer);
1225
1226 return rv;
1227}
1228
1229static gchar **
1230get_string_array_property (GDBusProxy *proxy, const gchar *property)
1231{
1232 GVariant *answer;
1233 gchar **rv;
1234
1235 if (!proxy)
1236 return NULL;
1237
1238 answer = g_dbus_proxy_get_cached_property (proxy, property);
1239
1240 if (!answer)
1241 {
1242 g_warning ("Could not get accounts property %s", property);
1243 return NULL;
1244 }
1245
1246 if (!g_variant_is_of_type (answer, G_VARIANT_TYPE ("as")))
1247 {
1248 g_warning ("Unexpected accounts property type for %s: %s",
1249 property, g_variant_get_type_string (answer));
1250 g_variant_unref (answer);
1251 return NULL;
1252 }
1253
1254 rv = g_variant_dup_strv (answer, NULL);
1255
1256 g_variant_unref (answer);
1257 return rv;
1258}
1259
1260static gboolean
1261load_accounts_service (LightDMUser *user)
1262{
1263 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1264 LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
1265 UserAccountObject *account = NULL;
1266 GList *iter;
1267 gchar **value;
1268
1269 /* First, find AccountObject proxy */
1270 for (iter = list_priv->user_account_objects; iter; iter = iter->next)
1271 {
1272 UserAccountObject *a = iter->data;
1273 if (a->user == user)
1274 {
1275 account = a;
1276 break;
1277 }
1278 }
1279 if (!account)
1280 return FALSE;
1281
1282 /* We have proxy, let's grab some properties */
1283 if (priv->language)
1284 g_free (priv->language);
1285 priv->language = get_string_property (account->proxy, "Language");
1286 if (priv->session)
1287 g_free (priv->session);
1288 priv->session = get_string_property (account->proxy, "XSession");
1289
1290 value = get_string_array_property (account->proxy, "XKeyboardLayouts");
1291 if (value)
1292 {
1293 if (value[0])
1294 {
1295 g_strfreev (priv->layouts);
1296 priv->layouts = value;
1297 }
1298 else
1299 g_strfreev (value);
1300 }
1301
1302 priv->has_messages = get_boolean_property (account->proxy, "XHasMessages");
1303
1304 return TRUE;
1305}
1306
1307/* Loads language/layout/session info for user */
1308static void
1309load_user_values (LightDMUser *user)
1310{
1311 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1312
1313 load_dmrc (user);
1314 load_accounts_service (user); // overrides dmrc values
1315
1316 /* Ensure a few guarantees */
1317 if (priv->layouts == NULL)
1318 {
1319 priv->layouts = g_malloc (sizeof (gchar *) * 1);
1320 priv->layouts[0] = NULL;
1321 }
1322}
1323
1324/**
1325 * lightdm_user_get_language:
1326 * @user: A #LightDMUser
1327 *
1328 * Get the language for a user.
1329 *
1330 * Return value: The language for the given user or #NULL if using system defaults.
1331 **/
1332const gchar *
1333lightdm_user_get_language (LightDMUser *user)
1334{
1335 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1336 load_user_values (user);
1337 return GET_USER_PRIVATE (user)->language;
1338}
1339
1340/**
1341 * lightdm_user_get_layout:
1342 * @user: A #LightDMUser
1343 *
1344 * Get the keyboard layout for a user.
1345 *
1346 * Return value: The keyboard layout for the given user or #NULL if using system defaults. Copy the value if you want to use it long term.
1347 **/
1348const gchar *
1349lightdm_user_get_layout (LightDMUser *user)
1350{
1351 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1352 load_user_values (user);
1353 return GET_USER_PRIVATE (user)->layouts[0];
1354}
1355
1356/**
1357 * lightdm_user_get_layouts:
1358 * @user: A #LightDMUser
1359 *
1360 * Get the configured keyboard layouts for a user.
1361 *
1362 * Return value: (transfer none): A NULL-terminated array of keyboard layouts for the given user. Copy the values if you want to use them long term.
1363 **/
1364const gchar * const *
1365lightdm_user_get_layouts (LightDMUser *user)
1366{
1367 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1368 load_user_values (user);
1369 return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
1370}
1371
1372/**
1373 * lightdm_user_get_session:
1374 * @user: A #LightDMUser
1375 *
1376 * Get the session for a user.
1377 *
1378 * Return value: The session for the given user or #NULL if using system defaults.
1379 **/
1380const gchar *
1381lightdm_user_get_session (LightDMUser *user)
1382{
1383 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1384 load_user_values (user);
1385 return GET_USER_PRIVATE (user)->session;
1386}
1387
1388/**
1389 * lightdm_user_get_logged_in:
1390 * @user: A #LightDMUser
1391 *
1392 * Check if a user is logged in.
1393 *
1394 * Return value: #TRUE if the user is currently logged in.
1395 **/
1396gboolean
1397lightdm_user_get_logged_in (LightDMUser *user)
1398{
1399 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1400 LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
1401 GList *link;
1402
1403 g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1404
1405 for (link = list_priv->sessions; link; link = link->next)
1406 {
1407 Session *session = link->data;
1408 if (strcmp (session->username, priv->name) == 0)
1409 return TRUE;
1410 }
1411
1412 return FALSE;
1413}
1414
1415/**
1416 * lightdm_user_get_has_messages:
1417 * @user: A #LightDMUser
1418 *
1419 * Check if a user has waiting messages.
1420 *
1421 * Return value: #TRUE if the user has waiting messages.
1422 **/
1423gboolean
1424lightdm_user_get_has_messages (LightDMUser *user)
1425{
1426 g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1427 load_user_values (user);
1428 return GET_USER_PRIVATE (user)->has_messages;
1429}
1430
1431static void
1432lightdm_user_init (LightDMUser *user)
1433{
1434}
1435
1436static void
1437lightdm_user_set_property (GObject *object,
1438 guint prop_id,
1439 const GValue *value,
1440 GParamSpec *pspec)
1441{
1442 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1443}
1444
1445static void
1446lightdm_user_get_property (GObject *object,
1447 guint prop_id,
1448 GValue *value,
1449 GParamSpec *pspec)
1450{
1451 LightDMUser *self;
1452
1453 self = LIGHTDM_USER (object);
1454
1455 switch (prop_id)
1456 {
1457 case USER_PROP_NAME:
1458 g_value_set_string (value, lightdm_user_get_name (self));
1459 break;
1460 case USER_PROP_REAL_NAME:
1461 g_value_set_string (value, lightdm_user_get_real_name (self));
1462 break;
1463 case USER_PROP_DISPLAY_NAME:
1464 g_value_set_string (value, lightdm_user_get_display_name (self));
1465 break;
1466 case USER_PROP_HOME_DIRECTORY:
1467 g_value_set_string (value, lightdm_user_get_home_directory (self));
1468 break;
1469 case USER_PROP_IMAGE:
1470 g_value_set_string (value, lightdm_user_get_image (self));
1471 break;
1472 case USER_PROP_BACKGROUND:
1473 g_value_set_string (value, lightdm_user_get_background (self));
1474 break;
1475 case USER_PROP_LANGUAGE:
1476 g_value_set_string (value, lightdm_user_get_language (self));
1477 break;
1478 case USER_PROP_LAYOUT:
1479 g_value_set_string (value, lightdm_user_get_layout (self));
1480 break;
1481 case USER_PROP_LAYOUTS:
1482 g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self)));
1483 break;
1484 case USER_PROP_SESSION:
1485 g_value_set_string (value, lightdm_user_get_session (self));
1486 break;
1487 case USER_PROP_LOGGED_IN:
1488 g_value_set_boolean (value, lightdm_user_get_logged_in (self));
1489 break;
1490 case USER_PROP_HAS_MESSAGES:
1491 g_value_set_boolean (value, lightdm_user_get_has_messages (self));
1492 break;
1493 default:
1494 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1495 break;
1496 }
1497}
1498
1499static void
1500lightdm_user_finalize (GObject *object)
1501{
1502 LightDMUser *self = LIGHTDM_USER (object);
1503 LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
1504
1505 g_free (priv->name);
1506 g_free (priv->real_name);
1507 g_free (priv->home_directory);
1508 g_free (priv->image);
1509 g_free (priv->background);
1510 g_strfreev (priv->layouts);
1511 if (priv->dmrc_file)
1512 g_key_file_free (priv->dmrc_file);
1513}
1514
1515static void
1516lightdm_user_class_init (LightDMUserClass *klass)
1517{
1518 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1519
1520 g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
1521
1522 object_class->set_property = lightdm_user_set_property;
1523 object_class->get_property = lightdm_user_get_property;
1524 object_class->finalize = lightdm_user_finalize;
1525
1526 g_object_class_install_property (object_class,
1527 USER_PROP_NAME,
1528 g_param_spec_string ("name",
1529 "name",
1530 "Username",
1531 NULL,
1532 G_PARAM_READWRITE));
1533 g_object_class_install_property (object_class,
1534 USER_PROP_REAL_NAME,
1535 g_param_spec_string ("real-name",
1536 "real-name",
1537 "Users real name",
1538 NULL,
1539 G_PARAM_READWRITE));
1540 g_object_class_install_property (object_class,
1541 USER_PROP_DISPLAY_NAME,
1542 g_param_spec_string ("display-name",
1543 "display-name",
1544 "Users display name",
1545 NULL,
1546 G_PARAM_READABLE));
1547 g_object_class_install_property (object_class,
1548 USER_PROP_HOME_DIRECTORY,
1549 g_param_spec_string ("home-directory",
1550 "home-directory",
1551 "Home directory",
1552 NULL,
1553 G_PARAM_READWRITE));
1554 g_object_class_install_property (object_class,
1555 USER_PROP_IMAGE,
1556 g_param_spec_string ("image",
1557 "image",
1558 "Avatar image",
1559 NULL,
1560 G_PARAM_READWRITE));
1561 g_object_class_install_property (object_class,
1562 USER_PROP_BACKGROUND,
1563 g_param_spec_string ("background",
1564 "background",
1565 "User background",
1566 NULL,
1567 G_PARAM_READWRITE));
1568 g_object_class_install_property (object_class,
1569 USER_PROP_LANGUAGE,
1570 g_param_spec_string ("language",
1571 "language",
1572 "Language used by this user",
1573 NULL,
1574 G_PARAM_READABLE));
1575 g_object_class_install_property (object_class,
1576 USER_PROP_LAYOUT,
1577 g_param_spec_string ("layout",
1578 "layout",
1579 "Keyboard layout used by this user",
1580 NULL,
1581 G_PARAM_READABLE));
1582 g_object_class_install_property (object_class,
1583 USER_PROP_LAYOUTS,
1584 g_param_spec_boxed ("layouts",
1585 "layouts",
1586 "Keyboard layouts used by this user",
1587 G_TYPE_STRV,
1588 G_PARAM_READABLE));
1589 g_object_class_install_property (object_class,
1590 USER_PROP_SESSION,
1591 g_param_spec_string ("session",
1592 "session",
1593 "Session used by this user",
1594 NULL,
1595 G_PARAM_READABLE));
1596 g_object_class_install_property (object_class,
1597 USER_PROP_LOGGED_IN,
1598 g_param_spec_boolean ("logged-in",
1599 "logged-in",
1600 "TRUE if the user is currently in a session",
1601 FALSE,
1602 G_PARAM_READWRITE));
1603 g_object_class_install_property (object_class,
1604 USER_PROP_LOGGED_IN,
1605 g_param_spec_boolean ("has-messages",
1606 "has-messages",
1607 "TRUE if the user is has waiting messages",
1608 FALSE,
1609 G_PARAM_READWRITE));
1610
1611 /**
1612 * LightDMUser::changed:
1613 * @user: A #LightDMUser
1614 *
1615 * The ::changed signal gets emitted this user account is modified.
1616 **/
1617 user_signals[CHANGED] =
1618 g_signal_new ("changed",
1619 G_TYPE_FROM_CLASS (klass),
1620 G_SIGNAL_RUN_LAST,
1621 G_STRUCT_OFFSET (LightDMUserClass, changed),
1622 NULL, NULL,
1623 g_cclosure_marshal_VOID__VOID,
1624 G_TYPE_NONE, 0);
1625}
1626
1627static void
1628session_init (Session *session)
1629{
1630}
1631
1632static void
1633session_finalize (GObject *object)
1634{
1635 Session *self = SESSION (object);
1636
1637 g_free (self->path);
1638 g_free (self->username);
1639}
1640
1641static void
1642session_class_init (SessionClass *klass)
1643{
1644 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1645 object_class->finalize = session_finalize;
1646}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette