Skip to content

Commit e0d69ec

Browse files
librepupDreamMaoMao
authored andcommitted
feat: add scroller stack support
1 parent 48737bb commit e0d69ec

8 files changed

Lines changed: 466 additions & 52 deletions

File tree

src/config/parse_config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,9 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
10801080
} else if (strcmp(func_name, "toggle_monitor") == 0) {
10811081
func = toggle_monitor;
10821082
(*arg).v = strdup(arg_value);
1083+
} else if (strcmp(func_name, "scroller_stack") == 0) {
1084+
func = scroller_stack;
1085+
(*arg).i = parse_direction(arg_value);
10831086
} else {
10841087
return NULL;
10851088
}

src/dispatch/bind_declare.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,5 @@ int32_t toggle_trackpad_enable(const Arg *arg);
6868
int32_t setoption(const Arg *arg);
6969
int32_t disable_monitor(const Arg *arg);
7070
int32_t enable_monitor(const Arg *arg);
71-
int32_t toggle_monitor(const Arg *arg);
71+
int32_t toggle_monitor(const Arg *arg);
72+
int32_t scroller_stack(const Arg *arg);

src/dispatch/bind_define.h

Lines changed: 100 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -550,12 +550,14 @@ int32_t set_proportion(const Arg *arg) {
550550
!scroller_ignore_proportion_single)
551551
return 0;
552552

553-
if (selmon->sel) {
553+
Client *tc = selmon->sel;
554+
555+
if (tc) {
556+
tc = get_scroll_stack_head(tc);
554557
uint32_t max_client_width =
555558
selmon->w.width - 2 * scroller_structs - gappih;
556-
selmon->sel->scroller_proportion = arg->f;
557-
selmon->sel->geom.width = max_client_width * arg->f;
558-
// resize(selmon->sel, selmon->sel->geom, 0);
559+
tc->scroller_proportion = arg->f;
560+
tc->geom.width = max_client_width * arg->f;
559561
arrange(selmon, false, false);
560562
}
561563
return 0;
@@ -971,11 +973,13 @@ int32_t switch_proportion_preset(const Arg *arg) {
971973
!scroller_ignore_proportion_single)
972974
return 0;
973975

974-
if (selmon->sel) {
976+
Client *tc = selmon->sel;
975977

978+
if (tc) {
979+
tc = get_scroll_stack_head(tc);
976980
for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) {
977981
if (config.scroller_proportion_preset[i] ==
978-
selmon->sel->scroller_proportion) {
982+
tc->scroller_proportion) {
979983
if (i == config.scroller_proportion_preset_count - 1) {
980984
target_proportion = config.scroller_proportion_preset[0];
981985
break;
@@ -993,9 +997,8 @@ int32_t switch_proportion_preset(const Arg *arg) {
993997

994998
uint32_t max_client_width =
995999
selmon->w.width - 2 * scroller_structs - gappih;
996-
selmon->sel->scroller_proportion = target_proportion;
997-
selmon->sel->geom.width = max_client_width * target_proportion;
998-
// resize(selmon->sel, selmon->sel->geom, 0);
1000+
tc->scroller_proportion = target_proportion;
1001+
tc->geom.width = max_client_width * target_proportion;
9991002
arrange(selmon, false, false);
10001003
}
10011004
return 0;
@@ -1093,6 +1096,7 @@ int32_t tagsilent(const Arg *arg) {
10931096
clear_fullscreen_flag(fc);
10941097
}
10951098
}
1099+
exit_scroller_stack(target_client);
10961100
focusclient(focustop(selmon), 1);
10971101
arrange(target_client->mon, false, false);
10981102
return 0;
@@ -1221,9 +1225,11 @@ int32_t toggleglobal(const Arg *arg) {
12211225
selmon->sel->isnamedscratchpad = 0;
12221226
}
12231227
selmon->sel->isglobal ^= 1;
1224-
// selmon->sel->tags =
1225-
// selmon->sel->isglobal ? TAGMASK : selmon->tagset[selmon->seltags];
1226-
// focustop(selmon);
1228+
if (selmon->sel->isglobal &&
1229+
(selmon->sel->prev_in_stack || selmon->sel->next_in_stack)) {
1230+
exit_scroller_stack(selmon->sel);
1231+
arrange(selmon, false, false);
1232+
}
12271233
setborder_color(selmon->sel);
12281234
return 0;
12291235
}
@@ -1585,3 +1591,85 @@ int32_t toggle_monitor(const Arg *arg) {
15851591
}
15861592
return 0;
15871593
}
1594+
1595+
int32_t scroller_stack(const Arg *arg) {
1596+
Client *c = selmon->sel;
1597+
Client *stack_head = NULL;
1598+
Client *source_stack_head = NULL;
1599+
if (!c || c->isfloating || !is_scroller_layout(selmon))
1600+
return 0;
1601+
1602+
if (c && (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal))
1603+
return 0;
1604+
1605+
Client *target_client = find_client_by_direction(c, arg, false, true);
1606+
1607+
if (target_client && (!client_only_in_one_tag(target_client) ||
1608+
target_client->isglobal || target_client->isunglobal))
1609+
return 0;
1610+
1611+
if (target_client) {
1612+
stack_head = get_scroll_stack_head(target_client);
1613+
}
1614+
1615+
if (c) {
1616+
source_stack_head = get_scroll_stack_head(c);
1617+
}
1618+
1619+
if (stack_head == source_stack_head) {
1620+
return 0;
1621+
}
1622+
1623+
if (c->isfullscreen) {
1624+
setfullscreen(c, 0);
1625+
}
1626+
1627+
if (c->ismaximizescreen) {
1628+
setmaximizescreen(c, 0);
1629+
}
1630+
1631+
if (c->prev_in_stack) {
1632+
exit_scroller_stack(c);
1633+
if (arg->i == LEFT || arg->i == UP) {
1634+
wl_list_remove(&c->link);
1635+
wl_list_insert(source_stack_head->link.prev, &c->link);
1636+
} else {
1637+
wl_list_remove(&c->link);
1638+
wl_list_insert(&source_stack_head->link, &c->link);
1639+
}
1640+
arrange(selmon, false, false);
1641+
return 0;
1642+
} else if (c->next_in_stack) {
1643+
Client *next_in_stack = c->next_in_stack;
1644+
exit_scroller_stack(c);
1645+
if (arg->i == LEFT || arg->i == UP) {
1646+
wl_list_remove(&c->link);
1647+
wl_list_insert(next_in_stack->link.prev, &c->link);
1648+
} else {
1649+
wl_list_remove(&c->link);
1650+
wl_list_insert(&next_in_stack->link, &c->link);
1651+
}
1652+
arrange(selmon, false, false);
1653+
return 0;
1654+
}
1655+
1656+
if (!target_client || target_client->mon != c->mon) {
1657+
return 0;
1658+
}
1659+
1660+
exit_scroller_stack(c);
1661+
1662+
// Find the tail of target_client's stack
1663+
Client *stack_tail = target_client;
1664+
while (stack_tail->next_in_stack) {
1665+
stack_tail = stack_tail->next_in_stack;
1666+
}
1667+
1668+
// Add c to the stack
1669+
stack_tail->next_in_stack = c;
1670+
c->prev_in_stack = stack_tail;
1671+
c->next_in_stack = NULL;
1672+
1673+
arrange(selmon, false, false);
1674+
return 0;
1675+
}

src/fetch/client.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,4 +447,12 @@ bool client_only_in_one_tag(Client *c) {
447447
} else {
448448
return false;
449449
}
450+
}
451+
452+
Client *get_scroll_stack_head(Client *c) {
453+
Client *scroller_stack_head = c;
454+
while (scroller_stack_head->prev_in_stack) {
455+
scroller_stack_head = scroller_stack_head->prev_in_stack;
456+
}
457+
return scroller_stack_head;
450458
}

src/layout/arrange.h

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
378378
int32_t offsety, uint32_t time, bool isvertical) {
379379
float delta_x, delta_y;
380380
float new_scroller_proportion;
381+
float new_stack_proportion;
382+
Client *stack_head = get_scroll_stack_head(grabc);
381383

382384
if (grabc && grabc->mon->visible_tiling_clients == 1 &&
383385
!scroller_ignore_proportion_single)
@@ -389,7 +391,8 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
389391
start_drag_window = true;
390392

391393
// 记录初始状态
392-
grabc->old_scroller_pproportion = grabc->scroller_proportion;
394+
stack_head->old_scroller_pproportion = stack_head->scroller_proportion;
395+
grabc->old_stack_proportion = grabc->stack_proportion;
393396

394397
grabc->cursor_in_left_half =
395398
cursor->x < grabc->geom.x + grabc->geom.width / 2;
@@ -409,15 +412,26 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
409412
grabc->old_master_inner_per = grabc->master_inner_per;
410413
grabc->old_stack_inner_per = grabc->stack_inner_per;
411414
grabc->drag_begin_geom = grabc->geom;
412-
grabc->old_scroller_pproportion = grabc->scroller_proportion;
415+
stack_head->old_scroller_pproportion =
416+
stack_head->scroller_proportion;
417+
grabc->old_stack_proportion = grabc->stack_proportion;
413418
grabc->cursor_in_upper_half = false;
414419
grabc->cursor_in_left_half = false;
415420
}
416421

417-
delta_x = (float)(offsetx) * (grabc->old_scroller_pproportion) /
418-
grabc->drag_begin_geom.width;
419-
delta_y = (float)(offsety) * (grabc->old_scroller_pproportion) /
420-
grabc->drag_begin_geom.height;
422+
if (isvertical) {
423+
delta_y = (float)(offsety) *
424+
(stack_head->old_scroller_pproportion) /
425+
grabc->drag_begin_geom.height;
426+
delta_x = (float)(offsetx) * (grabc->old_stack_proportion) /
427+
grabc->drag_begin_geom.width;
428+
} else {
429+
delta_x = (float)(offsetx) *
430+
(stack_head->old_scroller_pproportion) /
431+
grabc->drag_begin_geom.width;
432+
delta_y = (float)(offsety) * (grabc->old_stack_proportion) /
433+
grabc->drag_begin_geom.height;
434+
}
421435

422436
bool moving_up;
423437
bool moving_down;
@@ -452,18 +466,36 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
452466
delta_x = -fabsf(delta_x);
453467
}
454468

469+
if (isvertical) {
470+
if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) {
471+
delta_x = delta_x * -1.0f;
472+
}
473+
} else {
474+
if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) {
475+
delta_y = delta_y * -1.0f;
476+
}
477+
}
478+
455479
// 直接设置新的比例,基于初始值 + 变化量
456480
if (isvertical) {
457-
new_scroller_proportion = grabc->old_scroller_pproportion + delta_y;
481+
new_scroller_proportion =
482+
stack_head->old_scroller_pproportion + delta_y;
483+
new_stack_proportion = grabc->old_stack_proportion + delta_x;
484+
458485
} else {
459-
new_scroller_proportion = grabc->old_scroller_pproportion + delta_x;
486+
new_scroller_proportion =
487+
stack_head->old_scroller_pproportion + delta_x;
488+
new_stack_proportion = grabc->old_stack_proportion + delta_y;
460489
}
461490

462491
// 应用限制,确保比例在合理范围内
463492
new_scroller_proportion =
464493
fmaxf(0.1f, fminf(1.0f, new_scroller_proportion));
494+
new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion));
495+
496+
grabc->stack_proportion = new_stack_proportion;
465497

466-
grabc->scroller_proportion = new_scroller_proportion;
498+
stack_head->scroller_proportion = new_scroller_proportion;
467499

468500
if (!isdrag) {
469501
arrange(grabc->mon, false, false);
@@ -487,6 +519,9 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx,
487519
if (grabc->mon->isoverview)
488520
return;
489521

522+
int32_t animations_state_backup = animations;
523+
animations = 0;
524+
490525
const Layout *current_layout =
491526
grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag];
492527
if (current_layout->id == TILE || current_layout->id == DECK ||
@@ -505,6 +540,8 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx,
505540
} else if (current_layout->id == VERTICAL_SCROLLER) {
506541
resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, true);
507542
}
543+
544+
animations = animations_state_backup;
508545
}
509546

510547
void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
@@ -605,6 +642,10 @@ arrange(Monitor *m, bool want_animation, bool from_view) {
605642

606643
wl_list_for_each(c, &clients, link) {
607644

645+
if (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal) {
646+
exit_scroller_stack(c);
647+
}
648+
608649
if (from_view && (c->isglobal || c->isunglobal)) {
609650
set_size_per(m, c);
610651
}
@@ -627,7 +668,7 @@ arrange(Monitor *m, bool want_animation, bool from_view) {
627668
m->visible_tiling_clients++;
628669
}
629670

630-
if (ISSCROLLTILED(c)) {
671+
if (ISSCROLLTILED(c) && !c->prev_in_stack) {
631672
m->visible_scroll_tiling_clients++;
632673
}
633674
}

0 commit comments

Comments
 (0)