From e7ad15bc5ca5649f719679c3791244eccba0f057 Mon Sep 17 00:00:00 2001
From: Alberto Mardegan <mardy@users.sourceforge.net>
Date: Mon, 6 Nov 2023 13:00:29 +0300
Subject: [PATCH 6/8] ag-account: do not emit misleading enabled signals on
 account services

Something must have changed in the internals of GHashTable, so that now
the keys happen to be ordered in such a way that broke a libaccounts-qt
test in Ubuntu 22.04 [1]. The failure has been traced back to
libaccounts-glib, and happens when the enabled properties on an account
and on one of its services are changed in such a way that the overall
service status should remain disabled, yet two enabled signals (first
one with value "enabled", second "disabled") are emitted on the account
service. While the end result is correct, the two signals would be
better not be emitted at all, since the account service enabledness
never actually changed.

To fix this, instead of emitting the AgAccount::enabled signals while we
iterate the changes, we delay their emission until the end of the update
loop, so that the AgAccountService will already have the updated
information on the enabledness status and won't emit its enabled signal.

[1]: https://gitlab.com/accounts-sso/libaccounts-qt/-/merge_requests/18#note_1138904460
---
 libaccounts-glib/ag-account.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/libaccounts-glib/ag-account.c b/libaccounts-glib/ag-account.c
index 7e67ba7..ab19ba2 100644
--- a/libaccounts-glib/ag-account.c
+++ b/libaccounts-glib/ag-account.c
@@ -223,6 +223,11 @@ typedef struct {
     gpointer user_data;
 } AsyncReadyCbWrapperData;
 
+typedef struct {
+    gchar *service_name;
+    gboolean enabled;
+} EnabledSignalParams;
+
 #define AG_ITER_STAGE_UNSET     0
 #define AG_ITER_STAGE_ACCOUNT   1
 #define AG_ITER_STAGE_SERVICE   2
@@ -584,6 +589,7 @@ update_settings (AgAccount *account, GHashTable *services)
     AgServiceChanges *sc;
     gchar *service_name;
     GList *watch_list = NULL;
+    GSList *enabled_signals = NULL;
 
     g_hash_table_iter_init (&iter, services);
     while (g_hash_table_iter_next (&iter,
@@ -641,10 +647,12 @@ update_settings (AgAccount *account, GHashTable *services)
                     {
                         priv->enabled =
                             value ? g_variant_get_boolean (value) : FALSE;
-                        g_signal_emit (account, signals[ENABLED], 0,
-                                       NULL, priv->enabled);
                         g_object_notify_by_pspec ((GObject *)account,
                                                   properties[PROP_ENABLED]);
+                        EnabledSignalParams *params = g_new (EnabledSignalParams, 1);
+                        params->service_name = NULL;
+                        params->enabled = priv->enabled;
+                        enabled_signals = g_slist_prepend (enabled_signals, params);
                         continue;
                     }
                 }
@@ -665,12 +673,24 @@ update_settings (AgAccount *account, GHashTable *services)
             {
                 gboolean enabled =
                     value ? g_variant_get_boolean (value) : FALSE;
-                g_signal_emit (account, signals[ENABLED], 0,
-                               service_name, enabled);
+                EnabledSignalParams *params = g_new (EnabledSignalParams, 1);
+                params->service_name = service_name;
+                params->enabled = enabled;
+                enabled_signals = g_slist_prepend (enabled_signals, params);
             }
         }
     }
 
+    /* Emit all enabled signals */
+    while (enabled_signals)
+    {
+        EnabledSignalParams *params = enabled_signals->data;
+        g_signal_emit (account, signals[ENABLED], 0,
+                       params->service_name, params->enabled);
+        g_free (params);
+        enabled_signals = g_slist_delete_link (enabled_signals, enabled_signals);
+    }
+
     /* Invoke all watches
      * While whatches are running, let the receivers retrieve the changes
      * table with _ag_account_get_service_changes(): set it into the
-- 
2.44.0