From 9367499e4917c7fca9ec41169a9a7b8a493afe87 Mon Sep 17 00:00:00 2001 From: xtheeq Date: Thu, 7 May 2026 00:27:01 +0530 Subject: [PATCH 1/3] feat: add consume & expel for scroller stack --- src/config/parse_config.h | 4 ++++ src/dispatch/bind_define.h | 35 +++++++++++++++++++++++++++++++++++ src/mango.c | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index f70a17d6..853dda1c 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -537,6 +537,10 @@ int32_t parse_direction(const char *str) { return LEFT; } else if (strcmp(lowerStr, "right") == 0) { return RIGHT; + } else if (strcmp(lowerStr, "consume") == 0) { + return CONSUME; + } else if (strcmp(lowerStr, "expel") == 0) { + return EXPEL; } else { return UNDIR; } diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index f8822af3..19b89aa6 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1855,6 +1855,41 @@ int32_t scroller_stack(const Arg *arg) { if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) return 0; + if (arg->i == CONSUME) { + bool is_horizontal_layout = + c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER; + int32_t consume_dir = is_horizontal_layout ? RIGHT : DOWN; + + Client *target_client = find_client_by_direction(c, &(Arg){.i = consume_dir}, false, true); + + if (target_client) { + Client *stack_tail = get_scroll_stack_head(c); + while (stack_tail->next_in_stack) { + stack_tail = stack_tail->next_in_stack; + } + + scroller_insert_stack(target_client, stack_tail, false); + } + return 0; + } + + if (arg->i == EXPEL) { + Client *stack_head = get_scroll_stack_head(c); + Client *stack_tail = stack_head; + + while (stack_tail->next_in_stack) { + stack_tail = stack_tail->next_in_stack; + } + + if (stack_tail != stack_head) { + exit_scroller_stack(stack_tail); + wl_list_remove(&stack_tail->link); + wl_list_insert(&stack_head->link, &stack_tail->link); + arrange(selmon, false, false); + } + return 0; + } + Client *target_client = find_client_by_direction(c, arg, false, true); return scroller_apply_stack(c, target_client, arg->i); diff --git a/src/mango.c b/src/mango.c index b4bc67bf..e15fbb29 100644 --- a/src/mango.c +++ b/src/mango.c @@ -172,7 +172,7 @@ enum { NetLast }; /* EWMH atoms */ #endif -enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */ +enum { UP, DOWN, LEFT, RIGHT, UNDIR, CONSUME, EXPEL }; /* smartmovewin */ enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT }; enum { UNFOLD, FOLD, INVALIDFOLD }; enum { PREV, NEXT }; From 111e647c24448fd9d43aa8f95d673bf896f4e5cf Mon Sep 17 00:00:00 2001 From: xtheeq Date: Thu, 7 May 2026 13:01:37 +0530 Subject: [PATCH 2/3] docs: add scroller consume & expel --- docs/bindings/keys.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/bindings/keys.md b/docs/bindings/keys.md index b3a4ab64..8551c167 100644 --- a/docs/bindings/keys.md +++ b/docs/bindings/keys.md @@ -145,6 +145,8 @@ bindr=Super,Super_L,spawn,rofi -show run | `set_proportion` | `float` | Set scroller window proportion (0.0–1.0). | | `switch_proportion_preset` | - | Cycle proportion presets of scroller window. | | `scroller_stack` | `left/right/up/down` | Move window inside/outside scroller stack by direction. | +| `scroller_stack` | `consume` | Add the adjacent neighbor into the current stack. | +| `scroller_stack` | `expel` | Remove the last window from the current stack. | | `incgaps` | `+/-value` | Adjust gap size. | | `togglegaps` | - | Toggle gaps. | From 674618643b42c84969e264ae81db9f270814b42f Mon Sep 17 00:00:00 2001 From: xtheeq Date: Fri, 8 May 2026 10:39:33 +0530 Subject: [PATCH 3/3] refactor: split scroller_stack consume/expel into standalone dispatchers --- docs/bindings/keys.md | 4 +-- src/config/parse_config.h | 8 ++--- src/dispatch/bind_declare.h | 2 ++ src/dispatch/bind_define.h | 64 ++++++++++++++++++++++--------------- src/mango.c | 2 +- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/docs/bindings/keys.md b/docs/bindings/keys.md index 8551c167..b756082f 100644 --- a/docs/bindings/keys.md +++ b/docs/bindings/keys.md @@ -145,8 +145,8 @@ bindr=Super,Super_L,spawn,rofi -show run | `set_proportion` | `float` | Set scroller window proportion (0.0–1.0). | | `switch_proportion_preset` | - | Cycle proportion presets of scroller window. | | `scroller_stack` | `left/right/up/down` | Move window inside/outside scroller stack by direction. | -| `scroller_stack` | `consume` | Add the adjacent neighbor into the current stack. | -| `scroller_stack` | `expel` | Remove the last window from the current stack. | +| `scroller_stack_consume` | - | Add the adjacent neighbor into the current stack. | +| `scroller_stack_expel` | - | Remove the last window from the current stack. | | `incgaps` | `+/-value` | Adjust gap size. | | `togglegaps` | - | Toggle gaps. | diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 853dda1c..e51e80d6 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -537,10 +537,6 @@ int32_t parse_direction(const char *str) { return LEFT; } else if (strcmp(lowerStr, "right") == 0) { return RIGHT; - } else if (strcmp(lowerStr, "consume") == 0) { - return CONSUME; - } else if (strcmp(lowerStr, "expel") == 0) { - return EXPEL; } else { return UNDIR; } @@ -1216,6 +1212,10 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "scroller_stack") == 0) { func = scroller_stack; (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "scroller_stack_consume") == 0) { + func = scroller_stack_consume; + } else if (strcmp(func_name, "scroller_stack_expel") == 0) { + func = scroller_stack_expel; } else if (strcmp(func_name, "toggle_all_floating") == 0) { func = toggle_all_floating; } else { diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index dbeebd33..7fac6522 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -70,4 +70,6 @@ int32_t disable_monitor(const Arg *arg); int32_t enable_monitor(const Arg *arg); int32_t toggle_monitor(const Arg *arg); int32_t scroller_stack(const Arg *arg); +int32_t scroller_stack_consume(const Arg *arg); +int32_t scroller_stack_expel(const Arg *arg); int32_t toggle_all_floating(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 19b89aa6..4f629995 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1855,44 +1855,58 @@ int32_t scroller_stack(const Arg *arg) { if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) return 0; - if (arg->i == CONSUME) { - bool is_horizontal_layout = - c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER; - int32_t consume_dir = is_horizontal_layout ? RIGHT : DOWN; + Client *target_client = find_client_by_direction(c, arg, false, true); - Client *target_client = find_client_by_direction(c, &(Arg){.i = consume_dir}, false, true); + return scroller_apply_stack(c, target_client, arg->i); +} - if (target_client) { - Client *stack_tail = get_scroll_stack_head(c); - while (stack_tail->next_in_stack) { - stack_tail = stack_tail->next_in_stack; - } - - scroller_insert_stack(target_client, stack_tail, false); - } +int32_t scroller_stack_consume(const Arg *arg) { + if (!selmon) + return 0; + Client *c = selmon->sel; + if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) return 0; - } - if (arg->i == EXPEL) { - Client *stack_head = get_scroll_stack_head(c); - Client *stack_tail = stack_head; + bool is_horizontal_layout = + c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER; + int32_t consume_dir = is_horizontal_layout ? RIGHT : DOWN; + Client *target_client = find_client_by_direction(c, &(Arg){.i = consume_dir}, false, true); + + if (target_client) { + Client *stack_tail = get_scroll_stack_head(c); while (stack_tail->next_in_stack) { stack_tail = stack_tail->next_in_stack; } - if (stack_tail != stack_head) { - exit_scroller_stack(stack_tail); - wl_list_remove(&stack_tail->link); - wl_list_insert(&stack_head->link, &stack_tail->link); - arrange(selmon, false, false); + if (target_client != stack_tail) { + scroller_insert_stack(target_client, stack_tail, false); } + } + return 0; +} + +int32_t scroller_stack_expel(const Arg *arg) { + if (!selmon) return 0; + Client *c = selmon->sel; + if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) + return 0; + + Client *stack_head = get_scroll_stack_head(c); + Client *stack_tail = stack_head; + + while (stack_tail->next_in_stack) { + stack_tail = stack_tail->next_in_stack; } - Client *target_client = find_client_by_direction(c, arg, false, true); - - return scroller_apply_stack(c, target_client, arg->i); + if (stack_tail != stack_head) { + exit_scroller_stack(stack_tail); + wl_list_remove(&stack_tail->link); + wl_list_insert(&stack_head->link, &stack_tail->link); + arrange(selmon, false, false); + } + return 0; } int32_t toggle_all_floating(const Arg *arg) { diff --git a/src/mango.c b/src/mango.c index e15fbb29..b4bc67bf 100644 --- a/src/mango.c +++ b/src/mango.c @@ -172,7 +172,7 @@ enum { NetLast }; /* EWMH atoms */ #endif -enum { UP, DOWN, LEFT, RIGHT, UNDIR, CONSUME, EXPEL }; /* smartmovewin */ +enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */ enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT }; enum { UNFOLD, FOLD, INVALIDFOLD }; enum { PREV, NEXT };