[mutter] Improve handling of <Super>key combinations
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] Improve handling of <Super>key combinations
- Date: Wed, 13 Jul 2011 13:44:49 +0000 (UTC)
commit 12f71c9795e21cefd0faf1d98327d2139172ae71
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Fri Jul 8 20:48:01 2011 -0400
Improve handling of <Super>key combinations
When we get a press of the overlay key, and then another key is pressed,
first try to handle the combination as a global keybinding. If that fails,
call XAllowEvents(..., ReplayKeyboard, ...) to let it be handled by
our per-window keybindings or by the application.
This requires restructuring things to call XAllowEvents a bit later
so we can pass the right mode.
https://bugzilla.gnome.org/show_bug.cgi?id=624869
src/core/keybindings.c | 123 ++++++++++++++++++++++++++++++++++-------------
1 files changed, 89 insertions(+), 34 deletions(-)
---
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 79f1e42..0e7d355 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -1250,31 +1250,6 @@ primary_modifier_still_pressed (MetaDisplay *display,
return TRUE;
}
-static gboolean
-process_overlay_key (MetaDisplay *display,
- MetaScreen *Screen,
- XEvent *event,
- KeySym keysym)
-{
- if (event->xkey.keycode != display->overlay_key_combo.keycode)
- {
- display->overlay_key_only_pressed = FALSE;
- return FALSE;
- }
-
- if (event->xkey.type == KeyPress)
- {
- display->overlay_key_only_pressed = TRUE;
- }
- else if (event->xkey.type == KeyRelease && display->overlay_key_only_pressed)
- {
- display->overlay_key_only_pressed = FALSE;
- meta_display_overlay_key_activate (display);
- }
-
- return TRUE;
-}
-
static void
invoke_handler (MetaDisplay *display,
MetaScreen *screen,
@@ -1380,6 +1355,73 @@ process_event (MetaKeyBinding *bindings,
return FALSE;
}
+static gboolean
+process_overlay_key (MetaDisplay *display,
+ MetaScreen *screen,
+ XEvent *event,
+ KeySym keysym)
+{
+ if (display->overlay_key_only_pressed)
+ {
+ if (event->xkey.keycode != display->overlay_key_combo.keycode)
+ {
+ display->overlay_key_only_pressed = FALSE;
+
+ /* OK, the user hit modifier+key rather than pressing and
+ * releasing the ovelay key. We want to handle the key
+ * sequence "normally". Unfortunately, using
+ * XAllowEvents(..., ReplayKeyboard, ...) doesn't quite
+ * work, since global keybindings won't be activated ("this
+ * time, however, the function ignores any passive grabs at
+ * above (toward the root of) the grab_window of the grab
+ * just released.") So, we first explicitly check for one of
+ * our global keybindings, and if not found, we then replay
+ * the event. Other clients with global grabs will be out of
+ * luck.
+ */
+ if (process_event (display->key_bindings,
+ display->n_key_bindings,
+ display, screen, NULL, event, keysym,
+ FALSE))
+ {
+ /* As normally, after we've handled a global key
+ * binding, we unfreeze the keyboard but keep the grab
+ * (this is important for something like cycling
+ * windows */
+ XAllowEvents (display->xdisplay, AsyncKeyboard, event->xkey.time);
+ }
+ else
+ {
+ /* Replay the event so it gets delivered to our
+ * per-window key bindings or to the application */
+ XAllowEvents (display->xdisplay, ReplayKeyboard, event->xkey.time);
+ }
+ }
+ else if (event->xkey.type == KeyRelease)
+ {
+ display->overlay_key_only_pressed = FALSE;
+ /* We want to unfreeze events, but keep the grab so that if the user
+ * starts typing into the overlay we get all the keys */
+ XAllowEvents (display->xdisplay, AsyncKeyboard, event->xkey.time);
+ meta_display_overlay_key_activate (display);
+ }
+
+ return TRUE;
+ }
+ else if (event->xkey.type == KeyPress &&
+ event->xkey.keycode == display->overlay_key_combo.keycode)
+ {
+ display->overlay_key_only_pressed = TRUE;
+ /* We keep the keyboard frozen - this allows us to use ReplayKeyboard
+ * on the next event if it's not the release of the overlay key */
+ XAllowEvents (display->xdisplay, SyncKeyboard, event->xkey.time);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
/* Handle a key event. May be called recursively: some key events cause
* grabs to be ended and then need to be processed again in their own
* right. This cannot cause infinite recursion because we never call
@@ -1406,11 +1448,19 @@ meta_display_process_key_event (MetaDisplay *display,
const char *str;
MetaScreen *screen;
- XAllowEvents (display->xdisplay,
- all_bindings_disabled ? ReplayKeyboard : AsyncKeyboard,
- event->xkey.time);
if (all_bindings_disabled)
- return FALSE;
+ {
+ /* In this mode, we try to pretend we don't have grabs, so we
+ * immediately replay events and drop the grab. (This still
+ * messes up global passive grabs from other clients.) The
+ * FALSE return here is a little suspect, but we don't really
+ * know if we'll see the event again or not, and it's pretty
+ * poorly defined how this mode is supposed to interact with
+ * plugins.
+ */
+ XAllowEvents (display->xdisplay, ReplayKeyboard, event->xkey.time);
+ return FALSE;
+ }
/* if key event was on root window, we have a shortcut */
screen = meta_display_screen_for_root (display, event->xkey.window);
@@ -1440,8 +1490,17 @@ meta_display_process_key_event (MetaDisplay *display,
str ? str : "none", event->xkey.state,
window ? window->desc : "(no window)");
- keep_grab = TRUE;
all_keys_grabbed = window ? window->all_keys_grabbed : screen->all_keys_grabbed;
+ if (!all_keys_grabbed)
+ {
+ handled = process_overlay_key (display, screen, event, keysym);
+ if (handled)
+ return TRUE;
+ }
+
+ XAllowEvents (display->xdisplay, AsyncKeyboard, event->xkey.time);
+
+ keep_grab = TRUE;
if (all_keys_grabbed)
{
if (display->grab_op == META_GRAB_OP_NONE)
@@ -1527,10 +1586,6 @@ meta_display_process_key_event (MetaDisplay *display,
return TRUE;
}
- handled = process_overlay_key (display, screen, event, keysym);
- if (handled)
- return TRUE;
-
/* Do the normal keybindings */
return process_event (display->key_bindings,
display->n_key_bindings,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]