diff options
Diffstat (limited to 'src/keybindings.c')
-rw-r--r-- | src/keybindings.c | 425 |
1 files changed, 308 insertions, 117 deletions
diff --git a/src/keybindings.c b/src/keybindings.c index 8c0f9d57..38fa3bec 100644 --- a/src/keybindings.c +++ b/src/keybindings.c @@ -62,9 +62,19 @@ static void handle_workspace_left (MetaDisplay *display, XEvent *event, gpointer data); static void handle_workspace_right (MetaDisplay *display, - MetaWindow *window, - XEvent *event, - gpointer data); + MetaWindow *window, + XEvent *event, + gpointer data); + +static gboolean process_keyboard_move_grab (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + KeySym keysym); + +static gboolean process_tab_grab (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + KeySym keysym); typedef struct _MetaKeyBinding MetaKeyBinding; @@ -281,10 +291,30 @@ meta_window_grab_all_keys (MetaWindow *window) } else { - window->keys_grabbed = FALSE; - window->all_keys_grabbed = TRUE; - window->grab_on_frame = window->frame != NULL; - return TRUE; + /* Also grab the keyboard, so we get key releases and all key + * presses + */ + meta_error_trap_push (window->display); + /* FIXME CurrentTime bogus */ + XGrabKeyboard (window->display->xdisplay, + grabwindow, True, + GrabModeAsync, GrabModeAsync, + CurrentTime); + + result = meta_error_trap_pop (window->display); + if (result != Success) + { + meta_verbose ("XGrabKeyboard() failed for window %s\n", + window->desc); + return FALSE; + } + + meta_verbose ("Grabbed all keys on window %s\n", window->desc); + + window->keys_grabbed = FALSE; + window->all_keys_grabbed = TRUE; + window->grab_on_frame = window->frame != NULL; + return TRUE; } } @@ -302,6 +332,8 @@ meta_window_ungrab_all_keys (MetaWindow *window) XUngrabKey (window->display->xdisplay, AnyKey, AnyModifier, grabwindow); + /* FIXME CurrentTime bogus */ + XUngrabKeyboard (window->display->xdisplay, CurrentTime); meta_error_trap_pop (window->display); window->grab_on_frame = FALSE; @@ -317,29 +349,61 @@ static gboolean is_modifier (MetaDisplay *display, unsigned int keycode) { - int i; - int map_size; - XModifierKeymap *mod_keymap; - gboolean retval = FALSE; - - /* FIXME this is ass-slow, cache the modmap */ - - mod_keymap = XGetModifierMapping (display->xdisplay); - - map_size = 8 * mod_keymap->max_keypermod; - i = 0; - while (i < map_size) { - - if (keycode == mod_keymap->modifiermap[i]) { - retval = TRUE; - break; - } - ++i; - } - - XFreeModifiermap (mod_keymap); - - return retval; + int i; + int map_size; + XModifierKeymap *mod_keymap; + gboolean retval = FALSE; + + /* FIXME this is ass-slow, cache the modmap */ + + mod_keymap = XGetModifierMapping (display->xdisplay); + + map_size = 8 * mod_keymap->max_keypermod; + i = 0; + while (i < map_size) + { + if (keycode == mod_keymap->modifiermap[i]) + { + retval = TRUE; + break; + } + ++i; + } + + XFreeModifiermap (mod_keymap); + + return retval; +} + +#define MOD1_INDEX 3 /* shift, lock, control, mod1 */ +static gboolean +is_mod1_key (MetaDisplay *display, + unsigned int keycode) +{ + int i; + int end; + XModifierKeymap *mod_keymap; + gboolean retval = FALSE; + + /* FIXME this is ass-slow, cache the modmap */ + + mod_keymap = XGetModifierMapping (display->xdisplay); + + end = (MOD1_INDEX + 1) * mod_keymap->max_keypermod; + i = MOD1_INDEX * mod_keymap->max_keypermod; + while (i < end) + { + if (keycode == mod_keymap->modifiermap[i]) + { + retval = TRUE; + break; + } + ++i; + } + + XFreeModifiermap (mod_keymap); + + return retval; } static void @@ -384,57 +448,89 @@ meta_display_process_key_event (MetaDisplay *display, XKeysymToString (keysym), event->xkey.state, window ? window->desc : "(no window)"); - if (window == NULL || !window->all_keys_grabbed) + if (display->grab_op == META_GRAB_OP_NONE && + (window == NULL || !window->all_keys_grabbed)) { /* Do the normal keybindings */ process_event (screen_bindings, display, NULL, event, keysym); if (window) process_event (window_bindings, display, window, event, keysym); + return; } + + if (display->grab_op == META_GRAB_OP_NONE) + return; /* If we get here we have a global grab, because * we're in some special keyboard mode such as window move * mode. */ - if (display->grab_op == META_GRAB_OP_NONE) - return; - - /* don't end grabs on modifier key presses */ - if (is_modifier (display, event->xkey.keycode)) - return; - handled = FALSE; - if (display->grab_op == META_GRAB_OP_KEYBOARD_MOVING && - display->grab_window == window) + if (window == display->grab_window) { - int x, y; - int incr; - gboolean smart_snap; - int edge; - - if (event->type == KeyRelease) - return; /* don't care about releases */ - - if (window == NULL) - meta_bug ("NULL window while doing keyboard grab op\n"); + switch (display->grab_op) + { + case META_GRAB_OP_KEYBOARD_MOVING: + meta_verbose ("Processing event for keyboard move\n"); + handled = process_keyboard_move_grab (display, window, event, keysym); + break; + case META_GRAB_OP_KEYBOARD_TABBING: + meta_verbose ("Processing event for keyboard tabbing\n"); + handled = process_tab_grab (display, window, event, keysym); + break; + default: + break; + } + } + + /* end grab if a key that isn't used gets pressed */ + if (!handled) + { + meta_verbose ("Ending grab op %d on key event sym %s\n", + display->grab_op, XKeysymToString (keysym)); + meta_display_end_grab_op (display, event->xkey.time); + } +} + +static gboolean +process_keyboard_move_grab (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + KeySym keysym) +{ + gboolean handled; + int x, y; + int incr; + gboolean smart_snap; + int edge; + + handled = FALSE; - meta_window_get_position (window, &x, &y); + /* don't care about releases, but eat them, don't end grab */ + if (event->type == KeyRelease) + return TRUE; - smart_snap = (event->xkey.state & ShiftMask) != 0; + /* don't end grab on modifier key presses */ + if (is_modifier (display, event->xkey.keycode)) + return TRUE; + + meta_window_get_position (window, &x, &y); + + smart_snap = (event->xkey.state & ShiftMask) != 0; #define SMALL_INCREMENT 1 #define NORMAL_INCREMENT 10 - if (smart_snap) - incr = 0; - else if (event->xkey.state & ControlMask) - incr = SMALL_INCREMENT; - else - incr = NORMAL_INCREMENT; + if (smart_snap) + incr = 0; + else if (event->xkey.state & ControlMask) + incr = SMALL_INCREMENT; + else + incr = NORMAL_INCREMENT; /* When moving by increments, we still snap to edges if the move * to the edge is smaller than the increment. This is because @@ -442,71 +538,138 @@ meta_display_process_key_event (MetaDisplay *display, * people using just arrows shouldn't get too frustrated. */ - switch (keysym) - { - case XK_Up: - case XK_KP_Up: - edge = meta_window_find_next_horizontal_edge (window, FALSE); - y -= incr; + switch (keysym) + { + case XK_Up: + case XK_KP_Up: + edge = meta_window_find_next_horizontal_edge (window, FALSE); + y -= incr; - if (smart_snap || ((edge > y) && ABS (edge - y) < incr)) - y = edge; + if (smart_snap || ((edge > y) && ABS (edge - y) < incr)) + y = edge; - handled = TRUE; - break; - case XK_Down: - case XK_KP_Down: - edge = meta_window_find_next_horizontal_edge (window, TRUE); - y += incr; - - if (smart_snap || ((edge < y) && ABS (edge - y) < incr)) - y = edge; + handled = TRUE; + break; + case XK_Down: + case XK_KP_Down: + edge = meta_window_find_next_horizontal_edge (window, TRUE); + y += incr; + + if (smart_snap || ((edge < y) && ABS (edge - y) < incr)) + y = edge; - handled = TRUE; - break; - case XK_Left: - case XK_KP_Left: - edge = meta_window_find_next_vertical_edge (window, FALSE); - x -= incr; + handled = TRUE; + break; + case XK_Left: + case XK_KP_Left: + edge = meta_window_find_next_vertical_edge (window, FALSE); + x -= incr; - if (smart_snap || ((edge > x) && ABS (edge - x) < incr)) - x = edge; + if (smart_snap || ((edge > x) && ABS (edge - x) < incr)) + x = edge; + + handled = TRUE; + break; + case XK_Right: + case XK_KP_Right: + edge = meta_window_find_next_vertical_edge (window, TRUE); + x += incr; + if (smart_snap || ((edge < x) && ABS (edge - x) < incr)) + x = edge; + handled = TRUE; + break; + + case XK_Escape: + /* End move and restore to original position */ + meta_window_move_resize (display->grab_window, + display->grab_initial_window_pos.x, + display->grab_initial_window_pos.y, + display->grab_initial_window_pos.width, + display->grab_initial_window_pos.height); + break; + + default: + break; + } - handled = TRUE; - break; - case XK_Right: - case XK_KP_Right: - edge = meta_window_find_next_vertical_edge (window, TRUE); - x += incr; - if (smart_snap || ((edge < x) && ABS (edge - x) < incr)) - x = edge; - handled = TRUE; - break; + if (handled) + meta_window_move (window, x, y); - case XK_Escape: - /* End move and restore to original position */ - meta_window_move_resize (display->grab_window, - display->grab_initial_window_pos.x, - display->grab_initial_window_pos.y, - display->grab_initial_window_pos.width, - display->grab_initial_window_pos.height); - break; - - default: - break; - } + return handled; +} + +static gboolean +process_tab_grab (MetaDisplay *display, + MetaWindow *window, + XEvent *event, + KeySym keysym) +{ + MetaScreen *screen; - if (handled) - meta_window_move (window, x, y); - } + window = NULL; /* be sure we don't use this, it's irrelevant */ + + screen = display->grab_window->screen; + + g_return_val_if_fail (screen->tab_popup != NULL, FALSE); - /* end grab if a key that isn't used gets pressed */ - if (!handled) + if (event->type == KeyRelease && + is_mod1_key (display, event->xkey.keycode)) { - meta_verbose ("Ending grab op %d on key press event sym %s\n", - display->grab_op, XKeysymToString (keysym)); - meta_display_end_grab_op (display, event->xkey.time); + /* We're done, move to the new window. */ + Window target_xwindow; + MetaWindow *target_window; + + target_xwindow = + meta_ui_tab_popup_get_selected (screen->tab_popup); + target_window = + meta_display_lookup_x_window (display, target_xwindow); + + meta_verbose ("Ending tab operation, Mod1 released\n"); + + if (target_window) + { + meta_verbose ("Ending grab early so we can focus the target window\n"); + meta_display_end_grab_op (display, event->xkey.time); + + meta_verbose ("Focusing target window\n"); + meta_window_raise (target_window); + meta_window_focus (target_window, event->xkey.time); + + return TRUE; /* we already ended the grab */ + } + + return FALSE; /* end grab */ + } + + /* don't care about other releases, but eat them, don't end grab */ + if (event->type == KeyRelease) + return TRUE; + + /* don't end grab on modifier key presses */ + if (is_modifier (display, event->xkey.keycode)) + return TRUE; + + switch (keysym) + { + case XK_ISO_Left_Tab: + case XK_Tab: + if (event->xkey.state & ShiftMask) + meta_ui_tab_popup_backward (screen->tab_popup); + else + meta_ui_tab_popup_forward (screen->tab_popup); + + /* continue grab */ + meta_verbose ("Tab key pressed, moving tab focus in popup\n"); + return TRUE; + break; + + default: + break; } + + /* end grab */ + meta_verbose ("Ending tabbing, uninteresting key pressed\n"); + return FALSE; } static void @@ -694,8 +857,22 @@ handle_tab_forward (MetaDisplay *display, if (window) { - meta_window_raise (window); - meta_window_focus (window, event->xkey.time); + meta_verbose ("Starting tab forward, showing popup\n"); + + meta_display_begin_grab_op (window->display, + display->focus_window ? + display->focus_window : window, + META_GRAB_OP_KEYBOARD_TABBING, + FALSE, + 0, 0, + event->xkey.time, + 0, 0); + + meta_ui_tab_popup_select (window->screen->tab_popup, + window->xwindow); + /* only after selecting proper window */ + meta_ui_tab_popup_set_showing (window->screen->tab_popup, + TRUE); } } @@ -738,8 +915,22 @@ handle_tab_backward (MetaDisplay *display, if (window) { - meta_window_raise (window); - meta_window_focus (window, event->xkey.time); + meta_verbose ("Starting tab backward, showing popup\n"); + + meta_display_begin_grab_op (window->display, + display->focus_window ? + display->focus_window : window, + META_GRAB_OP_KEYBOARD_TABBING, + FALSE, + 0, 0, + event->xkey.time, + 0, 0); + + meta_ui_tab_popup_select (window->screen->tab_popup, + window->xwindow); + /* only after selecting proper window */ + meta_ui_tab_popup_set_showing (window->screen->tab_popup, + TRUE); } } |