From 42bd3bd41d69100308a22df43482569f6ab53dbe Mon Sep 17 00:00:00 2001 From: Ray Strode 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