2 * Copyright (C) 2010 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
5 * This library is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License as published by the Free
7 * Software Foundation; either version 3 of the License, or (at your option) any
8 * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
16 #include <sys/utsname.h>
20 #include "lightdm/user.h"
32 USER_PROP_DISPLAY_NAME,
33 USER_PROP_HOME_DIRECTORY,
47 static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
53 static guint user_signals[LAST_USER_SIGNAL] = { 0 };
57 /* Connection to AccountsService */
58 GDBusProxy *accounts_service_proxy;
59 GList *user_account_objects;
61 /* Connection to DisplayManager */
62 GDBusProxy *display_manager_proxy;
64 /* File monitor for password file */
65 GFileMonitor *passwd_monitor;
67 /* TRUE if have scanned users */
73 /* List of sessions */
75 } LightDMUserListPrivate;
85 LightDMUserList *user_list;
89 gchar *home_directory;
100 GObject parent_instance;
107 GObjectClass parent_class;
110 G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
111 G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
112 #define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
113 GType session_get_type (void);
114 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
116 #define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
117 #define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
119 #define PASSWD_FILE "/etc/passwd"
120 #define USER_CONFIG_FILE "/etc/lightdm/users.conf"
122 static LightDMUserList *singleton = NULL;
125 * lightdm_user_list_get_instance:
129 * Return value: (tranfer none): the #LightDMUserList
132 lightdm_user_list_get_instance (void)
135 singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
140 get_user_by_name (LightDMUserList *user_list, const gchar *username)
142 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
145 for (link = priv->users; link; link = link->next)
147 LightDMUser *user = link->data;
148 if (strcmp (lightdm_user_get_name (user), username) == 0)
156 compare_user (gconstpointer a, gconstpointer b)
158 LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
159 return strcmp (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
163 update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
165 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
167 if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
168 g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
169 g_strcmp0 (lightdm_user_get_image (user), image) == 0)
172 g_free (priv->real_name);
173 priv->real_name = g_strdup (real_name);
174 g_free (priv->home_directory);
175 priv->home_directory = g_strdup (home_directory);
176 g_free (priv->image);
177 priv->image = g_strdup (image);
183 user_changed_cb (LightDMUser *user, LightDMUserList *user_list)
185 g_signal_emit (user_list, list_signals[USER_CHANGED], 0, user);
189 load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
191 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
195 gchar **hidden_users, **hidden_shells;
196 GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
197 GError *error = NULL;
199 g_debug ("Loading user config from %s", USER_CONFIG_FILE);
201 config = g_key_file_new ();
202 if (!g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error) &&
203 !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
204 g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info
205 g_clear_error (&error);
207 if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
208 minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
212 value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
214 value = g_strdup ("nobody nobody4 noaccess");
215 hidden_users = g_strsplit (value, " ", -1);
218 value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
220 value = g_strdup ("/bin/false /usr/sbin/nologin");
221 hidden_shells = g_strsplit (value, " ", -1);
224 g_key_file_free (config);
230 struct passwd *entry;
232 LightDMUserPrivate *user_priv;
234 gchar *real_name, *image;
242 /* Ignore system users */
243 if (entry->pw_uid < minimum_uid)
246 /* Ignore users disabled by shell */
249 for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
250 if (hidden_shells[i])
254 /* Ignore certain users */
255 for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
259 tokens = g_strsplit (entry->pw_gecos, ",", -1);
260 if (tokens[0] != NULL && tokens[0][0] != '\0')
261 real_name = g_strdup (tokens[0]);
263 real_name = g_strdup ("");
266 image = g_build_filename (entry->pw_dir, ".face", NULL);
267 if (!g_file_test (image, G_FILE_TEST_EXISTS))
270 image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
271 if (!g_file_test (image, G_FILE_TEST_EXISTS))
278 user = g_object_new (LIGHTDM_TYPE_USER, NULL);
279 user_priv = GET_USER_PRIVATE (user);
280 user_priv->user_list = user_list;
281 g_free (user_priv->name);
282 user_priv->name = g_strdup (entry->pw_name);
283 g_free (user_priv->real_name);
284 user_priv->real_name = real_name;
285 g_free (user_priv->home_directory);
286 user_priv->home_directory = g_strdup (entry->pw_dir);
287 g_free (user_priv->image);
288 user_priv->image = image;
290 /* Update existing users if have them */
291 for (link = priv->users; link; link = link->next)
293 LightDMUser *info = link->data;
294 if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
296 if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
297 changed_users = g_list_insert_sorted (changed_users, info, compare_user);
298 g_object_unref (user);
305 /* Only notify once we have loaded the user list */
306 if (priv->have_users)
307 new_users = g_list_insert_sorted (new_users, user, compare_user);
309 users = g_list_insert_sorted (users, user, compare_user);
311 g_strfreev (hidden_users);
312 g_strfreev (hidden_shells);
315 g_warning ("Failed to read password database: %s", strerror (errno));
319 /* Use new user list */
320 old_users = priv->users;
323 /* Notify of changes */
324 for (link = new_users; link; link = link->next)
326 LightDMUser *info = link->data;
327 g_debug ("User %s added", lightdm_user_get_name (info));
328 g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), user_list);
330 g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
332 g_list_free (new_users);
333 for (link = changed_users; link; link = link->next)
335 LightDMUser *info = link->data;
336 g_debug ("User %s changed", lightdm_user_get_name (info));
337 g_signal_emit (info, user_signals[CHANGED], 0);
339 g_list_free (changed_users);
340 for (link = old_users; link; link = link->next)
344 /* See if this user is in the current list */
345 for (new_link = priv->users; new_link; new_link = new_link->next)
347 if (new_link->data == link->data)
353 LightDMUser *info = link->data;
354 g_debug ("User %s removed", lightdm_user_get_name (info));
355 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
356 g_object_unref (info);
359 g_list_free (old_users);
363 passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
365 if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
367 g_debug ("%s changed, reloading user list", g_file_get_path (file));
368 load_passwd_file (user_list, TRUE);
373 update_user (UserAccountObject *object)
375 LightDMUserPrivate *priv = GET_USER_PRIVATE (object->user);
376 GVariant *result, *value;
379 GError *error = NULL;
381 result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (object->proxy),
382 "org.freedesktop.Accounts",
383 g_dbus_proxy_get_object_path (object->proxy),
384 "org.freedesktop.DBus.Properties",
386 g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
387 G_VARIANT_TYPE ("(a{sv})"),
388 G_DBUS_CALL_FLAGS_NONE,
393 g_warning ("Error updating user %s: %s", g_dbus_proxy_get_object_path (object->proxy), error->message);
394 g_clear_error (&error);
398 g_variant_get (result, "(a{sv})", &iter);
399 while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
401 if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
404 g_variant_get (value, "&s", &user_name);
406 priv->name = g_strdup (user_name);
408 else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
411 g_variant_get (value, "&s", &real_name);
412 g_free (priv->real_name);
413 priv->real_name = g_strdup (real_name);
415 else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
417 gchar *home_directory;
418 g_variant_get (value, "&s", &home_directory);
419 g_free (priv->home_directory);
420 priv->home_directory = g_strdup (home_directory);
422 else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
425 g_variant_get (value, "&s", &icon_file);
426 g_free (priv->image);
427 if (strcmp (icon_file, "") == 0)
430 priv->image = g_strdup (icon_file);
433 g_variant_iter_free (iter);
435 g_variant_unref (result);
441 user_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, UserAccountObject *object)
443 if (strcmp (signal_name, "Changed") == 0)
445 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
447 g_debug ("User %s changed", g_dbus_proxy_get_object_path (object->proxy));
448 update_user (object);
449 g_signal_emit (object->user, user_signals[CHANGED], 0);
452 g_warning ("Got org.freedesktop.Accounts.User signal Changed with unknown parameters %s", g_variant_get_type_string (parameters));
456 static UserAccountObject *
457 user_account_object_new (LightDMUserList *user_list, const gchar *path)
460 UserAccountObject *object;
461 GError *error = NULL;
463 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
464 G_DBUS_PROXY_FLAGS_NONE,
466 "org.freedesktop.Accounts",
468 "org.freedesktop.Accounts.User",
472 g_warning ("Error getting user %s: %s", path, error->message);
473 g_clear_error (&error);
477 object = g_malloc0 (sizeof (UserAccountObject));
478 object->user = g_object_new (LIGHTDM_TYPE_USER, NULL);
479 GET_USER_PRIVATE (object->user)->user_list = user_list;
480 object->proxy = proxy;
481 g_signal_connect (proxy, "g-signal", G_CALLBACK (user_signal_cb), object);
487 user_account_object_free (UserAccountObject *object)
491 g_object_unref (object->user);
492 g_object_unref (object->proxy);
496 static UserAccountObject *
497 find_user_account_object (LightDMUserList *user_list, const gchar *path)
499 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
502 for (link = priv->user_account_objects; link; link = link->next)
504 UserAccountObject *object = link->data;
505 if (strcmp (g_dbus_proxy_get_object_path (object->proxy), path) == 0)
513 user_accounts_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
515 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
517 if (strcmp (signal_name, "UserAdded") == 0)
519 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
522 UserAccountObject *object;
524 g_variant_get (parameters, "(&o)", &path);
526 /* Ignore duplicate requests */
527 object = find_user_account_object (user_list, path);
531 object = user_account_object_new (user_list, path);
532 if (object && update_user (object))
534 g_debug ("User %s added", path);
535 priv->user_account_objects = g_list_append (priv->user_account_objects, object);
536 priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
537 g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
538 g_signal_emit (user_list, list_signals[USER_ADDED], 0, object->user);
541 user_account_object_free (object);
544 g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
546 else if (strcmp (signal_name, "UserDeleted") == 0)
548 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
551 UserAccountObject *object;
553 g_variant_get (parameters, "(&o)", &path);
555 object = find_user_account_object (user_list, path);
559 g_debug ("User %s deleted", path);
560 priv->users = g_list_remove (priv->users, object->user);
561 g_object_unref (object->user);
563 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, object->user);
565 priv->user_account_objects = g_list_remove (priv->user_account_objects, object);
566 user_account_object_free (object);
569 g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
574 load_session (LightDMUserList *user_list, const gchar *path)
576 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
577 Session *session = NULL;
578 GVariant *result, *username;
579 GError *error = NULL;
581 result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
582 "org.freedesktop.DisplayManager",
584 "org.freedesktop.DBus.Properties",
586 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
587 G_VARIANT_TYPE ("(v)"),
588 G_DBUS_CALL_FLAGS_NONE,
593 g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
594 g_clear_error (&error);
598 g_variant_get (result, "(v)", &username);
599 if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
603 g_variant_get (username, "&s", &name);
605 g_debug ("Loaded session %s (%s)", path, name);
606 session = g_object_new (session_get_type (), NULL);
607 session->username = g_strdup (name);
608 session->path = g_strdup (path);
609 priv->sessions = g_list_append (priv->sessions, session);
611 g_variant_unref (username);
612 g_variant_unref (result);
618 display_manager_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
620 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
622 if (strcmp (signal_name, "SessionAdded") == 0)
624 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
628 LightDMUser *user = NULL;
630 g_variant_get (parameters, "(&o)", &path);
631 session = load_session (user_list, path);
633 user = get_user_by_name (user_list, session->username);
635 g_signal_emit (user, user_signals[CHANGED], 0);
638 else if (strcmp (signal_name, "SessionRemoved") == 0)
640 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
645 g_variant_get (parameters, "(&o)", &path);
647 for (link = priv->sessions; link; link = link->next)
649 Session *session = link->data;
650 if (strcmp (session->path, path) == 0)
654 g_debug ("Session %s removed", path);
655 priv->sessions = g_list_remove_link (priv->sessions, link);
656 user = get_user_by_name (user_list, session->username);
658 g_signal_emit (user, user_signals[CHANGED], 0);
659 g_object_unref (session);
668 update_users (LightDMUserList *user_list)
670 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
671 GError *error = NULL;
673 if (priv->have_users)
675 priv->have_users = TRUE;
677 priv->accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
678 G_DBUS_PROXY_FLAGS_NONE,
680 "org.freedesktop.Accounts",
681 "/org/freedesktop/Accounts",
682 "org.freedesktop.Accounts",
685 if (!priv->accounts_service_proxy)
686 g_warning ("Error contacting org.freedesktop.Accounts: %s", error->message);
687 g_clear_error (&error);
689 /* Check if the service exists */
690 if (priv->accounts_service_proxy)
694 name = g_dbus_proxy_get_name_owner (priv->accounts_service_proxy);
697 g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file");
698 g_object_unref (priv->accounts_service_proxy);
699 priv->accounts_service_proxy = NULL;
704 if (priv->accounts_service_proxy)
708 g_signal_connect (priv->accounts_service_proxy, "g-signal", G_CALLBACK (user_accounts_signal_cb), user_list);
710 result = g_dbus_proxy_call_sync (priv->accounts_service_proxy,
712 g_variant_new ("()"),
713 G_DBUS_CALL_FLAGS_NONE,
718 g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
719 g_clear_error (&error);
723 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(ao)")))
728 g_debug ("Loading users from org.freedesktop.Accounts");
729 g_variant_get (result, "(ao)", &iter);
730 while (g_variant_iter_loop (iter, "&o", &path))
732 UserAccountObject *object;
734 g_debug ("Loading user %s", path);
736 object = user_account_object_new (user_list, path);
737 if (object && update_user (object))
739 priv->user_account_objects = g_list_append (priv->user_account_objects, object);
740 priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
741 g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
744 user_account_object_free (object);
746 g_variant_iter_free (iter);
749 g_warning ("Unexpected type from ListCachedUsers: %s", g_variant_get_type_string (result));
751 g_variant_unref (result);
757 load_passwd_file (user_list, FALSE);
759 /* Watch for changes to user list */
760 passwd_file = g_file_new_for_path (PASSWD_FILE);
761 priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
762 g_object_unref (passwd_file);
763 if (!priv->passwd_monitor)
764 g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
766 g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
767 g_clear_error (&error);
770 priv->display_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
771 G_DBUS_PROXY_FLAGS_NONE,
773 "org.freedesktop.DisplayManager",
774 "/org/freedesktop/DisplayManager",
775 "org.freedesktop.DisplayManager",
778 if (!priv->display_manager_proxy)
779 g_warning ("Error contacting org.freedesktop.DisplayManager: %s", error->message);
780 g_clear_error (&error);
782 if (priv->display_manager_proxy)
786 g_signal_connect (priv->display_manager_proxy, "g-signal", G_CALLBACK (display_manager_signal_cb), user_list);
788 result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
789 "org.freedesktop.DisplayManager",
790 "/org/freedesktop/DisplayManager",
791 "org.freedesktop.DBus.Properties",
793 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
794 G_VARIANT_TYPE ("(v)"),
795 G_DBUS_CALL_FLAGS_NONE,
800 g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
801 g_clear_error (&error);
805 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
811 g_variant_get (result, "(v)", &value);
813 g_debug ("Loading sessions from org.freedesktop.DisplayManager");
814 g_variant_get (value, "ao", &iter);
815 while (g_variant_iter_loop (iter, "&o", &path))
816 load_session (user_list, path);
817 g_variant_iter_free (iter);
819 g_variant_unref (value);
822 g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
824 g_variant_unref (result);
829 * lightdm_user_list_get_length:
830 * @user_list: a #LightDMUserList
832 * Return value: The number of users able to log in
835 lightdm_user_list_get_length (LightDMUserList *user_list)
837 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
838 update_users (user_list);
839 return g_list_length (GET_LIST_PRIVATE (user_list)->users);
843 * lightdm_user_list_get_users:
844 * @user_list: A #LightDMUserList
846 * Get a list of users to present to the user. This list may be a subset of the
847 * available users and may be empty depending on the server configuration.
849 * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user.
852 lightdm_user_list_get_users (LightDMUserList *user_list)
854 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
855 update_users (user_list);
856 return GET_LIST_PRIVATE (user_list)->users;
860 * lightdm_user_list_get_user_by_name:
861 * @user_list: A #LightDMUserList
862 * @username: Name of user to get.
864 * Get infomation about a given user or #NULL if this user doesn't exist.
866 * Return value: (transfer none): A #LightDMUser entry for the given user.
869 lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
871 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
872 g_return_val_if_fail (username != NULL, NULL);
874 update_users (user_list);
876 return get_user_by_name (user_list, username);
880 lightdm_user_list_init (LightDMUserList *user_list)
885 lightdm_user_list_set_property (GObject *object,
890 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
894 lightdm_user_list_get_property (GObject *object,
899 LightDMUserList *self;
901 self = LIGHTDM_USER_LIST (object);
904 case LIST_PROP_NUM_USERS:
905 g_value_set_int (value, lightdm_user_list_get_length (self));
908 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
914 lightdm_user_list_finalize (GObject *object)
916 LightDMUserList *self = LIGHTDM_USER_LIST (object);
917 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
919 if (priv->accounts_service_proxy)
920 g_object_unref (priv->accounts_service_proxy);
921 g_list_free_full (priv->user_account_objects, (GDestroyNotify) user_account_object_free);
922 if (priv->passwd_monitor)
923 g_object_unref (priv->passwd_monitor);
924 g_list_free_full (priv->users, g_object_unref);
925 g_list_free_full (priv->sessions, g_object_unref);
927 G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
931 lightdm_user_list_class_init (LightDMUserListClass *klass)
933 GObjectClass *object_class = G_OBJECT_CLASS (klass);
935 g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
937 object_class->set_property = lightdm_user_list_set_property;
938 object_class->get_property = lightdm_user_list_get_property;
939 object_class->finalize = lightdm_user_list_finalize;
941 g_object_class_install_property (object_class,
943 g_param_spec_int ("num-users",
945 "Number of login users",
949 * LightDMUserList::user-added:
950 * @user_list: A #LightDMUserList
951 * @user: The #LightDM user that has been added.
953 * The ::user-added signal gets emitted when a user account is created.
955 list_signals[USER_ADDED] =
956 g_signal_new ("user-added",
957 G_TYPE_FROM_CLASS (klass),
959 G_STRUCT_OFFSET (LightDMUserListClass, user_added),
961 g_cclosure_marshal_VOID__OBJECT,
962 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
965 * LightDMUserList::user-changed:
966 * @user_list: A #LightDMUserList
967 * @user: The #LightDM user that has been changed.
969 * The ::user-changed signal gets emitted when a user account is modified.
971 list_signals[USER_CHANGED] =
972 g_signal_new ("user-changed",
973 G_TYPE_FROM_CLASS (klass),
975 G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
977 g_cclosure_marshal_VOID__OBJECT,
978 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
981 * LightDMUserList::user-removed:
982 * @user_list: A #LightDMUserList
983 * @user: The #LightDM user that has been removed.
985 * The ::user-removed signal gets emitted when a user account is removed.
987 list_signals[USER_REMOVED] =
988 g_signal_new ("user-removed",
989 G_TYPE_FROM_CLASS (klass),
991 G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
993 g_cclosure_marshal_VOID__OBJECT,
994 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
998 * lightdm_user_get_name:
999 * @user: A #LightDMUser
1001 * Get the name of a user.
1003 * Return value: The name of the given user
1006 lightdm_user_get_name (LightDMUser *user)
1008 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1009 return GET_USER_PRIVATE (user)->name;
1013 * lightdm_user_get_real_name:
1014 * @user: A #LightDMUser
1016 * Get the real name of a user.
1018 * Return value: The real name of the given user
1021 lightdm_user_get_real_name (LightDMUser *user)
1023 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1024 return GET_USER_PRIVATE (user)->real_name;
1028 * lightdm_user_get_display_name:
1029 * @user: A #LightDMUser
1031 * Get the display name of a user.
1033 * Return value: The display name of the given user
1036 lightdm_user_get_display_name (LightDMUser *user)
1038 LightDMUserPrivate *priv;
1040 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1042 priv = GET_USER_PRIVATE (user);
1043 if (strcmp (priv->real_name, ""))
1044 return priv->real_name;
1050 * lightdm_user_get_home_directory:
1051 * @user: A #LightDMUser
1053 * Get the home directory for a user.
1055 * Return value: The users home directory
1058 lightdm_user_get_home_directory (LightDMUser *user)
1060 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1061 return GET_USER_PRIVATE (user)->home_directory;
1065 * lightdm_user_get_image:
1066 * @user: A #LightDMUser
1068 * Get the image URI for a user.
1070 * Return value: The image URI for the given user or #NULL if no URI
1073 lightdm_user_get_image (LightDMUser *user)
1075 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1076 return GET_USER_PRIVATE (user)->image;
1080 load_dmrc (LightDMUser *user)
1082 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1084 //gboolean have_dmrc;
1086 priv->dmrc_file = g_key_file_new ();
1088 /* Load from the user directory */
1089 path = g_build_filename (priv->home_directory, ".dmrc", NULL);
1090 /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
1093 /* If no ~/.dmrc, then load from the cache */
1096 // FIXME: Watch for changes
1099 g_free (priv->language);
1101 g_free (priv->layout);
1103 g_free (priv->session);
1105 priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
1106 priv->layout = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
1107 priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
1111 get_string_property (GDBusProxy *proxy, const gchar *property)
1119 answer = g_dbus_proxy_get_cached_property (proxy, property);
1122 g_warning ("Could not get accounts property %s", property);
1126 if (!g_variant_is_of_type (answer, G_VARIANT_TYPE ("s"))) {
1127 g_warning ("Unexpected accounts property type for %s: %s",
1128 property, g_variant_get_type_string (answer));
1129 g_variant_unref (answer);
1133 g_variant_get (answer, "s", &rv);
1135 g_variant_unref (answer);
1140 load_accounts_service (LightDMUser *user)
1142 // First, find AccountObject proxy
1143 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1144 LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
1146 UserAccountObject *account = NULL;
1148 for (iter = list_priv->user_account_objects; iter; iter = iter->next) {
1149 if (((UserAccountObject *)iter->data)->user == user) {
1150 account = (UserAccountObject *)iter->data;
1157 // We have proxy, let's grab some properties
1159 g_free (priv->language);
1161 g_free (priv->session);
1162 priv->language = get_string_property (account->proxy, "Language");
1163 priv->session = get_string_property (account->proxy, "XSession");
1166 /* Loads language/layout/session info for user */
1168 load_user_values (LightDMUser *user)
1171 load_accounts_service (user); // overrides dmrc values
1175 * lightdm_user_get_language
1176 * @user: A #LightDMUser
1178 * Get the language for a user.
1180 * Return value: The language for the given user or #NULL if using system defaults.
1183 lightdm_user_get_language (LightDMUser *user)
1185 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1186 load_user_values (user);
1187 return GET_USER_PRIVATE (user)->language;
1191 * lightdm_user_get_layout
1192 * @user: A #LightDMUser
1194 * Get the keyboard layout for a user.
1196 * Return value: The keyboard layoyt for the given user or #NULL if using system defaults.
1199 lightdm_user_get_layout (LightDMUser *user)
1201 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1202 load_user_values (user);
1203 return GET_USER_PRIVATE (user)->layout;
1207 * lightdm_user_get_session
1208 * @user: A #LightDMUser
1210 * Get the session for a user.
1212 * Return value: The session for the given user or #NULL if using system defaults.
1215 lightdm_user_get_session (LightDMUser *user)
1217 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1218 load_user_values (user);
1219 return GET_USER_PRIVATE (user)->session;
1223 * lightdm_user_get_logged_in:
1224 * @user: A #LightDMUser
1226 * Check if a user is logged in.
1228 * Return value: #TRUE if the user is currently logged in.
1231 lightdm_user_get_logged_in (LightDMUser *user)
1233 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1234 LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
1237 g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1239 for (link = list_priv->sessions; link; link = link->next)
1241 Session *session = link->data;
1242 if (strcmp (session->username, priv->name) == 0)
1250 lightdm_user_init (LightDMUser *user)
1252 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1254 priv->name = g_strdup ("");
1255 priv->real_name = g_strdup ("");
1256 priv->home_directory = g_strdup ("");
1257 priv->image = g_strdup ("");
1258 priv->language = g_strdup ("");
1259 priv->layout = g_strdup ("");
1260 priv->session = g_strdup ("");
1264 lightdm_user_set_property (GObject *object,
1266 const GValue *value,
1269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1273 lightdm_user_get_property (GObject *object,
1280 self = LIGHTDM_USER (object);
1283 case USER_PROP_NAME:
1284 g_value_set_string (value, lightdm_user_get_name (self));
1286 case USER_PROP_REAL_NAME:
1287 g_value_set_string (value, lightdm_user_get_real_name (self));
1289 case USER_PROP_DISPLAY_NAME:
1290 g_value_set_string (value, lightdm_user_get_display_name (self));
1292 case USER_PROP_HOME_DIRECTORY:
1293 g_value_set_string (value, lightdm_user_get_home_directory (self));
1295 case USER_PROP_IMAGE:
1296 g_value_set_string (value, lightdm_user_get_image (self));
1298 case USER_PROP_LANGUAGE:
1299 g_value_set_string (value, lightdm_user_get_language (self));
1301 case USER_PROP_LAYOUT:
1302 g_value_set_string (value, lightdm_user_get_layout (self));
1304 case USER_PROP_SESSION:
1305 g_value_set_string (value, lightdm_user_get_session (self));
1307 case USER_PROP_LOGGED_IN:
1308 g_value_set_boolean (value, lightdm_user_get_logged_in (self));
1311 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1317 lightdm_user_finalize (GObject *object)
1319 LightDMUser *self = LIGHTDM_USER (object);
1320 LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
1322 g_free (priv->name);
1323 g_free (priv->real_name);
1324 g_free (priv->home_directory);
1325 g_free (priv->image);
1326 if (priv->dmrc_file)
1327 g_key_file_free (priv->dmrc_file);
1331 lightdm_user_class_init (LightDMUserClass *klass)
1333 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1335 g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
1337 object_class->set_property = lightdm_user_set_property;
1338 object_class->get_property = lightdm_user_get_property;
1339 object_class->finalize = lightdm_user_finalize;
1341 g_object_class_install_property (object_class,
1343 g_param_spec_string ("name",
1347 G_PARAM_READWRITE));
1348 g_object_class_install_property (object_class,
1349 USER_PROP_REAL_NAME,
1350 g_param_spec_string ("real-name",
1354 G_PARAM_READWRITE));
1355 g_object_class_install_property (object_class,
1356 USER_PROP_DISPLAY_NAME,
1357 g_param_spec_string ("display-name",
1359 "Users display name",
1362 g_object_class_install_property (object_class,
1363 USER_PROP_HOME_DIRECTORY,
1364 g_param_spec_string ("home-directory",
1368 G_PARAM_READWRITE));
1369 g_object_class_install_property (object_class,
1371 g_param_spec_string ("image",
1375 G_PARAM_READWRITE));
1376 g_object_class_install_property (object_class,
1378 g_param_spec_string ("language",
1380 "Language used by this user",
1383 g_object_class_install_property (object_class,
1385 g_param_spec_string ("layout",
1387 "Keyboard layout used by this user",
1390 g_object_class_install_property (object_class,
1392 g_param_spec_string ("session",
1394 "Session used by this user",
1397 g_object_class_install_property (object_class,
1398 USER_PROP_LOGGED_IN,
1399 g_param_spec_boolean ("logged-in",
1401 "TRUE if the user is currently in a session",
1403 G_PARAM_READWRITE));
1406 * LightDMUser::changed:
1407 * @user: A #LightDMUser
1409 * The ::changed signal gets emitted this user account is modified.
1411 user_signals[CHANGED] =
1412 g_signal_new ("changed",
1413 G_TYPE_FROM_CLASS (klass),
1415 G_STRUCT_OFFSET (LightDMUserClass, changed),
1417 g_cclosure_marshal_VOID__VOID,
1422 session_init (Session *session)
1427 session_finalize (GObject *object)
1429 Session *self = SESSION (object);
1431 g_free (self->path);
1432 g_free (self->username);
1436 session_class_init (SessionClass *klass)
1438 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1439 object_class->finalize = session_finalize;