gnucash master: Bug 798749 - Fails to read gsettings on startup

Geert Janssens gjanssens at code.gnucash.org
Thu Feb 16 16:41:02 EST 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/286e1afa (commit)
	from  https://github.com/Gnucash/gnucash/commit/ec6d38ae (commit)



commit 286e1afa41842c42a0f80e70f2c022ec97f3b7ea
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Thu Feb 16 17:45:06 2023 +0100

    Bug 798749 - Fails to read gsettings on startup
    
    Only cache GSettings objects we need to keep
    track of callback functions.
    This means a bit more overhead per GSettings
    interaction, but as typical interactions are
    only a few objects at once at best, this
    overhead is unnoticeable.

diff --git a/libgnucash/app-utils/gnc-gsettings.cpp b/libgnucash/app-utils/gnc-gsettings.cpp
index 950e3bff8..238f3a8c7 100644
--- a/libgnucash/app-utils/gnc-gsettings.cpp
+++ b/libgnucash/app-utils/gnc-gsettings.cpp
@@ -89,32 +89,19 @@ static gboolean gnc_gsettings_is_valid_key(GSettings *settings, const gchar *key
 
 static GSettings * gnc_gsettings_get_settings_ptr (const gchar *schema_str)
 {
-    GSettings *gset = NULL;
-    gchar *full_name = gnc_gsettings_normalize_schema_name (schema_str);
-
     ENTER("");
-    if (!schema_hash)
-        schema_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-    gset = static_cast<GSettings*> (g_hash_table_lookup (schema_hash, full_name));
-    DEBUG ("Looking for schema %s returned gsettings %p", full_name, gset);
+    auto schema_source {g_settings_schema_source_get_default()};
+    auto full_name = gnc_gsettings_normalize_schema_name (schema_str);
+    auto schema {g_settings_schema_source_lookup(schema_source, full_name,
+                                                    TRUE)};
+    auto gset = g_settings_new_full (schema, nullptr, nullptr);
+    DEBUG ("Created gsettings object %p for schema %s", gset, full_name);
 
-    if (!gset)
-    {
-        auto schema_source {g_settings_schema_source_get_default()};
-        auto schema {g_settings_schema_source_lookup(schema_source, full_name,
-                                                     TRUE)};
-        gset = g_settings_new_full (schema, nullptr, nullptr);
-        DEBUG ("Created gsettings object %p for schema %s", gset, full_name);
-        if (G_IS_SETTINGS(gset))
-            g_hash_table_insert (schema_hash, full_name, gset);
-        else
-            PWARN ("Ignoring attempt to access unknown gsettings schema %s", full_name);
-    }
-    else
-    {
-        g_free(full_name);
-    }
+    if (!G_IS_SETTINGS(gset))
+        PWARN ("Ignoring attempt to access unknown gsettings schema %s", full_name);
+
+    g_free(full_name);
     LEAVE("");
     return gset;
 }
@@ -172,29 +159,35 @@ gnc_gsettings_register_cb (const gchar *schema,
                            gpointer func,
                            gpointer user_data)
 {
-    gulong retval = 0;
-    gchar *signal = NULL;
+    ENTER("");
+    g_return_val_if_fail (func, 0);
 
-    GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
 
-    ENTER("");
-    g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), retval);
-    g_return_val_if_fail (func, retval);
+    if (!schema_hash)
+        schema_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+    if (!registered_handlers_hash)
+        registered_handlers_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
 
-    if ((!key) || (*key == '\0'))
-        signal = g_strdup ("changed");
-    else
+    auto full_name = gnc_gsettings_normalize_schema_name (schema);
+    auto settings_ptr = static_cast<GSettings*> (g_hash_table_lookup (schema_hash, full_name));
+    if (!settings_ptr)
     {
-        if (gnc_gsettings_is_valid_key(settings_ptr, key))
-            signal = g_strconcat ("changed::", key, NULL);
+        settings_ptr = gnc_gsettings_get_settings_ptr (schema);
+        if (G_IS_SETTINGS (settings_ptr))
+            g_hash_table_insert (schema_hash, full_name, settings_ptr);
+        else
+            PWARN ("Ignoring attempt to access unknown gsettings schema %s", full_name);
     }
+    g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), 0);
 
-    retval = g_signal_connect (settings_ptr, signal, G_CALLBACK (func), user_data);
-
-    if (!registered_handlers_hash)
-        registered_handlers_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
+    auto signal = static_cast<char *> (nullptr);
+    if (!key || !*key)
+        signal = g_strdup ("changed");
+    else if (gnc_gsettings_is_valid_key(settings_ptr, key))
+        signal = g_strconcat ("changed::", key, nullptr);
 
-    if (retval != 0)
+    auto retval = g_signal_connect (settings_ptr, signal, G_CALLBACK (func), user_data);
+    if (retval)
     {
         g_hash_table_insert (registered_handlers_hash,
                              GINT_TO_POINTER(retval), settings_ptr); //key, value
@@ -209,26 +202,60 @@ gnc_gsettings_register_cb (const gchar *schema,
 }
 
 
+static void
+gnc_gsettings_remove_cb_by_id_internal (GSettings *settings_ptr,
+                                        guint handlerid)
+{
+    g_return_if_fail (G_IS_SETTINGS (settings_ptr));
+
+    ENTER ();
+
+    g_signal_handler_disconnect (settings_ptr, handlerid);
+
+    // remove the handlerid from the registerered_handlers_hash
+    g_hash_table_remove (registered_handlers_hash, GINT_TO_POINTER(handlerid));
+
+    // remove GSettings object if we're not using it any more for other handlers
+    auto used_settings_ptrs = g_hash_table_get_values (registered_handlers_hash);
+    if (!g_list_find (used_settings_ptrs, settings_ptr))
+    {
+        g_hash_table_remove(schema_hash, settings_ptr);
+        g_object_unref (settings_ptr);
+    }
+
+    // destroy hash table if size is 0
+    if (g_hash_table_size (registered_handlers_hash) == 0)
+    {
+        g_hash_table_destroy (registered_handlers_hash);
+        PINFO ("All registered preference callbacks removed");
+    }
+
+    LEAVE ("Schema: %p, handlerid: %d, hashtable size: %d - removed for handler",
+           settings_ptr, handlerid, g_hash_table_size (registered_handlers_hash));
+}
+
+
 void
 gnc_gsettings_remove_cb_by_func (const gchar *schema,
                                  const gchar *key,
                                  gpointer func,
                                  gpointer user_data)
 {
-    gint matched = 0;
-    GQuark quark = 0;
-    gulong handler_id = 0;
-
-    GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
-    g_return_if_fail (G_IS_SETTINGS (settings_ptr));
+    ENTER ();
     g_return_if_fail (func);
 
-    ENTER ();
+    auto full_name = gnc_gsettings_normalize_schema_name (schema);
+    auto settings_ptr = static_cast<GSettings*> (g_hash_table_lookup (schema_hash, full_name));
+    g_free (full_name);
 
-    if ((key) && (gnc_gsettings_is_valid_key(settings_ptr, key)))
-        quark = g_quark_from_string (key);
+    if (!G_IS_SETTINGS (settings_ptr))
+    {
+        LEAVE ("No valid GSettings object retrieved from hash table");
+        return;
+    }
 
-    handler_id = g_signal_handler_find (
+    auto quark = g_quark_from_string (key);
+    auto handler_id = g_signal_handler_find (
                   settings_ptr,
                   static_cast<GSignalMatchType> (G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA),
                   g_signal_lookup ("changed", G_TYPE_SETTINGS), /* signal_id */
@@ -237,10 +264,15 @@ gnc_gsettings_remove_cb_by_func (const gchar *schema,
                   func, /* callback function */
                   user_data);
 
+    auto matched = 0;
     while (handler_id)
     {
         matched ++;
-        gnc_gsettings_remove_cb_by_id (schema, handler_id);
+        gnc_gsettings_remove_cb_by_id_internal (settings_ptr, handler_id);
+
+        // Previous function will invalidate object if there is only one handler
+        if (!G_IS_SETTINGS (settings_ptr))
+            break;
 
         handler_id = g_signal_handler_find (
                       settings_ptr,
@@ -261,25 +293,22 @@ void
 gnc_gsettings_remove_cb_by_id (const gchar *schema,
                                guint handlerid)
 {
-    GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
-    g_return_if_fail (G_IS_SETTINGS (settings_ptr));
-
     ENTER ();
 
-    g_signal_handler_disconnect (settings_ptr, handlerid);
-
-    // remove the handlerid from the registerered_handlers_hash
-    g_hash_table_remove (registered_handlers_hash, GINT_TO_POINTER(handlerid));
+    auto full_name = gnc_gsettings_normalize_schema_name (schema);
+    auto settings_ptr = static_cast<GSettings*> (g_hash_table_lookup (schema_hash, full_name));
+    g_free (full_name);
 
-    // destroy hash table if size is 0
-    if (g_hash_table_size (registered_handlers_hash) == 0)
+    if (!G_IS_SETTINGS (settings_ptr))
     {
-        g_hash_table_destroy (registered_handlers_hash);
-        PINFO ("All registered preference callbacks removed");
+        LEAVE ("No valid GSettings object retrieved from hash table");
+        return;
     }
 
-    LEAVE ("Schema: %s, handlerid: %d, hashtable size: %d - removed for handler",
-            schema, handlerid, g_hash_table_size (registered_handlers_hash));
+    gnc_gsettings_remove_cb_by_id_internal (settings_ptr, handlerid);
+
+    LEAVE ("Schema: %p, handlerid: %d, hashtable size: %d - removed for handler",
+            settings_ptr, handlerid, g_hash_table_size (registered_handlers_hash));
 }
 
 
@@ -312,9 +341,9 @@ void gnc_gsettings_bind (const gchar *schema,
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
         g_settings_bind (settings_ptr, key, object, property, G_SETTINGS_BIND_DEFAULT);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-    }
+
+    g_object_unref (settings_ptr);
 }
 
 /************************************************************/
@@ -328,13 +357,14 @@ gnc_gsettings_get_bool (const gchar *schema,
     GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
     g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), FALSE);
 
+    auto val = false;
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
-        return g_settings_get_boolean (settings_ptr, key);
+        val = g_settings_get_boolean (settings_ptr, key);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-        return FALSE;
-    }
+
+    g_object_unref (settings_ptr);
+    return val;
 }
 
 gboolean
@@ -356,6 +386,7 @@ gnc_gsettings_set_bool (const gchar *schema,
     else
         PERR ("Invalid key %s for schema %s", key, schema);
 
+    g_object_unref (settings_ptr);
     LEAVE("result %i", result);
     return result;
 }
@@ -367,13 +398,14 @@ gnc_gsettings_get_int (const gchar *schema,
     GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
     g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), 0);
 
+    auto val = static_cast<int> (0);
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
-        return g_settings_get_int (settings_ptr, key);
+        val = g_settings_get_int (settings_ptr, key);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-        return 0;
-    }
+
+    g_object_unref (settings_ptr);
+    return val;
 }
 
 gboolean
@@ -394,6 +426,7 @@ gnc_gsettings_set_int (const gchar *schema,
     else
         PERR ("Invalid key %s for schema %s", key, schema);
 
+    g_object_unref (settings_ptr);
     return result;
 }
 
@@ -404,13 +437,14 @@ gnc_gsettings_get_float (const gchar *schema,
     GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
     g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), 0);
 
+    auto val = static_cast<double> (0);
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
-        return g_settings_get_double (settings_ptr, key);
+        val = g_settings_get_double (settings_ptr, key);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-        return 0;
-    }
+
+    g_object_unref (settings_ptr);
+    return val;
 }
 
 gboolean
@@ -431,6 +465,7 @@ gnc_gsettings_set_float (const gchar *schema,
     else
         PERR ("Invalid key %s for schema %s", key, schema);
 
+    g_object_unref (settings_ptr);
     return result;
 }
 
@@ -441,13 +476,14 @@ gnc_gsettings_get_string (const gchar *schema,
     GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
     g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), NULL);
 
+    auto val = static_cast<gchar *> (nullptr);
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
-        return g_settings_get_string (settings_ptr, key);
+        val = g_settings_get_string (settings_ptr, key);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-        return NULL;
-    }
+
+    g_object_unref (settings_ptr);
+    return val;
 }
 
 gboolean
@@ -469,6 +505,7 @@ gnc_gsettings_set_string (const gchar *schema,
     else
         PERR ("Invalid key %s for schema %s", key, schema);
 
+    g_object_unref (settings_ptr);
     LEAVE("result %i", result);
     return result;
 }
@@ -480,13 +517,14 @@ gnc_gsettings_get_enum (const gchar *schema,
     GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
     g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), 0);
 
+    auto val = static_cast<int> (0);
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
-        return g_settings_get_enum (settings_ptr, key);
+        val = g_settings_get_enum (settings_ptr, key);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-        return 0;
-    }
+
+    g_object_unref (settings_ptr);
+    return val;
 }
 
 gboolean
@@ -507,6 +545,7 @@ gnc_gsettings_set_enum (const gchar *schema,
     else
         PERR ("Invalid key %s for schema %s", key, schema);
 
+    g_object_unref (settings_ptr);
     return result;
 }
 
@@ -517,13 +556,14 @@ gnc_gsettings_get_value (const gchar *schema,
     GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
     g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), NULL);
 
+    auto val = static_cast<GVariant *> (nullptr);
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
-        return g_settings_get_value (settings_ptr, key);
+        val = g_settings_get_value (settings_ptr, key);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-        return NULL;
-    }
+
+    g_object_unref (settings_ptr);
+    return val;
 }
 
 gboolean
@@ -544,6 +584,7 @@ gnc_gsettings_set_value (const gchar *schema,
     else
         PERR ("Invalid key %s for schema %s", key, schema);
 
+    g_object_unref (settings_ptr);
     return result;
 }
 
@@ -558,6 +599,8 @@ gnc_gsettings_reset (const gchar *schema,
         g_settings_reset (settings_ptr, key);
     else
         PERR ("Invalid key %s for schema %s", key, schema);
+
+    g_object_unref (settings_ptr);
 }
 
 void
@@ -573,11 +616,17 @@ gnc_gsettings_reset_schema (const gchar *schema_str)
 
     g_object_get (settings, "settings-schema", &schema, NULL);
     if (!schema)
+    {
+        g_object_unref (settings);
         return;
+    }
 
     keys = g_settings_schema_list_keys (schema);
     if (!keys)
+    {
+        g_object_unref (settings);
         return;
+    }
 
     while (keys[counter])
     {
@@ -585,6 +634,7 @@ gnc_gsettings_reset_schema (const gchar *schema_str)
         counter++;
     }
 
+    g_object_unref (settings);
     g_strfreev (keys);
 }
 
@@ -643,13 +693,14 @@ gnc_gsettings_get_user_value (const gchar *schema,
     GSettings *settings_ptr = gnc_gsettings_get_settings_ptr (schema);
     g_return_val_if_fail (G_IS_SETTINGS (settings_ptr), NULL);
 
+    auto val = static_cast<GVariant *> (nullptr);
     if (gnc_gsettings_is_valid_key (settings_ptr, key))
-        return g_settings_get_user_value (settings_ptr, key);
+        val = g_settings_get_user_value (settings_ptr, key);
     else
-    {
         PERR ("Invalid key %s for schema %s", key, schema);
-        return NULL;
-    }
+
+    g_object_unref (settings_ptr);
+    return val;
 }
 
 using opt_str_vec = boost::optional<std::string>;



Summary of changes:
 libgnucash/app-utils/gnc-gsettings.cpp | 237 ++++++++++++++++++++-------------
 1 file changed, 144 insertions(+), 93 deletions(-)



More information about the gnucash-changes mailing list