From a39cabfadb1d160b284ca3a17fdbf4f9e7c6d42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 28 Aug 2012 15:28:11 +0200 Subject: [PATCH] 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 --- src/core/display-private.h | 3 + src/core/display.c | 18 ++++ src/core/keybindings.c | 196 +++++++++++++++++++++++++++++++++++-- src/core/util.c | 6 ++ src/meta/display.h | 5 + src/meta/util.h | 2 + 6 files changed, 223 insertions(+), 7 deletions(-) diff --git a/src/core/display-private.h b/src/core/display-private.h index c4abbfa86..c30d312af 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -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); diff --git a/src/core/display.c b/src/core/display.c index b1e654338..e3bf5f6b2 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -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, diff --git a/src/core/keybindings.c b/src/core/keybindings.c index 7f6be7eb0..b3bb1cecc 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -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); diff --git a/src/core/util.c b/src/core/util.c index 0ab87bb49..a8da0d2dd 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -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) { diff --git a/src/meta/display.h b/src/meta/display.h index b922b48c4..9ac8d202f 100644 --- a/src/meta/display.h +++ b/src/meta/display.h @@ -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); diff --git a/src/meta/util.h b/src/meta/util.h index 04bb7bfe1..b34d93569 100644 --- a/src/meta/util.h +++ b/src/meta/util.h @@ -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 #define _(x) dgettext (GETTEXT_PACKAGE, x) #define N_(x) x