opt: repl scroller layout

This commit is contained in:
DreamMaoMao 2026-05-10 19:07:10 +08:00
parent cabafb2393
commit 90a5d12ed4
8 changed files with 1427 additions and 925 deletions

View file

@ -629,15 +629,106 @@ int32_t set_proportion(const Arg *arg) {
return 0;
Client *tc = selmon->sel;
if (!tc)
return 0;
if (tc) {
tc = get_scroll_stack_head(tc);
uint32_t max_client_width =
selmon->w.width - 2 * config.scroller_structs - config.gappih;
tc->scroller_proportion = arg->f;
tc->geom.width = max_client_width * arg->f;
arrange(selmon, false, false);
/* 获取堆叠头部客户端 */
tc = get_scroll_stack_head(tc);
if (!tc)
return 0;
Monitor *m = tc->mon;
uint32_t tag = m->pertag->curtag;
struct TagScrollerState *st = m->pertag->scroller_state[tag];
struct ScrollerStackNode *node = NULL;
if (st)
node = find_scroller_node(st, tc);
/* 同时更新节点和客户端字段 */
if (node)
node->scroller_proportion = arg->f;
tc->scroller_proportion = arg->f;
/* 可选的即时几何更新arrange 时会重新计算 */
uint32_t max_client_width =
m->w.width - 2 * config.scroller_structs - config.gappih;
tc->geom.width = max_client_width * arg->f;
arrange(m, false, false);
return 0;
}
int32_t switch_proportion_preset(const Arg *arg) {
float target_proportion = 0;
if (!selmon)
return 0;
if (config.scroller_proportion_preset_count == 0)
return 0;
if (selmon->isoverview || !is_scroller_layout(selmon))
return 0;
if (selmon->visible_tiling_clients == 1 &&
!config.scroller_ignore_proportion_single)
return 0;
Client *tc = selmon->sel;
if (!tc)
return 0;
tc = get_scroll_stack_head(tc);
if (!tc)
return 0;
Monitor *m = tc->mon;
uint32_t tag = m->pertag->curtag;
struct TagScrollerState *st = m->pertag->scroller_state[tag];
struct ScrollerStackNode *node = NULL;
if (st)
node = find_scroller_node(st, tc);
/* 优先从节点读取当前比例,以确保切换基于正确的值 */
float current_proportion =
node ? node->scroller_proportion : tc->scroller_proportion;
/* 查找预设目标 */
for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) {
if (config.scroller_proportion_preset[i] == current_proportion) {
if (arg->i == NEXT) {
if (i == config.scroller_proportion_preset_count - 1)
target_proportion = config.scroller_proportion_preset[0];
else
target_proportion =
config.scroller_proportion_preset[i + 1];
} else {
if (i == 0)
target_proportion =
config.scroller_proportion_preset
[config.scroller_proportion_preset_count - 1];
else
target_proportion =
config.scroller_proportion_preset[i - 1];
}
break;
}
}
if (target_proportion == 0.0f)
target_proportion = config.scroller_proportion_preset[0];
/* 更新节点和客户端 */
if (node)
node->scroller_proportion = target_proportion;
tc->scroller_proportion = target_proportion;
uint32_t max_client_width =
m->w.width - 2 * config.scroller_structs - config.gappih;
tc->geom.width = max_client_width * target_proportion;
arrange(m, false, false);
return 0;
}
@ -1042,68 +1133,6 @@ int32_t switch_layout(const Arg *arg) {
return 0;
}
int32_t switch_proportion_preset(const Arg *arg) {
float target_proportion = 0;
if (!selmon)
return 0;
if (config.scroller_proportion_preset_count == 0) {
return 0;
}
if (selmon->isoverview || !is_scroller_layout(selmon))
return 0;
if (selmon->visible_tiling_clients == 1 &&
!config.scroller_ignore_proportion_single)
return 0;
Client *tc = selmon->sel;
if (tc) {
tc = get_scroll_stack_head(tc);
for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) {
if (config.scroller_proportion_preset[i] ==
tc->scroller_proportion) {
if (arg->i == NEXT) {
if (i == config.scroller_proportion_preset_count - 1) {
target_proportion =
config.scroller_proportion_preset[0];
break;
} else {
target_proportion =
config.scroller_proportion_preset[i + 1];
break;
}
} else {
if (i == 0) {
target_proportion =
config.scroller_proportion_preset
[config.scroller_proportion_preset_count - 1];
break;
} else {
target_proportion =
config.scroller_proportion_preset[i - 1];
break;
}
}
}
}
if (target_proportion == 0) {
target_proportion = config.scroller_proportion_preset[0];
}
uint32_t max_client_width =
selmon->w.width - 2 * config.scroller_structs - config.gappih;
tc->scroller_proportion = target_proportion;
tc->geom.width = max_client_width * target_proportion;
arrange(selmon, false, false);
}
return 0;
}
int32_t tag(const Arg *arg) {
if (!selmon)
return 0;
@ -1202,7 +1231,6 @@ int32_t tagsilent(const Arg *arg) {
clear_fullscreen_flag(fc);
}
}
exit_scroller_stack(target_client);
focusclient(focustop(selmon), 1);
arrange(target_client->mon, false, false);
return 0;
@ -1355,7 +1383,6 @@ int32_t toggleglobal(const Arg *arg) {
selmon->sel->isglobal ^= 1;
if (selmon->sel->isglobal &&
(selmon->sel->prev_in_stack || selmon->sel->next_in_stack)) {
exit_scroller_stack(selmon->sel);
arrange(selmon, false, false);
}
setborder_color(selmon->sel);
@ -1780,76 +1807,69 @@ int32_t toggle_monitor(const Arg *arg) {
int32_t scroller_apply_stack(Client *c, Client *target_client,
int32_t direction) {
if (!c || !c->mon || c->isfloating || !is_scroller_layout(c->mon))
return 0;
Client *source_stack_head = NULL;
Client *stack_head = NULL;
bool is_horizontal_layout =
c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER ? true
: false;
Monitor *m = c->mon;
uint32_t tag = m->pertag->curtag;
struct TagScrollerState *st = ensure_scroller_state(m, tag);
if (target_client) {
stack_head = get_scroll_stack_head(target_client);
}
/* 获取当前节点 */
struct ScrollerStackNode *cnode = find_scroller_node(st, c);
struct ScrollerStackNode *tnode =
target_client ? find_scroller_node(st, target_client) : NULL;
source_stack_head = get_scroll_stack_head(c);
bool is_horizontal = (m->pertag->ltidxs[tag]->id == SCROLLER);
if (source_stack_head == stack_head) {
/* 若方向为 UNDIR 且有目标,直接插入到目标尾部 */
if (direction == UNDIR && target_client && target_client->mon == c->mon) {
scroller_insert_stack(c, target_client, false);
return 0;
}
if (c->isfullscreen) {
setfullscreen(c, 0);
}
/* 处理从堆叠中移出的情况(方向 LEFT/UP 或 RIGHT/DOWN */
if (cnode && (cnode->prev_in_stack || cnode->next_in_stack)) {
bool to_left_or_up = (is_horizontal && direction == LEFT) ||
(!is_horizontal && direction == UP);
bool to_right_or_down = (is_horizontal && direction == RIGHT) ||
(!is_horizontal && direction == DOWN);
if (c->ismaximizescreen) {
setmaximizescreen(c, 0);
}
if (to_left_or_up || to_right_or_down) {
/* 找到当前堆叠的头节点,以便移动全局链表位置 */
struct ScrollerStackNode *head = cnode;
while (head->prev_in_stack)
head = head->prev_in_stack;
Client *source_stack_head = head->client;
if (c->prev_in_stack && direction != UNDIR) {
if ((is_horizontal_layout && direction == LEFT) ||
(!is_horizontal_layout && direction == UP)) {
exit_scroller_stack(c);
/* 从 tag 状态中移除该客户端对应的节点 */
scroller_node_remove(st, cnode);
/* 重新创建一个独立的节点(无堆叠关系) */
scroller_node_create(st, c);
/* 调整全局客户端链表顺序:移到源堆叠头的前面或后面 */
wl_list_remove(&c->link);
wl_list_insert(source_stack_head->link.prev, &c->link);
arrange(selmon, false, false);
if (to_left_or_up)
wl_list_insert(source_stack_head->link.prev, &c->link);
else
wl_list_insert(&source_stack_head->link, &c->link);
} else if ((is_horizontal_layout && direction == RIGHT) ||
(!is_horizontal_layout && direction == DOWN)) {
exit_scroller_stack(c);
wl_list_remove(&c->link);
wl_list_insert(&source_stack_head->link, &c->link);
arrange(selmon, false, false);
/* 同步到客户端字段并重排 */
sync_scroller_state_to_clients(m, tag);
arrange(m, false, false);
return 0;
}
return 0;
} else if (c->next_in_stack && direction != UNDIR) {
Client *next_in_stack = c->next_in_stack;
if ((is_horizontal_layout && direction == LEFT) ||
(!is_horizontal_layout && direction == UP)) {
exit_scroller_stack(c);
wl_list_remove(&c->link);
wl_list_insert(next_in_stack->link.prev, &c->link);
arrange(selmon, false, false);
} else if ((is_horizontal_layout && direction == RIGHT) ||
(!is_horizontal_layout && direction == DOWN)) {
exit_scroller_stack(c);
wl_list_remove(&c->link);
wl_list_insert(&next_in_stack->link, &c->link);
arrange(selmon, false, false);
}
return 0;
}
if (!target_client || target_client->mon != c->mon) {
if (!target_client || target_client->mon != c->mon)
return 0;
}
// Find the tail of target_client's stack
Client *stack_tail = target_client;
while (stack_tail->next_in_stack) {
stack_tail = stack_tail->next_in_stack;
}
/* 找到目标堆叠的尾部节点 */
struct ScrollerStackNode *tail = tnode;
while (tail->next_in_stack)
tail = tail->next_in_stack;
scroller_insert_stack(c, stack_tail, false);
/* 通过封装好的插入函数实现(尾部插入) */
scroller_insert_stack(c, tail->client, false);
return 0;
}