summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Terry <michael.terry@canonical.com>2014-01-31 19:48:26 -0500
committerMichael Terry <michael.terry@canonical.com>2014-01-31 19:48:26 -0500
commitd5bf5930e9c60fb08c04904fe5befc7ca1a36aa9 (patch)
tree1e87fac150938623de915156c7f21aac51b4f40e
parentc444c0d53b3e15ded97b0de9beb3159ca4247833 (diff)
downloadlightdm-d5bf5930e9c60fb08c04904fe5befc7ca1a36aa9.tar.gz
Split core of user.c out into a sharable class
-rw-r--r--common/user-list.c1565
-rw-r--r--common/user-list.h98
-rw-r--r--liblightdm-gobject/Makefile.am1
-rw-r--r--liblightdm-gobject/user.c1025
4 files changed, 1763 insertions, 926 deletions
diff --git a/common/user-list.c b/common/user-list.c
new file mode 100644
index 00000000..58c96aca
--- /dev/null
+++ b/common/user-list.c
@@ -0,0 +1,1565 @@
+/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
+ *
+ * Copyright (C) 2010 Robert Ancell.
+ * Copyright (C) 2014 Canonical, Ltd.
+ * Authors: Robert Ancell <robert.ancell@canonical.com>
+ * Michael Terry <michael.terry@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <pwd.h>
+#include <gio/gio.h>
+
+#include "user-list.h"
+
+enum
+{
+ LIST_PROP_0,
+ LIST_PROP_NUM_USERS,
+ LIST_PROP_USERS,
+};
+
+enum
+{
+ USER_PROP_0,
+ USER_PROP_NAME,
+ USER_PROP_REAL_NAME,
+ USER_PROP_DISPLAY_NAME,
+ USER_PROP_HOME_DIRECTORY,
+ USER_PROP_IMAGE,
+ USER_PROP_BACKGROUND,
+ USER_PROP_LANGUAGE,
+ USER_PROP_LAYOUT,
+ USER_PROP_LAYOUTS,
+ USER_PROP_SESSION,
+ USER_PROP_LOGGED_IN,
+ USER_PROP_HAS_MESSAGES
+};
+
+enum
+{
+ USER_ADDED,
+ USER_CHANGED,
+ USER_REMOVED,
+ LAST_LIST_SIGNAL
+};
+static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
+
+enum
+{
+ CHANGED,
+ LAST_USER_SIGNAL
+};
+static guint user_signals[LAST_USER_SIGNAL] = { 0 };
+
+typedef struct
+{
+ /* Bus connection being communicated on */
+ GDBusConnection *bus;
+
+ /* D-Bus signals for accounts service events */
+ guint user_added_signal;
+ guint user_removed_signal;
+
+ /* D-Bus signals for display manager events */
+ guint session_added_signal;
+ guint session_removed_signal;
+
+ /* File monitor for password file */
+ GFileMonitor *passwd_monitor;
+
+ /* TRUE if have scanned users */
+ gboolean have_users;
+
+ /* List of users */
+ GList *users;
+
+ /* List of sessions */
+ GList *sessions;
+} CommonUserListPrivate;
+
+typedef struct
+{
+ /* User list this user is part of */
+ CommonUserList *user_list;
+
+ /* TRUE if have loaded user properties */
+ gboolean loaded_values;
+
+ /* Accounts service path */
+ gchar *path;
+
+ /* DMRC file */
+ GKeyFile *dmrc_file;
+
+ /* Update signal from accounts service */
+ guint changed_signal;
+
+ /* Username */
+ gchar *name;
+
+ /* Descriptive name for user */
+ gchar *real_name;
+
+ /* Home directory of user */
+ gchar *home_directory;
+
+ /* Image for user */
+ gchar *image;
+
+ /* Background image for users */
+ gchar *background;
+
+ /* TRUE if this user has messages available */
+ gboolean has_messages;
+
+ /* User chosen language */
+ gchar *language;
+
+ /* User layout preferences */
+ gchar **layouts;
+
+ /* User default session */
+ gchar *session;
+} CommonUserPrivate;
+
+typedef struct
+{
+ GObject parent_instance;
+ gchar *path;
+ gchar *username;
+} Session;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} SessionClass;
+
+G_DEFINE_TYPE (CommonUserList, common_user_list, G_TYPE_OBJECT);
+G_DEFINE_TYPE (CommonUser, common_user, G_TYPE_OBJECT);
+#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
+GType session_get_type (void);
+G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
+
+#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), COMMON_TYPE_USER_LIST, CommonUserListPrivate)
+#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), COMMON_TYPE_USER, CommonUserPrivate)
+
+#define PASSWD_FILE "/etc/passwd"
+#define USER_CONFIG_FILE "/etc/lightdm/users.conf"
+
+static CommonUserList *singleton = NULL;
+
+/**
+ * common_user_list_get_instance:
+ *
+ * Get the user list.
+ *
+ * Return value: (transfer none): the #CommonUserList
+ **/
+CommonUserList *
+common_user_list_get_instance (void)
+{
+ if (!singleton)
+ singleton = g_object_new (COMMON_TYPE_USER_LIST, NULL);
+ return singleton;
+}
+
+static CommonUser *
+get_user_by_name (CommonUserList *user_list, const gchar *username)
+{
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GList *link;
+
+ for (link = priv->users; link; link = link->next)
+ {
+ CommonUser *user = link->data;
+ if (g_strcmp0 (common_user_get_name (user), username) == 0)
+ return user;
+ }
+
+ return NULL;
+}
+
+static CommonUser *
+get_user_by_path (CommonUserList *user_list, const gchar *path)
+{
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GList *link;
+
+ for (link = priv->users; link; link = link->next)
+ {
+ CommonUser *user = link->data;
+ if (g_strcmp0 (GET_USER_PRIVATE (user)->path, path) == 0)
+ return user;
+ }
+
+ return NULL;
+}
+
+static gint
+compare_user (gconstpointer a, gconstpointer b)
+{
+ CommonUser *user_a = (CommonUser *) a, *user_b = (CommonUser *) b;
+ return g_strcmp0 (common_user_get_display_name (user_a), common_user_get_display_name (user_b));
+}
+
+static gboolean
+update_passwd_user (CommonUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
+{
+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
+
+ /* Skip if already set to this */
+ if (g_strcmp0 (common_user_get_real_name (user), real_name) == 0 &&
+ g_strcmp0 (common_user_get_home_directory (user), home_directory) == 0 &&
+ g_strcmp0 (common_user_get_image (user), image) == 0)
+ return FALSE;
+
+ g_free (priv->real_name);
+ priv->real_name = g_strdup (real_name);
+ g_free (priv->home_directory);
+ priv->home_directory = g_strdup (home_directory);
+ g_free (priv->image);
+ priv->image = g_strdup (image);
+
+ return TRUE;
+}
+
+static void
+user_changed_cb (CommonUser *user)
+{
+ g_signal_emit (GET_USER_PRIVATE (user)->user_list, list_signals[USER_CHANGED], 0, user);
+}
+
+static void
+load_passwd_file (CommonUserList *user_list, gboolean emit_add_signal)
+{
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GKeyFile *config;
+ gchar *value;
+ gint minimum_uid;
+ gchar **hidden_users, **hidden_shells;
+ GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
+ GError *error = NULL;
+
+ g_debug ("Loading user config from %s", USER_CONFIG_FILE);
+
+ config = g_key_file_new ();
+ g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error);
+ if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+ g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message);
+ g_clear_error (&error);
+
+ if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
+ minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
+ else
+ minimum_uid = 500;
+
+ value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
+ if (!value)
+ value = g_strdup ("nobody nobody4 noaccess");
+ hidden_users = g_strsplit (value, " ", -1);
+ g_free (value);
+
+ value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
+ if (!value)
+ value = g_strdup ("/bin/false /usr/sbin/nologin");
+ hidden_shells = g_strsplit (value, " ", -1);
+ g_free (value);
+
+ g_key_file_free (config);
+
+ setpwent ();
+
+ while (TRUE)
+ {
+ struct passwd *entry;
+ CommonUser *user;
+ CommonUserPrivate *user_priv;
+ char **tokens;
+ gchar *real_name, *image;
+ int i;
+
+ errno = 0;
+ entry = getpwent ();
+ if (!entry)
+ break;
+
+ /* Ignore system users */
+ if (entry->pw_uid < minimum_uid)
+ continue;
+
+ /* Ignore users disabled by shell */
+ if (entry->pw_shell)
+ {
+ for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
+ if (hidden_shells[i])
+ continue;
+ }
+
+ /* Ignore certain users */
+ for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
+ if (hidden_users[i])
+ continue;
+
+ tokens = g_strsplit (entry->pw_gecos, ",", -1);
+ if (tokens[0] != NULL && tokens[0][0] != '\0')
+ real_name = g_strdup (tokens[0]);
+ else
+ real_name = g_strdup ("");
+ g_strfreev (tokens);
+
+ image = g_build_filename (entry->pw_dir, ".face", NULL);
+ if (!g_file_test (image, G_FILE_TEST_EXISTS))
+ {
+ g_free (image);
+ image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
+ if (!g_file_test (image, G_FILE_TEST_EXISTS))
+ {
+ g_free (image);
+ image = NULL;
+ }
+ }
+
+ user = g_object_new (COMMON_TYPE_USER, NULL);
+ user_priv = GET_USER_PRIVATE (user);
+ user_priv->user_list = user_list;
+ g_free (user_priv->name);
+ user_priv->name = g_strdup (entry->pw_name);
+ g_free (user_priv->real_name);
+ user_priv->real_name = real_name;
+ g_free (user_priv->home_directory);
+ user_priv->home_directory = g_strdup (entry->pw_dir);
+ g_free (user_priv->image);
+ user_priv->image = image;
+
+ /* Update existing users if have them */
+ for (link = priv->users; link; link = link->next)
+ {
+ CommonUser *info = link->data;
+ if (strcmp (common_user_get_name (info), common_user_get_name (user)) == 0)
+ {
+ if (update_passwd_user (info, common_user_get_real_name (user), common_user_get_home_directory (user), common_user_get_image (user)))
+ changed_users = g_list_insert_sorted (changed_users, info, compare_user);
+ g_object_unref (user);
+ user = info;
+ break;
+ }
+ }
+ if (!link)
+ {
+ /* Only notify once we have loaded the user list */
+ if (priv->have_users)
+ new_users = g_list_insert_sorted (new_users, user, compare_user);
+ }
+ users = g_list_insert_sorted (users, user, compare_user);
+ }
+ g_strfreev (hidden_users);
+ g_strfreev (hidden_shells);
+
+ if (errno != 0)
+ g_warning ("Failed to read password database: %s", strerror (errno));
+
+ endpwent ();
+
+ /* Use new user list */
+ old_users = priv->users;
+ priv->users = users;
+
+ /* Notify of changes */
+ for (link = new_users; link; link = link->next)
+ {
+ CommonUser *info = link->data;
+ g_debug ("User %s added", common_user_get_name (info));
+ g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), NULL);
+ if (emit_add_signal)
+ g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
+ }
+ g_list_free (new_users);
+ for (link = changed_users; link; link = link->next)
+ {
+ CommonUser *info = link->data;
+ g_debug ("User %s changed", common_user_get_name (info));
+ g_signal_emit (info, user_signals[CHANGED], 0);
+ }
+ g_list_free (changed_users);
+ for (link = old_users; link; link = link->next)
+ {
+ GList *new_link;
+
+ /* See if this user is in the current list */
+ for (new_link = priv->users; new_link; new_link = new_link->next)
+ {
+ if (new_link->data == link->data)
+ break;
+ }
+
+ if (!new_link)
+ {
+ CommonUser *info = link->data;
+ g_debug ("User %s removed", common_user_get_name (info));
+ g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
+ g_object_unref (info);
+ }
+ }
+ g_list_free (old_users);
+}
+
+static void
+passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, CommonUserList *user_list)
+{
+ if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
+ {
+ g_debug ("%s changed, reloading user list", g_file_get_path (file));
+ load_passwd_file (user_list, TRUE);
+ }
+}
+
+static gboolean load_accounts_user (CommonUser *user);
+
+static void
+accounts_user_changed_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer data)
+{
+ CommonUser *user = data;
+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
+
+ g_debug ("User %s changed", priv->path);
+ if (load_accounts_user (user))
+ g_signal_emit (user, user_signals[CHANGED], 0);
+}
+
+static gboolean
+load_accounts_user (CommonUser *user)
+{
+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
+ GVariant *result, *value;
+ GVariantIter *iter;
+ gchar *name;
+ gboolean system_account = FALSE;
+ GError *error = NULL;
+
+ /* Get the properties for this user */
+ if (!priv->changed_signal)
+ priv->changed_signal = g_dbus_connection_signal_subscribe (GET_LIST_PRIVATE (priv->user_list)->bus,
+ "org.freedesktop.Accounts",
+ "org.freedesktop.Accounts.User",
+ "Changed",
+ priv->path,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ accounts_user_changed_cb,
+ user,
+ NULL);
+ result = g_dbus_connection_call_sync (GET_LIST_PRIVATE (priv->user_list)->bus,
+ "org.freedesktop.Accounts",
+ priv->path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
+ G_VARIANT_TYPE ("(a{sv})"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error updating user %s: %s", priv->path, error->message);
+ g_clear_error (&error);
+ if (!result)
+ return FALSE;
+
+ /* Store the properties we need */
+ g_variant_get (result, "(a{sv})", &iter);
+ while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
+ {
+ if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ g_free (priv->name);
+ priv->name = g_variant_dup_string (value, NULL);
+ }
+ else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ g_free (priv->real_name);
+ priv->real_name = g_variant_dup_string (value, NULL);
+ }
+ else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ g_free (priv->home_directory);
+ priv->home_directory = g_variant_dup_string (value, NULL);
+ }
+ else if (strcmp (name, "SystemAccount") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
+ system_account = g_variant_get_boolean (value);
+ else if (strcmp (name, "Language") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ if (priv->language)
+ g_free (priv->language);
+ priv->language = g_variant_dup_string (value, NULL);
+ }
+ else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ g_free (priv->image);
+ priv->image = g_variant_dup_string (value, NULL);
+ if (strcmp (priv->image, "") == 0)
+ {
+ g_free (priv->image);
+ priv->image = NULL;
+ }
+ }
+ else if (strcmp (name, "XSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ g_free (priv->session);
+ priv->session = g_variant_dup_string (value, NULL);
+ }
+ else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ g_free (priv->background);
+ priv->background = g_variant_dup_string (value, NULL);
+ if (strcmp (priv->background, "") == 0)
+ {
+ g_free (priv->background);
+ priv->background = NULL;
+ }
+ }
+ else if (strcmp (name, "XKeyboardLayouts") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY))
+ {
+ g_strfreev (priv->layouts);
+ priv->layouts = g_variant_dup_strv (value, NULL);
+ if (!priv->layouts)
+ {
+ priv->layouts = g_malloc (sizeof (gchar *) * 1);
+ priv->layouts[0] = NULL;
+ }
+ }
+ else if (strcmp (name, "XHasMessages") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
+ priv->has_messages = g_variant_get_boolean (value);
+ }
+ g_variant_iter_free (iter);
+
+ g_variant_unref (result);
+
+ priv->loaded_values = TRUE;
+
+ return !system_account;
+}
+
+static void
+add_accounts_user (CommonUserList *user_list, const gchar *path, gboolean emit_signal)
+{
+ CommonUserListPrivate *list_priv = GET_LIST_PRIVATE (user_list);
+ CommonUser *user;
+ CommonUserPrivate *priv;
+
+ user = g_object_new (COMMON_TYPE_USER, NULL);
+ priv = GET_USER_PRIVATE (user);
+
+ g_debug ("User %s added", path);
+ priv->user_list = user_list;
+ priv->path = g_strdup (path);
+ g_signal_connect (user, "changed", G_CALLBACK (user_changed_cb), NULL);
+ if (load_accounts_user (user))
+ {
+ list_priv->users = g_list_insert_sorted (list_priv->users, user, compare_user);
+ if (emit_signal)
+ g_signal_emit (user_list, list_signals[USER_ADDED], 0, user);
+ }
+ else
+ g_object_unref (user);
+}
+
+static void
+accounts_user_added_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer data)
+{
+ CommonUserList *user_list = data;
+ gchar *path;
+ CommonUser *user;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
+ return;
+ }
+
+ g_variant_get (parameters, "(&o)", &path);
+
+ /* Add user if we haven't got them */
+ user = get_user_by_path (user_list, path);
+ if (!user)
+ add_accounts_user (user_list, path, TRUE);
+}
+
+static void
+accounts_user_deleted_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer data)
+{
+ CommonUserList *user_list = data;
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ gchar *path;
+ CommonUser *user;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
+ return;
+ }
+
+ g_variant_get (parameters, "(&o)", &path);
+
+ /* Delete user if we know of them */
+ user = get_user_by_path (user_list, path);
+ if (user)
+ {
+ g_debug ("User %s deleted", path);
+ priv->users = g_list_remove (priv->users, user);
+
+ g_signal_emit (user_list, list_signals[USER_REMOVED], 0, user);
+
+ g_object_unref (user);
+ }
+}
+
+static Session *
+load_session (CommonUserList *user_list, const gchar *path)
+{
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ Session *session = NULL;
+ GVariant *result, *username;
+ GError *error = NULL;
+
+ result = g_dbus_connection_call_sync (priv->bus,
+ "org.freedesktop.DisplayManager",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
+ G_VARIANT_TYPE ("(v)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
+ g_clear_error (&error);
+ if (!result)
+ return NULL;
+
+ g_variant_get (result, "(v)", &username);
+ if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
+ {
+ gchar *name;
+
+ g_variant_get (username, "&s", &name);
+
+ g_debug ("Loaded session %s (%s)", path, name);
+ session = g_object_new (session_get_type (), NULL);
+ session->username = g_strdup (name);
+ session->path = g_strdup (path);
+ priv->sessions = g_list_append (priv->sessions, session);
+ }
+ g_variant_unref (username);
+ g_variant_unref (result);
+
+ return session;
+}
+
+static void
+session_added_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer data)
+{
+ CommonUserList *user_list = data;
+ gchar *path;
+ Session *session;
+ CommonUser *user = NULL;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ g_warning ("Got DisplayManager signal SessionAdded with unknown parameters %s", g_variant_get_type_string (parameters));
+ return;
+ }
+
+ g_variant_get (parameters, "(&o)", &path);
+ session = load_session (user_list, path);
+ if (session)
+ user = get_user_by_name (user_list, session->username);
+ if (user)
+ g_signal_emit (user, user_signals[CHANGED], 0);
+}
+
+static void
+session_removed_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer data)
+{
+ CommonUserList *user_list = data;
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ gchar *path;
+ GList *link;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ g_warning ("Got DisplayManager signal SessionRemoved with unknown parameters %s", g_variant_get_type_string (parameters));
+ return;
+ }
+
+ g_variant_get (parameters, "(&o)", &path);
+
+ for (link = priv->sessions; link; link = link->next)
+ {
+ Session *session = link->data;
+ if (strcmp (session->path, path) == 0)
+ {
+ CommonUser *user;
+
+ g_debug ("Session %s removed", path);
+ priv->sessions = g_list_remove_link (priv->sessions, link);
+ user = get_user_by_name (user_list, session->username);
+ if (user)
+ g_signal_emit (user, user_signals[CHANGED], 0);
+ g_object_unref (session);
+ break;
+ }
+ }
+}
+
+static void
+load_users (CommonUserList *user_list)
+{
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GVariant *result;
+ GError *error = NULL;
+
+ if (priv->have_users)
+ return;
+ priv->have_users = TRUE;
+
+ /* Get user list from accounts service and fall back to /etc/passwd if that fails */
+ priv->user_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
+ "org.freedesktop.Accounts",
+ "org.freedesktop.Accounts",
+ "UserAdded",
+ "/org/freedesktop/Accounts",
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ accounts_user_added_cb,
+ user_list,
+ NULL);
+ priv->user_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
+ "org.freedesktop.Accounts",
+ "org.freedesktop.Accounts",
+ "UserDeleted",
+ "/org/freedesktop/Accounts",
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ accounts_user_deleted_cb,
+ user_list,
+ NULL);
+ result = g_dbus_connection_call_sync (priv->bus,
+ "org.freedesktop.Accounts",
+ "/org/freedesktop/Accounts",
+ "org.freedesktop.Accounts",
+ "ListCachedUsers",
+ g_variant_new ("()"),
+ G_VARIANT_TYPE ("(ao)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
+ g_clear_error (&error);
+ if (result)
+ {
+ GVariantIter *iter;
+ const gchar *path;
+
+ g_debug ("Loading users from org.freedesktop.Accounts");
+ g_variant_get (result, "(ao)", &iter);
+ while (g_variant_iter_loop (iter, "&o", &path))
+ add_accounts_user (user_list, path, FALSE);
+ g_variant_iter_free (iter);
+ g_variant_unref (result);
+ }
+ else
+ {
+ GFile *passwd_file;
+
+ g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
+ priv->user_added_signal = 0;
+ g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
+ priv->user_removed_signal = 0;
+
+ load_passwd_file (user_list, FALSE);
+
+ /* Watch for changes to user list */
+
+ passwd_file = g_file_new_for_path (PASSWD_FILE);
+ priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
+ g_object_unref (passwd_file);
+ if (error)
+ g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
+ else
+ g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
+ g_clear_error (&error);
+ }
+
+ priv->session_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
+ "org.freedesktop.DisplayManager",
+ "org.freedesktop.DisplayManager",
+ "SessionAdded",
+ "/org/freedesktop/DisplayManager",
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ session_added_cb,
+ user_list,
+ NULL);
+ priv->session_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
+ "org.freedesktop.DisplayManager",
+ "org.freedesktop.DisplayManager",
+ "SessionRemoved",
+ "/org/freedesktop/DisplayManager",
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ session_removed_cb,
+
+ user_list,
+ NULL);
+ result = g_dbus_connection_call_sync (priv->bus,
+ "org.freedesktop.DisplayManager",
+ "/org/freedesktop/DisplayManager",
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
+ G_VARIANT_TYPE ("(v)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
+ g_clear_error (&error);
+ if (result)
+ {
+ if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
+ {
+ GVariant *value;
+ GVariantIter *iter;
+ const gchar *path;
+
+ g_variant_get (result, "(v)", &value);
+
+ g_debug ("Loading sessions from org.freedesktop.DisplayManager");
+ g_variant_get (value, "ao", &iter);
+ while (g_variant_iter_loop (iter, "&o", &path))
+ load_session (user_list, path);
+ g_variant_iter_free (iter);
+
+ g_variant_unref (value);
+ }
+ else
+ g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
+
+ g_variant_unref (result);
+ }
+}
+
+/**
+ * common_user_list_get_length:
+ * @user_list: a #CommonUserList
+ *
+ * Return value: The number of users able to log in
+ **/
+gint
+common_user_list_get_length (CommonUserList *user_list)
+{
+ g_return_val_if_fail (COMMON_IS_USER_LIST (user_list), 0);
+ load_users (user_list);
+ return g_list_length (GET_LIST_PRIVATE (user_list)->users);
+}
+
+/**
+ * common_user_list_get_users:
+ * @user_list: A #CommonUserList
+ *
+ * Get a list of users to present to the user. This list may be a subset of the
+ * available users and may be empty depending on the server configuration.
+ *
+ * Return value: (element-type CommonUser) (transfer none): A list of #CommonUser that should be presented to the user.
+ **/
+GList *
+common_user_list_get_users (CommonUserList *user_list)
+{
+ g_return_val_if_fail (COMMON_IS_USER_LIST (user_list), NULL);
+ load_users (user_list);
+ return GET_LIST_PRIVATE (user_list)->users;
+}
+
+/**
+ * common_user_list_get_user_by_name:
+ * @user_list: A #CommonUserList
+ * @username: Name of user to get.
+ *
+ * Get infomation about a given user or #NULL if this user doesn't exist.
+ *
+ * Return value: (transfer none): A #CommonUser entry for the given user.
+ **/
+CommonUser *
+common_user_list_get_user_by_name (CommonUserList *user_list, const gchar *username)
+{
+ g_return_val_if_fail (COMMON_IS_USER_LIST (user_list), NULL);
+ g_return_val_if_fail (username != NULL, NULL);
+
+ load_users (user_list);
+
+ return get_user_by_name (user_list, username);
+}
+
+static void
+common_user_list_init (CommonUserList *user_list)
+{
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+
+ priv->bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
+}
+
+static void
+common_user_list_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+common_user_list_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CommonUserList *self;
+
+ self = COMMON_USER_LIST (object);
+
+ switch (prop_id)
+ {
+ case LIST_PROP_NUM_USERS:
+ g_value_set_int (value, common_user_list_get_length (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+common_user_list_finalize (GObject *object)
+{
+ CommonUserList *self = COMMON_USER_LIST (object);
+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (self);
+
+ /* Remove children first, they might access us */
+ g_list_free_full (priv->users, g_object_unref);
+ g_list_free_full (priv->sessions, g_object_unref);
+
+ if (priv->user_added_signal)
+ g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
+ if (priv->user_removed_signal)
+ g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
+ if (priv->session_added_signal)
+ g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_added_signal);
+ if (priv->session_removed_signal)
+ g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_removed_signal);
+ g_object_unref (priv->bus);
+ if (priv->passwd_monitor)
+ g_object_unref (priv->passwd_monitor);
+
+ G_OBJECT_CLASS (common_user_list_parent_class)->finalize (object);
+}
+
+static void
+common_user_list_class_init (CommonUserListClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (CommonUserListPrivate));
+
+ object_class->set_property = common_user_list_set_property;
+ object_class->get_property = common_user_list_get_property;
+ object_class->finalize = common_user_list_finalize;
+
+ g_object_class_install_property (object_class,
+ LIST_PROP_NUM_USERS,
+ g_param_spec_int ("num-users",
+ "num-users",
+ "Number of login users",
+ 0, G_MAXINT, 0,
+ G_PARAM_READABLE));
+ /**
+ * CommonUserList::user-added:
+ * @user_list: A #CommonUserList
+ * @user: The #CommonUser that has been added.
+ *
+ * The ::user-added signal gets emitted when a user account is created.
+ **/
+ list_signals[USER_ADDED] =
+ g_signal_new ("user-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CommonUserListClass, user_added),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1, COMMON_TYPE_USER);
+
+ /**
+ * CommonUserList::user-changed:
+ * @user_list: A #CommonUserList
+ * @user: The #CommonUser that has been changed.
+ *
+ * The ::user-changed signal gets emitted when a user account is modified.
+ **/
+ list_signals[USER_CHANGED] =
+ g_signal_new ("user-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CommonUserListClass, user_changed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1, COMMON_TYPE_USER);
+
+ /**
+ * CommonUserList::user-removed:
+ * @user_list: A #CommonUserList
+ * @user: The #CommonUser that has been removed.
+ *
+ * The ::user-removed signal gets emitted when a user account is removed.
+ **/
+ list_signals[USER_REMOVED] =
+ g_signal_new ("user-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CommonUserListClass, user_removed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1, COMMON_TYPE_USER);
+}
+
+static void
+load_dmrc (CommonUser *user)
+{
+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
+ gchar *path;
+ //gboolean have_dmrc;
+
+ if (!priv->dmrc_file)
+ priv->dmrc_file = g_key_file_new ();
+
+ /* Load from the user directory */
+ path = g_build_filename (priv->home_directory, ".dmrc", NULL);
+ /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
+ g_free (path);
+
+ /* If no ~/.dmrc, then load from the cache */
+ // FIXME
+
+ // FIXME: Watch for changes
+
+ /* The Language field contains the locale */
+ if (priv->language)
+ g_free (priv->language);
+ priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
+
+ if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
+ {
+ g_strfreev (priv->layouts);
+ priv->layouts = g_malloc (sizeof (gchar *) * 2);
+ priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
+ priv->layouts[1] = NULL;
+ }
+
+ if (priv->session)
+ g_free (priv->session);
+ priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
+}
+
+/* Loads language/layout/session info for user */
+static void
+load_user_values (CommonUser *user)
+{
+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
+
+ if (priv->loaded_values)
+ return;
+ priv->loaded_values = TRUE;
+
+ if (!priv->path)
+ load_dmrc (user);
+}
+
+/**
+ * common_user_get_name:
+ * @user: A #CommonUser
+ *
+ * Get the name of a user.
+ *
+ * Return value: The name of the given user
+ **/
+const gchar *
+common_user_get_name (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->name;
+}
+
+/**
+ * common_user_get_real_name:
+ * @user: A #CommonUser
+ *
+ * Get the real name of a user.
+ *
+ * Return value: The real name of the given user
+ **/
+const gchar *
+common_user_get_real_name (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->real_name;
+}
+
+/**
+ * common_user_get_display_name:
+ * @user: A #CommonUser
+ *
+ * Get the display name of a user.
+ *
+ * Return value: The display name of the given user
+ **/
+const gchar *
+common_user_get_display_name (CommonUser *user)
+{
+ CommonUserPrivate *priv;
+
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+
+ load_user_values (user);
+
+ priv = GET_USER_PRIVATE (user);
+ if (!priv->real_name || strcmp (priv->real_name, "") == 0)
+ return priv->name;
+ else
+ return priv->real_name;
+}
+
+/**
+ * common_user_get_home_directory:
+ * @user: A #CommonUser
+ *
+ * Get the home directory for a user.
+ *
+ * Return value: The users home directory
+ */
+const gchar *
+common_user_get_home_directory (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->home_directory;
+}
+
+/**
+ * common_user_get_image:
+ * @user: A #CommonUser
+ *
+ * Get the image URI for a user.
+ *
+ * Return value: The image URI for the given user or #NULL if no URI
+ **/
+const gchar *
+common_user_get_image (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->image;
+}
+
+/**
+ * common_user_get_background:
+ * @user: A #CommonUser
+ *
+ * Get the background file path for a user.
+ *
+ * Return value: The background file path for the given user or #NULL if no path
+ **/
+const gchar *
+common_user_get_background (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->background;
+}
+
+/**
+ * common_user_get_language:
+ * @user: A #CommonUser
+ *
+ * Get the language for a user.
+ *
+ * Return value: The language in the form of a local specification (e.g. "de_DE.UTF-8") for the given user or #NULL if using the system default locale.
+ **/
+const gchar *
+common_user_get_language (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->language;
+}
+
+/**
+ * common_user_get_layout:
+ * @user: A #CommonUser
+ *
+ * Get the keyboard layout for a user.
+ *
+ * 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.
+ **/
+const gchar *
+common_user_get_layout (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->layouts[0];
+}
+
+/**
+ * common_user_get_layouts:
+ * @user: A #CommonUser
+ *
+ * Get the configured keyboard layouts for a user.
+ *
+ * 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.
+ **/
+const gchar * const *
+common_user_get_layouts (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
+}
+
+/**
+ * common_user_get_session:
+ * @user: A #CommonUser
+ *
+ * Get the session for a user.
+ *
+ * Return value: The session for the given user or #NULL if using system defaults.
+ **/
+const gchar *
+common_user_get_session (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->session;
+}
+
+/**
+ * common_user_get_logged_in:
+ * @user: A #CommonUser
+ *
+ * Check if a user is logged in.
+ *
+ * Return value: #TRUE if the user is currently logged in.
+ **/
+gboolean
+common_user_get_logged_in (CommonUser *user)
+{
+ CommonUserPrivate *priv;
+ CommonUserListPrivate *list_priv;
+ GList *link;
+
+ g_return_val_if_fail (COMMON_IS_USER (user), FALSE);
+
+ priv = GET_USER_PRIVATE (user);
+ list_priv = GET_LIST_PRIVATE (priv->user_list);
+
+ for (link = list_priv->sessions; link; link = link->next)
+ {
+ Session *session = link->data;
+ if (strcmp (session->username, priv->name) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * common_user_get_has_messages:
+ * @user: A #CommonUser
+ *
+ * Check if a user has waiting messages.
+ *
+ * Return value: #TRUE if the user has waiting messages.
+ **/
+gboolean
+common_user_get_has_messages (CommonUser *user)
+{
+ g_return_val_if_fail (COMMON_IS_USER (user), FALSE);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->has_messages;
+}
+
+static void
+common_user_init (CommonUser *user)
+{
+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
+ priv->layouts = g_malloc (sizeof (gchar *) * 1);
+ priv->layouts[0] = NULL;
+}
+
+static void
+common_user_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+common_user_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CommonUser *self;
+
+ self = COMMON_USER (object);
+
+ switch (prop_id)
+ {
+ case USER_PROP_NAME:
+ g_value_set_string (value, common_user_get_name (self));
+ break;
+ case USER_PROP_REAL_NAME:
+ g_value_set_string (value, common_user_get_real_name (self));
+ break;
+ case USER_PROP_DISPLAY_NAME:
+ g_value_set_string (value, common_user_get_display_name (self));
+ break;
+ case USER_PROP_HOME_DIRECTORY:
+ g_value_set_string (value, common_user_get_home_directory (self));
+ break;
+ case USER_PROP_IMAGE:
+ g_value_set_string (value, common_user_get_image (self));
+ break;
+ case USER_PROP_BACKGROUND:
+ g_value_set_string (value, common_user_get_background (self));
+ break;
+ case USER_PROP_LANGUAGE:
+ g_value_set_string (value, common_user_get_language (self));
+ break;
+ case USER_PROP_LAYOUT:
+ g_value_set_string (value, common_user_get_layout (self));
+ break;
+ case USER_PROP_LAYOUTS:
+ g_value_set_boxed (value, g_strdupv ((gchar **) common_user_get_layouts (self)));
+ break;
+ case USER_PROP_SESSION:
+ g_value_set_string (value, common_user_get_session (self));
+ break;
+ case USER_PROP_LOGGED_IN:
+ g_value_set_boolean (value, common_user_get_logged_in (self));
+ break;
+ case USER_PROP_HAS_MESSAGES:
+ g_value_set_boolean (value, common_user_get_has_messages (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+common_user_finalize (GObject *object)
+{
+ CommonUser *self = COMMON_USER (object);
+ CommonUserPrivate *priv = GET_USER_PRIVATE (self);
+
+ g_free (priv->path);
+ if (priv->changed_signal)
+ g_dbus_connection_signal_unsubscribe (GET_LIST_PRIVATE (priv->user_list)->bus, priv->changed_signal);
+ g_free (priv->name);
+ g_free (priv->real_name);
+ g_free (priv->home_directory);
+ g_free (priv->image);
+ g_free (priv->background);
+ g_strfreev (priv->layouts);
+ if (priv->dmrc_file)
+ g_key_file_free (priv->dmrc_file);
+}
+
+static void
+common_user_class_init (CommonUserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (CommonUserPrivate));
+
+ object_class->set_property = common_user_set_property;
+ object_class->get_property = common_user_get_property;
+ object_class->finalize = common_user_finalize;
+
+ g_object_class_install_property (object_class,
+ USER_PROP_NAME,
+ g_param_spec_string ("name",
+ "name",
+ "Username",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_REAL_NAME,
+ g_param_spec_string ("real-name",
+ "real-name",
+ "Users real name",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_DISPLAY_NAME,
+ g_param_spec_string ("display-name",
+ "display-name",
+ "Users display name",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_HOME_DIRECTORY,
+ g_param_spec_string ("home-directory",
+ "home-directory",
+ "Home directory",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_IMAGE,
+ g_param_spec_string ("image",
+ "image",
+ "Avatar image",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_BACKGROUND,
+ g_param_spec_string ("background",
+ "background",
+ "User background",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LANGUAGE,
+ g_param_spec_string ("language",
+ "language",
+ "Language used by this user",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LAYOUT,
+ g_param_spec_string ("layout",
+ "layout",
+ "Keyboard layout used by this user",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LAYOUTS,
+ g_param_spec_boxed ("layouts",
+ "layouts",
+ "Keyboard layouts used by this user",
+ G_TYPE_STRV,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_SESSION,
+ g_param_spec_string ("session",
+ "session",
+ "Session used by this user",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LOGGED_IN,
+ g_param_spec_boolean ("logged-in",
+ "logged-in",
+ "TRUE if the user is currently in a session",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LOGGED_IN,
+ g_param_spec_boolean ("has-messages",
+ "has-messages",
+ "TRUE if the user is has waiting messages",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ /**
+ * CommonUser::changed:
+ * @user: A #CommonUser
+ *
+ * The ::changed signal gets emitted this user account is modified.
+ **/
+ user_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CommonUserClass, changed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+session_init (Session *session)
+{
+}
+
+static void
+session_finalize (GObject *object)
+{
+ Session *self = SESSION (object);
+
+ g_free (self->path);
+ g_free (self->username);
+}
+
+static void
+session_class_init (SessionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = session_finalize;
+}
diff --git a/common/user-list.h b/common/user-list.h
new file mode 100644
index 00000000..19926cf2
--- /dev/null
+++ b/common/user-list.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010 Robert Ancell.
+ * Copyright (C) 2014 Canonical, Ltd.
+ * Authors: Robert Ancell <robert.ancell@canonical.com>
+ * Michael Terry <michael.terry@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+#ifndef COMMON_USER_LIST_H_
+#define COMMON_USER_LIST_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define COMMON_TYPE_USER_LIST (common_user_list_get_type())
+#define COMMON_USER_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMMON_TYPE_USER_LIST, CommonUserList));
+#define COMMON_USER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COMMON_TYPE_USER_LIST, CommonUserListClass))
+#define COMMON_IS_USER_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMMON_TYPE_USER_LIST))
+#define COMMON_IS_USER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COMMON_TYPE_USER_LIST))
+#define COMMON_USER_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COMMON_TYPE_USER_LIST, CommonUserListClass))
+
+#define COMMON_TYPE_USER (common_user_get_type())
+#define COMMON_USER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMMON_TYPE_USER, CommonUser));
+#define COMMON_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COMMON_TYPE_USER, CommonUserClass))
+#define COMMON_IS_USER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMMON_TYPE_USER))
+#define COMMON_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COMMON_TYPE_USER))
+#define COMMON_USER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COMMON_TYPE_USER, CommonUserClass))
+
+typedef struct
+{
+ GObject parent_instance;
+} CommonUser;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (*changed)(CommonUser *user);
+} CommonUserClass;
+
+typedef struct
+{
+ GObject parent_instance;
+} CommonUserList;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (*user_added)(CommonUserList *user_list, CommonUser *user);
+ void (*user_changed)(CommonUserList *user_list, CommonUser *user);
+ void (*user_removed)(CommonUserList *user_list, CommonUser *user);
+} CommonUserListClass;
+
+GType common_user_list_get_type (void);
+
+GType common_user_get_type (void);
+
+CommonUserList *common_user_list_get_instance (void);
+
+gint common_user_list_get_length (CommonUserList *user_list);
+
+CommonUser *common_user_list_get_user_by_name (CommonUserList *user_list, const gchar *username);
+
+GList *common_user_list_get_users (CommonUserList *user_list);
+
+const gchar *common_user_get_name (CommonUser *user);
+
+const gchar *common_user_get_real_name (CommonUser *user);
+
+const gchar *common_user_get_display_name (CommonUser *user);
+
+const gchar *common_user_get_home_directory (CommonUser *user);
+
+const gchar *common_user_get_image (CommonUser *user);
+
+const gchar *common_user_get_background (CommonUser *user);
+
+const gchar *common_user_get_language (CommonUser *user);
+
+const gchar *common_user_get_layout (CommonUser *user);
+
+const gchar * const *common_user_get_layouts (CommonUser *user);
+
+const gchar *common_user_get_session (CommonUser *user);
+
+gboolean common_user_get_logged_in (CommonUser *user);
+
+gboolean common_user_get_has_messages (CommonUser *user);
+
+G_END_DECLS
+
+#endif /* COMMON_USER_LIST_H_ */
diff --git a/liblightdm-gobject/Makefile.am b/liblightdm-gobject/Makefile.am
index 9ab209e8..770ea13b 100644
--- a/liblightdm-gobject/Makefile.am
+++ b/liblightdm-gobject/Makefile.am
@@ -29,6 +29,7 @@ liblightdm_gobject_1_la_SOURCES= \
power.c \
session.c \
user.c \
+ $(top_srcdir)/common/user-list.c \
$(liblightdm_gobject_1include_HEADERS)
if HAVE_INTROSPECTION
diff --git a/liblightdm-gobject/user.c b/liblightdm-gobject/user.c
index 5ee75193..664cfa64 100644
--- a/liblightdm-gobject/user.c
+++ b/liblightdm-gobject/user.c
@@ -1,7 +1,9 @@
/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
*
* Copyright (C) 2010 Robert Ancell.
- * Author: Robert Ancell <robert.ancell@canonical.com>
+ * Copyright (C) 2014 Canonical, Ltd.
+ * Authors: Robert Ancell <robert.ancell@canonical.com>
+ * Michael Terry <michael.terry@canonical.com>
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
@@ -11,12 +13,7 @@
#include <config.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/utsname.h>
-#include <pwd.h>
-#include <gio/gio.h>
-
+#include "common/user-list.h"
#include "lightdm/user.h"
enum
@@ -29,6 +26,7 @@ enum
enum
{
USER_PROP_0,
+ USER_PROP_COMMON_USER,
USER_PROP_NAME,
USER_PROP_REAL_NAME,
USER_PROP_DISPLAY_NAME,
@@ -61,99 +59,23 @@ static guint user_signals[LAST_USER_SIGNAL] = { 0 };
typedef struct
{
- /* Bus connection being communicated on */
- GDBusConnection *bus;
-
- /* D-Bus signals for accounts service events */
- guint user_added_signal;
- guint user_removed_signal;
-
- /* D-Bus signals for display manager events */
- guint session_added_signal;
- guint session_removed_signal;
-
- /* File monitor for password file */
- GFileMonitor *passwd_monitor;
-
- /* TRUE if have scanned users */
- gboolean have_users;
+ gboolean initialized;
- /* List of users */
- GList *users;
-
- /* List of sessions */
- GList *sessions;
+ /* Wrapper list, kept locally to preserve transfer-none promises */
+ GList *lightdm_list;
} LightDMUserListPrivate;
typedef struct
{
- /* User list this user is part of */
- LightDMUserList *user_list;
-
- /* TRUE if have loaded user properties */
- gboolean loaded_values;
-
- /* Accounts service path */
- gchar *path;
-
- /* DMRC file */
- GKeyFile *dmrc_file;
-
- /* Update signal from accounts service */
- guint changed_signal;
-
- /* Username */
- gchar *name;
-
- /* Descriptive name for user */
- gchar *real_name;
-
- /* Home directory of user */
- gchar *home_directory;
-
- /* Image for user */
- gchar *image;
-
- /* Background image for users */
- gchar *background;
-
- /* TRUE if this user has messages available */
- gboolean has_messages;
-
- /* User chosen language */
- gchar *language;
-
- /* User layout preferences */
- gchar **layouts;
-
- /* User default session */
- gchar *session;
+ CommonUser *common_user;
} LightDMUserPrivate;
-typedef struct
-{
- GObject parent_instance;
- gchar *path;
- gchar *username;
-} Session;
-
-typedef struct
-{
- GObjectClass parent_class;
-} SessionClass;
-
G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
-#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
-GType session_get_type (void);
-G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
-#define PASSWD_FILE "/etc/passwd"
-#define USER_CONFIG_FILE "/etc/lightdm/users.conf"
-
static LightDMUserList *singleton = NULL;
/**
@@ -171,725 +93,84 @@ lightdm_user_list_get_instance (void)
return singleton;
}
-static LightDMUser *
-get_user_by_name (LightDMUserList *user_list, const gchar *username)
+static void
+user_changed_cb (CommonUser *common_user, LightDMUser *lightdm_user)
{
- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
- GList *link;
-
- for (link = priv->users; link; link = link->next)
- {
- LightDMUser *user = link->data;
- if (g_strcmp0 (lightdm_user_get_name (user), username) == 0)
- return user;
- }
-
- return NULL;
+ g_signal_emit (lightdm_user, user_signals[CHANGED], 0);
}
static LightDMUser *
-get_user_by_path (LightDMUserList *user_list, const gchar *path)
-{
- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
- GList *link;
-
- for (link = priv->users; link; link = link->next)
- {
- LightDMUser *user = link->data;
- if (g_strcmp0 (GET_USER_PRIVATE (user)->path, path) == 0)
- return user;
- }
-
- return NULL;
-}
-
-static gint
-compare_user (gconstpointer a, gconstpointer b)
-{
- LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
- return g_strcmp0 (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
-}
-
-static gboolean
-update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
-{
- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
-
- /* Skip if already set to this */
- if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
- g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
- g_strcmp0 (lightdm_user_get_image (user), image) == 0)
- return FALSE;
-
- g_free (priv->real_name);
- priv->real_name = g_strdup (real_name);
- g_free (priv->home_directory);
- priv->home_directory = g_strdup (home_directory);
- g_free (priv->image);
- priv->image = g_strdup (image);
-
- return TRUE;
-}
-
-static void
-user_changed_cb (LightDMUser *user)
+wrap_common_user (CommonUser *user)
{
- g_signal_emit (GET_USER_PRIVATE (user)->user_list, list_signals[USER_CHANGED], 0, user);
+ LightDMUser *lightdm_user = g_object_new (LIGHTDM_TYPE_USER, "common-user", user, NULL);
+ g_signal_connect (user, "changed", G_CALLBACK (user_changed_cb), lightdm_user);
+ return lightdm_user;
}
static void
-load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
+user_list_added_cb (CommonUserList *common_list, CommonUser *common_user, LightDMUserList *user_list)
{
LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
- GKeyFile *config;
- gchar *value;
- gint minimum_uid;
- gchar **hidden_users, **hidden_shells;
- GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
- GError *error = NULL;
-
- g_debug ("Loading user config from %s", USER_CONFIG_FILE);
-
- config = g_key_file_new ();
- g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error);
- if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
- g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message);
- g_clear_error (&error);
-
- if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
- minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
- else
- minimum_uid = 500;
-
- value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
- if (!value)
- value = g_strdup ("nobody nobody4 noaccess");
- hidden_users = g_strsplit (value, " ", -1);
- g_free (value);
-
- value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
- if (!value)
- value = g_strdup ("/bin/false /usr/sbin/nologin");
- hidden_shells = g_strsplit (value, " ", -1);
- g_free (value);
-
- g_key_file_free (config);
-
- setpwent ();
-
- while (TRUE)
- {
- struct passwd *entry;
- LightDMUser *user;
- LightDMUserPrivate *user_priv;
- char **tokens;
- gchar *real_name, *image;
- int i;
-
- errno = 0;
- entry = getpwent ();
- if (!entry)
- break;
-
- /* Ignore system users */
- if (entry->pw_uid < minimum_uid)
- continue;
-
- /* Ignore users disabled by shell */
- if (entry->pw_shell)
- {
- for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
- if (hidden_shells[i])
- continue;
- }
-
- /* Ignore certain users */
- for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
- if (hidden_users[i])
- continue;
-
- tokens = g_strsplit (entry->pw_gecos, ",", -1);
- if (tokens[0] != NULL && tokens[0][0] != '\0')
- real_name = g_strdup (tokens[0]);
- else
- real_name = g_strdup ("");
- g_strfreev (tokens);
-
- image = g_build_filename (entry->pw_dir, ".face", NULL);
- if (!g_file_test (image, G_FILE_TEST_EXISTS))
- {
- g_free (image);
- image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
- if (!g_file_test (image, G_FILE_TEST_EXISTS))
- {
- g_free (image);
- image = NULL;
- }
- }
-
- user = g_object_new (LIGHTDM_TYPE_USER, NULL);
- user_priv = GET_USER_PRIVATE (user);
- user_priv->user_list = user_list;
- g_free (user_priv->name);
- user_priv->name = g_strdup (entry->pw_name);
- g_free (user_priv->real_name);
- user_priv->real_name = real_name;
- g_free (user_priv->home_directory);
- user_priv->home_directory = g_strdup (entry->pw_dir);
- g_free (user_priv->image);
- user_priv->image = image;
-
- /* Update existing users if have them */
- for (link = priv->users; link; link = link->next)
- {
- LightDMUser *info = link->data;
- if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
- {
- if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
- changed_users = g_list_insert_sorted (changed_users, info, compare_user);
- g_object_unref (user);
- user = info;
- break;
- }
- }
- if (!link)
- {
- /* Only notify once we have loaded the user list */
- if (priv->have_users)
- new_users = g_list_insert_sorted (new_users, user, compare_user);
- }
- users = g_list_insert_sorted (users, user, compare_user);
- }
- g_strfreev (hidden_users);
- g_strfreev (hidden_shells);
-
- if (errno != 0)
- g_warning ("Failed to read password database: %s", strerror (errno));
-
- endpwent ();
-
- /* Use new user list */
- old_users = priv->users;
- priv->users = users;
-
- /* Notify of changes */
- for (link = new_users; link; link = link->next)
- {
- LightDMUser *info = link->data;
- g_debug ("User %s added", lightdm_user_get_name (info));
- g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), NULL);
- if (emit_add_signal)
- g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
- }
- g_list_free (new_users);
- for (link = changed_users; link; link = link->next)
- {
- LightDMUser *info = link->data;
- g_debug ("User %s changed", lightdm_user_get_name (info));
- g_signal_emit (info, user_signals[CHANGED], 0);
- }
- g_list_free (changed_users);
- for (link = old_users; link; link = link->next)
- {
- GList *new_link;
-
- /* See if this user is in the current list */
- for (new_link = priv->users; new_link; new_link = new_link->next)
- {
- if (new_link->data == link->data)
- break;
- }
-
- if (!new_link)
- {
- LightDMUser *info = link->data;
- g_debug ("User %s removed", lightdm_user_get_name (info));
- g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
- g_object_unref (info);
- }
- }
- g_list_free (old_users);
-}
-
-static void
-passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
-{
- if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
- {
- g_debug ("%s changed, reloading user list", g_file_get_path (file));
- load_passwd_file (user_list, TRUE);
- }
-}
-
-static gboolean load_accounts_user (LightDMUser *user);
-
-static void
-accounts_user_changed_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer data)
-{
- LightDMUser *user = data;
- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
-
- g_debug ("User %s changed", priv->path);
- if (load_accounts_user (user))
- g_signal_emit (user, user_signals[CHANGED], 0);
-}
-
-static gboolean
-load_accounts_user (LightDMUser *user)
-{
- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
- GVariant *result, *value;
- GVariantIter *iter;
- gchar *name;
- gboolean system_account = FALSE;
- GError *error = NULL;
-
- /* Get the properties for this user */
- if (!priv->changed_signal)
- priv->changed_signal = g_dbus_connection_signal_subscribe (GET_LIST_PRIVATE (priv->user_list)->bus,
- "org.freedesktop.Accounts",
- "org.freedesktop.Accounts.User",
- "Changed",
- priv->path,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- accounts_user_changed_cb,
- user,
- NULL);
- result = g_dbus_connection_call_sync (GET_LIST_PRIVATE (priv->user_list)->bus,
- "org.freedesktop.Accounts",
- priv->path,
- "org.freedesktop.DBus.Properties",
- "GetAll",
- g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
- G_VARIANT_TYPE ("(a{sv})"),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
- if (error)
- g_warning ("Error updating user %s: %s", priv->path, error->message);
- g_clear_error (&error);
- if (!result)
- return FALSE;
-
- /* Store the properties we need */
- g_variant_get (result, "(a{sv})", &iter);
- while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
- {
- if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- g_free (priv->name);
- priv->name = g_variant_dup_string (value, NULL);
- }
- else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- g_free (priv->real_name);
- priv->real_name = g_variant_dup_string (value, NULL);
- }
- else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- g_free (priv->home_directory);
- priv->home_directory = g_variant_dup_string (value, NULL);
- }
- else if (strcmp (name, "SystemAccount") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
- system_account = g_variant_get_boolean (value);
- else if (strcmp (name, "Language") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- if (priv->language)
- g_free (priv->language);
- priv->language = g_variant_dup_string (value, NULL);
- }
- else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- g_free (priv->image);
- priv->image = g_variant_dup_string (value, NULL);
- if (strcmp (priv->image, "") == 0)
- {
- g_free (priv->image);
- priv->image = NULL;
- }
- }
- else if (strcmp (name, "XSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- g_free (priv->session);
- priv->session = g_variant_dup_string (value, NULL);
- }
- else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- g_free (priv->background);
- priv->background = g_variant_dup_string (value, NULL);
- if (strcmp (priv->background, "") == 0)
- {
- g_free (priv->background);
- priv->background = NULL;
- }
- }
- else if (strcmp (name, "XKeyboardLayouts") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY))
- {
- g_strfreev (priv->layouts);
- priv->layouts = g_variant_dup_strv (value, NULL);
- if (!priv->layouts)
- {
- priv->layouts = g_malloc (sizeof (gchar *) * 1);
- priv->layouts[0] = NULL;
- }
- }
- else if (strcmp (name, "XHasMessages") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
- priv->has_messages = g_variant_get_boolean (value);
- }
- g_variant_iter_free (iter);
-
- g_variant_unref (result);
-
- priv->loaded_values = TRUE;
-
- return !system_account;
-}
-
-static void
-add_accounts_user (LightDMUserList *user_list, const gchar *path, gboolean emit_signal)
-{
- LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (user_list);
- LightDMUser *user;
- LightDMUserPrivate *priv;
-
- user = g_object_new (LIGHTDM_TYPE_USER, NULL);
- priv = GET_USER_PRIVATE (user);
-
- g_debug ("User %s added", path);
- priv->user_list = user_list;
- priv->path = g_strdup (path);
- g_signal_connect (user, "changed", G_CALLBACK (user_changed_cb), NULL);
- if (load_accounts_user (user))
- {
- list_priv->users = g_list_insert_sorted (list_priv->users, user, compare_user);
- if (emit_signal)
- g_signal_emit (user_list, list_signals[USER_ADDED], 0, user);
- }
- else
- g_object_unref (user);
+ GList *common_users = common_user_list_get_users (common_list);
+ LightDMUser *lightdm_user = wrap_common_user (common_user);
+ priv->lightdm_list = g_list_insert (priv->lightdm_list, lightdm_user, g_list_index (common_users, common_user));
+ g_signal_emit (user_list, list_signals[USER_ADDED], 0, lightdm_user);
}
static void
-accounts_user_added_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer data)
+user_list_changed_cb (CommonUserList *common_list, CommonUser *common_user, LightDMUserList *user_list)
{
- LightDMUserList *user_list = data;
- gchar *path;
- LightDMUser *user;
-
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
- {
- g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
- return;
- }
-
- g_variant_get (parameters, "(&o)", &path);
-
- /* Add user if we haven't got them */
- user = get_user_by_path (user_list, path);
- if (!user)
- add_accounts_user (user_list, path, TRUE);
-}
-
-static void
-accounts_user_deleted_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer data)
-{
- LightDMUserList *user_list = data;
LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
- gchar *path;
- LightDMUser *user;
-
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
- {
- g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
- return;
- }
-
- g_variant_get (parameters, "(&o)", &path);
-
- /* Delete user if we know of them */
- user = get_user_by_path (user_list, path);
- if (user)
- {
- g_debug ("User %s deleted", path);
- priv->users = g_list_remove (priv->users, user);
-
- g_signal_emit (user_list, list_signals[USER_REMOVED], 0, user);
-
- g_object_unref (user);
- }
-}
-
-static Session *
-load_session (LightDMUserList *user_list, const gchar *path)
-{
- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
- Session *session = NULL;
- GVariant *result, *username;
- GError *error = NULL;
-
- result = g_dbus_connection_call_sync (priv->bus,
- "org.freedesktop.DisplayManager",
- path,
- "org.freedesktop.DBus.Properties",
- "Get",
- g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
- G_VARIANT_TYPE ("(v)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
- if (error)
- g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
- g_clear_error (&error);
- if (!result)
- return NULL;
-
- g_variant_get (result, "(v)", &username);
- if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
- {
- gchar *name;
-
- g_variant_get (username, "&s", &name);
-
- g_debug ("Loaded session %s (%s)", path, name);
- session = g_object_new (session_get_type (), NULL);
- session->username = g_strdup (name);
- session->path = g_strdup (path);
- priv->sessions = g_list_append (priv->sessions, session);
- }
- g_variant_unref (username);
- g_variant_unref (result);
-
- return session;
+ GList *common_users = common_user_list_get_users (common_list);
+ LightDMUser *lightdm_user = g_list_nth_data (priv->lightdm_list, g_list_index (common_users, common_user));
+ g_signal_emit (user_list, list_signals[USER_CHANGED], 0, lightdm_user);
}
static void
-session_added_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer data)
+user_list_removed_cb (CommonUserList *common_list, CommonUser *common_user, LightDMUserList *user_list)
{
- LightDMUserList *user_list = data;
- gchar *path;
- Session *session;
- LightDMUser *user = NULL;
-
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
- {
- g_warning ("Got DisplayManager signal SessionAdded with unknown parameters %s", g_variant_get_type_string (parameters));
- return;
- }
-
- g_variant_get (parameters, "(&o)", &path);
- session = load_session (user_list, path);
- if (session)
- user = get_user_by_name (user_list, session->username);
- if (user)
- g_signal_emit (user, user_signals[CHANGED], 0);
-}
-
-static void
-session_removed_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer data)
-{
- LightDMUserList *user_list = data;
LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
- gchar *path;
GList *link;
- if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ for (link = priv->lightdm_list; link; link = link->next)
{
- g_warning ("Got DisplayManager signal SessionRemoved with unknown parameters %s", g_variant_get_type_string (parameters));
- return;
- }
-
- g_variant_get (parameters, "(&o)", &path);
-
- for (link = priv->sessions; link; link = link->next)
- {
- Session *session = link->data;
- if (strcmp (session->path, path) == 0)
+ LightDMUser *lightdm_user = link->data;
+ LightDMUserPrivate *user_priv = GET_USER_PRIVATE (lightdm_user);
+ if (user_priv->common_user == common_user)
{
- LightDMUser *user;
-
- g_debug ("Session %s removed", path);
- priv->sessions = g_list_remove_link (priv->sessions, link);
- user = get_user_by_name (user_list, session->username);
- if (user)
- g_signal_emit (user, user_signals[CHANGED], 0);
- g_object_unref (session);
+ priv->lightdm_list = g_list_delete_link (priv->lightdm_list, link);
+ g_signal_emit (user_list, list_signals[USER_REMOVED], 0, lightdm_user);
+ g_object_unref (lightdm_user);
break;
}
}
}
static void
-load_users (LightDMUserList *user_list)
+initialize_user_list_if_needed (LightDMUserList *user_list)
{
LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
- GVariant *result;
- GError *error = NULL;
+ GList *common_users;
+ GList *link;
- if (priv->have_users)
+ if (priv->initialized)
return;
- priv->have_users = TRUE;
-
- /* Get user list from accounts service and fall back to /etc/passwd if that fails */
- priv->user_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
- "org.freedesktop.Accounts",
- "org.freedesktop.Accounts",
- "UserAdded",
- "/org/freedesktop/Accounts",
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- accounts_user_added_cb,
- user_list,
- NULL);
- priv->user_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
- "org.freedesktop.Accounts",
- "org.freedesktop.Accounts",
- "UserDeleted",
- "/org/freedesktop/Accounts",
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- accounts_user_deleted_cb,
- user_list,
- NULL);
- result = g_dbus_connection_call_sync (priv->bus,
- "org.freedesktop.Accounts",
- "/org/freedesktop/Accounts",
- "org.freedesktop.Accounts",
- "ListCachedUsers",
- g_variant_new ("()"),
- G_VARIANT_TYPE ("(ao)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
- if (error)
- g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
- g_clear_error (&error);
- if (result)
- {
- GVariantIter *iter;
- const gchar *path;
-
- g_debug ("Loading users from org.freedesktop.Accounts");
- g_variant_get (result, "(ao)", &iter);
- while (g_variant_iter_loop (iter, "&o", &path))
- add_accounts_user (user_list, path, FALSE);
- g_variant_iter_free (iter);
- g_variant_unref (result);
- }
- else
- {
- GFile *passwd_file;
-
- g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
- priv->user_added_signal = 0;
- g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
- priv->user_removed_signal = 0;
-
- load_passwd_file (user_list, FALSE);
-
- /* Watch for changes to user list */
- passwd_file = g_file_new_for_path (PASSWD_FILE);
- priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
- g_object_unref (passwd_file);
- if (error)
- g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
- else
- g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
- g_clear_error (&error);
- }
-
- priv->session_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
- "org.freedesktop.DisplayManager",
- "org.freedesktop.DisplayManager",
- "SessionAdded",
- "/org/freedesktop/DisplayManager",
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- session_added_cb,
- user_list,
- NULL);
- priv->session_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
- "org.freedesktop.DisplayManager",
- "org.freedesktop.DisplayManager",
- "SessionRemoved",
- "/org/freedesktop/DisplayManager",
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- session_removed_cb,
-
- user_list,
- NULL);
- result = g_dbus_connection_call_sync (priv->bus,
- "org.freedesktop.DisplayManager",
- "/org/freedesktop/DisplayManager",
- "org.freedesktop.DBus.Properties",
- "Get",
- g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
- G_VARIANT_TYPE ("(v)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
- if (error)
- g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
- g_clear_error (&error);
- if (result)
+ common_users = common_user_list_get_users (common_user_list_get_instance ());
+ for (link = common_users; link; link = link->next)
{
- if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
- {
- GVariant *value;
- GVariantIter *iter;
- const gchar *path;
-
- g_variant_get (result, "(v)", &value);
-
- g_debug ("Loading sessions from org.freedesktop.DisplayManager");
- g_variant_get (value, "ao", &iter);
- while (g_variant_iter_loop (iter, "&o", &path))
- load_session (user_list, path);
- g_variant_iter_free (iter);
+ CommonUser *user = link->data;
+ LightDMUser *lightdm_user = wrap_common_user (user);
+ priv->lightdm_list = g_list_prepend (priv->lightdm_list, lightdm_user);
+ }
+ priv->lightdm_list = g_list_reverse (priv->lightdm_list);
- g_variant_unref (value);
- }
- else
- g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
+ CommonUserList *common_list = common_user_list_get_instance ();
+ g_signal_connect (common_list, "user-added", G_CALLBACK (user_list_added_cb), user_list);
+ g_signal_connect (common_list, "user-changed", G_CALLBACK (user_list_changed_cb), user_list);
+ g_signal_connect (common_list, "user-removed", G_CALLBACK (user_list_removed_cb), user_list);
- g_variant_unref (result);
- }
+ priv->initialized = TRUE;
}
/**
@@ -902,8 +183,8 @@ gint
lightdm_user_list_get_length (LightDMUserList *user_list)
{
g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
- load_users (user_list);
- return g_list_length (GET_LIST_PRIVATE (user_list)->users);
+ initialize_user_list_if_needed (user_list);
+ return g_list_length (GET_LIST_PRIVATE (user_list)->lightdm_list);
}
/**
@@ -919,8 +200,8 @@ GList *
lightdm_user_list_get_users (LightDMUserList *user_list)
{
g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
- load_users (user_list);
- return GET_LIST_PRIVATE (user_list)->users;
+ initialize_user_list_if_needed (user_list);
+ return GET_LIST_PRIVATE (user_list)->lightdm_list;
}
/**
@@ -935,20 +216,26 @@ lightdm_user_list_get_users (LightDMUserList *user_list)
LightDMUser *
lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
{
+ GList *link;
+
g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
g_return_val_if_fail (username != NULL, NULL);
- load_users (user_list);
+ initialize_user_list_if_needed (user_list);
- return get_user_by_name (user_list, username);
+ for (link = GET_LIST_PRIVATE (user_list)->lightdm_list; link; link = link->next)
+ {
+ LightDMUser *user = link->data;
+ if (g_strcmp0 (lightdm_user_get_name (user), username) == 0)
+ return user;
+ }
+
+ return NULL;
}
static void
lightdm_user_list_init (LightDMUserList *user_list)
{
- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
-
- priv->bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
}
static void
@@ -987,21 +274,7 @@ lightdm_user_list_finalize (GObject *object)
LightDMUserList *self = LIGHTDM_USER_LIST (object);
LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
- /* Remove children first, they might access us */
- g_list_free_full (priv->users, g_object_unref);
- g_list_free_full (priv->sessions, g_object_unref);
-
- if (priv->user_added_signal)
- g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
- if (priv->user_removed_signal)
- g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
- if (priv->session_added_signal)
- g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_added_signal);
- if (priv->session_removed_signal)
- g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_removed_signal);
- g_object_unref (priv->bus);
- if (priv->passwd_monitor)
- g_object_unref (priv->passwd_monitor);
+ g_list_free_full (priv->lightdm_list, g_object_unref);
G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
}
@@ -1073,58 +346,6 @@ lightdm_user_list_class_init (LightDMUserListClass *klass)
G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
}
-static void
-load_dmrc (LightDMUser *user)
-{
- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
- gchar *path;
- //gboolean have_dmrc;
-
- if (!priv->dmrc_file)
- priv->dmrc_file = g_key_file_new ();
-
- /* Load from the user directory */
- path = g_build_filename (priv->home_directory, ".dmrc", NULL);
- /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
- g_free (path);
-
- /* If no ~/.dmrc, then load from the cache */
- // FIXME
-
- // FIXME: Watch for changes
-
- /* The Language field contains the locale */
- if (priv->language)
- g_free (priv->language);
- priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
-
- if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
- {
- g_strfreev (priv->layouts);
- priv->layouts = g_malloc (sizeof (gchar *) * 2);
- priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
- priv->layouts[1] = NULL;
- }
-
- if (priv->session)
- g_free (priv->session);
- priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
-}
-
-/* Loads language/layout/session info for user */
-static void
-load_user_values (LightDMUser *user)
-{
- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
-
- if (priv->loaded_values)
- return;
- priv->loaded_values = TRUE;
-
- if (!priv->path)
- load_dmrc (user);
-}
-
/**
* lightdm_user_get_name:
* @user: A #LightDMUser
@@ -1137,8 +358,7 @@ const gchar *
lightdm_user_get_name (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->name;
+ return common_user_get_name (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1153,8 +373,7 @@ const gchar *
lightdm_user_get_real_name (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->real_name;
+ return common_user_get_real_name (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1168,17 +387,8 @@ lightdm_user_get_real_name (LightDMUser *user)
const gchar *
lightdm_user_get_display_name (LightDMUser *user)
{
- LightDMUserPrivate *priv;
-
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
-
- load_user_values (user);
-
- priv = GET_USER_PRIVATE (user);
- if (!priv->real_name || strcmp (priv->real_name, "") == 0)
- return priv->name;
- else
- return priv->real_name;
+ return common_user_get_display_name (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1193,8 +403,7 @@ const gchar *
lightdm_user_get_home_directory (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->home_directory;
+ return common_user_get_home_directory (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1209,8 +418,7 @@ const gchar *
lightdm_user_get_image (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->image;
+ return common_user_get_image (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1225,8 +433,7 @@ const gchar *
lightdm_user_get_background (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->background;
+ return common_user_get_background (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1241,8 +448,7 @@ const gchar *
lightdm_user_get_language (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->language;
+ return common_user_get_language (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1257,8 +463,7 @@ const gchar *
lightdm_user_get_layout (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->layouts[0];
+ return common_user_get_layout (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1273,8 +478,7 @@ const gchar * const *
lightdm_user_get_layouts (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
+ return common_user_get_layouts (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1289,8 +493,7 @@ const gchar *
lightdm_user_get_session (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->session;
+ return common_user_get_session (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1304,23 +507,8 @@ lightdm_user_get_session (LightDMUser *user)
gboolean
lightdm_user_get_logged_in (LightDMUser *user)
{
- LightDMUserPrivate *priv;
- LightDMUserListPrivate *list_priv;
- GList *link;
-
g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
-
- priv = GET_USER_PRIVATE (user);
- list_priv = GET_LIST_PRIVATE (priv->user_list);
-
- for (link = list_priv->sessions; link; link = link->next)
- {
- Session *session = link->data;
- if (strcmp (session->username, priv->name) == 0)
- return TRUE;
- }
-
- return FALSE;
+ return common_user_get_logged_in (GET_USER_PRIVATE (user)->common_user);
}
/**
@@ -1335,16 +523,12 @@ gboolean
lightdm_user_get_has_messages (LightDMUser *user)
{
g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
- load_user_values (user);
- return GET_USER_PRIVATE (user)->has_messages;
+ return common_user_get_has_messages (GET_USER_PRIVATE (user)->common_user);
}
static void
lightdm_user_init (LightDMUser *user)
{
- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
- priv->layouts = g_malloc (sizeof (gchar *) * 1);
- priv->layouts[0] = NULL;
}
static void
@@ -1353,7 +537,18 @@ lightdm_user_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ LightDMUser *self = LIGHTDM_USER (object);
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
+
+ switch (prop_id)
+ {
+ case USER_PROP_COMMON_USER:
+ priv->common_user = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
static void
@@ -1416,17 +611,9 @@ lightdm_user_finalize (GObject *object)
LightDMUser *self = LIGHTDM_USER (object);
LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
- g_free (priv->path);
- if (priv->changed_signal)
- g_dbus_connection_signal_unsubscribe (GET_LIST_PRIVATE (priv->user_list)->bus, priv->changed_signal);
- g_free (priv->name);
- g_free (priv->real_name);
- g_free (priv->home_directory);
- g_free (priv->image);
- g_free (priv->background);
- g_strfreev (priv->layouts);
- if (priv->dmrc_file)
- g_key_file_free (priv->dmrc_file);
+ g_object_unref (priv->common_user);
+
+ G_OBJECT_CLASS (lightdm_user_parent_class)->finalize (object);
}
static void
@@ -1441,6 +628,13 @@ lightdm_user_class_init (LightDMUserClass *klass)
object_class->finalize = lightdm_user_finalize;
g_object_class_install_property (object_class,
+ USER_PROP_COMMON_USER,
+ g_param_spec_object ("common-user",
+ "common-user",
+ "Internal user object",
+ COMMON_TYPE_USER,
+ G_PARAM_PRIVATE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_WRITABLE));
+ g_object_class_install_property (object_class,
USER_PROP_NAME,
g_param_spec_string ("name",
"name",
@@ -1540,24 +734,3 @@ lightdm_user_class_init (LightDMUserClass *klass)
NULL,
G_TYPE_NONE, 0);
}
-
-static void
-session_init (Session *session)
-{
-}
-
-static void
-session_finalize (GObject *object)
-{
- Session *self = SESSION (object);
-
- g_free (self->path);
- g_free (self->username);
-}
-
-static void
-session_class_init (SessionClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = session_finalize;
-}