From b6f2b111bc2b9e701639eb4684bdbfe4bf4b97c9 Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Fri, 7 Sep 2018 11:44:47 +0100 Subject: [PATCH] Block registered prefs when preference dialogue loaded When the preference dialogue is loaded and options are set, the ones with registered callbacks fire causing parts of Gnucash to be updated. This was observed with gnc_split_register_load being executed 5 times for each open register when the preference dialogue was loaded. To overcome this, a couple of functions have been created to block and unblock all registered prefs and used while the preference dialogue is loaded. --- gnucash/gnome-utils/dialog-preferences.c | 11 ++-- libgnucash/app-utils/gnc-gsettings.c | 76 +++++++++++++++++++++++- libgnucash/app-utils/gnc-gsettings.h | 10 ++++ libgnucash/core-utils/gnc-prefs-p.h | 4 ++ libgnucash/core-utils/gnc-prefs.c | 11 ++++ libgnucash/core-utils/gnc-prefs.h | 8 +++ 6 files changed, 113 insertions(+), 7 deletions(-) diff --git a/gnucash/gnome-utils/dialog-preferences.c b/gnucash/gnome-utils/dialog-preferences.c index 2e4e779233..98c0801b45 100644 --- a/gnucash/gnome-utils/dialog-preferences.c +++ b/gnucash/gnome-utils/dialog-preferences.c @@ -1153,9 +1153,8 @@ gnc_prefs_connect_one (const gchar *name, GList* child = gtk_container_get_children(GTK_CONTAINER(widget)); widget_child = child->data; g_list_free(child); - DEBUG(" %s - hbox", name); - DEBUG("Hbox widget type is %s and name is %s", gtk_widget_get_name(GTK_WIDGET(widget_child)), name); - + DEBUG(" %s - box", name); + DEBUG("Box widget type is %s and name is %s", gtk_widget_get_name(GTK_WIDGET(widget_child)), name); if (GNC_IS_CURRENCY_EDIT(widget_child)) { DEBUG(" %s - currency_edit", name); @@ -1163,7 +1162,7 @@ gnc_prefs_connect_one (const gchar *name, } else if (GNC_IS_PERIOD_SELECT(widget_child)) { - DEBUG(" %s - period_Select", name); + DEBUG(" %s - period_select", name); gnc_prefs_connect_period_select(GNC_PERIOD_SELECT(widget_child), name ); } else if (GNC_IS_DATE_EDIT(widget_child)) @@ -1173,7 +1172,7 @@ gnc_prefs_connect_one (const gchar *name, } else if (GTK_FILE_CHOOSER_BUTTON(widget_child)) { - DEBUG(" %s - file chooser buuton", name); + DEBUG(" %s - file chooser button", name); gnc_prefs_connect_file_chooser_button(GTK_FILE_CHOOSER_BUTTON(widget_child), name ); } } @@ -1344,7 +1343,9 @@ gnc_preferences_dialog_create(GtkWindow *parent) gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0); DEBUG("We have the following interesting widgets:"); + gnc_prefs_block_all(); // Block All Registered callbacks g_hash_table_foreach(prefs_table, (GHFunc)gnc_prefs_connect_one, dialog); + gnc_prefs_unblock_all(); // UnBlock All Registered callbacks DEBUG("Done with interesting widgets."); /* Other stuff */ diff --git a/libgnucash/app-utils/gnc-gsettings.c b/libgnucash/app-utils/gnc-gsettings.c index 6e174eebb1..d2f0fc69d6 100644 --- a/libgnucash/app-utils/gnc-gsettings.c +++ b/libgnucash/app-utils/gnc-gsettings.c @@ -53,6 +53,8 @@ static GHashTable *schema_hash = NULL; static const gchar *gsettings_prefix; static xmlExternalEntityLoader defaultEntityLoader = NULL; +static GHashTable *registered_handlers_hash = NULL; + /* This static indicates the debugging module that this .o belongs to. */ static QofLogModule log_module = "gnc.app-utils.gsettings"; @@ -131,6 +133,19 @@ static GSettings * gnc_gsettings_get_settings_ptr (const gchar *schema_str) return gset; } +static void +handlers_hash_block_helper (gpointer key, gpointer settings_ptr, gpointer pointer) +{ + g_signal_handler_block (settings_ptr, (gulong)key); // block signal_handler + PINFO("Block handler_id %ld for settings_ptr %p", (gulong)key, settings_ptr); +} + +static void +handlers_hash_unblock_helper (gpointer key, gpointer settings_ptr, gpointer pointer) +{ + g_signal_handler_unblock (settings_ptr, (gulong)key); // unblock signal_handler + PINFO("UnBlock handler_id %ld for settings_ptr %p", (gulong)key, settings_ptr); +} /************************************************************/ /* GSettings Utilities */ @@ -203,6 +218,17 @@ gnc_gsettings_register_cb (const gchar *schema, 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); + + if (retval != 0) + { + g_hash_table_insert (registered_handlers_hash, + GINT_TO_POINTER(retval), settings_ptr); //key, value + + PINFO("schema: %s, key: %s, settings_ptr: %p, handler_id: %ld", + schema, key, settings_ptr, retval); + } g_free (signal); LEAVE(""); @@ -218,6 +244,7 @@ gnc_gsettings_remove_cb_by_func (const gchar *schema, { 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)); @@ -228,7 +255,7 @@ gnc_gsettings_remove_cb_by_func (const gchar *schema, if ((key) && (gnc_gsettings_is_valid_key(settings_ptr, key))) quark = g_quark_from_string (key); - matched = g_signal_handlers_disconnect_matched ( + handler_id = g_signal_handler_find ( settings_ptr, G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, g_signal_lookup ("changed", G_TYPE_SETTINGS), /* signal_id */ @@ -236,7 +263,24 @@ gnc_gsettings_remove_cb_by_func (const gchar *schema, NULL, /* closure */ G_CALLBACK (func), /* callback function */ user_data); - LEAVE ("Schema: %s, key: %s - removed %d handlers for 'changed' signal", schema, key, matched); + + while (handler_id) + { + matched ++; + gnc_gsettings_remove_cb_by_id (schema, handler_id); + + handler_id = g_signal_handler_find ( + settings_ptr, + G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, + g_signal_lookup ("changed", G_TYPE_SETTINGS), /* signal_id */ + quark, /* signal_detail */ + NULL, /* closure */ + G_CALLBACK (func), /* callback function */ + user_data); + } + + LEAVE ("Schema: %s, key: %s, hashtable size: %d - removed %d handlers for 'changed' signal", + schema, key, g_hash_table_size (registered_handlers_hash), matched); } @@ -247,7 +291,15 @@ gnc_gsettings_remove_cb_by_id (const gchar *schema, 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)); + + LEAVE ("Schema: %s, handlerid: %d, hashtable size: %d - removed for handler", + schema, handlerid, g_hash_table_size (registered_handlers_hash)); } @@ -600,6 +652,8 @@ void gnc_gsettings_load_backend (void) prefsbackend->set_value = gnc_gsettings_set_value; prefsbackend->reset = gnc_gsettings_reset; prefsbackend->reset_group = gnc_gsettings_reset_schema; + prefsbackend->block_all = gnc_gsettings_block_all; + prefsbackend->unblock_all = gnc_gsettings_unblock_all; LEAVE("Prefsbackend bind = %p", prefsbackend->bind); } @@ -850,3 +904,21 @@ void gnc_gsettings_version_upgrade (void) if (cur_maj_min > old_maj_min) gnc_gsettings_set_int (GNC_PREFS_GROUP_GENERAL, GNC_PREF_VERSION, cur_maj_min); } + + +void gnc_gsettings_block_all (void) +{ + PINFO("block registered_handlers_hash list size is %d", + g_hash_table_size (registered_handlers_hash)); + g_hash_table_foreach (registered_handlers_hash, + handlers_hash_block_helper, NULL); +} + + +void gnc_gsettings_unblock_all (void) +{ + PINFO("unblock registered_handlers_hash list size is %d", + g_hash_table_size (registered_handlers_hash)); + g_hash_table_foreach (registered_handlers_hash, + handlers_hash_unblock_helper, NULL); +} diff --git a/libgnucash/app-utils/gnc-gsettings.h b/libgnucash/app-utils/gnc-gsettings.h index 44dcb9910f..7f058684e5 100644 --- a/libgnucash/app-utils/gnc-gsettings.h +++ b/libgnucash/app-utils/gnc-gsettings.h @@ -86,6 +86,16 @@ void gnc_gsettings_set_prefix (const gchar *prefix); const gchar *gnc_gsettings_get_prefix (void); +/** Block all prefs callbacks, used while preference dialog is loaded. + */ +void gnc_gsettings_block_all (void); + + +/** UnBlock all prefs callbacks, used while preference dialog is loaded. + */ +void gnc_gsettings_unblock_all (void); + + /** @name Listening for changes @{ */ diff --git a/libgnucash/core-utils/gnc-prefs-p.h b/libgnucash/core-utils/gnc-prefs-p.h index b780fee549..a5ab85580e 100644 --- a/libgnucash/core-utils/gnc-prefs-p.h +++ b/libgnucash/core-utils/gnc-prefs-p.h @@ -104,6 +104,10 @@ typedef struct void (*reset_group) (const gchar *group); + void (*block_all) (void); + + void (*unblock_all) (void); + } PrefsBackend; extern PrefsBackend *prefsbackend; diff --git a/libgnucash/core-utils/gnc-prefs.c b/libgnucash/core-utils/gnc-prefs.c index 73eec923d3..d59e91f636 100644 --- a/libgnucash/core-utils/gnc-prefs.c +++ b/libgnucash/core-utils/gnc-prefs.c @@ -368,3 +368,14 @@ gboolean gnc_prefs_is_set_up (void) return (prefsbackend !=NULL); } +void gnc_prefs_block_all (void) +{ + if (prefsbackend && prefsbackend->block_all) + (prefsbackend->block_all) (); +} + +void gnc_prefs_unblock_all (void) +{ + if (prefsbackend && prefsbackend->unblock_all) + (prefsbackend->unblock_all) (); +} diff --git a/libgnucash/core-utils/gnc-prefs.h b/libgnucash/core-utils/gnc-prefs.h index 41c241d461..c665a26214 100644 --- a/libgnucash/core-utils/gnc-prefs.h +++ b/libgnucash/core-utils/gnc-prefs.h @@ -124,6 +124,14 @@ guint gnc_prefs_get_long_version( void ); */ gboolean gnc_prefs_is_set_up (void); +/** Block all preference callbacks +*/ +void gnc_prefs_block_all (void); + +/** Unblock all preferences callbacks +*/ +void gnc_prefs_unblock_all (void); + /** @name Listening for changes @{ */