keybindings: Add external grab API

During compositor grabs, all global keybindings that don't go
through mutter's keybinding system are blocked. To allow other
processes to make use of it, gnome-shell will expose a simple
grab API on DBus; for this, add API to grab key combos directly
instead of parsing accelerators stored in GSettings.

https://bugzilla.gnome.org/show_bug.cgi?id=643111
This commit is contained in:
Florian Müllner 2012-08-28 15:28:11 +02:00
parent 4df3e987c6
commit a39cabfadb
6 changed files with 223 additions and 7 deletions

View File

@ -460,6 +460,9 @@ void meta_display_queue_autoraise_callback (MetaDisplay *display,
void meta_display_remove_autoraise_callback (MetaDisplay *display);
void meta_display_overlay_key_activate (MetaDisplay *display);
void meta_display_accelerator_activate (MetaDisplay *display,
guint action,
guint deviceid);
/* In above-tab-keycode.c */
guint meta_display_get_above_tab_keycode (MetaDisplay *display);

View File

@ -138,6 +138,7 @@ G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
enum
{
OVERLAY_KEY,
ACCELERATOR_ACTIVATED,
FOCUS_WINDOW,
WINDOW_CREATED,
WINDOW_DEMANDS_ATTENTION,
@ -246,6 +247,14 @@ meta_display_class_init (MetaDisplayClass *klass)
NULL, NULL, NULL,
G_TYPE_NONE, 0);
display_signals[ACCELERATOR_ACTIVATED] =
g_signal_new ("accelerator-activated",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
display_signals[WINDOW_CREATED] =
g_signal_new ("window-created",
G_TYPE_FROM_CLASS (klass),
@ -5662,6 +5671,15 @@ meta_display_overlay_key_activate (MetaDisplay *display)
g_signal_emit (display, display_signals[OVERLAY_KEY], 0);
}
void
meta_display_accelerator_activate (MetaDisplay *display,
guint action,
guint deviceid)
{
g_signal_emit (display, display_signals[ACCELERATOR_ACTIVATED],
0, action, deviceid);
}
void
meta_display_get_compositor_version (MetaDisplay *display,
int *major,

View File

@ -145,6 +145,7 @@ static void regrab_key_bindings (MetaDisplay *display);
static GHashTable *key_handlers;
static GHashTable *external_grabs;
#define HANDLER(name) g_hash_table_lookup (key_handlers, (name))
@ -157,6 +158,22 @@ key_handler_free (MetaKeyHandler *handler)
g_free (handler);
}
typedef struct _MetaKeyGrab MetaKeyGrab;
struct _MetaKeyGrab {
char *name;
guint action;
MetaKeyCombo *combo;
};
static void
meta_key_grab_free (MetaKeyGrab *grab)
{
g_free (grab->name);
g_free (grab->combo);
g_free (grab);
}
static void
reload_keymap (MetaDisplay *display)
{
@ -390,13 +407,14 @@ static void
rebuild_binding_table (MetaDisplay *display,
MetaKeyBinding **bindings_p,
int *n_bindings_p,
GList *prefs)
GList *prefs,
GList *grabs)
{
GList *p;
GList *p, *g;
int n_bindings;
int i;
n_bindings = count_bindings (prefs);
n_bindings = count_bindings (prefs) + g_list_length (grabs);
g_free (*bindings_p);
*bindings_p = g_new0 (MetaKeyBinding, n_bindings);
@ -449,6 +467,27 @@ rebuild_binding_table (MetaDisplay *display,
p = p->next;
}
g = grabs;
while (g)
{
MetaKeyGrab *grab = (MetaKeyGrab*)g->data;
if (grab->combo && (grab->combo->keysym != None || grab->combo->keycode != 0))
{
MetaKeyHandler *handler = HANDLER ("external-grab");
(*bindings_p)[i].name = grab->name;
(*bindings_p)[i].handler = handler;
(*bindings_p)[i].keysym = grab->combo->keysym;
(*bindings_p)[i].keycode = grab->combo->keycode;
(*bindings_p)[i].modifiers = grab->combo->modifiers;
(*bindings_p)[i].mask = 0;
++i;
}
g = g->next;
}
g_assert (i == n_bindings);
*n_bindings_p = i;
@ -461,17 +500,19 @@ rebuild_binding_table (MetaDisplay *display,
static void
rebuild_key_binding_table (MetaDisplay *display)
{
GList *prefs;
GList *prefs, *grabs;
meta_topic (META_DEBUG_KEYBINDINGS,
"Rebuilding key binding table from preferences\n");
prefs = meta_prefs_get_keybindings ();
grabs = g_hash_table_get_values (external_grabs);
rebuild_binding_table (display,
&display->key_bindings,
&display->n_key_bindings,
prefs);
prefs, grabs);
g_list_free (prefs);
g_list_free (grabs);
}
static void
@ -699,9 +740,17 @@ meta_display_get_keybinding_action (MetaDisplay *display,
binding = display_get_keybinding (display, META_KEY_ABOVE_TAB, keycode, mask);
if (binding)
return (guint) meta_prefs_get_keybinding_action (binding->name);
{
MetaKeyGrab *grab = g_hash_table_lookup (external_grabs, binding->name);
if (grab)
return grab->action;
else
return (guint) meta_prefs_get_keybinding_action (binding->name);
}
else
return META_KEYBINDING_ACTION_NONE;
{
return META_KEYBINDING_ACTION_NONE;
}
}
void
@ -1046,6 +1095,128 @@ meta_window_ungrab_keys (MetaWindow *window)
}
}
static void
handle_external_grab (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XIDeviceEvent *event,
MetaKeyBinding *binding,
gpointer user_data)
{
guint action = meta_display_get_keybinding_action (display,
binding->keycode,
binding->mask);
meta_display_accelerator_activate (display, action, event->deviceid);
}
guint
meta_display_grab_accelerator (MetaDisplay *display,
const char *accelerator)
{
MetaKeyGrab *grab;
guint keysym = 0;
guint keycode = 0;
guint mask = 0;
MetaVirtualModifier modifiers = 0;
GSList *l;
int i;
if (!meta_ui_parse_accelerator (accelerator, &keysym, &keycode, &modifiers))
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to parse accelerator\n");
meta_warning (_("\"%s\" is not a valid accelerator\n"), accelerator);
return META_KEYBINDING_ACTION_NONE;
}
meta_display_devirtualize_modifiers (display, modifiers, &mask);
keycode = keysym_to_keycode (display, keysym);
if (keycode == 0)
return META_KEYBINDING_ACTION_NONE;
for (i = 0; i < display->n_key_bindings; i++)
if (display->key_bindings[i].keycode == keycode &&
display->key_bindings[i].mask == mask)
return META_KEYBINDING_ACTION_NONE;
for (l = display->screens; l; l = l->next)
{
MetaScreen *screen = l->data;
meta_grab_key (display, screen->xroot, keysym, keycode, mask);
}
grab = g_new0 (MetaKeyGrab, 1);
grab->action = next_dynamic_keybinding_action ();
grab->name = meta_external_binding_name_for_action (grab->action);
grab->combo = g_malloc0 (sizeof (MetaKeyCombo));
grab->combo->keysym = keysym;
grab->combo->keycode = keycode;
grab->combo->modifiers = modifiers;
g_hash_table_insert (external_grabs, grab->name, grab);
display->n_key_bindings++;
display->key_bindings = g_renew (MetaKeyBinding,
display->key_bindings,
display->n_key_bindings);
MetaKeyBinding *binding = &display->key_bindings[display->n_key_bindings - 1];
binding->name = grab->name;
binding->handler = HANDLER ("external-grab");
binding->keysym = grab->combo->keysym;
binding->keycode = grab->combo->keycode;
binding->modifiers = grab->combo->modifiers;
binding->mask = mask;
return grab->action;
}
gboolean
meta_display_ungrab_accelerator (MetaDisplay *display,
guint action)
{
MetaKeyGrab *grab;
char *key;
int i;
g_return_val_if_fail (action != META_KEYBINDING_ACTION_NONE, FALSE);
key = meta_external_binding_name_for_action (action);
grab = g_hash_table_lookup (external_grabs, key);
if (!grab)
return FALSE;
for (i = 0; i < display->n_key_bindings; i++)
if (display->key_bindings[i].keysym == grab->combo->keysym &&
display->key_bindings[i].keycode == grab->combo->keycode &&
display->key_bindings[i].modifiers == grab->combo->modifiers)
{
GSList *l;
for (l = display->screens; l; l = l->next)
{
MetaScreen *screen = l->data;
meta_change_keygrab (display, screen->xroot, FALSE,
display->key_bindings[i].keysym,
display->key_bindings[i].keycode,
display->key_bindings[i].mask);
}
display->key_bindings[i].keysym = 0;
display->key_bindings[i].keycode = 0;
display->key_bindings[i].modifiers = 0;
display->key_bindings[i].mask = 0;
break;
}
g_hash_table_remove (external_grabs, key);
g_free (key);
return TRUE;
}
#ifdef WITH_VERBOSE_MODE
static const char*
grab_status_to_string (int status)
@ -4335,6 +4506,17 @@ meta_display_init_keys (MetaDisplay *display)
g_hash_table_insert (key_handlers, g_strdup ("overlay-key"), handler);
handler = g_new0 (MetaKeyHandler, 1);
handler->name = g_strdup ("external-grab");
handler->func = handle_external_grab;
handler->default_func = handle_external_grab;
g_hash_table_insert (key_handlers, g_strdup ("external-grab"), handler);
external_grabs = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
(GDestroyNotify)meta_key_grab_free);
init_builtin_key_bindings (display);
rebuild_key_binding_table (display);

View File

@ -555,6 +555,12 @@ meta_gravity_to_string (int gravity)
}
}
char*
meta_external_binding_name_for_action (guint keybinding_action)
{
return g_strdup_printf ("external-grab-%u", keybinding_action);
}
static gboolean
zenity_supports_option (const char *section, const char *option)
{

View File

@ -139,6 +139,11 @@ guint meta_display_add_keybinding (MetaDisplay *display,
gboolean meta_display_remove_keybinding (MetaDisplay *display,
const char *name);
guint meta_display_grab_accelerator (MetaDisplay *display,
const char *accelerator);
gboolean meta_display_ungrab_accelerator (MetaDisplay *display,
guint action_id);
guint meta_display_get_keybinding_action (MetaDisplay *display,
unsigned int keycode,
unsigned long mask);

View File

@ -93,6 +93,8 @@ guint meta_unsigned_long_hash (gconstpointer v);
const char* meta_frame_type_to_string (MetaFrameType type);
const char* meta_gravity_to_string (int gravity);
char* meta_external_binding_name_for_action (guint keybinding_action);
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x