Skip to content

Commit d45af02

Browse files
committed
merge ov_tab_mode to switcher
1 parent faf256d commit d45af02

9 files changed

Lines changed: 53 additions & 140 deletions

File tree

docs/bindings/keys.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,8 @@ bindr=Super,Super_L,spawn,rofi -show run
117117
| `focusdir` | `left/right/up/down` | Focus window in direction. |
118118
| `focus_window_or_workspace` | `left/right/up/down` | Focus window in direction; otherwise jump to the nearest adjacent tag that has clients, falling back to the next/previous tag if none. |
119119
| `focusstack` | `next/prev` | Cycle focus within the stack. |
120-
| `overcicle` | - | Open overview when closed; while it is open, each trigger cycles focus to the next window on the current monitor. |
121120
| `focuslast` | - | Focus the previously active window. |
122-
| `switcher` | `next/prev` | Open or cycle the all-tag, all-monitor thumbnail switcher. Releasing any modifier key selects. |
121+
| `switcher` | `next/prev`, `all_tag_next/all_tag_prev`, `all_next/all_prev` | Open or cycle the thumbnail switcher. `next`/`prev` list the current tag's windows, `all_tag_next`/`all_tag_prev` list all tags on the current monitor, `all_next`/`all_prev` list all monitors and tags. Releasing any modifier key selects. |
123122
| `exchange_client` | `left/right/up/down` | Swap window with neighbor in direction. |
124123
| `exchange_stack_client` | `next/prev` | Exchange window position in stack. |
125124
| `zoom` | - | Swap focused window with Master. |

docs/window-management/overview.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ description: Configure the overview mode for window navigation.
2121
- `hotarea_corner` — Corner that triggers the hot area (0: top-left, 1: top-right, 2: bottom-left, 3: bottom-right).
2222
- `jump_labels` — Defines the ordered characters used for jump hints when in overview jump mode. Each visible window is assigned a label in this order, and pressing the corresponding key jumps to that window. The number of labels limits how many windows can be assigned hints at once.
2323

24-
[`overcicle`](/docs/bindings/keys#focus--movement) opens overview; while
25-
overview is open, each trigger cycles focus to the next window on the current
26-
monitor. Release a modifier key or run `toggleoverview` to close it.
24+
To cycle through windows, use the
25+
[`switcher`](/docs/bindings/keys#focus--movement) command; release a modifier
26+
key to select.
2727

2828
### Mouse Interaction in Overview
2929

src/config/parse_config.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,8 +1214,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
12141214
if (strcmp(func_name, "focusstack") == 0) {
12151215
func = focusstack;
12161216
(*arg).i = parse_circle_direction(arg_value);
1217-
} else if (strcmp(func_name, "overcicle") == 0) {
1218-
func = overcicle;
12191217
} else if (strcmp(func_name, "groupfocus") == 0) {
12201218
func = groupfocus;
12211219
(*arg).i = parse_circle_direction(arg_value);
@@ -1299,7 +1297,25 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
12991297
func = focuslast;
13001298
} else if (strcmp(func_name, "switcher") == 0) {
13011299
func = switcher;
1302-
(*arg).i = parse_circle_direction(arg_value);
1300+
if (strcmp(arg_value, "all_next") == 0) {
1301+
(*arg).i = NEXT;
1302+
(*arg).i2 = SW_ALL_MON;
1303+
} else if (strcmp(arg_value, "all_prev") == 0) {
1304+
(*arg).i = PREV;
1305+
(*arg).i2 = SW_ALL_MON;
1306+
} else if (strcmp(arg_value, "all_tag_next") == 0) {
1307+
(*arg).i = NEXT;
1308+
(*arg).i2 = SW_ALL_TAG;
1309+
} else if (strcmp(arg_value, "all_tag_prev") == 0) {
1310+
(*arg).i = PREV;
1311+
(*arg).i2 = SW_ALL_TAG;
1312+
} else if (strcmp(arg_value, "prev") == 0) {
1313+
(*arg).i = PREV;
1314+
(*arg).i2 = SW_CURRENT_TAG;
1315+
} else {
1316+
(*arg).i = NEXT;
1317+
(*arg).i2 = SW_CURRENT_TAG;
1318+
}
13031319
} else if (strcmp(func_name, "toggle_trackpad_enable") == 0) {
13041320
func = toggle_trackpad_enable;
13051321
} else if (strcmp(func_name, "setoption") == 0) {

src/dispatch/bind_declare.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ void toggleglobal(const Arg *arg);
4444
void incnmaster(const Arg *arg);
4545
void focusmon(const Arg *arg);
4646
void focusstack(const Arg *arg);
47-
void overcicle(const Arg *arg);
4847
void groupfocus(const Arg *arg);
4948
void chvt(const Arg *arg);
5049
void reload_config(const Arg *arg);

src/dispatch/bind_define.h

Lines changed: 2 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -384,115 +384,6 @@ void focusstack(const Arg *arg) {
384384
return;
385385
}
386386

387-
static bool overcicle_candidate(Client *c, Monitor *m) {
388-
return c && c->mon == m && !c->isunglobal && !c->iskilling &&
389-
!c->isminimized && !client_is_unmanaged(c) &&
390-
!client_is_x11_popup(c) && client_surface(c) &&
391-
client_surface(c)->mapped && VISIBLEON(c, m);
392-
}
393-
394-
static void overcicle_clear(Monitor *m) {
395-
if (!m)
396-
return;
397-
free(m->overcicle_clients);
398-
m->overcicle_clients = NULL;
399-
m->overcicle_count = 0;
400-
m->overcicle_index = 0;
401-
}
402-
403-
/* 打开 overview 时按 fstack/flink 顺序建立循环快照:
404-
* 当前焦点在第 0 位,上一次切换的焦点在第 1 位;
405-
* 首次触发即切到第 1 位,之后单向遍历全部窗口 */
406-
static void overcicle_build(Monitor *m) {
407-
overcicle_clear(m);
408-
if (!m)
409-
return;
410-
411-
Client *c;
412-
int n = 0;
413-
wl_list_for_each(c, &fstack, flink) {
414-
if (overcicle_candidate(c, m))
415-
n++;
416-
}
417-
if (n <= 0)
418-
return;
419-
420-
m->overcicle_clients = ecalloc(n, sizeof(Client *));
421-
n = 0;
422-
wl_list_for_each(c, &fstack, flink) {
423-
if (overcicle_candidate(c, m))
424-
m->overcicle_clients[n++] = c;
425-
}
426-
m->overcicle_count = n;
427-
m->overcicle_index = 0;
428-
}
429-
430-
/* 窗口销毁时从快照中移除,避免悬挂指针 */
431-
static void overcicle_remove_client(Client *c) {
432-
if (!c || !c->mon || !c->mon->overcicle_clients ||
433-
c->mon->overcicle_count <= 0)
434-
return;
435-
436-
Monitor *m = c->mon;
437-
int i;
438-
for (i = 0; i < m->overcicle_count; i++) {
439-
if (m->overcicle_clients[i] == c)
440-
break;
441-
}
442-
if (i == m->overcicle_count)
443-
return;
444-
445-
if (m->overcicle_index > i)
446-
m->overcicle_index--;
447-
memmove(&m->overcicle_clients[i], &m->overcicle_clients[i + 1],
448-
(m->overcicle_count - i - 1) * sizeof(Client *));
449-
m->overcicle_count--;
450-
if (m->overcicle_count <= 0) {
451-
overcicle_clear(m);
452-
return;
453-
}
454-
if (m->overcicle_index >= m->overcicle_count)
455-
m->overcicle_index = m->overcicle_count - 1;
456-
}
457-
458-
/* overcicle: 打开/循环 overview(居中 tab 布局)
459-
* - 未进入 overview:进入 overview,并按 flink 建立循环快照
460-
* - 已在 overview 中:每次触发单向向前遍历快照(首次切到上一次切换的焦点) */
461-
void overcicle(const Arg *arg) {
462-
if (!selmon || grabc)
463-
return;
464-
465-
Client *sel = arg->tc ? arg->tc : selmon->sel;
466-
467-
if (selmon->isoverview && !selmon->is_jump_mode &&
468-
!selmon->ov_normal_mode && sel) {
469-
/* 快照缺失时(如由 toggleoverview 等进入)先按 flink 建立 */
470-
if (selmon->overcicle_count <= 0)
471-
overcicle_build(selmon);
472-
if (selmon->overcicle_count <= 0)
473-
return;
474-
475-
selmon->overcicle_index =
476-
(selmon->overcicle_index + 1 + selmon->overcicle_count) %
477-
selmon->overcicle_count;
478-
479-
Client *tc = selmon->overcicle_clients[selmon->overcicle_index];
480-
focusclient(tc, 1);
481-
if (config.warpcursor)
482-
warp_cursor(tc);
483-
484-
/* 切换焦点后重排,让 tab 布局跟随焦点 */
485-
arrange(selmon, true, false);
486-
return;
487-
}
488-
489-
/* 未进入 overview:打开(tab 布局),并按 flink 建立循环快照 */
490-
toggleoverview(arg);
491-
492-
if (selmon && selmon->isoverview)
493-
overcicle_build(selmon);
494-
}
495-
496387
void groupfocus(const Arg *arg) {
497388
Client *c = arg->tc ? arg->tc : selmon->sel;
498389
if (!c || !c->mon)
@@ -2035,10 +1926,8 @@ void toggleoverview(const Arg *arg) {
20351926
uint32_t target;
20361927
uint32_t visible_client_number = 0;
20371928

2038-
if (!selmon->isoverview) {
2039-
overcicle_clear(selmon);
2040-
if (selmon->is_jump_mode)
2041-
finish_jump_mode(selmon);
1929+
if (!selmon->isoverview && selmon->is_jump_mode) {
1930+
finish_jump_mode(selmon);
20421931
}
20431932

20441933
if (selmon->isoverview) {

src/manage/client.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,7 +2028,6 @@ void unmapnotify(struct wl_listener *listener, void *data) {
20282028
Client *nextfocus = NULL;
20292029
c->iskilling = 1;
20302030
switcher_remove_client(c);
2031-
overcicle_remove_client(c);
20322031
struct ScrollerStackNode *target_node =
20332032
c->mon ? find_scroller_node(
20342033
c->mon->pertag->scroller_state[c->mon->pertag->curtag], c)
@@ -2210,7 +2209,6 @@ destroynotify(struct wl_listener *listener, void *data) {
22102209
wl_list_remove(&c->set_decoration_mode.link);
22112210
}
22122211
switcher_remove_client(c);
2213-
overcicle_remove_client(c);
22142212
free(c);
22152213
}
22162214

src/manage/monitor.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,6 @@ void createmon(struct wl_listener *listener, void *data) {
480480
m->sel = NULL;
481481
m->is_in_hotarea = 0;
482482
m->ov_normal_mode = 0;
483-
m->overcicle_clients = NULL;
484-
m->overcicle_count = 0;
485-
m->overcicle_index = 0;
486483
m->m.x = INT32_MAX;
487484
m->m.y = INT32_MAX;
488485

@@ -669,8 +666,6 @@ void cleanupmon(struct wl_listener *listener, void *data) {
669666

670667
m->iscleanuping = true;
671668

672-
overcicle_clear(m);
673-
674669
/* m->layers[i] are intentionally not unlinked */
675670
for (i = 0; i < LENGTH(m->layers); i++) {
676671
wl_list_for_each_safe(l, tmp, &m->layers[i], link)

src/mango.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */
222222
enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT, OVERVIEW };
223223
enum { UNFOLD, FOLD, INVALIDFOLD };
224224
enum { PREV, NEXT };
225+
enum { SW_CURRENT_TAG, SW_ALL_TAG, SW_ALL_MON }; /* switcher 候选范围 */
225226
enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED };
226227
enum { FORCE, UNFORCE };
227228

@@ -616,10 +617,7 @@ struct Monitor {
616617
int32_t isoverview;
617618
int32_t is_jump_mode;
618619
int32_t is_in_hotarea;
619-
int32_t ov_normal_mode; /* 热区进入时使用普通网格布局 */
620-
Client **overcicle_clients; /* overcicle 快照:打开时按 flink 排序 */
621-
int overcicle_count;
622-
int overcicle_index;
620+
int32_t ov_normal_mode; /* 热区进入时使用普通网格布局 */
623621
int32_t only_sleep;
624622
uint32_t visible_clients;
625623
uint32_t visible_tiling_clients;

src/switcher/switcher.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static struct {
3939
int count;
4040
int index;
4141
int tile_h;
42+
int scope;
4243
} sw;
4344

4445
static bool switcher_is_active(void) { return sw.tree != NULL; }
@@ -48,6 +49,11 @@ static bool switcher_candidate(Client *c) {
4849
c->is_logic_hide || !client_surface(c) || !client_surface(c)->mapped ||
4950
client_is_unmanaged(c) || client_is_x11_popup(c))
5051
return false;
52+
53+
if (sw.scope == SW_CURRENT_TAG)
54+
return c->mon == sw.mon && VISIBLEON(c, sw.mon);
55+
if (sw.scope == SW_ALL_TAG)
56+
return c->mon == sw.mon;
5157
return (int32_t)c->tags > 0;
5258
}
5359

@@ -381,7 +387,10 @@ static void switcher_remove_client(Client *c) {
381387

382388
static void switcher_commit_client(Client *tc) {
383389
switcher_close();
384-
if (!switcher_candidate(tc))
390+
if (!tc || !tc->mon || tc->iskilling || tc->isminimized || tc->isunglobal ||
391+
tc->is_logic_hide || !client_surface(tc) ||
392+
!client_surface(tc)->mapped || client_is_unmanaged(tc) ||
393+
client_is_x11_popup(tc))
385394
return;
386395
if (!VISIBLEON(tc, tc->mon))
387396
view_in_mon(&(Arg){.ui = get_tags_first_tag(tc->tags)}, true, tc->mon,
@@ -412,7 +421,7 @@ static Client *switcher_client_at(double lx, double ly) {
412421
return NULL;
413422
}
414423

415-
static void switcher_open(void) {
424+
static void switcher_open(int scope) {
416425
Client *c;
417426
Monitor *m;
418427
int n = 0;
@@ -421,14 +430,17 @@ static void switcher_open(void) {
421430
if (m->isoverview)
422431
return;
423432
}
433+
434+
sw.mon = selmon;
435+
sw.scope = scope;
436+
424437
wl_list_for_each(c, &fstack, flink) {
425438
if (switcher_candidate(c))
426439
n++;
427440
}
428441
if (n == 0)
429442
return;
430443

431-
sw.mon = selmon;
432444
int max_row_w = (int)(sw.mon->m.width * SW_PANEL_FRAC) - 2 * SW_MARGIN;
433445
int max_panel_h = (int)(sw.mon->m.height * SW_PANEL_FRAC);
434446
// size against the widest allowed tile so the panel always fits
@@ -477,10 +489,17 @@ static void switcher_cycle(int dir) {
477489

478490
void switcher(const Arg *arg) {
479491
int dir = arg && arg->i == PREV ? -1 : 1;
492+
int scope = arg ? arg->i2 : SW_CURRENT_TAG;
480493
if (locked || !selmon || selmon->is_jump_mode)
481494
return;
482-
if (switcher_is_active())
483-
switcher_cycle(dir);
484-
else
485-
switcher_open();
495+
if (switcher_is_active()) {
496+
if (scope != sw.scope) {
497+
switcher_close();
498+
switcher_open(scope);
499+
} else {
500+
switcher_cycle(dir);
501+
}
502+
} else {
503+
switcher_open(scope);
504+
}
486505
}

0 commit comments

Comments
 (0)