Fix fallback to builtin defaults for key bindings

The change to reduce GConf trips by using
gconf_client_all_entries() broke the fallback to builtin values
because update_binding() was no longer called for bindings not
found in GConf. Fix this by keeping track of the bindings we
find from GConf in a hash table, then looping through and setting
all the bindings at the end.

This also improves efficiency by avoiding a linear scan for each
binding in GConf.

https://bugzilla.gnome.org/show_bug.cgi?id=609710
This commit is contained in:
Owen W. Taylor 2010-02-16 11:57:00 -05:00
parent 8875e73765
commit 8fa83e1be7

View File

@ -124,9 +124,10 @@ static gboolean no_tab_popup = FALSE;
#ifdef HAVE_GCONF #ifdef HAVE_GCONF
static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value); static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value);
static gboolean update_key_binding (const char *name, static char *binding_name (const char *gconf_key);
const char *value);
static gboolean update_key_binding (const char *key,
const char *value);
typedef enum typedef enum
{ {
META_LIST_OF_STRINGS, META_LIST_OF_STRINGS,
@ -134,10 +135,10 @@ typedef enum
} MetaStringListType; } MetaStringListType;
static gboolean find_and_update_list_binding (MetaKeyPref *bindings, static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
const char *name, const char *key,
GSList *value, GSList *value,
MetaStringListType type_of_value); MetaStringListType type_of_value);
static gboolean update_key_list_binding (const char *name, static gboolean update_key_list_binding (const char *key,
GSList *value, GSList *value,
MetaStringListType type_of_value); MetaStringListType type_of_value);
static gboolean update_command (const char *name, static gboolean update_command (const char *name,
@ -154,8 +155,8 @@ static char* gconf_key_for_workspace_name (int i);
static void queue_changed (MetaPreference pref); static void queue_changed (MetaPreference pref);
static gboolean update_list_binding (MetaKeyPref *binding, static gboolean update_list_binding (MetaKeyPref *binding,
GSList *value, GSList *value,
MetaStringListType type_of_value); MetaStringListType type_of_value);
static void cleanup_error (GError **error); static void cleanup_error (GError **error);
@ -1909,6 +1910,9 @@ init_bindings (void)
const char *key; const char *key;
GConfEntry *entry; GConfEntry *entry;
GConfValue *value; GConfValue *value;
GHashTable *to_update;
to_update = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
for (i = 0; prefix[i]; i++) for (i = 0; prefix[i]; i++)
{ {
@ -1920,6 +1924,11 @@ init_bindings (void)
value = gconf_entry_get_value (entry); value = gconf_entry_get_value (entry);
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX)) if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
{ {
/* List bindings are used in addition to the normal bindings and never
* have defaults, so we just go ahead and set them immediately; there
* will be only a few of them, so don't worry about the linear scan
* in find_and_update_list_binding.
*/
list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, NULL); list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, NULL);
update_key_list_binding (key, list_val, META_LIST_OF_STRINGS); update_key_list_binding (key, list_val, META_LIST_OF_STRINGS);
@ -1929,13 +1938,24 @@ init_bindings (void)
else else
{ {
str_val = gconf_value_get_string (value); str_val = gconf_value_get_string (value);
update_key_binding (key, str_val); g_hash_table_insert (to_update, binding_name (key), g_strdup (str_val));
} }
gconf_entry_free (entry); gconf_entry_free (entry);
} }
g_slist_free (list); g_slist_free (list);
} }
i = 0;
while (key_bindings[i].name)
{
update_binding (&key_bindings[i],
g_hash_table_lookup (to_update, key_bindings[i].name));
++i;
}
g_hash_table_destroy (to_update);
#else /* HAVE_GCONF */ #else /* HAVE_GCONF */
int i = 0; int i = 0;
while (key_bindings[i].name) while (key_bindings[i].name)
@ -2260,16 +2280,22 @@ update_list_binding (MetaKeyPref *binding,
return changed; return changed;
} }
static const gchar* static char *
relative_key (const gchar* key) binding_name (const char *gconf_key)
{ {
const gchar* end; const char *start, *end;
end = strrchr (key, '/');
++end; if (*gconf_key == '/')
start = strrchr (gconf_key, '/') + 1;
else
start = gconf_key;
return end; if (g_str_has_suffix (gconf_key, KEY_LIST_BINDINGS_SUFFIX))
end = gconf_key + strlen(gconf_key) - strlen (KEY_LIST_BINDINGS_SUFFIX);
else
end = gconf_key + strlen(gconf_key);
return g_strndup (start, end - start);
} }
/* Return value is TRUE if a preference changed and we need to /* Return value is TRUE if a preference changed and we need to
@ -2277,22 +2303,19 @@ relative_key (const gchar* key)
*/ */
static gboolean static gboolean
find_and_update_binding (MetaKeyPref *bindings, find_and_update_binding (MetaKeyPref *bindings,
const char *name, const char *key,
const char *value) const char *value)
{ {
const char *key; char *name = binding_name (key);
int i; int i;
if (*name == '/')
key = relative_key (name);
else
key = name;
i = 0; i = 0;
while (bindings[i].name && while (bindings[i].name &&
strcmp (key, bindings[i].name) != 0) strcmp (name, bindings[i].name) != 0)
++i; ++i;
g_free (name);
if (bindings[i].name) if (bindings[i].name)
return update_binding (&bindings[i], value); return update_binding (&bindings[i], value);
else else
@ -2300,35 +2323,27 @@ find_and_update_binding (MetaKeyPref *bindings,
} }
static gboolean static gboolean
update_key_binding (const char *name, update_key_binding (const char *key,
const char *value) const char *value)
{ {
return find_and_update_binding (key_bindings, name, value); return find_and_update_binding (key_bindings, key, value);
} }
static gboolean static gboolean
find_and_update_list_binding (MetaKeyPref *bindings, find_and_update_list_binding (MetaKeyPref *bindings,
const char *name, const char *key,
GSList *value, GSList *value,
MetaStringListType type_of_value) MetaStringListType type_of_value)
{ {
const char *key; char *name = binding_name (key);
int i; int i;
gchar *name_without_suffix = g_strdup(name);
name_without_suffix[strlen(name_without_suffix) - strlen(KEY_LIST_BINDINGS_SUFFIX)] = 0;
if (*name_without_suffix == '/')
key = relative_key (name_without_suffix);
else
key = name_without_suffix;
i = 0; i = 0;
while (bindings[i].name && while (bindings[i].name &&
strcmp (key, bindings[i].name) != 0) strcmp (name, bindings[i].name) != 0)
++i; ++i;
g_free (name_without_suffix); g_free (name);
if (bindings[i].name) if (bindings[i].name)
return update_list_binding (&bindings[i], value, type_of_value); return update_list_binding (&bindings[i], value, type_of_value);
@ -2337,11 +2352,11 @@ find_and_update_list_binding (MetaKeyPref *bindings,
} }
static gboolean static gboolean
update_key_list_binding (const char *name, update_key_list_binding (const char *key,
GSList *value, GSList *value,
MetaStringListType type_of_value) MetaStringListType type_of_value)
{ {
return find_and_update_list_binding (key_bindings, name, value, type_of_value); return find_and_update_list_binding (key_bindings, key, value, type_of_value);
} }
static gboolean static gboolean