VirtualBox

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

最後變更 在這個檔案從82968是 69506,由 vboxsync 提交於 7 年 前

More scm updates

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

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