[gdm] Get users from account service, fallback to old way



commit b236a9dab5dcf709546a8721ce823ae7ea989cf0
Author: Ray Strode <rstrode redhat com>
Date:   Tue Mar 16 03:07:19 2010 -0400

    Get users from account service, fallback to old way
    
    https://bugzilla.gnome.org/show_bug.cgi?id=610179

 gui/simple-greeter/gdm-user-manager.c |  413 +++++++++++++++++++++++++-------
 gui/simple-greeter/gdm-user.c         |  276 +++++++++++++++++-----
 gui/simple-greeter/gdm-user.h         |    4 +
 gui/user-switch-applet/applet.c       |    7 +-
 4 files changed, 543 insertions(+), 157 deletions(-)
---
diff --git a/gui/simple-greeter/gdm-user-manager.c b/gui/simple-greeter/gdm-user-manager.c
index a91b999..857314a 100644
--- a/gui/simple-greeter/gdm-user-manager.c
+++ b/gui/simple-greeter/gdm-user-manager.c
@@ -61,9 +61,9 @@
 /* Prefs Defaults */
 
 #ifdef __sun
-#define DEFAULT_MINIMAL_UID     100
+#define FALLBACK_MINIMAL_UID     100
 #else
-#define DEFAULT_MINIMAL_UID     500
+#define FALLBACK_MINIMAL_UID     500
 #endif
 
 #ifndef _PATH_SHELLS
@@ -78,13 +78,19 @@
 #define GDM_USERNAME "gdm"
 #endif
 
+#define ACCOUNTS_NAME      "org.freedesktop.Accounts"
+#define ACCOUNTS_PATH      "/org/freedesktop/Accounts"
+#define ACCOUNTS_INTERFACE "org.freedesktop.Accounts"
+
 struct GdmUserManagerPrivate
 {
         GHashTable            *users_by_name;
+        GHashTable            *users_by_object_path;
         GHashTable            *sessions;
         GHashTable            *shells;
         DBusGConnection       *connection;
         DBusGProxy            *seat_proxy;
+        DBusGProxy            *accounts_proxy;
         char                  *seat_id;
 
         GFileMonitor          *passwd_monitor;
@@ -127,7 +133,7 @@ static void     gdm_user_manager_class_init (GdmUserManagerClass *klass);
 static void     gdm_user_manager_init       (GdmUserManager      *user_manager);
 static void     gdm_user_manager_finalize   (GObject             *object);
 
-static void load_users (GdmUserManager *manager);
+static void load_users_manually (GdmUserManager *manager);
 static void monitor_local_users (GdmUserManager *manager);
 
 static gpointer user_manager_object = NULL;
@@ -638,10 +644,19 @@ static void
 add_user (GdmUserManager *manager,
           GdmUser        *user)
 {
+        const char *object_path;
+
         g_hash_table_insert (manager->priv->users_by_name,
                              g_strdup (gdm_user_get_user_name (user)),
                              g_object_ref (user));
 
+        object_path = gdm_user_get_object_path (user);
+        if (object_path != NULL) {
+                g_hash_table_insert (manager->priv->users_by_object_path,
+                                     (gpointer) object_path,
+                                     g_object_ref (user));
+        }
+
         if (manager->priv->is_loaded) {
                 g_signal_emit (manager, signals[USER_ADDED], 0, user);
         }
@@ -657,12 +672,15 @@ add_new_user_for_pwent (GdmUserManager *manager,
 {
         GdmUser *user;
 
-        g_debug ("Creating new user");
+        g_debug ("Creating new user from password entry");
 
         user = create_user (manager);
         _gdm_user_update_from_pwent (user, pwent);
 
         add_user (manager, user);
+        g_object_unref (user);
+
+        user = g_hash_table_lookup (manager->priv->users_by_name, pwent->pw_name);
 
         return user;
 }
@@ -673,6 +691,9 @@ remove_user (GdmUserManager *manager,
 {
         g_signal_handlers_disconnect_by_func (user, on_user_changed, manager);
         g_signal_handlers_disconnect_by_func (user, on_user_sessions_changed, manager);
+        if (gdm_user_get_object_path (user) != NULL) {
+                g_hash_table_remove (manager->priv->users_by_object_path, gdm_user_get_object_path (user));
+        }
         g_hash_table_remove (manager->priv->users_by_name, gdm_user_get_user_name (user));
         g_signal_emit (manager, signals[USER_REMOVED], 0, user);
 
@@ -681,6 +702,62 @@ remove_user (GdmUserManager *manager,
         }
 }
 
+static void
+add_new_user_for_object_path (const char     *object_path,
+                              GdmUserManager *manager)
+{
+        GdmUser *user;
+        const char *username;
+
+        if (g_hash_table_lookup (manager->priv->users_by_object_path, object_path)) {
+                return;
+        }
+        user = gdm_user_new_from_object_path (object_path);
+
+        if (user == NULL) {
+                return;
+        }
+
+        username = gdm_user_get_user_name (user);
+        if (user_in_exclude_list (manager, username)) {
+                g_debug ("GdmUserManager: excluding user '%s'", username);
+                g_object_unref (user);
+                return;
+        }
+
+        g_signal_connect (user, "sessions-changed",
+                          G_CALLBACK (on_user_sessions_changed), manager);
+        g_signal_connect (user, "changed",
+                          G_CALLBACK (on_user_changed), manager);
+
+        add_user (manager, user);
+        g_object_unref (user);
+}
+
+static void
+on_new_user_in_accounts_service (DBusGProxy *proxy,
+                                 const char *object_path,
+                                 gpointer    user_data)
+{
+        GdmUserManager *manager = GDM_USER_MANAGER (user_data);
+
+        add_new_user_for_object_path (object_path, manager);
+}
+
+static void
+on_user_removed_in_accounts_service (DBusGProxy *proxy,
+                                     const char *object_path,
+                                     gpointer    user_data)
+{
+        GdmUserManager *manager = GDM_USER_MANAGER (user_data);
+        GdmUser *user;
+
+        user = g_hash_table_lookup (manager->priv->users_by_object_path, object_path);
+        g_object_ref (user);
+        remove_user (manager, user);
+        g_object_unref (user);
+}
+
 static char *
 get_current_seat_id (DBusGConnection *connection)
 {
@@ -777,6 +854,101 @@ get_uid_from_session_id (GdmUserManager *manager,
         return TRUE;
 }
 
+static char *
+get_user_object_path_from_accounts_service (GdmUserManager *manager,
+                                            const char     *name)
+{
+        GError          *error;
+        char            *object_path;
+        gboolean         res;
+
+        g_assert (manager->priv->accounts_proxy != NULL);
+
+        error = NULL;
+        object_path = NULL;
+        res = dbus_g_proxy_call (manager->priv->accounts_proxy,
+                                 "FindUserByName",
+                                 &error,
+                                 G_TYPE_STRING,
+                                 name,
+                                 G_TYPE_INVALID,
+                                 DBUS_TYPE_G_OBJECT_PATH,
+                                 &object_path,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                if (error != NULL) {
+                        g_debug ("Failed to find user %s: %s", name, error->message);
+                        g_error_free (error);
+                } else {
+                        g_debug ("Failed to find user %s", name);
+                }
+                return NULL;
+        }
+        return object_path;
+}
+
+static void
+set_is_loaded (GdmUserManager *manager,
+               gboolean        is_loaded)
+{
+        if (manager->priv->is_loaded != is_loaded) {
+                manager->priv->is_loaded = is_loaded;
+                g_object_notify (G_OBJECT (manager), "is-loaded");
+        }
+}
+
+static void
+on_list_cached_users_finished (DBusGProxy     *proxy,
+                               DBusGProxyCall *call_id,
+                               gpointer        data)
+{
+        GdmUserManager *manager = data;
+        GError *error = NULL;
+        GPtrArray *paths;
+
+        if (!dbus_g_proxy_end_call (proxy,
+                                    call_id,
+                                    &error,
+                                    dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &paths,
+                                    G_TYPE_INVALID)) {
+                g_debug ("ListCachedUsers failed: %s", error->message);
+                g_error_free (error);
+
+                g_object_unref (manager->priv->accounts_proxy);
+                manager->priv->accounts_proxy = NULL;
+
+                load_users_manually (manager);
+
+                return;
+        }
+
+        g_ptr_array_foreach (paths, (GFunc)add_new_user_for_object_path, manager);
+
+        g_ptr_array_foreach (paths, (GFunc)g_free, NULL);
+        g_ptr_array_free (paths, TRUE);
+
+        /* Add users who are specifically included */
+        if (manager->priv->include_usernames != NULL) {
+                GSList *l;
+
+                for (l = manager->priv->include_usernames; l != NULL; l = l->next) {
+                        GdmUser *user;
+
+                        g_debug ("Adding included user %s", (char *)l->data);
+                        /*
+                         * The call to gdm_user_manager_get_user will add the user if it is
+                         * valid and not already in the hash.
+                         */
+                        user = gdm_user_manager_get_user (manager, l->data);
+                        if (user == NULL) {
+                                g_debug ("GdmUserManager: unable to lookup user '%s'", (char *)l->data);
+                        }
+                }
+        }
+
+        set_is_loaded (manager, TRUE);
+}
+
 static void
 maybe_add_session (GdmUserManager *manager,
                    const char     *session_id)
@@ -785,7 +957,6 @@ maybe_add_session (GdmUserManager *manager,
         gboolean       res;
         struct passwd *pwent;
         GdmUser       *user;
-        gboolean       is_new;
         char          *x11_display;
 
         res = get_uid_from_session_id (manager, session_id, &uid);
@@ -816,22 +987,9 @@ maybe_add_session (GdmUserManager *manager,
                 return;
         }
 
-        user = g_hash_table_lookup (manager->priv->users_by_name, pwent->pw_name);
-        if (user == NULL) {
-                g_debug ("Creating new user");
-
-                user = create_user (manager);
-                _gdm_user_update_from_pwent (user, pwent);
-                is_new = TRUE;
-        } else {
-                is_new = FALSE;
-        }
-
-        add_session_for_user (manager, user, session_id);
-
-        /* only add the user if it was newly created */
-        if (is_new) {
-                add_user (manager, user);
+        user = gdm_user_manager_get_user (manager, pwent->pw_name);
+        if (user != NULL) {
+                add_session_for_user (manager, user, session_id);
         }
 }
 
@@ -939,6 +1097,60 @@ get_seat_proxy (GdmUserManager *manager)
 
 }
 
+static void
+on_accounts_proxy_destroy (DBusGProxy     *proxy,
+                           GdmUserManager *manager)
+{
+        g_debug ("GdmUserManager: accounts proxy destroyed");
+
+        manager->priv->accounts_proxy = NULL;
+}
+
+static void
+get_accounts_proxy (GdmUserManager *manager)
+{
+        DBusGProxy      *proxy;
+        GError          *error;
+
+        g_assert (manager->priv->accounts_proxy == NULL);
+
+        error = NULL;
+        proxy = dbus_g_proxy_new_for_name_owner (manager->priv->connection,
+                                                 ACCOUNTS_NAME,
+                                                 ACCOUNTS_PATH,
+                                                 ACCOUNTS_INTERFACE,
+                                                 &error);
+        manager->priv->accounts_proxy = proxy;
+
+        if (proxy != NULL) {
+                g_signal_connect (proxy, "destroy",
+                                  G_CALLBACK (on_accounts_proxy_destroy),
+                                  manager);
+
+                dbus_g_proxy_add_signal (proxy,
+                                         "UserAdded",
+                                         DBUS_TYPE_G_OBJECT_PATH,
+                                         G_TYPE_INVALID);
+                dbus_g_proxy_add_signal (proxy,
+                                         "UserDeleted",
+                                         DBUS_TYPE_G_OBJECT_PATH,
+                                         G_TYPE_INVALID);
+
+                dbus_g_proxy_connect_signal (proxy,
+                                             "UserAdded",
+                                             G_CALLBACK (on_new_user_in_accounts_service),
+                                             manager,
+                                             NULL);
+                dbus_g_proxy_connect_signal (proxy,
+                                             "UserDeleted",
+                                             G_CALLBACK (on_user_removed_in_accounts_service),
+                                             manager,
+                                             NULL);
+        } else {
+                g_debug ("GdmUserManager: Unable to connect to accounts service");
+        }
+}
+
 /**
  * gdm_manager_get_user:
  * @manager: the manager to query.
@@ -960,13 +1172,24 @@ gdm_user_manager_get_user (GdmUserManager *manager,
 
         user = g_hash_table_lookup (manager->priv->users_by_name, username);
 
+        /* if we don't have it loaded try to load it now */
         if (user == NULL) {
-                struct passwd *pwent;
+                if (manager->priv->accounts_proxy != NULL) {
+                        char *object_path;
 
-                pwent = getpwnam (username);
+                        object_path = get_user_object_path_from_accounts_service (manager, username);
 
-                if (pwent != NULL) {
-                        user = add_new_user_for_pwent (manager, pwent);
+                        if (object_path != NULL) {
+                                add_new_user_for_object_path (object_path, manager);
+                                g_free (object_path);
+                                user = g_hash_table_lookup (manager->priv->users_by_name, username);
+                        }
+                } else {
+                        struct passwd *pwent;
+                        pwent = getpwnam (username);
+                        if (pwent != NULL) {
+                                user = add_new_user_for_pwent (manager, pwent);
+                        }
                 }
         }
 
@@ -977,7 +1200,6 @@ GdmUser *
 gdm_user_manager_get_user_by_uid (GdmUserManager *manager,
                                   gulong          uid)
 {
-        GdmUser       *user;
         struct passwd *pwent;
 
         g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL);
@@ -988,13 +1210,7 @@ gdm_user_manager_get_user_by_uid (GdmUserManager *manager,
                 return NULL;
         }
 
-        user = g_hash_table_lookup (manager->priv->users_by_name, pwent->pw_name);
-
-        if (user == NULL) {
-                user = add_new_user_for_pwent (manager, pwent);
-        }
-
-        return user;
+        return gdm_user_manager_get_user (manager, pwent->pw_name);
 }
 
 static void
@@ -1138,16 +1354,6 @@ process_ck_history_line (GdmUserManager *manager,
         g_free (username);
 }
 
-static void
-set_is_loaded (GdmUserManager *manager,
-               gboolean        is_loaded)
-{
-        if (manager->priv->is_loaded != is_loaded) {
-                manager->priv->is_loaded = is_loaded;
-                g_object_notify (G_OBJECT (manager), "is-loaded");
-        }
-}
-
 static gboolean
 ck_history_watch (GIOChannel     *source,
                   GIOCondition    condition,
@@ -1351,7 +1557,7 @@ reload_passwd_file (GHashTable *valid_shells,
                      pwent = fgetpwent (fp)) {
 
                         /* Skip users below MinimalUID... */
-                        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
+                        if (pwent->pw_uid < FALLBACK_MINIMAL_UID) {
                                 continue;
                         }
 
@@ -1575,6 +1781,65 @@ load_sessions (GdmUserManager *manager)
         g_ptr_array_free (sessions, TRUE);
 }
 
+static void
+reload_shells (GdmUserManager *manager)
+{
+        char *shell;
+
+        setusershell ();
+
+        g_hash_table_remove_all (manager->priv->shells);
+        for (shell = getusershell (); shell != NULL; shell = getusershell ()) {
+                /* skip well known not-real shells */
+                if (shell == NULL
+                    || strcmp (shell, "/sbin/nologin") == 0
+                    || strcmp (shell, "/bin/false") == 0) {
+                        g_debug ("GdmUserManager: skipping shell %s", shell);
+                        continue;
+                }
+                g_hash_table_insert (manager->priv->shells,
+                                     g_strdup (shell),
+                                     GUINT_TO_POINTER (TRUE));
+        }
+
+        endusershell ();
+}
+
+static void
+load_users_manually (GdmUserManager *manager)
+{
+        gboolean res;
+
+        manager->priv->shells = g_hash_table_new_full (g_str_hash,
+                                                       g_str_equal,
+                                                       g_free,
+                                                       NULL);
+        reload_shells (manager);
+
+        load_sessions (manager);
+
+        res = load_ck_history (manager);
+        schedule_reload_passwd (manager);
+}
+
+static void
+load_users (GdmUserManager *manager)
+{
+        if (manager->priv->accounts_proxy != NULL) {
+                g_debug ("GdmUserManager: calling 'ListCachedUsers'");
+
+                dbus_g_proxy_begin_call (manager->priv->accounts_proxy,
+                                         "ListCachedUsers",
+                                         on_list_cached_users_finished,
+                                         manager,
+                                         NULL,
+                                         G_TYPE_INVALID);
+        } else {
+                g_debug ("GdmUserManager: Getting users manually");
+                load_users_manually (manager);
+        }
+}
+
 static gboolean
 load_users_idle (GdmUserManager *manager)
 {
@@ -1614,30 +1879,6 @@ queue_reload_passwd (GdmUserManager *manager)
 }
 
 static void
-reload_shells (GdmUserManager *manager)
-{
-        char *shell;
-
-        setusershell ();
-
-        g_hash_table_remove_all (manager->priv->shells);
-        for (shell = getusershell (); shell != NULL; shell = getusershell ()) {
-                /* skip well known not-real shells */
-                if (shell == NULL
-                    || strcmp (shell, "/sbin/nologin") == 0
-                    || strcmp (shell, "/bin/false") == 0) {
-                        g_debug ("GdmUserManager: skipping shell %s", shell);
-                        continue;
-                }
-                g_hash_table_insert (manager->priv->shells,
-                                     g_strdup (shell),
-                                     GUINT_TO_POINTER (TRUE));
-        }
-
-        endusershell ();
-}
-
-static void
 on_shells_monitor_changed (GFileMonitor     *monitor,
                            GFile            *file,
                            GFile            *other_file,
@@ -1819,23 +2060,6 @@ monitor_local_users (GdmUserManager *manager)
 }
 
 static void
-load_users (GdmUserManager *manager)
-{
-        gboolean res;
-
-        manager->priv->shells = g_hash_table_new_full (g_str_hash,
-                                                       g_str_equal,
-                                                       g_free,
-                                                       NULL);
-        reload_shells (manager);
-
-        load_sessions (manager);
-
-        res = load_ck_history (manager);
-        schedule_reload_passwd (manager);
-}
-
-static void
 gdm_user_manager_class_init (GdmUserManagerClass *klass)
 {
         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
@@ -1944,9 +2168,10 @@ gdm_user_manager_init (GdmUserManager *manager)
                                                               g_free,
                                                               (GDestroyNotify) g_object_run_dispose);
 
-        if (manager->priv->include_all == TRUE) {
-                monitor_local_users (manager);
-        }
+        manager->priv->users_by_object_path = g_hash_table_new_full (g_str_hash,
+                                                                     g_str_equal,
+                                                                     NULL,
+                                                                     (GDestroyNotify) g_object_unref);
 
         g_assert (manager->priv->seat_proxy == NULL);
 
@@ -1965,7 +2190,7 @@ gdm_user_manager_init (GdmUserManager *manager)
         manager->priv->cancellable = g_cancellable_new ();
 
         get_seat_proxy (manager);
-
+        get_accounts_proxy (manager);
         queue_load_users (manager);
 }
 
@@ -2017,10 +2242,16 @@ gdm_user_manager_finalize (GObject *object)
 
         g_hash_table_destroy (manager->priv->sessions);
 
-        g_file_monitor_cancel (manager->priv->passwd_monitor);
+        if (manager->priv->passwd_monitor != NULL) {
+                g_file_monitor_cancel (manager->priv->passwd_monitor);
+        }
+
         g_hash_table_destroy (manager->priv->users_by_name);
+        g_hash_table_destroy (manager->priv->users_by_object_path);
 
-        g_file_monitor_cancel (manager->priv->shells_monitor);
+        if (manager->priv->shells_monitor != NULL) {
+                g_file_monitor_cancel (manager->priv->shells_monitor);
+        }
         g_hash_table_destroy (manager->priv->shells);
 
         g_free (manager->priv->seat_id);
diff --git a/gui/simple-greeter/gdm-user.c b/gui/simple-greeter/gdm-user.c
index a83076b..4f6194f 100644
--- a/gui/simple-greeter/gdm-user.c
+++ b/gui/simple-greeter/gdm-user.c
@@ -26,6 +26,9 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <dbus/dbus-glib.h>
+
+#include <glib.h>
 #include <glib/gi18n.h>
 #include <gio/gio.h>
 #include <gtk/gtk.h>
@@ -41,6 +44,9 @@
 #define MAX_FILE_SIZE     65536
 #define MINIMAL_UID       100
 
+#define USER_ACCOUNTS_NAME      "org.freedesktop.Accounts"
+#define USER_ACCOUNTS_INTERFACE "org.freedesktop.Accounts.User"
+
 enum {
         CHANGED,
         SESSIONS_CHANGED,
@@ -50,11 +56,14 @@ enum {
 struct _GdmUser {
         GObject         parent;
 
+        DBusGConnection *connection;
+        DBusGProxy      *accounts_proxy;
+        char            *object_path;
+
         uid_t           uid;
         char           *user_name;
         char           *real_name;
-        char           *home_dir;
-        char           *shell;
+        char           *icon_file;
         GList          *sessions;
         gulong          login_frequency;
 };
@@ -65,6 +74,8 @@ typedef struct _GdmUserClass
 } GdmUserClass;
 
 static void gdm_user_finalize     (GObject      *object);
+static gboolean check_user_file (const char *filename,
+                                 gssize      max_file_size);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
@@ -158,9 +169,17 @@ gdm_user_class_init (GdmUserClass *class)
 static void
 gdm_user_init (GdmUser *user)
 {
+        GError *error;
+
         user->user_name = NULL;
         user->real_name = NULL;
         user->sessions = NULL;
+
+        error = NULL;
+        user->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (user->connection == NULL) {
+                g_warning ("Couldn't connect to system bus: %s", error->message);
+        }
 }
 
 static void
@@ -172,6 +191,15 @@ gdm_user_finalize (GObject *object)
 
         g_free (user->user_name);
         g_free (user->real_name);
+        g_free (user->icon_file);
+
+        if (user->accounts_proxy != NULL) {
+                g_object_unref (user->accounts_proxy);
+        }
+
+        if (user->connection != NULL) {
+                dbus_g_connection_unref (user->connection);
+        }
 
         if (G_OBJECT_CLASS (gdm_user_parent_class)->finalize)
                 (*G_OBJECT_CLASS (gdm_user_parent_class)->finalize) (object);
@@ -195,6 +223,7 @@ _gdm_user_update_from_pwent (GdmUser             *user,
 
         g_return_if_fail (GDM_IS_USER (user));
         g_return_if_fail (pwent != NULL);
+        g_return_if_fail (user->object_path == NULL);
 
         changed = FALSE;
 
@@ -253,6 +282,23 @@ _gdm_user_update_from_pwent (GdmUser             *user,
             (pwent->pw_name &&
              user->user_name &&
              strcmp (user->user_name, pwent->pw_name) != 0)) {
+
+                g_free (user->icon_file);
+                user->icon_file = NULL;
+                if (pwent->pw_name != NULL) {
+                        gboolean      res;
+
+                        user->icon_file = g_build_filename (GDM_CACHE_DIR, pwent->pw_name, "face", NULL);
+
+                        res = check_user_file (user->icon_file,
+                                               MAX_FILE_SIZE);
+
+                        if (!res) {
+                                g_free (user->icon_file);
+                                user->icon_file = g_build_filename (GLOBAL_FACEDIR, pwent->pw_name, NULL);
+                        }
+                }
+
                 g_free (user->user_name);
                 user->user_name = g_strdup (pwent->pw_name);
                 changed = TRUE;
@@ -431,31 +477,6 @@ check_user_file (const char *filename,
         return TRUE;
 }
 
-static GdkPixbuf *
-render_icon_from_cache (GdmUser *user,
-                        int      icon_size)
-{
-        GdkPixbuf  *retval;
-        char       *path;
-        gboolean    res;
-
-        path = g_build_filename (GDM_CACHE_DIR, user->user_name, "face", NULL);
-        res = check_user_file (path,
-                               MAX_FILE_SIZE);
-        if (res) {
-                retval = gdk_pixbuf_new_from_file_at_size (path,
-                                                           icon_size,
-                                                           icon_size,
-                                                           NULL);
-        } else {
-                g_debug ("Could not access face icon %s", path);
-                retval = NULL;
-        }
-        g_free (path);
-
-        return retval;
-}
-
 static void
 rounded_rectangle (cairo_t *cr,
                    gdouble  aspect,
@@ -689,55 +710,41 @@ gdm_user_render_icon (GdmUser   *user,
 {
         GdkPixbuf    *pixbuf;
         GdkPixbuf    *framed;
-        char         *path;
-        char         *tmp;
         gboolean      res;
+        GError       *error;
 
         g_return_val_if_fail (GDM_IS_USER (user), NULL);
         g_return_val_if_fail (icon_size > 12, NULL);
 
-        path = NULL;
-
-        pixbuf = render_icon_from_cache (user, icon_size);
-        if (pixbuf != NULL) {
-                goto out;
-        }
-
-        /* Try ${GlobalFaceDir}/${username} */
-        path = g_build_filename (GLOBAL_FACEDIR, user->user_name, NULL);
-        res = check_user_file (path,
-                               MAX_FILE_SIZE);
-        if (res) {
-                pixbuf = gdk_pixbuf_new_from_file_at_size (path,
-                                                           icon_size,
-                                                           icon_size,
-                                                           NULL);
-        } else {
-                g_debug ("Could not access global face icon %s", path);
-                pixbuf = NULL;
+        pixbuf = NULL;
+        if (user->icon_file) {
+                res = check_user_file (user->icon_file,
+                                       MAX_FILE_SIZE);
+                if (res) {
+                        pixbuf = gdk_pixbuf_new_from_file_at_size (user->icon_file,
+                                                                   icon_size,
+                                                                   icon_size,
+                                                                   NULL);
+                } else {
+                        pixbuf = NULL;
+                }
         }
 
-        g_free (path);
         if (pixbuf != NULL) {
                 goto out;
         }
 
-        /* Finally, ${GlobalFaceDir}/${username}.png */
-        tmp = g_strconcat (user->user_name, ".png", NULL);
-        path = g_build_filename (GLOBAL_FACEDIR, tmp, NULL);
-        g_free (tmp);
-        res = check_user_file (path,
-                               MAX_FILE_SIZE);
-        if (res) {
-                pixbuf = gdk_pixbuf_new_from_file_at_size (path,
-                                                           icon_size,
-                                                           icon_size,
-                                                           NULL);
-        } else {
-                g_debug ("Could not access global face icon %s", path);
-                pixbuf = NULL;
+        error = NULL;
+        pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+
+                                           "avatar-default",
+                                           icon_size,
+                                           GTK_ICON_LOOKUP_FORCE_SIZE,
+                                           &error);
+        if (error) {
+                g_warning ("%s", error->message);
+                g_error_free (error);
         }
-        g_free (path);
  out:
 
         if (pixbuf != NULL) {
@@ -751,6 +758,22 @@ gdm_user_render_icon (GdmUser   *user,
         return pixbuf;
 }
 
+G_CONST_RETURN gchar *
+gdm_user_get_icon_file (GdmUser *user)
+{
+        g_return_val_if_fail (GDM_IS_USER (user), NULL);
+
+        return user->icon_file;
+}
+
+G_CONST_RETURN gchar *
+gdm_user_get_object_path (GdmUser *user)
+{
+        g_return_val_if_fail (GDM_IS_USER (user), NULL);
+
+        return user->object_path;
+}
+
 G_CONST_RETURN char *
 gdm_user_get_primary_session_id (GdmUser *user)
 {
@@ -780,3 +803,128 @@ out:
         return primary_ssid;
 }
 
+static void
+collect_props (const gchar    *key,
+               const GValue   *value,
+               GdmUser        *user)
+{
+        gboolean handled = TRUE;
+
+        if (strcmp (key, "Uid") == 0) {
+                user->uid = g_value_get_uint64 (value);
+        } else if (strcmp (key, "UserName") == 0) {
+                g_free (user->user_name);
+                user->user_name = g_value_dup_string (value);
+        } else if (strcmp (key, "RealName") == 0) {
+                g_free (user->real_name);
+                user->real_name = g_value_dup_string (value);
+        } else if (strcmp (key, "AccountType") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "Email") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "Language") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "Location") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "LoginFrequency") == 0) {
+                user->login_frequency = g_value_get_uint64 (value);
+        } else if (strcmp (key, "IconFile") == 0) {
+                g_free (user->icon_file);
+                user->icon_file = g_value_dup_string (value);
+        } else if (strcmp (key, "Locked") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "AutomaticLogin") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "PasswordMode") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "PasswordHint") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "HomeDirectory") == 0) {
+                /* ignore */
+        } else if (strcmp (key, "Shell") == 0) {
+                /* ignore */
+        } else {
+                handled = FALSE;
+        }
+
+        if (!handled) {
+                g_debug ("unhandled property %s", key);
+        }
+}
+
+static gboolean
+update_info (GdmUser *user)
+{
+        GError *error;
+        DBusGProxy *proxy;
+        GHashTable *hash_table;
+        gboolean retval;
+
+        proxy = dbus_g_proxy_new_for_name (user->connection,
+                                           USER_ACCOUNTS_NAME,
+                                           user->object_path,
+                                           DBUS_INTERFACE_PROPERTIES);
+
+        error = NULL;
+        if (!dbus_g_proxy_call (proxy,
+                                "GetAll",
+                                &error,
+                                G_TYPE_STRING,
+                                USER_ACCOUNTS_INTERFACE,
+                                G_TYPE_INVALID,
+                                dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
+                                &hash_table,
+                                G_TYPE_INVALID)) {
+                g_debug ("Error calling GetAll() when retrieving properties for %s: %s", user->object_path, error->message);
+                g_error_free (error);
+                retval = FALSE;
+                goto out;
+        }
+        g_hash_table_foreach (hash_table, (GHFunc) collect_props, user);
+        g_hash_table_unref (hash_table);
+
+        retval = TRUE;
+ out:
+        g_object_unref (proxy);
+        return retval;
+}
+
+static void
+changed_handler (DBusGProxy *proxy,
+                 gpointer   *data)
+{
+        GdmUser *user = GDM_USER (data);
+
+        if (update_info (user)) {
+                g_signal_emit (user, signals[CHANGED], 0);
+        }
+}
+
+GdmUser *
+gdm_user_new_from_object_path (const gchar *object_path)
+{
+        GdmUser *user;
+
+        user = (GdmUser *)g_object_new (GDM_TYPE_USER, NULL);
+        user->object_path = g_strdup (object_path);
+
+        user->accounts_proxy = dbus_g_proxy_new_for_name (user->connection,
+                                                          USER_ACCOUNTS_NAME,
+                                                          user->object_path,
+                                                          USER_ACCOUNTS_INTERFACE);
+        dbus_g_proxy_set_default_timeout (user->accounts_proxy, INT_MAX);
+        dbus_g_proxy_add_signal (user->accounts_proxy, "Changed", G_TYPE_INVALID);
+
+        dbus_g_proxy_connect_signal (user->accounts_proxy, "Changed",
+                                     G_CALLBACK (changed_handler), user, NULL);
+
+        if (!update_info (user)) {
+                goto error;
+        }
+
+        return user;
+
+ error:
+        g_object_unref (user);
+        return NULL;
+}
diff --git a/gui/simple-greeter/gdm-user.h b/gui/simple-greeter/gdm-user.h
index 725c06a..ff566a7 100644
--- a/gui/simple-greeter/gdm-user.h
+++ b/gui/simple-greeter/gdm-user.h
@@ -39,12 +39,16 @@ typedef struct _GdmUser GdmUser;
 
 GType                 gdm_user_get_type            (void) G_GNUC_CONST;
 
+GdmUser              *gdm_user_new_from_object_path (const gchar *path);
+const char           *gdm_user_get_object_path      (GdmUser *user);
+
 gulong                gdm_user_get_uid             (GdmUser   *user);
 G_CONST_RETURN char  *gdm_user_get_user_name       (GdmUser   *user);
 G_CONST_RETURN char  *gdm_user_get_real_name       (GdmUser   *user);
 guint                 gdm_user_get_num_sessions    (GdmUser   *user);
 gboolean              gdm_user_is_logged_in        (GdmUser   *user);
 gulong                gdm_user_get_login_frequency (GdmUser   *user);
+G_CONST_RETURN char  *gdm_user_get_icon_file       (GdmUser   *user);
 G_CONST_RETURN char  *gdm_user_get_primary_session_id (GdmUser *user);
 
 GdkPixbuf            *gdm_user_render_icon         (GdmUser   *user,
diff --git a/gui/user-switch-applet/applet.c b/gui/user-switch-applet/applet.c
index 72e77bd..c824eb1 100644
--- a/gui/user-switch-applet/applet.c
+++ b/gui/user-switch-applet/applet.c
@@ -791,9 +791,12 @@ on_account_activate (GtkMenuItem   *item,
         GdkScreen *screen;
         gboolean   res;
 
-        args[0] = g_find_program_in_path ("gnome-about-me");
+        args[0] = g_find_program_in_path ("accounts-dialog");
         if (args[0] == NULL) {
-                return;
+                args[0] = g_find_program_in_path ("gnome-about-me");
+                if (args[0] == NULL) {
+                        return;
+                }
         }
         args[1] = NULL;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]