add Alt+ backtick to cycle a tab's stacked windows backward
This commit is contained in:
parent
1ef4e4423c
commit
753b37ee7e
2 changed files with 83 additions and 2 deletions
|
|
@ -196,6 +196,7 @@ model.
|
|||
| `Alt+Shift+Down` | Move the active tab later in the list |
|
||||
| `Alt+Delete` | Close the active tab (SIGTERM, SIGKILL fallback) |
|
||||
| `Alt+Shift+T` | Open a new terminal tab next to the current one |
|
||||
| `` Alt+` `` | Cycle the active tab's stacked windows (hold to keep cycling) |
|
||||
|
||||
The tab-management prefix is `Alt` by default. Pass `--modifier super` to
|
||||
use `Super` (Windows/Meta key, Mod4) instead: `Super` hold shows the
|
||||
|
|
|
|||
84
kick.c
84
kick.c
|
|
@ -458,8 +458,9 @@ struct kick_host {
|
|||
uint32_t repeat_key;
|
||||
int repeat_dir;
|
||||
/* What each repeat tick should do: REPEAT_CYCLE switches tabs,
|
||||
REPEAT_REORDER moves the active tab within the list. */
|
||||
enum { REPEAT_CYCLE, REPEAT_REORDER } repeat_kind;
|
||||
REPEAT_REORDER moves the active tab within the list, REPEAT_SUBCYCLE
|
||||
rotates the active tab's stacked windows. */
|
||||
enum { REPEAT_CYCLE, REPEAT_REORDER, REPEAT_SUBCYCLE } repeat_kind;
|
||||
};
|
||||
|
||||
static struct kick_server server;
|
||||
|
|
@ -2905,6 +2906,60 @@ static void sub_refocus_owner(struct kick_app *app) {
|
|||
kick_request_redraw();
|
||||
}
|
||||
|
||||
/* Rotate the active tab's window stack one step in `dir` (-1 = backward):
|
||||
the rotation visits every mapped stacked sub-window in creation order,
|
||||
then the main surface, then wraps. Backward from a window means the
|
||||
one stacked just before it; backward from the oldest is the main
|
||||
surface; backward from the main surface wraps to the newest. The list
|
||||
order itself is never mutated -- focus_sub alone tracks where the
|
||||
rotation sits, so repeated steps walk the windows deterministically.
|
||||
Returns false when the tab has no mapped sub-windows (nothing to
|
||||
rotate), leaving the key free to pass through to the client. */
|
||||
static bool cycle_stack(struct kick_app *app, int dir) {
|
||||
struct kick_sub_window *subs[16];
|
||||
struct kick_sub_window *sub;
|
||||
int n = 0;
|
||||
wl_list_for_each(sub, &app->sub_windows, link)
|
||||
if (sub->mapped && n < 16) subs[n++] = sub;
|
||||
|
||||
if (n == 0)
|
||||
return false;
|
||||
|
||||
/* Position of the shown window in the rotation [w0..w_{n-1}, MAIN]:
|
||||
-1 when the main surface is showing (or nothing is yet). */
|
||||
int cur = -1;
|
||||
for (int i = 0; i < n; i++)
|
||||
if (subs[i] == app->focus_sub) { cur = i; break; }
|
||||
|
||||
int next = (cur + dir) % (n + 1);
|
||||
if (next < 0) next += n + 1;
|
||||
|
||||
if (next == n) {
|
||||
/* MAIN's turn: drop keyboard focus from the stacked sub;
|
||||
show_current() below reveals the main surface and hides every
|
||||
sub, making it drawn and reachable again. */
|
||||
if (app->focus_sub) {
|
||||
sub_set_activated(app->focus_sub, false);
|
||||
app->focus_sub = NULL;
|
||||
}
|
||||
if (app_has_window(app)) {
|
||||
app_set_activated(app, true);
|
||||
struct wlr_keyboard *kbd = wlr_seat_get_keyboard(server.seat);
|
||||
if (!kbd) kbd = &server.keyboard;
|
||||
wlr_seat_keyboard_notify_enter(server.seat,
|
||||
app_surface(app),
|
||||
kbd->keycodes, kbd->num_keycodes, &kbd->modifiers);
|
||||
}
|
||||
} else {
|
||||
sub_enter(subs[next]);
|
||||
}
|
||||
|
||||
show_current(app);
|
||||
kick_log(KICK_LOG_INFO, "[sub] cycle app=%d\n", app_index(app));
|
||||
kick_request_redraw();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void handle_sub_commit(struct wl_listener *listener, void *data) {
|
||||
(void)data;
|
||||
struct kick_sub_window *sub = wl_container_of(listener, sub, commit);
|
||||
|
|
@ -4158,6 +4213,8 @@ static int kbd_repeat_cb(void *data) {
|
|||
return 0;
|
||||
if (host.repeat_kind == REPEAT_REORDER)
|
||||
reorder_active_tab(host.repeat_dir);
|
||||
else if (host.repeat_kind == REPEAT_SUBCYCLE)
|
||||
cycle_stack(server.active_app, host.repeat_dir);
|
||||
else
|
||||
cycle_tab(host.repeat_dir);
|
||||
if (host.repeat_timer)
|
||||
|
|
@ -5999,6 +6056,27 @@ static bool process_key_event(uint32_t time, uint32_t key, uint32_t state,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
/* Alt+` rotates the active tab's stacked windows backward: from the
|
||||
shown window to the one added just before it, wrapping from the
|
||||
oldest through the main surface back to the newest. Consumed only
|
||||
when the tab actually has stacked windows, so a client that binds
|
||||
Alt+` itself still sees the key elsewhere. */
|
||||
{ bool is_grave = server.xkb_state
|
||||
? (sym == XKB_KEY_grave)
|
||||
: key == 41;
|
||||
if (alt && is_grave && server.active_app &&
|
||||
!wl_list_empty(&server.active_app->sub_windows)) {
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
if (host.repeat_key != key) {
|
||||
cycle_stack(server.active_app, -1);
|
||||
kbd_repeat_start(key, -1, REPEAT_SUBCYCLE);
|
||||
}
|
||||
} else {
|
||||
kbd_repeat_cancel();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* prefix+Delete closes the active tab. Grabbed so the focused client never
|
||||
sees the key; a latch drops host-synthesized repeats so one hold can't
|
||||
close a tab per repeat. The active surface already moved to the right
|
||||
|
|
@ -7561,6 +7639,8 @@ int main(int argc, char *argv[]) {
|
|||
" Delete Close the active tab.\n"
|
||||
" Shift+T Open a new terminal tab "
|
||||
"($TERMINAL).\n"
|
||||
" ` (grave) Cycle the tab's stacked "
|
||||
"windows; hold to keep cycling.\n"
|
||||
" Ctrl+Alt+F1..F12 Switch virtual terminals "
|
||||
"(standalone only).\n",
|
||||
argv[0], argv[0]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue