summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Müllner <fmuellner@gnome.org>2011-11-04 19:18:57 +0100
committerFlorian Müllner <fmuellner@gnome.org>2011-11-22 00:42:30 +0100
commit0e50287aea24af9a165a78856da05c1eb1a63e04 (patch)
treea947197c4138bbde772ce2207a725021181b2bd5
parentd42a2a3c2741b8b44b48f83eb79a82fb4fcd5bbd (diff)
downloadmutter-0e50287aea24af9a165a78856da05c1eb1a63e04.tar.gz
keybindings: Allow to add/remove keybindings at runtime
Add meta_display_add_keybinding()/meta_display_remove_keybinding(), which allow to add/remove keybindings dynamically at runtime. https://bugzilla.gnome.org/show_bug.cgi?id=663428
-rw-r--r--src/core/keybindings-private.h3
-rw-r--r--src/core/keybindings.c144
-rw-r--r--src/core/prefs.c52
-rw-r--r--src/meta/display.h10
-rw-r--r--src/meta/keybindings.h5
-rw-r--r--src/meta/prefs.h14
6 files changed, 214 insertions, 14 deletions
diff --git a/src/core/keybindings-private.h b/src/core/keybindings-private.h
index a3dbfcc2d..507b162f2 100644
--- a/src/core/keybindings-private.h
+++ b/src/core/keybindings-private.h
@@ -77,6 +77,9 @@ gboolean meta_prefs_add_keybinding (const char *name,
MetaKeyBindingAction action,
MetaKeyBindingFlags flags);
+gboolean meta_prefs_remove_keybinding (const char *name);
+
+
#endif
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 8897eacff..5510d2876 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -59,6 +59,49 @@ static gboolean add_builtin_keybinding (MetaDisplay *display,
MetaKeyHandlerFunc handler,
int handler_arg);
+static void
+meta_key_binding_free (MetaKeyBinding *binding)
+{
+ g_slice_free (MetaKeyBinding, binding);
+}
+
+static MetaKeyBinding *
+meta_key_binding_copy (MetaKeyBinding *binding)
+{
+ return g_slice_dup (MetaKeyBinding, binding);
+}
+
+GType
+meta_key_binding_get_type (void)
+{
+ static GType type_id = 0;
+
+ if (G_UNLIKELY (type_id == 0))
+ type_id = g_boxed_type_register_static (g_intern_static_string ("MetaKeyBinding"),
+ (GBoxedCopyFunc)meta_key_binding_copy,
+ (GBoxedFreeFunc)meta_key_binding_free);
+
+ return type_id;
+}
+
+const char *
+meta_key_binding_get_name (MetaKeyBinding *binding)
+{
+ return binding->name;
+}
+
+MetaVirtualModifier
+meta_key_binding_get_modifiers (MetaKeyBinding *binding)
+{
+ return binding->modifiers;
+}
+
+guint
+meta_key_binding_get_mask (MetaKeyBinding *binding)
+{
+ return binding->mask;
+}
+
/* These can't be bound to anything, but they are used to handle
* various other events. TODO: Possibly we should include them as event
* handler functions and have some kind of flag to say they're unbindable.
@@ -501,13 +544,15 @@ display_get_keybinding (MetaDisplay *display,
}
static gboolean
-add_builtin_keybinding (MetaDisplay *display,
- const char *name,
- const char *schema,
- MetaKeyBindingFlags flags,
- MetaKeyBindingAction action,
- MetaKeyHandlerFunc func,
- int data)
+add_keybinding_internal (MetaDisplay *display,
+ const char *name,
+ const char *schema,
+ MetaKeyBindingFlags flags,
+ MetaKeyBindingAction action,
+ MetaKeyHandlerFunc func,
+ int data,
+ gpointer user_data,
+ GDestroyNotify free_data)
{
MetaKeyHandler *handler;
@@ -520,18 +565,103 @@ add_builtin_keybinding (MetaDisplay *display,
handler->default_func = func;
handler->data = data;
handler->flags = flags;
+ handler->user_data = user_data;
+ handler->user_data_free_func = free_data;
g_hash_table_insert (key_handlers, g_strdup (name), handler);
return TRUE;
}
+static gboolean
+add_builtin_keybinding (MetaDisplay *display,
+ const char *name,
+ const char *schema,
+ MetaKeyBindingFlags flags,
+ MetaKeyBindingAction action,
+ MetaKeyHandlerFunc handler,
+ int handler_arg)
+{
+ return add_keybinding_internal (display, name, schema,
+ flags | META_KEY_BINDING_BUILTIN,
+ action, handler, handler_arg, NULL, NULL);
+}
+
+/**
+ * meta_display_add_keybinding:
+ * @display: a #MetaDisplay
+ * @name: the binding's name
+ * @schema: the #GSettings schema where @name is stored
+ * @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
+ *
+ * Add a keybinding at runtime. The key @name in @schema needs to be of
+ * type %G_VARIANT_TYPE_STRING_ARRAY, with each string describing a
+ * keybinding in the form of "<Control>a" or "<Shift><Alt>F1". The parser
+ * is fairly liberal and allows lower or upper case, and also abbreviations
+ * such as "<Ctl>" and "<Ctrl>". If the key is set to the empty list or a
+ * list with a single element of either "" or "disabled", the keybinding is
+ * disabled.
+ * If %META_KEY_BINDING_REVERSES is specified in @flags, the binding
+ * may be reversed by holding down the "shift" key; therefore, "<Shift>"
+ * cannot be one of the keys used. @handler is expected to check for the
+ * "shift" modifier in this case and reverse its action.
+ *
+ * Use meta_display_remove_keybinding() to remove the binding.
+ *
+ * Returns: %TRUE if the keybinding was added successfully,
+ * otherwise %FALSE
+ */
+gboolean
+meta_display_add_keybinding (MetaDisplay *display,
+ const char *name,
+ const char *schema,
+ MetaKeyBindingFlags flags,
+ MetaKeyHandlerFunc handler,
+ gpointer user_data,
+ GDestroyNotify free_data)
+{
+ return add_keybinding_internal (display, name, schema, flags,
+ META_KEYBINDING_ACTION_NONE,
+ handler, 0, user_data, free_data);
+}
+
+/**
+ * meta_display_remove_keybinding:
+ * @display: the #MetaDisplay
+ * @name: name of the keybinding to remove
+ *
+ * Remove keybinding @name; the function will fail if @name is not a known
+ * keybinding or has not been added with meta_display_add_keybinding().
+ *
+ * Returns: %TRUE if the binding has been removed sucessfully,
+ * otherwise %FALSE
+ */
+gboolean
+meta_display_remove_keybinding (MetaDisplay *display,
+ const char *name)
+{
+ if (!meta_prefs_remove_keybinding (name))
+ return FALSE;
+
+ g_hash_table_remove (key_handlers, name);
+
+ return TRUE;
+}
+
/**
* meta_display_get_keybinding_action:
* @display: A #MetaDisplay
* @keycode: Raw keycode
* @mask: Event mask
*
+ * Get the #MetaKeyBindingAction bound to %keycode. Only builtin
+ * keybindings have an associated #MetaKeyBindingAction, for
+ * bindings added dynamically with meta_display_add_keybinding()
+ * the function will always return %META_KEYBINDING_ACTION_NONE.
+ *
* Returns: The action that should be taken for the given key, or
* %META_KEYBINDING_ACTION_NONE.
*/
diff --git a/src/core/prefs.c b/src/core/prefs.c
index 3455de0af..0d3fd5900 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -1919,8 +1919,9 @@ meta_prefs_add_keybinding (const char *name,
if (settings == NULL)
{
settings = g_settings_new (schema);
- g_signal_connect (settings, "changed",
- G_CALLBACK (bindings_changed), NULL);
+ if ((flags & META_KEY_BINDING_BUILTIN) != 0)
+ g_signal_connect (settings, "changed",
+ G_CALLBACK (bindings_changed), NULL);
g_hash_table_insert (settings_schemas, g_strdup (schema), settings);
}
@@ -1931,6 +1932,7 @@ meta_prefs_add_keybinding (const char *name,
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;
strokes = g_settings_get_strv (settings, name);
update_binding (pref, strokes);
@@ -1938,11 +1940,55 @@ meta_prefs_add_keybinding (const char *name,
g_hash_table_insert (key_bindings, g_strdup (name), pref);
+ if (!pref->builtin)
+ {
+ guint id;
+ char *changed_signal = g_strdup_printf ("changed::%s", name);
+ id = g_signal_connect (settings, changed_signal,
+ G_CALLBACK (bindings_changed), NULL);
+ g_free (changed_signal);
+
+ g_object_set_data (G_OBJECT (settings), name, GUINT_TO_POINTER (id));
+
+ queue_changed (META_PREF_KEYBINDINGS);
+ }
+
+ return TRUE;
+}
+
+gboolean
+meta_prefs_remove_keybinding (const char *name)
+{
+ MetaKeyPref *pref;
+ GSettings *settings;
+ guint id;
+
+ pref = g_hash_table_lookup (key_bindings, name);
+ if (!pref)
+ {
+ meta_warning ("Trying to remove non-existent keybinding \"%s\".\n", name);
+ return FALSE;
+ }
+
+ if (pref->builtin)
+ {
+ meta_warning ("Trying to remove builtin keybinding \"%s\".\n", name);
+ return FALSE;
+ }
+
+ settings = SETTINGS (pref->schema);
+ id = GPOINTER_TO_UINT (g_object_steal_data (G_OBJECT (settings), name));
+ g_signal_handler_disconnect (settings, id);
+
+ g_hash_table_remove (key_bindings, name);
+
+ queue_changed (META_PREF_KEYBINDINGS);
+
return TRUE;
}
/**
- * meta_prefs_get_keybindings: (skip)
+ * meta_prefs_get_keybindings:
* Return: (element-type MetaKeyPref) (transfer container):
*/
GList *
diff --git a/src/meta/display.h b/src/meta/display.h
index feeb12c6c..a9edc003d 100644
--- a/src/meta/display.h
+++ b/src/meta/display.h
@@ -124,6 +124,16 @@ void meta_display_end_grab_op (MetaDisplay *display,
MetaGrabOp meta_display_get_grab_op (MetaDisplay *display);
+gboolean meta_display_add_keybinding (MetaDisplay *display,
+ const char *name,
+ const char *schema,
+ MetaKeyBindingFlags flags,
+ MetaKeyHandlerFunc handler,
+ gpointer user_data,
+ GDestroyNotify free_data);
+gboolean meta_display_remove_keybinding (MetaDisplay *display,
+ const char *name);
+
MetaKeyBindingAction meta_display_get_keybinding_action (MetaDisplay *display,
unsigned int keycode,
unsigned long mask);
diff --git a/src/meta/keybindings.h b/src/meta/keybindings.h
index 7b5171bff..862e1b214 100644
--- a/src/meta/keybindings.h
+++ b/src/meta/keybindings.h
@@ -23,6 +23,11 @@
#include <meta/display.h>
#include <meta/common.h>
+#define META_TYPE_KEY_BINDING (meta_key_binding_get_type ())
+
+const char *meta_key_binding_get_name (MetaKeyBinding *binding);
+MetaVirtualModifier meta_key_binding_get_modifiers (MetaKeyBinding *binding);
+guint meta_key_binding_get_mask (MetaKeyBinding *binding);
gboolean meta_keybindings_set_custom_handler (const gchar *name,
MetaKeyHandlerFunc handler,
diff --git a/src/meta/prefs.h b/src/meta/prefs.h
index d973e4b22..6007c7c03 100644
--- a/src/meta/prefs.h
+++ b/src/meta/prefs.h
@@ -238,8 +238,9 @@ typedef enum
{
META_KEY_BINDING_NONE,
META_KEY_BINDING_PER_WINDOW = 1 << 0,
- META_KEY_BINDING_REVERSES = 1 << 1,
- META_KEY_BINDING_IS_REVERSED = 1 << 2
+ META_KEY_BINDING_BUILTIN = 1 << 1,
+ META_KEY_BINDING_REVERSES = 1 << 2,
+ META_KEY_BINDING_IS_REVERSED = 1 << 3
} MetaKeyBindingFlags;
typedef struct
@@ -250,7 +251,8 @@ typedef struct
} MetaKeyCombo;
/**
- * MetaKeyHandlerFunc: (skip)
+ * MetaKeyHandlerFunc:
+ * @event: (type gpointer):
*
*/
typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
@@ -262,7 +264,6 @@ typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
typedef struct _MetaKeyHandler MetaKeyHandler;
-
typedef struct
{
char *name;
@@ -282,8 +283,13 @@ typedef struct
/** for keybindings that apply only to a window */
gboolean per_window:1;
+
+ /** for keybindings not added with meta_display_add_keybinding() */
+ gboolean builtin:1;
} MetaKeyPref;
+GType meta_key_binding_get_type (void);
+
GList *meta_prefs_get_keybindings (void);
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);