[gdm/f14/master] Fix "invisible user switch applet" problem

Ray Strode rstrode at fedoraproject.org
Wed Sep 15 15:48:19 UTC 2010


commit 54f970e92c0a334a0634e3a02badb53bf1f067d7
Author: Ray Strode <rstrode at redhat.com>
Date:   Wed Sep 15 11:45:54 2010 -0400

    Fix "invisible user switch applet" problem
    
    There is a period of time when first starting up that
    get_user calls will fail to function properly because
    it communicates with the accounts service synchronously
    while the user manager is doing it's initial bring up
    asynchronously.
    
    This package makes get_user asynchronous like the rest of
    the user manager code, and also enforces an ordering
    requirement that get_user requests are deferred until
    after the user manager is loaded.
    
    The upshot is that the user switcher should consistently
    present the user's name now when the accounts service
    is disabled.

 fix-user-async-issue.patch |  333 ++++++++++++++++++++++++++++++++++++++++++++
 gdm.spec                   |    5 +-
 2 files changed, 337 insertions(+), 1 deletions(-)
---
diff --git a/fix-user-async-issue.patch b/fix-user-async-issue.patch
index 146f388..35b8107 100644
--- a/fix-user-async-issue.patch
+++ b/fix-user-async-issue.patch
@@ -1177,4 +1177,337 @@ index 5aa2cfa..4a79c58 100644
          pixbuf = gdm_user_render_icon (user, size);
 -- 
 1.7.2.3
+From 885da996c1dde9b81eebea76936751f5ccbdbd52 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Tue, 14 Sep 2010 17:22:13 -0400
+Subject: [PATCH] Defer get_user requests until manager loaded
+
+There is a period of time when first starting up that
+get_user calls will fail to function properly because
+it communicates with the accounts service synchronously
+while the user manager is doing it's initial bring up
+asynchronously.
+
+This commit makes get_user asynchronous like the rest of
+the user manager code, and also enforces an ordering
+requirement that get_user requests are deferred until
+after the user manager is loaded.
+---
+ gui/simple-greeter/gdm-user-manager.c |  244 ++++++++++++++++++++++++++++-----
+ 1 files changed, 212 insertions(+), 32 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-user-manager.c b/gui/simple-greeter/gdm-user-manager.c
+index 305fd93..178bf90 100644
+--- a/gui/simple-greeter/gdm-user-manager.c
++++ b/gui/simple-greeter/gdm-user-manager.c
+@@ -131,6 +131,24 @@ typedef struct
+         char                            *x11_display;
+ } GdmUserManagerNewSession;
+ 
++typedef enum {
++        GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED = 0,
++        GDM_USER_MANAGER_GET_USER_STATE_WAIT_FOR_LOADED,
++        GDM_USER_MANAGER_GET_USER_STATE_ASK_ACCOUNTS_SERVICE,
++        GDM_USER_MANAGER_GET_USER_STATE_FETCHED
++} GdmUserManagerGetUserState;
++
++typedef struct
++{
++        GdmUserManager             *manager;
++        GdmUserManagerGetUserState  state;
++        GdmUser                    *user;
++        char                       *username;
++        char                       *object_path;
++
++        DBusGProxyCall             *call;
++} GdmUserManagerFetchUserRequest;
++
+ struct GdmUserManagerPrivate
+ {
+         GHashTable            *users_by_name;
+@@ -145,6 +163,7 @@ struct GdmUserManagerPrivate
+ 
+         GSList                *new_sessions;
+         GSList                *new_users;
++        GSList                *fetch_user_requests;
+ 
+         GFileMonitor          *passwd_monitor;
+         GFileMonitor          *shells_monitor;
+@@ -203,6 +222,12 @@ static void     set_is_loaded (GdmUserManager *manager, gboolean is_loaded);
+ static void     on_new_user_loaded (GdmUser        *user,
+                                     GParamSpec     *pspec,
+                                     GdmUserManager *manager);
++static void     give_up_and_fetch_user_locally (GdmUserManager                 *manager,
++                                                GdmUserManagerFetchUserRequest *request);
++static void     fetch_user_locally             (GdmUserManager *manager,
++                                                GdmUser        *user,
++                                                const char     *username);
++static void     fetch_user_incrementally       (GdmUserManagerFetchUserRequest *request);
+ 
+ static gpointer user_manager_object = NULL;
+ 
+@@ -1058,37 +1083,80 @@ failed:
+         unload_new_session (new_session);
+ }
+ 
+-static char *
+-get_user_object_path_from_accounts_service (GdmUserManager *manager,
+-                                            const char     *name)
++static void
++on_find_user_by_name_finished (DBusGProxy                     *proxy,
++                               DBusGProxyCall                 *call,
++                               GdmUserManagerFetchUserRequest *request)
+ {
++        GdmUserManager  *manager;
+         GError          *error;
+         char            *object_path;
+         gboolean         res;
+ 
+-        g_assert (manager->priv->accounts_proxy != NULL);
++        g_assert (request->call == call);
+ 
+         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);
++        manager = request->manager;
++        res = dbus_g_proxy_end_call (manager->priv->accounts_proxy,
++                                     call,
++                                     &error,
++                                     DBUS_TYPE_G_OBJECT_PATH,
++                                     &object_path,
++                                     G_TYPE_INVALID);
+         if (! res) {
+                 if (error != NULL) {
+-                        g_debug ("GdmUserManager: Failed to find user %s: %s", name, error->message);
++                        g_debug ("GdmUserManager: Failed to find user %s: %s",
++                                 request->username, error->message);
+                         g_error_free (error);
+                 } else {
+-                        g_debug ("GdmUserManager: Failed to find user %s", name);
++                        g_debug ("GdmUserManager: Failed to find user %s",
++                                 request->username);
+                 }
+-                return NULL;
++                give_up_and_fetch_user_locally (manager, request);
++                return;
++        }
++
++        g_debug ("GdmUserManager: Found object path of user '%s': %s",
++                 request->username, object_path);
++        request->object_path = object_path;
++        request->state++;
++
++        fetch_user_incrementally (request);
++}
++
++static void
++find_user_in_accounts_service (GdmUserManager                 *manager,
++                               GdmUserManagerFetchUserRequest *request)
++{
++        DBusGProxyCall  *call;
++
++        g_debug ("GdmUserManager: Looking for user %s in accounts service",
++                 request->username);
++
++        g_assert (manager->priv->accounts_proxy != NULL);
++
++        call = dbus_g_proxy_begin_call (manager->priv->accounts_proxy,
++                                        "FindUserByName",
++                                        (DBusGProxyCallNotify)
++                                        on_find_user_by_name_finished,
++                                        request,
++                                        NULL,
++                                        G_TYPE_STRING,
++                                        request->username,
++                                        G_TYPE_INVALID);
++
++        if (call == NULL) {
++                g_warning ("GdmUserManager: failed to make FindUserByName('%s') call",
++                           request->username);
++                goto failed;
+         }
+-        return object_path;
++
++        request->call = call;
++        return;
++
++failed:
++        give_up_and_fetch_user_locally (manager, request);
+ }
+ 
+ static void
+@@ -1531,6 +1599,127 @@ load_new_session_incrementally (GdmUserManagerNewSession *new_session)
+         }
+ }
+ 
++static void
++free_fetch_user_request (GdmUserManagerFetchUserRequest *request)
++{
++        GdmUserManager *manager;
++
++        manager = request->manager;
++
++        manager->priv->fetch_user_requests = g_slist_remove (manager->priv->fetch_user_requests, request);
++        g_free (request->username);
++        g_free (request->object_path);
++        g_slice_free (GdmUserManagerFetchUserRequest, request);
++}
++
++static void
++give_up_and_fetch_user_locally (GdmUserManager                 *manager,
++                                GdmUserManagerFetchUserRequest *request)
++{
++
++        g_debug ("GdmUserManager: account service unavailable, "
++                 "fetching user %s locally",
++                 request->username);
++        fetch_user_locally (manager, request->user, request->username);
++        request->state = GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED;
++}
++
++static void
++on_user_manager_maybe_ready_for_request (GdmUserManager                 *manager,
++                                         GParamSpec                     *pspec,
++                                         GdmUserManagerFetchUserRequest *request)
++{
++        if (!manager->priv->is_loaded) {
++                return;
++        }
++
++        g_signal_handlers_disconnect_by_func (manager, on_user_manager_maybe_ready_for_request, request);
++
++        request->state++;
++        fetch_user_incrementally (request);
++}
++
++static void
++fetch_user_incrementally (GdmUserManagerFetchUserRequest *request)
++{
++        GdmUserManager *manager;
++
++        g_debug ("GdmUserManager: finding user %s state %d",
++                 request->username, request->state);
++        manager = request->manager;
++        switch (request->state) {
++        case GDM_USER_MANAGER_GET_USER_STATE_WAIT_FOR_LOADED:
++                if (manager->priv->is_loaded) {
++                        request->state++;
++                        fetch_user_incrementally (request);
++                } else {
++                        g_debug ("GdmUserManager: waiting for user manager to load before finding user %s",
++                                 request->username);
++                        g_signal_connect (manager, "notify::is-loaded",
++                                          G_CALLBACK (on_user_manager_maybe_ready_for_request), request);
++
++                }
++                break;
++
++        case GDM_USER_MANAGER_GET_USER_STATE_ASK_ACCOUNTS_SERVICE:
++                if (manager->priv->accounts_proxy == NULL) {
++                        give_up_and_fetch_user_locally (manager, request);
++                } else {
++                        find_user_in_accounts_service (manager, request);
++                }
++                break;
++        case GDM_USER_MANAGER_GET_USER_STATE_FETCHED:
++                g_debug ("GdmUserManager: user %s fetched", request->username);
++                _gdm_user_update_from_object_path (request->user, request->object_path);
++                break;
++        case GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED:
++                g_debug ("GdmUserManager: user %s was not fetched", request->username);
++                break;
++        default:
++                g_assert_not_reached ();
++        }
++
++        if (request->state == GDM_USER_MANAGER_GET_USER_STATE_FETCHED  ||
++            request->state == GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED) {
++                g_debug ("GdmUserManager: finished handling request for user %s",
++                         request->username);
++                free_fetch_user_request (request);
++        }
++}
++
++static void
++fetch_user_from_accounts_service (GdmUserManager *manager,
++                                  GdmUser        *user,
++                                  const char     *username)
++{
++        GdmUserManagerFetchUserRequest *request;
++
++        request = g_slice_new0 (GdmUserManagerFetchUserRequest);
++
++        request->manager = manager;
++        request->username = g_strdup (username);
++        request->user = user;
++        request->state = GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED + 1;
++
++        manager->priv->fetch_user_requests = g_slist_prepend (manager->priv->fetch_user_requests,
++                                                              request);
++        fetch_user_incrementally (request);
++}
++
++static void
++fetch_user_locally (GdmUserManager *manager,
++                    GdmUser        *user,
++                    const char     *username)
++{
++        struct passwd *pwent;
++
++        get_pwent_for_name (username, &pwent);
++
++        if (pwent != NULL) {
++                _gdm_user_update_from_pwent (user, pwent);
++        }
++}
++
+ /**
+  * gdm_manager_get_user:
+  * @manager: the manager to query.
+@@ -1557,22 +1746,9 @@ gdm_user_manager_get_user (GdmUserManager *manager,
+                 user = create_new_user (manager);
+ 
+                 if (manager->priv->accounts_proxy != NULL) {
+-                        char *object_path;
+-
+-                        object_path = get_user_object_path_from_accounts_service (manager, username);
+-
+-                        if (object_path != NULL) {
+-                                _gdm_user_update_from_object_path (user, object_path);
+-                                g_free (object_path);
+-                        }
++                        fetch_user_from_accounts_service (manager, user, username);
+                 } else {
+-                        struct passwd *pwent;
+-
+-                        get_pwent_for_name (username, &pwent);
+-
+-                        if (pwent != NULL) {
+-                                _gdm_user_update_from_pwent (user, pwent);
+-                        }
++                        fetch_user_locally (manager, user, username);
+                 }
+         }
+ 
+@@ -2769,6 +2945,10 @@ gdm_user_manager_finalize (GObject *object)
+                          (GFunc) unload_new_session, NULL);
+         g_slist_free (manager->priv->new_sessions);
+ 
++        g_slist_foreach (manager->priv->fetch_user_requests,
++                         (GFunc) free_fetch_user_request, NULL);
++        g_slist_free (manager->priv->fetch_user_requests);
++
+         node = manager->priv->new_users;
+         while (node != NULL) {
+                 GdmUser *user;
+-- 
+1.7.2.3
 
diff --git a/gdm.spec b/gdm.spec
index 1f8d6d3..eb6331c 100644
--- a/gdm.spec
+++ b/gdm.spec
@@ -15,7 +15,7 @@
 Summary: The GNOME Display Manager
 Name: gdm
 Version: 2.31.90
-Release: 6%{?dist}
+Release: 7%{?dist}
 Epoch: 1
 License: GPLv2+
 Group: User Interface/X
@@ -374,6 +374,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || :
 %{_libdir}/gdm/simple-greeter/plugins/fingerprint.so
 
 %changelog
+* Wed Sep 15 2010 Ray Strode <rstrode at redhat.com> 2.31.90-7
+- More user switch applet fixes
+
 * Mon Sep 13 2010 Ray Strode <rstrode at redhat.com> 2.31.90-6
 - Fix crashing-in-a-loop gdm when accounts service is enabled
   (caused by -5)


More information about the scm-commits mailing list