mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 09:30:45 -05:00
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
This commit is contained in:
parent
d42a2a3c27
commit
0e50287aea
@ -77,6 +77,9 @@ gboolean meta_prefs_add_keybinding (const char *name,
|
|||||||
MetaKeyBindingAction action,
|
MetaKeyBindingAction action,
|
||||||
MetaKeyBindingFlags flags);
|
MetaKeyBindingFlags flags);
|
||||||
|
|
||||||
|
gboolean meta_prefs_remove_keybinding (const char *name);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,6 +59,49 @@ static gboolean add_builtin_keybinding (MetaDisplay *display,
|
|||||||
MetaKeyHandlerFunc handler,
|
MetaKeyHandlerFunc handler,
|
||||||
int handler_arg);
|
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
|
/* These can't be bound to anything, but they are used to handle
|
||||||
* various other events. TODO: Possibly we should include them as event
|
* various other events. TODO: Possibly we should include them as event
|
||||||
* handler functions and have some kind of flag to say they're unbindable.
|
* handler functions and have some kind of flag to say they're unbindable.
|
||||||
@ -501,13 +544,15 @@ display_get_keybinding (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
add_builtin_keybinding (MetaDisplay *display,
|
add_keybinding_internal (MetaDisplay *display,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *schema,
|
const char *schema,
|
||||||
MetaKeyBindingFlags flags,
|
MetaKeyBindingFlags flags,
|
||||||
MetaKeyBindingAction action,
|
MetaKeyBindingAction action,
|
||||||
MetaKeyHandlerFunc func,
|
MetaKeyHandlerFunc func,
|
||||||
int data)
|
int data,
|
||||||
|
gpointer user_data,
|
||||||
|
GDestroyNotify free_data)
|
||||||
{
|
{
|
||||||
MetaKeyHandler *handler;
|
MetaKeyHandler *handler;
|
||||||
|
|
||||||
@ -520,18 +565,103 @@ add_builtin_keybinding (MetaDisplay *display,
|
|||||||
handler->default_func = func;
|
handler->default_func = func;
|
||||||
handler->data = data;
|
handler->data = data;
|
||||||
handler->flags = flags;
|
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);
|
g_hash_table_insert (key_handlers, g_strdup (name), handler);
|
||||||
|
|
||||||
return TRUE;
|
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:
|
* meta_display_get_keybinding_action:
|
||||||
* @display: A #MetaDisplay
|
* @display: A #MetaDisplay
|
||||||
* @keycode: Raw keycode
|
* @keycode: Raw keycode
|
||||||
* @mask: Event mask
|
* @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
|
* Returns: The action that should be taken for the given key, or
|
||||||
* %META_KEYBINDING_ACTION_NONE.
|
* %META_KEYBINDING_ACTION_NONE.
|
||||||
*/
|
*/
|
||||||
|
@ -1919,6 +1919,7 @@ meta_prefs_add_keybinding (const char *name,
|
|||||||
if (settings == NULL)
|
if (settings == NULL)
|
||||||
{
|
{
|
||||||
settings = g_settings_new (schema);
|
settings = g_settings_new (schema);
|
||||||
|
if ((flags & META_KEY_BINDING_BUILTIN) != 0)
|
||||||
g_signal_connect (settings, "changed",
|
g_signal_connect (settings, "changed",
|
||||||
G_CALLBACK (bindings_changed), NULL);
|
G_CALLBACK (bindings_changed), NULL);
|
||||||
g_hash_table_insert (settings_schemas, g_strdup (schema), settings);
|
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->bindings = NULL;
|
||||||
pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0;
|
pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0;
|
||||||
pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 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);
|
strokes = g_settings_get_strv (settings, name);
|
||||||
update_binding (pref, strokes);
|
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);
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_prefs_get_keybindings: (skip)
|
* meta_prefs_get_keybindings:
|
||||||
* Return: (element-type MetaKeyPref) (transfer container):
|
* Return: (element-type MetaKeyPref) (transfer container):
|
||||||
*/
|
*/
|
||||||
GList *
|
GList *
|
||||||
|
@ -124,6 +124,16 @@ void meta_display_end_grab_op (MetaDisplay *display,
|
|||||||
|
|
||||||
MetaGrabOp meta_display_get_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,
|
MetaKeyBindingAction meta_display_get_keybinding_action (MetaDisplay *display,
|
||||||
unsigned int keycode,
|
unsigned int keycode,
|
||||||
unsigned long mask);
|
unsigned long mask);
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
#include <meta/display.h>
|
#include <meta/display.h>
|
||||||
#include <meta/common.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,
|
gboolean meta_keybindings_set_custom_handler (const gchar *name,
|
||||||
MetaKeyHandlerFunc handler,
|
MetaKeyHandlerFunc handler,
|
||||||
|
@ -238,8 +238,9 @@ typedef enum
|
|||||||
{
|
{
|
||||||
META_KEY_BINDING_NONE,
|
META_KEY_BINDING_NONE,
|
||||||
META_KEY_BINDING_PER_WINDOW = 1 << 0,
|
META_KEY_BINDING_PER_WINDOW = 1 << 0,
|
||||||
META_KEY_BINDING_REVERSES = 1 << 1,
|
META_KEY_BINDING_BUILTIN = 1 << 1,
|
||||||
META_KEY_BINDING_IS_REVERSED = 1 << 2
|
META_KEY_BINDING_REVERSES = 1 << 2,
|
||||||
|
META_KEY_BINDING_IS_REVERSED = 1 << 3
|
||||||
} MetaKeyBindingFlags;
|
} MetaKeyBindingFlags;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -250,7 +251,8 @@ typedef struct
|
|||||||
} MetaKeyCombo;
|
} MetaKeyCombo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MetaKeyHandlerFunc: (skip)
|
* MetaKeyHandlerFunc:
|
||||||
|
* @event: (type gpointer):
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
|
typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
|
||||||
@ -262,7 +264,6 @@ typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
|
|||||||
|
|
||||||
typedef struct _MetaKeyHandler MetaKeyHandler;
|
typedef struct _MetaKeyHandler MetaKeyHandler;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
@ -282,8 +283,13 @@ typedef struct
|
|||||||
|
|
||||||
/** for keybindings that apply only to a window */
|
/** for keybindings that apply only to a window */
|
||||||
gboolean per_window:1;
|
gboolean per_window:1;
|
||||||
|
|
||||||
|
/** for keybindings not added with meta_display_add_keybinding() */
|
||||||
|
gboolean builtin:1;
|
||||||
} MetaKeyPref;
|
} MetaKeyPref;
|
||||||
|
|
||||||
|
GType meta_key_binding_get_type (void);
|
||||||
|
|
||||||
GList *meta_prefs_get_keybindings (void);
|
GList *meta_prefs_get_keybindings (void);
|
||||||
|
|
||||||
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
|
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
|
||||||
|
Loading…
Reference in New Issue
Block a user