maomaowm/src/layout/vertical.h

360 lines
9.9 KiB
C
Raw Normal View History

2025-10-09 13:09:40 +08:00
void vertical_tile(Monitor *m) {
int32_t i, n = 0, w, r, ie = enablegaps, mh, mx, tx;
Client *c = NULL;
2025-10-09 13:09:40 +08:00
Client *fc = NULL;
double mfact = 0;
int32_t master_num = 0;
int32_t stack_num = 0;
n = m->visible_tiling_clients;
2025-10-09 13:09:40 +08:00
master_num = m->pertag->nmasters[m->pertag->curtag];
master_num = n > master_num ? master_num : n;
2025-10-09 13:09:40 +08:00
stack_num = n - master_num;
if (n == 0)
return;
int32_t cur_gapih = enablegaps ? m->gappih : 0;
int32_t cur_gapiv = enablegaps ? m->gappiv : 0;
int32_t cur_gapoh = enablegaps ? m->gappoh : 0;
int32_t cur_gapov = enablegaps ? m->gappov : 0;
cur_gapih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapih;
cur_gapiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapiv;
cur_gapoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapoh;
cur_gapov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapov;
2025-10-09 13:09:40 +08:00
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
break;
}
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
if (n > m->pertag->nmasters[m->pertag->curtag])
mh = m->pertag->nmasters[m->pertag->curtag]
? (m->w.height + cur_gapiv * ie) * mfact
: 0;
else
2025-10-09 13:09:40 +08:00
mh = m->w.height - 2 * cur_gapov + cur_gapiv * ie;
2025-10-09 13:09:40 +08:00
i = 0;
mx = tx = cur_gapoh;
int32_t master_surplus_width =
(m->w.width - 2 * cur_gapoh - cur_gapih * ie * (master_num - 1));
float master_surplus_ratio = 1.0;
int32_t slave_surplus_width =
(m->w.width - 2 * cur_gapoh - cur_gapih * ie * (stack_num - 1));
float slave_surplus_ratio = 1.0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
2025-10-09 13:09:40 +08:00
if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
if (c->master_inner_per > 0.0f) {
w = master_surplus_width * c->master_inner_per /
master_surplus_ratio;
master_surplus_width = master_surplus_width - w;
master_surplus_ratio =
master_surplus_ratio - c->master_inner_per;
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
} else {
w = (m->w.width - mx - cur_gapih - cur_gapih * ie * (r - 1)) /
r;
c->master_inner_per = w / (m->w.width - mx - cur_gapih -
cur_gapih * ie * (r - 1));
c->master_mfact_per = mfact;
}
resize(c,
2025-10-09 13:09:40 +08:00
(struct wlr_box){.x = m->w.x + mx,
.y = m->w.y + cur_gapov,
.width = w,
.height = mh - cur_gapiv * ie},
0);
2025-10-09 13:09:40 +08:00
mx += c->geom.width + cur_gapih * ie;
} else {
r = n - i;
2025-12-11 15:44:49 +08:00
if (c->stack_inner_per > 0.0f) {
w = slave_surplus_width * c->stack_inner_per /
slave_surplus_ratio;
slave_surplus_width = slave_surplus_width - w;
2025-12-11 15:44:49 +08:00
slave_surplus_ratio = slave_surplus_ratio - c->stack_inner_per;
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
} else {
w = (m->w.width - tx - cur_gapih - cur_gapih * ie * (r - 1)) /
r;
2025-12-11 15:44:49 +08:00
c->stack_inner_per = w / (m->w.width - tx - cur_gapih -
cur_gapih * ie * (r - 1));
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
}
resize(c,
(struct wlr_box){.x = m->w.x + tx,
.y = m->w.y + mh + cur_gapov,
.width = w,
.height = m->w.height - mh - 2 * cur_gapov},
0);
tx += c->geom.width + cur_gapih * ie;
}
i++;
}
}
2025-10-15 07:24:40 +08:00
void vertical_deck(Monitor *m) {
int32_t mh, mx;
int32_t i, n = 0;
2025-10-15 07:24:40 +08:00
Client *c = NULL;
Client *fc = NULL;
float mfact;
2026-01-27 14:45:28 +08:00
uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag];
2025-10-15 07:24:40 +08:00
int32_t cur_gappiv = enablegaps ? m->gappiv : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
2025-10-15 07:24:40 +08:00
cur_gappiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
2025-10-15 07:24:40 +08:00
n = m->visible_tiling_clients;
if (n == 0)
return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
break;
}
// Calculate master width using mfact from pertag
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
2026-01-27 14:45:28 +08:00
if (n > nmasters)
mh = nmasters ? round((m->w.height - 2 * cur_gappov) * mfact) : 0;
2025-10-15 07:24:40 +08:00
else
mh = m->w.height - 2 * cur_gappov;
i = mx = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
2026-01-27 14:45:28 +08:00
if (i < nmasters) {
2025-10-15 07:24:40 +08:00
resize(
c,
(struct wlr_box){.x = m->w.x + cur_gappoh + mx,
.y = m->w.y + cur_gappov,
.width = (m->w.width - 2 * cur_gappoh - mx) /
2026-01-27 14:45:28 +08:00
(MIN(n, nmasters) - i),
2025-10-15 07:24:40 +08:00
.height = mh},
0);
mx += c->geom.width;
} else {
resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + mh + cur_gappov + cur_gappiv,
.width = m->w.width - 2 * cur_gappoh,
.height = m->w.height - mh -
2 * cur_gappov - cur_gappiv},
0);
if (c == focustop(m))
wlr_scene_node_raise_to_top(&c->scene->node);
}
i++;
}
}
2025-10-11 16:27:54 +08:00
void vertical_grid(Monitor *m) {
int32_t i, n;
int32_t cx, cy, cw, ch;
int32_t dy;
int32_t rows, cols, overrows;
2025-10-11 16:27:54 +08:00
Client *c = NULL;
int32_t target_gappo =
enablegaps ? m->isoverview ? config.overviewgappo : config.gappov : 0;
int32_t target_gappi =
enablegaps ? m->isoverview ? config.overviewgappi : config.gappiv : 0;
2025-10-11 18:25:08 +08:00
float single_width_ratio = m->isoverview ? 0.7 : 0.9;
float single_height_ratio = m->isoverview ? 0.8 : 0.9;
2025-10-11 16:27:54 +08:00
n = m->isoverview ? m->visible_clients : m->visible_tiling_clients;
if (n == 0) {
return;
}
if (n == 1) {
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
2025-11-08 12:41:38 +08:00
((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) {
2025-10-11 18:25:08 +08:00
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
2025-10-11 16:27:54 +08:00
c->geom.x = m->w.x + (m->w.width - cw) / 2;
c->geom.y = m->w.y + (m->w.height - ch) / 2;
2025-10-15 16:23:46 +08:00
c->geom.width = cw;
c->geom.height = ch;
2025-10-11 16:27:54 +08:00
resize(c, c->geom, 0);
return;
}
}
}
if (n == 2) {
2025-10-11 18:25:08 +08:00
ch = (m->w.height - 2 * target_gappo - target_gappi) / 2;
cw = (m->w.width - 2 * target_gappo) * 0.65;
2025-10-11 16:27:54 +08:00
i = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
2025-11-08 12:41:38 +08:00
((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) {
2025-10-11 16:27:54 +08:00
if (i == 0) {
2025-10-11 18:25:08 +08:00
c->geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
c->geom.y = m->w.y + target_gappo;
2025-10-15 16:23:46 +08:00
c->geom.width = cw;
c->geom.height = ch;
2025-10-11 16:27:54 +08:00
resize(c, c->geom, 0);
} else if (i == 1) {
2025-10-11 18:25:08 +08:00
c->geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
c->geom.y = m->w.y + ch + target_gappo + target_gappi;
2025-10-15 16:23:46 +08:00
c->geom.width = cw;
c->geom.height = ch;
2025-10-11 16:27:54 +08:00
resize(c, c->geom, 0);
}
i++;
}
}
return;
}
for (rows = 0; rows <= n / 2; rows++) {
if (rows * rows >= n) {
break;
}
}
cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
2025-10-11 18:25:08 +08:00
cw = (m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols;
ch = (m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows;
2025-10-11 16:27:54 +08:00
overrows = n % rows;
if (overrows) {
2025-10-11 18:25:08 +08:00
dy = (m->w.height - overrows * ch - (overrows - 1) * target_gappi) / 2 -
target_gappo;
2025-10-11 16:27:54 +08:00
}
i = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
2025-11-08 12:41:38 +08:00
((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) {
2025-10-11 18:25:08 +08:00
cx = m->w.x + (i / rows) * (cw + target_gappi);
cy = m->w.y + (i % rows) * (ch + target_gappi);
2025-10-11 16:27:54 +08:00
if (overrows && i >= n - overrows) {
cy += dy;
}
2025-10-11 18:25:08 +08:00
c->geom.x = cx + target_gappo;
c->geom.y = cy + target_gappo;
2025-10-15 16:23:46 +08:00
c->geom.width = cw;
c->geom.height = ch;
2025-10-11 16:27:54 +08:00
resize(c, c->geom, 0);
i++;
}
}
2026-05-16 08:23:48 +08:00
}
void vertical_fair(Monitor *m) {
int32_t i, n = 0;
Client *c = NULL;
n = m->visible_tiling_clients;
if (n == 0)
return;
// 间隙参数处理
int32_t cur_gappiv = enablegaps ? m->gappiv : 0;
int32_t cur_gappih = enablegaps ? m->gappih : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
// 智能间隙
cur_gappiv = config.smartgaps && n == 1 ? 0 : cur_gappiv;
cur_gappih = config.smartgaps && n == 1 ? 0 : cur_gappih;
cur_gappov = config.smartgaps && n == 1 ? 0 : cur_gappov;
cur_gappoh = config.smartgaps && n == 1 ? 0 : cur_gappoh;
// 计算最佳行数 rows = ceil(sqrt(n))
int32_t rows;
for (rows = 0; rows <= n; rows++) {
if (rows * rows >= n)
break;
}
int32_t base_cols = n / rows; // 每行的基础列数
int32_t remainder = n % rows; // 多出来的窗口,分配给前 remainder 行
// 计算标准行高
int32_t row_height =
(m->w.height - 2 * cur_gappov - (rows - 1) * cur_gappiv) / rows;
i = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
int32_t row_idx, col_idx, cols_in_this_row;
// 判断当前窗口属于哪一行、哪一列
if (i < remainder * (base_cols + 1)) {
row_idx = i / (base_cols + 1);
col_idx = i % (base_cols + 1);
cols_in_this_row = base_cols + 1;
} else {
int32_t offset = i - remainder * (base_cols + 1);
row_idx = remainder + offset / base_cols;
col_idx = offset % base_cols;
cols_in_this_row = base_cols;
}
// 计算 Y 坐标和高度 (最后一行吃掉剩余像素)
int32_t cy = m->w.y + cur_gappov + row_idx * (row_height + cur_gappiv);
int32_t ch = (row_idx == rows - 1)
? (m->w.height - 2 * cur_gappov -
row_idx * (row_height + cur_gappiv))
: row_height;
// 计算 X 坐标和宽度 (最后一列吃掉剩余像素,防止缝隙)
int32_t base_cw = (m->w.width - 2 * cur_gappoh -
(cols_in_this_row - 1) * cur_gappih) /
cols_in_this_row;
int32_t cx = m->w.x + cur_gappoh + col_idx * (base_cw + cur_gappih);
int32_t cw = (col_idx == cols_in_this_row - 1)
? (m->w.width - 2 * cur_gappoh -
col_idx * (base_cw + cur_gappih))
: base_cw;
resize(c, (struct wlr_box){.x = cx, .y = cy, .width = cw, .height = ch},
0);
i++;
}
2025-10-11 16:27:54 +08:00
}