feat: support group

This commit is contained in:
DreamMaoMao 2026-06-20 18:44:28 +08:00
parent 0fc7559c3c
commit d1cab2c4b7
14 changed files with 483 additions and 233 deletions

View file

@ -37,21 +37,6 @@ void set_size_per(Monitor *m, Client *c) {
}
}
void monocle_set_focus(Client *c, bool focused) {
if (!c || !c->mon)
return;
c->is_monocle_hide = !focused;
mango_tab_bar_node_set_focus(c->tab_bar_node, focused);
wlr_scene_node_set_enabled(&c->scene->node, focused);
if (!focused) {
c->animation.current = c->animainit_geom = c->animation.initial =
c->pending = c->current = c->geom;
}
}
void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time,
int32_t type) {
@ -1147,16 +1132,6 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
client_add_jump_label_node(c);
}
if (m->pertag->ltidxs[m->pertag->curtag]->id == MONOCLE &&
!c->tab_bar_node) {
client_add_tab_bar_node(c);
}
if (c->tab_bar_node && c->mon == m) {
wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node,
false);
}
if (c->mon == m && (c->isglobal || c->isunglobal)) {
c->tags = m->tagset[m->seltags];
}

View file

@ -261,7 +261,7 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
!node->client->ismaximizescreen) {
struct wlr_box box = {ax, ay, MANGO_MAX(1, aw),
MANGO_MAX(1, ah)};
resize(node->client, box, 0);
client_tile_resize(node->client, box, 0);
}
}
return;

View file

@ -545,83 +545,32 @@ void deck(Monitor *m) {
}
}
void monocle(Monitor *m) {
Client *c = NULL, *fc = NULL;
void // 17
monocle(Monitor *m) {
Client *c = NULL;
struct wlr_box geom;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gapiv = enablegaps ? m->gappiv : 0;
int32_t cur_gapih = enablegaps ? m->gappih : 0;
if (config.smartgaps && m->visible_fake_tiling_clients == 1) {
cur_gappov = cur_gappoh = cur_gapiv = cur_gapih = 0;
}
int n = m->visible_fake_tiling_clients;
if (n == 0)
return;
wl_list_for_each(c, &fstack, flink) {
if (c->iskilling || c->isunglobal || !ISFAKETILED(c))
continue;
if (VISIBLEON(c, m)) {
fc = c;
break;
}
}
if (n == 1) {
geom.x = m->w.x + cur_gappoh;
geom.y = m->w.y + cur_gappov;
geom.width = m->w.width - 2 * cur_gappoh;
geom.height = m->w.height - 2 * cur_gappov;
client_tile_resize(fc, geom, 0);
monocle_set_focus(fc, true);
return;
}
int tab_bar_height = config.tab_bar_height;
int tab_bar_inner_gap_height =
config.tab_bar_height > 0 ? 2 * cur_gapiv : 0;
int tab_bar_y_offset = config.tab_bar_height > 0 ? cur_gapiv : 0;
int tab_y = m->w.y + cur_gappov;
int main_y = tab_y + tab_bar_height + tab_bar_y_offset;
int main_height = m->w.height - 2 * cur_gappov - tab_bar_inner_gap_height -
tab_bar_height;
int tab_area_width = m->w.width - 2 * cur_gappoh;
int total_gaps = (n - 1) * cur_gapih;
int base_width = (tab_area_width - total_gaps) / n;
int remainder = (tab_area_width - total_gaps) % n;
int tab_x = m->w.x + cur_gappoh;
int idx = 0;
cur_gappoh = config.smartgaps && m->visible_fake_tiling_clients == 1
? 0
: cur_gappoh;
cur_gappov = config.smartgaps && m->visible_fake_tiling_clients == 1
? 0
: cur_gappov;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue;
if (c == fc) {
monocle_set_focus(c, true);
} else {
monocle_set_focus(c, false);
}
geom.x = m->w.x + cur_gappoh;
geom.y = main_y;
geom.y = m->w.y + cur_gappov;
geom.width = m->w.width - 2 * cur_gappoh;
geom.height = main_height;
geom.height = m->w.height - 2 * cur_gappov;
client_tile_resize(c, geom, 0);
int tw = base_width + (idx < remainder ? 1 : 0);
global_draw_tab_bar(c, tab_x, tab_y, tw, tab_bar_height);
tab_x += tw + cur_gapih;
idx++;
}
if ((c = focustop(m)))
wlr_scene_node_raise_to_top(&c->scene->node);
}
// 网格布局窗口大小和位置计算

View file

@ -1,4 +1,3 @@
typedef struct {
float x, y, w, h;
} OvPlacedRect;
@ -232,16 +231,20 @@ void overview_scale(Monitor *m) {
float base_x = m->w.x + target_gappo + dx;
float base_y = m->w.y + target_gappo + dy;
// 收集所有客户端的目标几何,最后统一调用 client_tile_resize
struct wlr_box overview_boxes[n]; // C99 VLAn > 0 时有效
for (int k = 0; k < n; k++) {
Client *cl = items[k].c;
struct wlr_box geom;
geom.x = (int)(base_x + placed[k].x + 0.5f);
geom.y = (int)(base_y + placed[k].y + 0.5f);
float w = items[k].orig_w * best_s;
float h = items[k].orig_h * best_s;
geom.width = (int)(geom.x + w + 0.5f) - geom.x;
geom.height = (int)(geom.y + h + 0.5f) - geom.y;
resize(cl, geom, 0);
int ix = (int)(base_x + placed[k].x + 0.5f);
int iy = (int)(base_y + placed[k].y + 0.5f);
int iw = (int)(ix + w + 0.5f) - ix;
int ih = (int)(iy + h + 0.5f) - iy;
overview_boxes[k] = (struct wlr_box){ix, iy, iw, ih};
}
for (int k = 0; k < n; k++) {
client_tile_resize(items[k].c, overview_boxes[k], 0);
}
}
@ -280,74 +283,69 @@ void overview_resize(Monitor *m) {
return;
}
// 临时存储每个客户端的目标几何
struct wlr_box boxes[n]; // C99 VLA
if (n == 1) {
int32_t cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
int32_t ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
c_arr[0]->geom.x = m->w.x + (m->w.width - cw) / 2;
c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2;
c_arr[0]->geom.width = cw;
c_arr[0]->geom.height = ch;
resize(c_arr[0], c_arr[0]->geom, 0);
free(c_arr);
return;
}
if (n == 2) {
boxes[0].x = m->w.x + (m->w.width - cw) / 2;
boxes[0].y = m->w.y + (m->w.height - ch) / 2;
boxes[0].width = cw;
boxes[0].height = ch;
} else if (n == 2) {
int32_t cw = (m->w.width - 2 * target_gappo - target_gappi) / 2;
int32_t ch = (m->w.height - 2 * target_gappo) * 0.65f;
c_arr[0]->geom.x = m->w.x + target_gappo;
c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
c_arr[0]->geom.width = cw;
c_arr[0]->geom.height = ch;
resize(c_arr[0], c_arr[0]->geom, 0);
boxes[0].x = m->w.x + target_gappo;
boxes[0].y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
boxes[0].width = cw;
boxes[0].height = ch;
c_arr[1]->geom.x = m->w.x + cw + target_gappo + target_gappi;
c_arr[1]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
c_arr[1]->geom.width = cw;
c_arr[1]->geom.height = ch;
resize(c_arr[1], c_arr[1]->geom, 0);
boxes[1].x = m->w.x + cw + target_gappo + target_gappi;
boxes[1].y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
boxes[1].width = cw;
boxes[1].height = ch;
} else {
int32_t cols = 1;
while (cols * cols < n)
cols++;
int32_t rows = (n + cols - 1) / cols;
free(c_arr);
return;
}
int32_t ch =
(m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows;
int32_t cw =
(m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols;
int32_t cols = 1;
while (cols * cols < n) {
cols++;
}
int32_t rows = (n + cols - 1) / cols;
if (ch < 1)
ch = 1;
if (cw < 1)
cw = 1;
int32_t ch =
(m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows;
int32_t cw =
(m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols;
if (ch < 1)
ch = 1;
if (cw < 1)
cw = 1;
int32_t overcols = n % cols;
int32_t dx = 0;
if (overcols) {
dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) / 2 -
target_gappo;
}
for (int i = 0; i < n; i++) {
int32_t cx = m->w.x + (i % cols) * (cw + target_gappi);
int32_t cy = m->w.y + (i / cols) * (ch + target_gappi);
if (overcols && i >= n - overcols) {
cx += dx;
int32_t overcols = n % cols;
int32_t dx = 0;
if (overcols) {
dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) /
2 -
target_gappo;
}
c_arr[i]->geom.x = cx + target_gappo;
c_arr[i]->geom.y = cy + target_gappo;
c_arr[i]->geom.width = cw;
c_arr[i]->geom.height = ch;
resize(c_arr[i], c_arr[i]->geom, 0);
for (int i = 0; i < n; i++) {
int32_t cx = m->w.x + (i % cols) * (cw + target_gappi);
int32_t cy = m->w.y + (i / cols) * (ch + target_gappi);
if (overcols && i >= n - overcols)
cx += dx;
boxes[i].x = cx + target_gappo;
boxes[i].y = cy + target_gappo;
boxes[i].width = cw;
boxes[i].height = ch;
}
}
// 统一应用所有几何变更,使用 client_tile_resize
for (int k = 0; k < n; k++) {
client_tile_resize(c_arr[k], boxes[k], 0);
}
free(c_arr);
@ -365,9 +363,7 @@ void create_jump_hints(Monitor *m) {
char c_char = jump_labels[label_idx];
c->jump_char = c_char;
// 把字符变成字符串
char label_text[2] = {c_char, '\0'};
mango_jump_label_node_update(c->jump_label_node, label_text, 1.0f);
wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node,
true);
@ -385,12 +381,10 @@ void create_jump_hints(Monitor *m) {
void begin_jump_mode(Monitor *m) { m->is_jump_mode = 1; }
void finish_jump_mode(Monitor *m) {
Client *c = NULL;
if (!m->is_jump_mode) {
if (!m->is_jump_mode)
return;
}
Client *c;
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m)) {
if (c->jump_label_node->scene_buffer->node.enabled) {
@ -400,12 +394,10 @@ void finish_jump_mode(Monitor *m) {
}
}
}
m->is_jump_mode = 0;
}
void overview(Monitor *m) {
if (config.ov_no_resize) {
overview_scale(m);
} else {
@ -415,4 +407,4 @@ void overview(Monitor *m) {
if (m->is_jump_mode) {
create_jump_hints(m);
}
}
}

View file

@ -36,7 +36,6 @@ scroller_node_create(struct TagScrollerState *st, Client *c) {
return n;
}
/* 从 tag 状态中移除一个节点并释放 */
static void scroller_node_remove(struct TagScrollerState *st,
struct ScrollerStackNode *target) {
if (!st || !target)
@ -223,7 +222,7 @@ void arrange_stack_node(struct ScrollerStackNode *head, struct wlr_box geometry,
.y = current_y,
.width = geometry.width,
.height = client_height};
resize(iter->client, client_geom, 0);
client_tile_resize(iter->client, client_geom, 0);
remain_proportion -= iter->stack_proportion;
remain_client_height -= client_height;
current_y += client_height + gappiv;
@ -272,7 +271,7 @@ void arrange_stack_vertical_node(struct ScrollerStackNode *head,
.x = current_x,
.height = geometry.height,
.width = client_width};
resize(iter->client, client_geom, 0);
client_tile_resize(iter->client, client_geom, 0);
remain_proportion -= iter->stack_proportion;
remain_client_width -= client_width;
current_x += client_width + gappih;
@ -508,6 +507,7 @@ void scroller(Monitor *m) {
void vertical_scroller(Monitor *m) {
uint32_t tag = m->pertag->curtag;
int32_t bar_height = 0;
struct TagScrollerState *st = ensure_scroller_state(m, tag);
Client *c = NULL;
float scroller_default_proportion_single =
@ -696,7 +696,12 @@ void vertical_scroller(Monitor *m) {
arrange_stack_vertical_node(heads[focus_index], target_geom,
cur_gappih);
} else {
target_geom.y = root_client->geom.y;
bar_height = !root_client->isfullscreen && (root_client->group_prev ||
root_client->group_next)
? config.tab_bar_height
: 0;
target_geom.y = root_client->geom.y - bar_height;
vertical_check_scroller_root_inside_mon(heads[focus_index]->client,
&target_geom);
arrange_stack_vertical_node(heads[focus_index], target_geom,
@ -709,8 +714,15 @@ void vertical_scroller(Monitor *m) {
up_geom.width = m->w.width - 2 * cur_gappoh;
up_geom.height = max_client_height * cur->scroller_proportion;
vertical_scroll_adjust_fullandmax(cur->client, &up_geom);
bar_height = !heads[focus_index - i + 1]->client->isfullscreen &&
(heads[focus_index - i + 1]->client->group_prev ||
heads[focus_index - i + 1]->client->group_next)
? config.tab_bar_height
: 0;
up_geom.y = heads[focus_index - i + 1]->client->geom.y - cur_gappiv -
up_geom.height;
up_geom.height - bar_height;
arrange_stack_vertical_node(cur, up_geom, cur_gappih);
}
@ -902,7 +914,6 @@ static void update_scroller_state(Monitor *m) {
break;
}
/* 移除不再可见的节点 */
struct ScrollerStackNode *n = st->all_first;
while (n) {
bool found = false;