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
This commit is contained in:
Owen W. Taylor 2011-07-08 20:48:01 -04:00
parent b369c75e1b
commit 12f71c9795

View File

@ -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,