Blob Blame Raw
From 42bd3bd41d69100308a22df43482569f6ab53dbe Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 27 Sep 2017 14:44:48 -0400
Subject: [PATCH 05/13] lib: consolidate change notification

if the daemon sends out multiple change notifications for a user
because several properties changed in quick succession, try to
batch them up, and only update info at the end.
---
 src/libaccountsservice/act-user.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/libaccountsservice/act-user.c b/src/libaccountsservice/act-user.c
index dbb9b53..17acacb 100644
--- a/src/libaccountsservice/act-user.c
+++ b/src/libaccountsservice/act-user.c
@@ -113,60 +113,62 @@ struct _ActUser {
         char            *object_path;
 
         uid_t           uid;
         char           *user_name;
         char           *real_name;
         char           *password_hint;
         char           *home_dir;
         char           *shell;
         char           *email;
         char           *location;
         char           *icon_file;
         char           *language;
         char           *x_session;
         GList          *our_sessions;
         GList          *other_sessions;
         int             login_frequency;
         gint64          login_time;
         GVariant       *login_history;
 
         ActUserAccountType  account_type;
         ActUserPasswordMode password_mode;
 
         guint           uid_set : 1;
 
         guint           is_loaded : 1;
         guint           locked : 1;
         guint           automatic_login : 1;
         guint           system_account : 1;
         guint           local_account : 1;
         guint           nonexistent : 1;
+
+        guint           update_info_timeout_id;
 };
 
 struct _ActUserClass
 {
         GObjectClass parent_class;
 };
 
 static void act_user_finalize     (GObject      *object);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (ActUser, act_user, G_TYPE_OBJECT)
 
 static int
 session_compare (const char *a,
                  const char *b)
 {
         if (a == NULL) {
                 return 1;
         } else if (b == NULL) {
                 return -1;
         }
 
         return strcmp (a, b);
 }
 
 void
 _act_user_add_session (ActUser    *user,
                        const char *ssid,
                        gboolean    is_ours)
@@ -573,60 +575,64 @@ act_user_finalize (GObject *object)
 
         g_free (user->user_name);
         g_free (user->real_name);
         g_free (user->icon_file);
         g_free (user->language);
         g_free (user->object_path);
         g_free (user->password_hint);
         g_free (user->home_dir);
         g_free (user->shell);
         g_free (user->email);
         g_free (user->location);
         if (user->login_history)
           g_variant_unref (user->login_history);
 
         if (user->accounts_proxy != NULL) {
                 g_object_unref (user->accounts_proxy);
         }
 
         if (user->object_proxy != NULL) {
                 g_object_unref (user->object_proxy);
         }
 
         if (user->get_all_cancellable != NULL) {
                 g_object_unref (user->get_all_cancellable);
         }
 
         if (user->connection != NULL) {
                 g_object_unref (user->connection);
         }
 
+        if (user->update_info_timeout_id != 0) {
+                g_source_remove (user->update_info_timeout_id);
+        }
+
         if (G_OBJECT_CLASS (act_user_parent_class)->finalize)
                 (*G_OBJECT_CLASS (act_user_parent_class)->finalize) (object);
 }
 
 static void
 set_is_loaded (ActUser  *user,
                gboolean  is_loaded)
 {
         if (user->is_loaded != is_loaded) {
                 user->is_loaded = is_loaded;
                 g_object_notify (G_OBJECT (user), "is-loaded");
         }
 }
 
 /**
  * act_user_get_uid:
  * @user: the user object to examine.
  *
  * Retrieves the ID of @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 
 uid_t
 act_user_get_uid (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), -1);
 
         return user->uid;
@@ -1339,67 +1345,79 @@ on_get_all_finished (GObject        *object,
         g_variant_unref (res);
 
         if (!user->is_loaded) {
                 set_is_loaded (user, TRUE);
         }
 
         g_signal_emit (user, signals[CHANGED], 0);
 }
 
 static void
 update_info (ActUser *user)
 {
         g_assert (G_IS_DBUS_PROXY (user->object_proxy));
 
         if (user->get_all_cancellable != NULL) {
                 g_cancellable_cancel (user->get_all_cancellable);
                 g_clear_object (&user->get_all_cancellable);
         }
 
         user->get_all_cancellable = g_cancellable_new ();
         g_dbus_proxy_call (user->object_proxy,
                            "GetAll",
                            g_variant_new ("(s)", ACCOUNTS_USER_INTERFACE),
                            G_DBUS_CALL_FLAGS_NONE,
                            -1,
                            user->get_all_cancellable,
                            on_get_all_finished,
                            user);
 }
 
+static gboolean
+on_timeout_update_info (ActUser *user)
+{
+        update_info (user);
+        user->update_info_timeout_id = 0;
+
+        return G_SOURCE_REMOVE;
+}
+
 static void
 changed_handler (AccountsUser *object,
                  gpointer   *data)
 {
         ActUser *user = ACT_USER (data);
 
-        update_info (user);
+        if (user->update_info_timeout_id != 0)
+                return;
+
+        user->update_info_timeout_id = g_timeout_add (250, (GSourceFunc) on_timeout_update_info, user);
 }
 
 /**
  * _act_user_update_as_nonexistent:
  * @user: the user object to update.
  *
  * Set's the 'non-existent' property of @user to #TRUE
  * Can only be called before the user is loaded.
  **/
 void
 _act_user_update_as_nonexistent (ActUser *user)
 {
         g_return_if_fail (ACT_IS_USER (user));
         g_return_if_fail (!act_user_is_loaded (user));
         g_return_if_fail (user->object_path == NULL);
 
         user->nonexistent = TRUE;
         g_object_notify (G_OBJECT (user), "nonexistent");
 
         set_is_loaded (user, TRUE);
 }
 
 /**
  * _act_user_update_from_object_path:
  * @user: the user object to update.
  * @object_path: the object path of the user to use.
  *
  * Updates the properties of @user from the accounts service via
  * the object path in @object_path.
  **/
-- 
2.14.1