mirror of
https://github.com/brl/mutter.git
synced 2024-11-30 03:50:47 -05:00
Fix custom-alt-tabs for single-handling of key events
The changes to enforce single handling of all key events were breaking custom-alt-tab keypress handlers, since that code was assuming that key event would get to process_tab_grab(), and then maybe to process_event() and then to the plugin's xevent_filter to detect a key release. We centeralize all of this handling into process_tab_grab() and either - Invoke a custom handler for the key press - Select the current window on modifier release by calling a new pseudo-binding "tab_popup_select" - Cancel the grab on an unbound key by calling a new pseudo-binding "tab_popup_cancel" http://bugzilla.gnome.org/show_bug.cgi?id=590754
This commit is contained in:
parent
67682a2683
commit
7b0ba87b24
@ -475,8 +475,8 @@ regrab_key_bindings (MetaDisplay *display)
|
|||||||
g_slist_free (windows);
|
g_slist_free (windows);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MetaKeyBindingAction
|
static MetaKeyBinding *
|
||||||
display_get_keybinding_action (MetaDisplay *display,
|
display_get_keybinding (MetaDisplay *display,
|
||||||
unsigned int keysym,
|
unsigned int keysym,
|
||||||
unsigned int keycode,
|
unsigned int keycode,
|
||||||
unsigned long mask)
|
unsigned long mask)
|
||||||
@ -490,12 +490,28 @@ display_get_keybinding_action (MetaDisplay *display,
|
|||||||
display->key_bindings[i].keycode == keycode &&
|
display->key_bindings[i].keycode == keycode &&
|
||||||
display->key_bindings[i].mask == mask)
|
display->key_bindings[i].mask == mask)
|
||||||
{
|
{
|
||||||
return meta_prefs_get_keybinding_action (display->key_bindings[i].name);
|
return &display->key_bindings[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaKeyBindingAction
|
||||||
|
display_get_keybinding_action (MetaDisplay *display,
|
||||||
|
unsigned int keysym,
|
||||||
|
unsigned int keycode,
|
||||||
|
unsigned long mask)
|
||||||
|
{
|
||||||
|
MetaKeyBinding *binding;
|
||||||
|
|
||||||
|
binding = display_get_keybinding (display, keysym, keycode, mask);
|
||||||
|
|
||||||
|
if (binding)
|
||||||
|
return meta_prefs_get_keybinding_action (binding->name);
|
||||||
|
else
|
||||||
return META_KEYBINDING_ACTION_NONE;
|
return META_KEYBINDING_ACTION_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1197,6 +1213,45 @@ process_overlay_key (MetaDisplay *display,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
invoke_handler (MetaDisplay *display,
|
||||||
|
MetaScreen *screen,
|
||||||
|
MetaKeyHandler *handler,
|
||||||
|
MetaWindow *window,
|
||||||
|
XEvent *event,
|
||||||
|
MetaKeyBinding *binding)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (handler->func)
|
||||||
|
(* handler->func) (display, screen,
|
||||||
|
handler->flags & BINDING_PER_WINDOW ?
|
||||||
|
window : NULL,
|
||||||
|
event,
|
||||||
|
binding,
|
||||||
|
handler->user_data);
|
||||||
|
else
|
||||||
|
(* handler->default_func) (display, screen,
|
||||||
|
handler->flags & BINDING_PER_WINDOW ?
|
||||||
|
window: NULL,
|
||||||
|
event,
|
||||||
|
binding,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
invoke_handler_by_name (MetaDisplay *display,
|
||||||
|
MetaScreen *screen,
|
||||||
|
const char *handler_name,
|
||||||
|
MetaWindow *window,
|
||||||
|
XEvent *event)
|
||||||
|
{
|
||||||
|
MetaKeyHandler *handler;
|
||||||
|
|
||||||
|
handler = find_handler (key_handlers, handler_name);
|
||||||
|
if (handler)
|
||||||
|
invoke_handler (display, screen, handler, window, event, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* now called from only one place, may be worth merging */
|
/* now called from only one place, may be worth merging */
|
||||||
static gboolean
|
static gboolean
|
||||||
process_event (MetaKeyBinding *bindings,
|
process_event (MetaKeyBinding *bindings,
|
||||||
@ -1253,20 +1308,7 @@ process_event (MetaKeyBinding *bindings,
|
|||||||
*/
|
*/
|
||||||
display->allow_terminal_deactivation = TRUE;
|
display->allow_terminal_deactivation = TRUE;
|
||||||
|
|
||||||
if (handler->func)
|
invoke_handler (display, screen, handler, window, event, &bindings[i]);
|
||||||
(* handler->func) (display, screen,
|
|
||||||
bindings[i].handler->flags & BINDING_PER_WINDOW ?
|
|
||||||
window: NULL,
|
|
||||||
event,
|
|
||||||
&bindings[i],
|
|
||||||
handler->user_data);
|
|
||||||
else
|
|
||||||
(* handler->default_func) (display, screen,
|
|
||||||
bindings[i].handler->flags & BINDING_PER_WINDOW ?
|
|
||||||
window: NULL,
|
|
||||||
event,
|
|
||||||
&bindings[i],
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -1985,6 +2027,7 @@ process_tab_grab (MetaDisplay *display,
|
|||||||
XEvent *event,
|
XEvent *event,
|
||||||
KeySym keysym)
|
KeySym keysym)
|
||||||
{
|
{
|
||||||
|
MetaKeyBinding *binding;
|
||||||
MetaKeyBindingAction action;
|
MetaKeyBindingAction action;
|
||||||
gboolean popup_not_showing;
|
gboolean popup_not_showing;
|
||||||
gboolean backward;
|
gboolean backward;
|
||||||
@ -1994,79 +2037,78 @@ process_tab_grab (MetaDisplay *display,
|
|||||||
if (screen != display->grab_screen)
|
if (screen != display->grab_screen)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
action = display_get_keybinding_action (display,
|
binding = display_get_keybinding (display,
|
||||||
keysym,
|
keysym,
|
||||||
event->xkey.keycode,
|
event->xkey.keycode,
|
||||||
display->grab_mask);
|
display->grab_mask);
|
||||||
|
if (binding)
|
||||||
|
action = meta_prefs_get_keybinding_action (binding->name);
|
||||||
|
else
|
||||||
|
action = META_KEYBINDING_ACTION_NONE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is no tab_pop up object, i.e., there is some custom handler
|
* There are currently two different ways of customizing Alt-Tab, you can either
|
||||||
* implementing Alt+Tab & Co., we call this custom handler; we do not
|
* provide a replacement AltTabHandler object, or you can hook into the keybindings
|
||||||
* mess about with the grab, as that is up to the handler to deal with.
|
* meta_keybindings_set_custom_handler() and call meta_display_begin_grab_op()
|
||||||
|
* yourself with one of the "tabbing" grab ops META_GRAB_OP_KEYBOARD_TABBING_NORMAL,
|
||||||
|
* etc. See meta_display_process_key_event() for the complete list. If screen->tab_handler
|
||||||
|
* is NULL, the latter mechanism is being used. We skip most of our normal
|
||||||
|
* processing and just make sure that the right custom handlers get called.
|
||||||
*/
|
*/
|
||||||
if (!screen->tab_handler)
|
if (!screen->tab_handler)
|
||||||
{
|
{
|
||||||
MetaKeyHandler *handler = NULL;
|
if (event->type == KeyRelease)
|
||||||
const gchar *handler_name = NULL;
|
{
|
||||||
|
if (end_keyboard_grab (display, event->xkey.keycode))
|
||||||
|
{
|
||||||
|
invoke_handler_by_name (display, screen, "tab_popup_select", NULL, event);
|
||||||
|
|
||||||
|
/* We return FALSE to end the grab; if the handler ended the grab itself
|
||||||
|
* that will be a noop. If the handler didn't end the grab, then it's a
|
||||||
|
* safety measure to prevent a stuck grab.
|
||||||
|
*/
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case META_KEYBINDING_ACTION_CYCLE_PANELS:
|
case META_KEYBINDING_ACTION_CYCLE_PANELS:
|
||||||
handler_name = "cycle_group";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_CYCLE_WINDOWS:
|
case META_KEYBINDING_ACTION_CYCLE_WINDOWS:
|
||||||
handler_name = "cycle_windows";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD:
|
case META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD:
|
||||||
handler_name = "cycle_panels_backward";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD:
|
case META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD:
|
||||||
handler_name = "cycle_windows_backward";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_SWITCH_PANELS:
|
case META_KEYBINDING_ACTION_SWITCH_PANELS:
|
||||||
handler_name = "switch_panels";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_SWITCH_WINDOWS:
|
case META_KEYBINDING_ACTION_SWITCH_WINDOWS:
|
||||||
handler_name = "switch_windows";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD:
|
case META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD:
|
||||||
handler_name = "switch_panels_backward";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD:
|
case META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD:
|
||||||
handler_name = "switch_windows_backward";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_CYCLE_GROUP:
|
case META_KEYBINDING_ACTION_CYCLE_GROUP:
|
||||||
handler_name = "cycle_group";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD:
|
case META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD:
|
||||||
handler_name = "cycle_group_backward";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_SWITCH_GROUP:
|
case META_KEYBINDING_ACTION_SWITCH_GROUP:
|
||||||
handler_name = "switch_group";
|
|
||||||
break;
|
|
||||||
case META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD:
|
case META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD:
|
||||||
handler_name = "switch_group_backward";
|
/* These are the tab-popup bindings. If a custom Alt-Tab implementation
|
||||||
break;
|
* is in effect, we expect it to want to handle all of these as a group
|
||||||
default:
|
*
|
||||||
/*
|
* If there are some of them that the custom implementation didn't
|
||||||
* This is the case when the Alt key is released; we preserve
|
* handle, we treat them as "unbound" for the duration - running the
|
||||||
* the grab, as it is up to the custom implementaiton to free it
|
* normal handlers could get us into trouble.
|
||||||
* (a plugin can catch this in their xevent_filter function).
|
|
||||||
*/
|
*/
|
||||||
|
if (binding->handler &&
|
||||||
|
binding->handler->func &&
|
||||||
|
binding->handler->func != binding->handler->default_func)
|
||||||
|
{
|
||||||
|
invoke_handler (display, screen, binding->handler, NULL, event, binding);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/* Some unhandled key press */
|
||||||
* We do not want to actually call the handler, we just want to ensure
|
invoke_handler_by_name (display, screen, "tab_popup_cancel", NULL, event);
|
||||||
* that if a custom handler is installed, we do not release the grab here.
|
|
||||||
* The handler will get called as normal in the process_event() function.
|
|
||||||
*/
|
|
||||||
handler = find_handler (key_handlers, handler_name);
|
|
||||||
|
|
||||||
if (!handler || !handler->func || handler->func == handler->default_func)
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->type == KeyRelease &&
|
if (event->type == KeyRelease &&
|
||||||
@ -3048,6 +3090,27 @@ handle_cycle (MetaDisplay *display,
|
|||||||
backwards, FALSE);
|
backwards, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_tab_popup_select (MetaDisplay *display,
|
||||||
|
MetaScreen *screen,
|
||||||
|
MetaWindow *window,
|
||||||
|
XEvent *event,
|
||||||
|
MetaKeyBinding *binding,
|
||||||
|
gpointer dummy)
|
||||||
|
{
|
||||||
|
/* Stub for custom handlers; no default implementation */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_tab_popup_cancel (MetaDisplay *display,
|
||||||
|
MetaScreen *screen,
|
||||||
|
MetaWindow *window,
|
||||||
|
XEvent *event,
|
||||||
|
MetaKeyBinding *binding,
|
||||||
|
gpointer dummy)
|
||||||
|
{
|
||||||
|
/* Stub for custom handlers; no default implementation */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_toggle_fullscreen (MetaDisplay *display,
|
handle_toggle_fullscreen (MetaDisplay *display,
|
||||||
|
@ -187,6 +187,18 @@ keybind (cycle_panels_backward, handle_cycle, META_TAB_LIST_DOCKS,
|
|||||||
|
|
||||||
/***********************************/
|
/***********************************/
|
||||||
|
|
||||||
|
/* These two are special pseudo-bindings that are provided for allowing
|
||||||
|
* custom handlers, but will never be bound to a key. While a tab
|
||||||
|
* grab is in effect, they are invoked for releasing the primary modifier
|
||||||
|
* or pressing some unbound key, respectively.
|
||||||
|
*/
|
||||||
|
keybind (tab_popup_select, handle_tab_popup_select, 0, 0, NULL,
|
||||||
|
"Select window from tab popup")
|
||||||
|
keybind (tab_popup_cancel, handle_tab_popup_cancel, 0, 0, NULL,
|
||||||
|
"Cancel tab popup")
|
||||||
|
|
||||||
|
/***********************************/
|
||||||
|
|
||||||
keybind (show_desktop, handle_show_desktop, 0, 0, "<Control><Alt>d",
|
keybind (show_desktop, handle_show_desktop, 0, 0, "<Control><Alt>d",
|
||||||
_("Hide all normal windows and set focus to the desktop"))
|
_("Hide all normal windows and set focus to the desktop"))
|
||||||
keybind (panel_main_menu, handle_panel,
|
keybind (panel_main_menu, handle_panel,
|
||||||
|
Loading…
Reference in New Issue
Block a user