diff --git a/src/core/keybindings-private.h b/src/core/keybindings-private.h index 7be9c24cf..b891d118e 100644 --- a/src/core/keybindings-private.h +++ b/src/core/keybindings-private.h @@ -75,6 +75,7 @@ void meta_display_process_mapping_event (MetaDisplay *display, gboolean meta_prefs_add_keybinding (const char *name, GSettings *settings, + const char *hardcoded_key, MetaKeyBindingAction action, MetaKeyBindingFlags flags); diff --git a/src/core/keybindings.c b/src/core/keybindings.c index 48929425a..94f57ac6b 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -539,6 +539,7 @@ static gboolean add_keybinding_internal (MetaDisplay *display, const char *name, GSettings *settings, + const char *hardcoded_key, MetaKeyBindingFlags flags, MetaKeyBindingAction action, MetaKeyHandlerFunc func, @@ -548,7 +549,7 @@ add_keybinding_internal (MetaDisplay *display, { MetaKeyHandler *handler; - if (!meta_prefs_add_keybinding (name, settings, action, flags)) + if (!meta_prefs_add_keybinding (name, settings, hardcoded_key, action, flags)) return FALSE; handler = g_new0 (MetaKeyHandler, 1); @@ -574,7 +575,7 @@ add_builtin_keybinding (MetaDisplay *display, MetaKeyHandlerFunc handler, int handler_arg) { - return add_keybinding_internal (display, name, settings, + return add_keybinding_internal (display, name, settings, NULL, flags | META_KEY_BINDING_BUILTIN, action, handler, handler_arg, NULL, NULL); } @@ -615,11 +616,58 @@ meta_display_add_keybinding (MetaDisplay *display, gpointer user_data, GDestroyNotify free_data) { - return add_keybinding_internal (display, name, settings, flags, - META_KEYBINDING_ACTION_NONE, + return add_keybinding_internal (display, name, settings, NULL, + flags, META_KEYBINDING_ACTION_NONE, handler, 0, user_data, free_data); } +/** + * meta_display_add_grabbed_key: + * @display: a #MetaDisplay + * @name: the binding's name + * @keyval: the key combination that should trigger this keybinding + * @flags: flags to specify binding details + * @handler: function to run when the keybinding is invoked + * @user_data: the data to pass to @handler + * @free_data: function to free @user_data + * + * This function is similar to meta_display_add_keybinding(), except + * that the keybinding is hardcoded to @keyval, which should be a GTK + * key string combination. + */ +gboolean +meta_display_add_grabbed_key (MetaDisplay *display, + const char *name, + const char *keyval, + MetaKeyBindingFlags flags, + MetaKeyHandlerFunc handler, + gpointer user_data, + GDestroyNotify free_data) +{ + return add_keybinding_internal (display, name, NULL, keyval, + flags, META_KEYBINDING_ACTION_NONE, + handler, 0, user_data, free_data); +} + +/** + * meta_display_remove_grabbed_key: + * @display: the #MetaDisplay + * @name: the name that was passed to meta_display_add_grabbed_key() + * + * Undoes the effect of meta_display_add_grabbed_key() + */ +gboolean +meta_display_remove_grabbed_key (MetaDisplay *display, + const char *name) +{ + if (!meta_prefs_remove_keybinding (name)) + return FALSE; + + g_hash_table_remove (key_handlers, name); + + return TRUE; +} + /** * meta_display_remove_keybinding: * @display: the #MetaDisplay diff --git a/src/core/prefs.c b/src/core/prefs.c index 802d620ea..c8604073c 100644 --- a/src/core/prefs.c +++ b/src/core/prefs.c @@ -110,13 +110,12 @@ static gboolean workspaces_only_on_primary = FALSE; static gboolean no_tab_popup = FALSE; +static GHashTable *key_bindings; static void handle_preference_update_enum (GSettings *settings, gchar *key); static gboolean update_binding (MetaKeyPref *binding, gchar **strokes); -static gboolean update_key_binding (const char *key, - gchar **strokes); static gboolean update_workspace_names (void); static void settings_changed (GSettings *settings, @@ -1052,13 +1051,30 @@ bindings_changed (GSettings *settings, gchar *key, gpointer data) { + gchar *static_strokes[2]; gchar **strokes; - strokes = g_settings_get_strv (settings, key); + MetaKeyPref *pref; - if (update_key_binding (key, strokes)) - queue_changed (META_PREF_KEYBINDINGS); + pref = g_hash_table_lookup (key_bindings, key); + if (!pref) + return; - g_strfreev (strokes); + if (pref->is_single) + { + static_strokes[0] = g_settings_get_string (settings, key); + static_strokes[1] = NULL; + strokes = static_strokes; + } + else + strokes = g_settings_get_strv (settings, key); + + update_binding (pref, strokes); + queue_changed (META_PREF_KEYBINDINGS); + + if (strokes != static_strokes) + g_strfreev(strokes); + else + g_free(static_strokes[0]); } /** @@ -1693,7 +1709,9 @@ meta_key_pref_free (MetaKeyPref *pref) update_binding (pref, NULL); g_free (pref->name); - g_object_unref (pref->settings); + if (pref->settings) + g_object_unref (pref->settings); + g_free (pref->hardcoded_key); g_free (pref); } @@ -1785,18 +1803,6 @@ update_binding (MetaKeyPref *binding, return changed; } -static gboolean -update_key_binding (const char *key, - gchar **strokes) -{ - MetaKeyPref *pref = g_hash_table_lookup (key_bindings, key); - - if (pref) - return update_binding (pref, strokes); - else - return FALSE; -} - static gboolean update_workspace_names (void) { @@ -1929,11 +1935,13 @@ meta_prefs_get_visual_bell_type (void) gboolean meta_prefs_add_keybinding (const char *name, GSettings *settings, + const char *hardcoded_key, MetaKeyBindingAction action, MetaKeyBindingFlags flags) { MetaKeyPref *pref; char **strokes; + char *static_strokes[2]; guint id; if (g_hash_table_lookup (key_bindings, name)) @@ -1944,19 +1952,44 @@ meta_prefs_add_keybinding (const char *name, pref = g_new0 (MetaKeyPref, 1); pref->name = g_strdup (name); - pref->settings = g_object_ref (settings); + pref->settings = settings ? g_object_ref (settings) : NULL; + pref->hardcoded_key = g_strdup (hardcoded_key); pref->action = action; pref->bindings = NULL; pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0; pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0; pref->builtin = (flags & META_KEY_BINDING_BUILTIN) != 0; + pref->is_single = (flags & META_KEY_BINDING_IS_SINGLE) != 0; + + if (settings) + { + if (pref->is_single) + { + static_strokes[0] = g_settings_get_string (settings, name); + static_strokes[1] = NULL; + strokes = static_strokes; + } + else + strokes = g_settings_get_strv (settings, name); + } + else + { + static_strokes[0] = (char*)hardcoded_key; + static_strokes[1] = NULL; + strokes = static_strokes; + } - strokes = g_settings_get_strv (settings, name); update_binding (pref, strokes); - g_strfreev (strokes); - g_hash_table_insert (key_bindings, g_strdup (name), pref); + if (strokes != static_strokes) + g_strfreev (strokes); + else if (static_strokes[0] != hardcoded_key) + g_free (static_strokes[0]); + + if (!settings) + return TRUE; + if (pref->builtin) { if (g_object_get_data (G_OBJECT (settings), "changed-signal") == NULL) diff --git a/src/meta/display.h b/src/meta/display.h index 04d545c36..7af830b22 100644 --- a/src/meta/display.h +++ b/src/meta/display.h @@ -134,6 +134,15 @@ gboolean meta_display_add_keybinding (MetaDisplay *display, MetaKeyHandlerFunc handler, gpointer user_data, GDestroyNotify free_data); +gboolean meta_display_add_grabbed_key (MetaDisplay *display, + const char *name, + const char *keyval, + MetaKeyBindingFlags flags, + MetaKeyHandlerFunc handler, + gpointer user_data, + GDestroyNotify free_data); +gboolean meta_display_remove_grabbed_key(MetaDisplay *display, + const char *name); gboolean meta_display_remove_keybinding (MetaDisplay *display, const char *name); diff --git a/src/meta/prefs.h b/src/meta/prefs.h index ff6984cc2..c63ab6829 100644 --- a/src/meta/prefs.h +++ b/src/meta/prefs.h @@ -234,7 +234,8 @@ typedef enum META_KEY_BINDING_PER_WINDOW = 1 << 0, META_KEY_BINDING_BUILTIN = 1 << 1, META_KEY_BINDING_REVERSES = 1 << 2, - META_KEY_BINDING_IS_REVERSED = 1 << 3 + META_KEY_BINDING_IS_REVERSED = 1 << 3, + META_KEY_BINDING_IS_SINGLE = 1 << 4, } MetaKeyBindingFlags; typedef struct @@ -262,6 +263,7 @@ typedef struct { char *name; GSettings *settings; + char *hardcoded_key; MetaKeyBindingAction action; @@ -280,6 +282,10 @@ typedef struct /** for keybindings not added with meta_display_add_keybinding() */ gboolean builtin:1; + + /** for keybindings that are stored as a single value, not + as a list */ + gboolean is_single:1; } MetaKeyPref; GType meta_key_binding_get_type (void);