mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 15:40:41 -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,
|
||||
MetaKeyBindingFlags flags);
|
||||
|
||||
gboolean meta_prefs_remove_keybinding (const char *name);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 *
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user