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.
This commit is contained in:
Robert Fewell 2018-09-07 11:44:47 +01:00
parent 5057703d30
commit b6f2b111bc
6 changed files with 113 additions and 7 deletions

View File

@ -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 */

View File

@ -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);
}

View File

@ -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
@{
*/

View File

@ -104,6 +104,10 @@ typedef struct
void (*reset_group) (const gchar *group);
void (*block_all) (void);
void (*unblock_all) (void);
} PrefsBackend;
extern PrefsBackend *prefsbackend;

View File

@ -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) ();
}

View File

@ -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
@{
*/