diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index 50f6ad33..e2edf387 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -99,11 +99,14 @@ Actions are used in menus and keyboard/mouse bindings. Resize and move active window according to the given region. See labwc-config(5) for further information on how to define regions. -** - Cycle focus to next window. - +**++ ** - Cycle focus to previous window. + Cycle focus to next/previous window respectively.++ + Default keybind for NextWindow is Alt-Tab. + + The shift key is used to reverse direction while cycling. + + The arrow keys are used to move forwards/backwards while cycling. ** Re-load configuration and theme files. diff --git a/include/labwc.h b/include/labwc.h index e3f1ad23..a19f8243 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -210,6 +210,12 @@ struct seat { struct lab_data_buffer; struct workspace; +enum lab_cycle_dir { + LAB_CYCLE_DIR_NONE, + LAB_CYCLE_DIR_FORWARD, + LAB_CYCLE_DIR_BACKWARD, +}; + struct server { struct wl_display *wl_display; struct wl_event_loop *wl_event_loop; /* Can be used for timer events */ @@ -349,6 +355,8 @@ struct server { struct wlr_scene_tree *preview_parent; struct wlr_scene_node *preview_anchor; struct multi_rect *preview_outline; + enum lab_cycle_dir initial_direction; + bool initial_keybind_contained_shift; } osd_state; struct theme *theme; @@ -442,12 +450,6 @@ struct view *desktop_topmost_focusable_view(struct server *server); */ void desktop_update_top_layer_visiblity(struct server *server); -enum lab_cycle_dir { - LAB_CYCLE_DIR_NONE, - LAB_CYCLE_DIR_FORWARD, - LAB_CYCLE_DIR_BACKWARD, -}; - /** * desktop_cycle_view - return view to 'cycle' to * @start_view: reference point for finding next view to cycle to diff --git a/src/action.c b/src/action.c index 80231b95..0aa45d7a 100644 --- a/src/action.c +++ b/src/action.c @@ -701,6 +701,26 @@ run_if_action(struct view *view, struct server *server, struct action *action) return !strcmp(branch, "then"); } +static bool +shift_is_pressed(struct server *server) +{ + uint32_t modifiers = wlr_keyboard_get_modifiers( + &server->seat.keyboard_group->keyboard); + return modifiers & WLR_MODIFIER_SHIFT; +} + +static void +start_window_cycling(struct server *server, enum lab_cycle_dir direction) +{ + /* Remember direction so it can be followed by subsequent key presses */ + server->osd_state.initial_direction = direction; + server->osd_state.initial_keybind_contained_shift = + shift_is_pressed(server); + server->osd_state.cycle_view = desktop_cycle_view(server, + server->osd_state.cycle_view, direction); + osd_update(server); +} + void actions_run(struct view *activator, struct server *server, struct wl_list *actions, uint32_t resize_edges) @@ -791,14 +811,10 @@ actions_run(struct view *activator, struct server *server, } break; case ACTION_TYPE_NEXT_WINDOW: - server->osd_state.cycle_view = desktop_cycle_view(server, - server->osd_state.cycle_view, LAB_CYCLE_DIR_FORWARD); - osd_update(server); + start_window_cycling(server, LAB_CYCLE_DIR_FORWARD); break; case ACTION_TYPE_PREVIOUS_WINDOW: - server->osd_state.cycle_view = desktop_cycle_view(server, - server->osd_state.cycle_view, LAB_CYCLE_DIR_BACKWARD); - osd_update(server); + start_window_cycling(server, LAB_CYCLE_DIR_BACKWARD); break; case ACTION_TYPE_RECONFIGURE: kill(getpid(), SIGHUP); diff --git a/src/input/keyboard.c b/src/input/keyboard.c index 147ec4dc..5806441a 100644 --- a/src/input/keyboard.c +++ b/src/input/keyboard.c @@ -383,6 +383,16 @@ handle_menu_keys(struct server *server, struct keysyms *syms) } } +static void +toggle_direction(enum lab_cycle_dir *direction) +{ + if (*direction == LAB_CYCLE_DIR_FORWARD) { + *direction = LAB_CYCLE_DIR_BACKWARD; + } else if (*direction == LAB_CYCLE_DIR_BACKWARD) { + *direction = LAB_CYCLE_DIR_FORWARD; + } +} + static void handle_cycle_view_key(struct server *server, struct keyinfo *keyinfo) { @@ -397,21 +407,36 @@ handle_cycle_view_key(struct server *server, struct keyinfo *keyinfo) /* cycle to next */ if (!keyinfo->is_modifier) { - bool back_key = false; + enum lab_cycle_dir direction = server->osd_state.initial_direction; for (int i = 0; i < keyinfo->translated.nr_syms; i++) { if (keyinfo->translated.syms[i] == XKB_KEY_Up || keyinfo->translated.syms[i] == XKB_KEY_Left) { - back_key = true; - break; + direction = LAB_CYCLE_DIR_BACKWARD; + goto miss_shift_toggle; + } + if (keyinfo->translated.syms[i] == XKB_KEY_Down + || keyinfo->translated.syms[i] == XKB_KEY_Right) { + direction = LAB_CYCLE_DIR_FORWARD; + goto miss_shift_toggle; } } - bool backwards = (keyinfo->modifiers & WLR_MODIFIER_SHIFT) || back_key; - enum lab_cycle_dir dir = backwards - ? LAB_CYCLE_DIR_BACKWARD - : LAB_CYCLE_DIR_FORWARD; + bool shift_is_pressed = keyinfo->modifiers & WLR_MODIFIER_SHIFT; + if (shift_is_pressed != server->osd_state.initial_keybind_contained_shift) { + /* + * Shift reverses the direction - unless shift was part of the + * original keybind in which case we do the opposite. + * For example with S-A-Tab bound to PreviousWindow, shift with + * subsequent key presses should carry on cycling backwards. + */ + toggle_direction(&direction); + } + + /* Only one direction modifier is allowed, either arrow keys OR shift */ +miss_shift_toggle: + server->osd_state.cycle_view = desktop_cycle_view(server, - server->osd_state.cycle_view, dir); + server->osd_state.cycle_view, direction); osd_update(server); } }