maomaowm/src/layout/horizontal.h

753 lines
21 KiB
C
Raw Normal View History

// 网格布局窗口大小和位置计算
void grid(Monitor *m) {
int32_t i, n;
int32_t cx, cy, cw, ch;
int32_t dx;
int32_t cols, rows, overcols;
Client *c = NULL;
n = 0;
int32_t target_gappo =
enablegaps ? m->isoverview ? config.overviewgappo : config.gappoh : 0;
int32_t target_gappi =
enablegaps ? m->isoverview ? config.overviewgappi : config.gappih : 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;
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-07 11:34:12 +08:00
((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) {
2025-10-11 18:25:08 +08:00
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
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;
resize(c, c->geom, 0);
return;
}
}
}
if (n == 2) {
2025-10-11 18:25:08 +08:00
cw = (m->w.width - 2 * target_gappo - target_gappi) / 2;
ch = (m->w.height - 2 * target_gappo) * 0.65;
i = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
2025-11-07 11:34:12 +08:00
((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) {
if (i == 0) {
2025-10-11 18:25:08 +08:00
c->geom.x = m->w.x + target_gappo;
c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
2025-10-15 16:23:46 +08:00
c->geom.width = cw;
c->geom.height = ch;
resize(c, c->geom, 0);
} else if (i == 1) {
2025-10-11 18:25:08 +08:00
c->geom.x = m->w.x + cw + target_gappo + target_gappi;
c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
2025-10-15 16:23:46 +08:00
c->geom.width = cw;
c->geom.height = ch;
resize(c, c->geom, 0);
}
i++;
}
}
return;
}
// 计算列数和行数
for (cols = 0; cols <= n / 2; cols++) {
if (cols * cols >= n) {
break;
}
}
rows = (cols && (cols - 1) * cols >= n) ? cols - 1 : cols;
// 计算每个客户端的高度和宽度
2025-10-11 18:25:08 +08:00
ch = (m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows;
cw = (m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols;
// 处理多余的列
overcols = n % cols;
if (overcols) {
2025-10-11 18:25:08 +08:00
dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) / 2 -
target_gappo;
}
// 调整每个客户端的位置和大小
i = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
2025-12-09 09:40:22 +08:00
if (VISIBLEON(c, m) && !c->isunglobal &&
2025-11-07 11:34:12 +08:00
((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) {
2025-10-11 18:25:08 +08:00
cx = m->w.x + (i % cols) * (cw + target_gappi);
cy = m->w.y + (i / cols) * (ch + target_gappi);
if (overcols && i >= n - overcols) {
cx += dx;
}
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;
resize(c, c->geom, 0);
i++;
}
}
}
void deck(Monitor *m) {
int32_t mw, my;
int32_t i, n = 0;
Client *c = NULL;
2025-10-09 13:09:40 +08:00
Client *fc = NULL;
float mfact;
2026-01-27 14:45:28 +08:00
uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag];
2025-10-09 13:09:40 +08:00
int32_t cur_gappih = enablegaps ? m->gappih : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
n = m->visible_tiling_clients;
if (n == 0)
return;
2025-10-09 13:09:40 +08:00
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
break;
}
// Calculate master width using mfact from pertag
2025-10-09 13:09:40 +08:00
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
// Calculate master width including outer gaps
2026-01-27 14:45:28 +08:00
if (n > nmasters)
mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0;
else
mw = m->w.width - 2 * cur_gappoh;
i = my = 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-09 13:09:40 +08:00
c->master_mfact_per = mfact;
// Master area clients
2025-07-09 23:31:16 +08:00
resize(
c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + cur_gappov + my,
.width = mw,
.height = (m->w.height - 2 * cur_gappov - my) /
2026-01-27 14:45:28 +08:00
(MIN(n, nmasters) - i)},
2025-07-09 23:31:16 +08:00
0);
my += c->geom.height;
} else {
// Stack area clients
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
resize(c,
(struct wlr_box){.x = m->w.x + mw + cur_gappoh + cur_gappih,
.y = m->w.y + cur_gappov,
.width = m->w.width - mw - 2 * cur_gappoh -
cur_gappih,
.height = m->w.height - 2 * cur_gappov},
0);
if (c == focustop(m))
wlr_scene_node_raise_to_top(&c->scene->node);
}
i++;
}
}
2025-09-26 21:30:45 +08:00
void center_tile(Monitor *m) {
int32_t i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw;
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;
2025-09-26 21:30:45 +08:00
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;
2025-09-26 21:30:45 +08:00
if (n == 0)
return;
2025-10-09 13:09:40 +08:00
// 获取第一个可见的平铺客户端用于主区域宽度百分比
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
break;
2025-09-26 21:30:45 +08:00
}
2025-10-09 13:09:40 +08:00
// 间隙参数处理
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; // 外部水平间隙
2025-10-09 13:09:40 +08:00
// 智能间隙处理
cur_gappiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
2025-10-09 13:09:40 +08:00
int32_t nmasters = m->pertag->nmasters[m->pertag->curtag];
2025-10-09 13:09:40 +08:00
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
2025-09-26 21:30:45 +08:00
// 初始化区域
mw = m->w.width;
2025-10-09 13:09:40 +08:00
mx = cur_gappoh;
my = cur_gappov;
2025-09-26 21:30:45 +08:00
tw = mw;
// 判断是否需要主区域铺满
int32_t should_overspread =
config.center_master_overspread && (n <= nmasters);
int32_t master_surplus_height =
2025-12-10 18:32:06 +08:00
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1));
float master_surplus_ratio = 1.0;
int32_t slave_left_surplus_height =
2025-12-10 18:32:06 +08:00
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num / 2 - 1));
float slave_left_surplus_ratio = 1.0;
int32_t slave_right_surplus_height =
2025-12-10 18:32:06 +08:00
(m->w.height - 2 * cur_gappov -
cur_gappiv * ie * ((stack_num + 1) / 2 - 1));
float slave_right_surplus_ratio = 1.0;
if (n > nmasters || !should_overspread) {
// 计算主区域宽度(居中模式)
2025-10-09 13:09:40 +08:00
mw = nmasters ? (m->w.width - 2 * cur_gappoh - cur_gappih * ie) * mfact
: 0;
2025-09-26 21:30:45 +08:00
if (n - nmasters > 1) {
// 多个堆叠窗口:主区域居中,左右两侧各有一个堆叠区域
2025-10-09 13:09:40 +08:00
tw = (m->w.width - mw) / 2 - cur_gappoh - cur_gappih * ie;
mx = cur_gappoh + tw + cur_gappih * ie;
} else if (n - nmasters == 1) {
// 单个堆叠窗口的处理
if (config.center_when_single_stack) {
2025-10-09 13:09:40 +08:00
// stack在右边master居中左边空着
tw = (m->w.width - mw) / 2 - cur_gappoh - cur_gappih * ie;
mx = cur_gappoh + tw + cur_gappih * ie; // master居中
} else {
2025-10-09 13:09:40 +08:00
// stack在右边master在左边
tw = m->w.width - mw - 2 * cur_gappoh - cur_gappih * ie;
mx = cur_gappoh; // master在左边
}
} else {
// 只有主区域窗口:居中显示
2025-10-09 13:09:40 +08:00
tw = (m->w.width - mw) / 2 - cur_gappoh - cur_gappih * ie;
mx = cur_gappoh + tw + cur_gappih * ie;
2025-09-26 21:30:45 +08:00
}
} else {
// 主区域铺满模式(只有主区域窗口时)
2025-10-09 13:09:40 +08:00
mw = m->w.width - 2 * cur_gappoh;
mx = cur_gappoh;
tw = 0; // 堆叠区域宽度为0
2025-09-26 21:30:45 +08:00
}
2025-10-09 13:09:40 +08:00
oty = cur_gappov;
ety = cur_gappov;
2025-09-26 21:30:45 +08:00
i = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
if (i < nmasters) {
// 主区域窗口
2025-10-09 13:09:40 +08:00
r = MIN(n, nmasters) - i;
if (c->master_inner_per > 0.0f) {
2025-12-10 18:32:06 +08:00
h = master_surplus_height * c->master_inner_per /
master_surplus_ratio;
master_surplus_height = master_surplus_height - h;
2025-12-10 18:32:06 +08:00
master_surplus_ratio =
master_surplus_ratio - c->master_inner_per;
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
} else {
h = (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->master_inner_per = h / (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
2025-09-26 21:30:45 +08:00
resize(c,
(struct wlr_box){.x = m->w.x + mx,
.y = m->w.y + my,
2025-10-15 15:45:04 +08:00
.width = mw,
2025-09-26 21:30:45 +08:00
.height = h},
0);
2025-10-09 13:09:40 +08:00
my += c->geom.height + cur_gappiv * ie;
2025-09-26 21:30:45 +08:00
} else {
// 堆叠区域窗口
int32_t stack_index = i - nmasters;
2025-09-26 21:30:45 +08:00
if (n - nmasters == 1) {
// 单个堆叠窗口
2025-10-09 13:09:40 +08:00
r = n - i;
2025-12-11 15:44:08 +08:00
if (c->stack_inner_per > 0.0f) {
2025-10-09 13:09:40 +08:00
h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (stack_num - 1)) *
2025-12-11 15:44:08 +08:00
c->stack_inner_per;
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
} else {
h = (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
2025-12-11 15:44:08 +08:00
c->stack_inner_per = h / (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1));
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
}
2025-09-26 21:30:45 +08:00
int32_t stack_x;
if (config.center_when_single_stack) {
2025-10-09 13:09:40 +08:00
// 放在右侧master居中时stack在右边
stack_x = m->w.x + mx + mw + cur_gappih * ie;
} else {
2025-10-09 13:09:40 +08:00
// 放在右侧master在左边时stack在右边
stack_x = m->w.x + mx + mw + cur_gappih * ie;
}
2025-09-26 21:30:45 +08:00
resize(c,
(struct wlr_box){.x = stack_x,
.y = m->w.y + ety,
2025-10-15 15:45:04 +08:00
.width = tw,
2025-09-26 21:30:45 +08:00
.height = h},
0);
2025-10-09 13:09:40 +08:00
ety += c->geom.height + cur_gappiv * ie;
2025-09-26 21:30:45 +08:00
} else {
// 多个堆叠窗口:交替放在左右两侧
2025-10-09 13:09:40 +08:00
r = (n - i + 1) / 2;
2025-09-26 21:30:45 +08:00
if ((stack_index % 2) ^ (n % 2 == 0)) {
2025-09-26 21:30:45 +08:00
// 右侧堆叠窗口
2025-12-11 15:44:08 +08:00
if (c->stack_inner_per > 0.0f) {
h = slave_right_surplus_height * c->stack_inner_per /
2025-12-10 18:32:06 +08:00
slave_right_surplus_ratio;
slave_right_surplus_height =
slave_right_surplus_height - h;
slave_right_surplus_ratio =
2025-12-11 15:44:08 +08:00
slave_right_surplus_ratio - c->stack_inner_per;
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
} else {
h = (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
2025-12-11 15:44:08 +08:00
c->stack_inner_per =
2025-10-09 13:09:40 +08:00
h / (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
int32_t stack_x = m->w.x + mx + mw + cur_gappih * ie;
2025-10-15 15:45:04 +08:00
2025-09-26 21:30:45 +08:00
resize(c,
(struct wlr_box){.x = stack_x,
.y = m->w.y + ety,
2025-10-15 15:45:04 +08:00
.width = tw,
2025-09-26 21:30:45 +08:00
.height = h},
0);
2025-10-09 13:09:40 +08:00
ety += c->geom.height + cur_gappiv * ie;
2025-09-26 21:30:45 +08:00
} else {
// 左侧堆叠窗口
2025-12-11 15:44:08 +08:00
if (c->stack_inner_per > 0.0f) {
h = slave_left_surplus_height * c->stack_inner_per /
2025-12-10 18:32:06 +08:00
slave_left_surplus_ratio;
slave_left_surplus_height =
slave_left_surplus_height - h;
slave_left_surplus_ratio =
2025-12-11 15:44:08 +08:00
slave_left_surplus_ratio - c->stack_inner_per;
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
} else {
h = (m->w.height - oty - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
2025-12-11 15:44:08 +08:00
c->stack_inner_per =
2025-10-09 13:09:40 +08:00
h / (m->w.height - oty - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
int32_t stack_x = m->w.x + cur_gappoh;
2025-09-26 21:30:45 +08:00
resize(c,
(struct wlr_box){.x = stack_x,
.y = m->w.y + oty,
2025-10-15 15:45:04 +08:00
.width = tw,
2025-09-26 21:30:45 +08:00
.height = h},
0);
2025-10-09 13:09:40 +08:00
oty += c->geom.height + cur_gappiv * ie;
2025-09-26 21:30:45 +08:00
}
}
}
i++;
}
}
void tile(Monitor *m) {
int32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty;
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_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 && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
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])
mw = m->pertag->nmasters[m->pertag->curtag]
2025-10-09 13:09:40 +08:00
? (m->w.width + cur_gappih * ie) * mfact
: 0;
else
2025-07-09 23:31:16 +08:00
mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie;
i = 0;
2025-07-09 23:31:16 +08:00
my = ty = cur_gappov;
int32_t master_surplus_height =
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1));
float master_surplus_ratio = 1.0;
int32_t slave_surplus_height =
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1));
float slave_surplus_ratio = 1.0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
2025-10-09 13:09:40 +08:00
if (c->master_inner_per > 0.0f) {
h = master_surplus_height * c->master_inner_per /
master_surplus_ratio;
master_surplus_height = master_surplus_height - h;
master_surplus_ratio =
master_surplus_ratio - c->master_inner_per;
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
} else {
h = (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->master_inner_per = h / (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
resize(c,
2025-07-09 23:31:16 +08:00
(struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + my,
2025-07-09 23:31:16 +08:00
.width = mw - cur_gappih * ie,
.height = h},
0);
2025-07-09 23:31:16 +08:00
my += c->geom.height + cur_gappiv * ie;
} else {
r = n - i;
2025-12-11 15:44:08 +08:00
if (c->stack_inner_per > 0.0f) {
h = slave_surplus_height * c->stack_inner_per /
slave_surplus_ratio;
slave_surplus_height = slave_surplus_height - h;
2025-12-11 15:44:08 +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 {
h = (m->w.height - ty - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
2025-12-11 15:44:08 +08:00
c->stack_inner_per = h / (m->w.height - ty - cur_gappov -
cur_gappiv * ie * (r - 1));
2025-10-09 13:09:40 +08:00
c->master_mfact_per = mfact;
}
2025-12-11 15:44:08 +08:00
// wlr_log(WLR_ERROR, "stack_inner_per: %f", c->stack_inner_per);
2025-10-09 13:09:40 +08:00
resize(c,
2025-07-09 23:31:16 +08:00
(struct wlr_box){.x = m->w.x + mw + cur_gappoh,
.y = m->w.y + ty,
2025-07-09 23:31:16 +08:00
.width = m->w.width - mw - 2 * cur_gappoh,
.height = h},
0);
2025-07-09 23:31:16 +08:00
ty += c->geom.height + cur_gappiv * ie;
}
i++;
}
}
2025-10-15 13:22:41 +08:00
void right_tile(Monitor *m) {
int32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty;
2025-10-15 13:22:41 +08:00
Client *c = NULL;
Client *fc = NULL;
double mfact = 0;
int32_t master_num = 0;
int32_t stack_num = 0;
2025-10-15 13:22:41 +08:00
n = m->visible_tiling_clients;
master_num = m->pertag->nmasters[m->pertag->curtag];
master_num = n > master_num ? master_num : n;
2025-10-15 13:22:41 +08:00
stack_num = n - master_num;
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;
2025-10-15 13:22:41 +08:00
cur_gappiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
2025-10-15 13:22:41 +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])
mw = m->pertag->nmasters[m->pertag->curtag]
? (m->w.width + cur_gappih * ie) * mfact
: 0;
else
mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie;
i = 0;
my = ty = cur_gappov;
int32_t master_surplus_height =
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1));
float master_surplus_ratio = 1.0;
int32_t slave_surplus_height =
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1));
float slave_surplus_ratio = 1.0;
2025-10-15 13:22:41 +08:00
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
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) {
h = master_surplus_height * c->master_inner_per /
master_surplus_ratio;
master_surplus_height = master_surplus_height - h;
master_surplus_ratio =
master_surplus_ratio - c->master_inner_per;
2025-10-15 13:22:41 +08:00
c->master_mfact_per = mfact;
} else {
h = (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->master_inner_per = h / (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
resize(c,
(struct wlr_box){.x = m->w.x + m->w.width - mw - cur_gappoh +
cur_gappih * ie,
.y = m->w.y + my,
.width = mw - cur_gappih * ie,
.height = h},
0);
my += c->geom.height + cur_gappiv * ie;
} else {
r = n - i;
2025-12-11 15:44:08 +08:00
if (c->stack_inner_per > 0.0f) {
h = slave_surplus_height * c->stack_inner_per /
slave_surplus_ratio;
slave_surplus_height = slave_surplus_height - h;
2025-12-11 15:44:08 +08:00
slave_surplus_ratio = slave_surplus_ratio - c->stack_inner_per;
2025-10-15 13:22:41 +08:00
c->master_mfact_per = mfact;
} else {
h = (m->w.height - ty - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
2025-12-11 15:44:08 +08:00
c->stack_inner_per = h / (m->w.height - ty - cur_gappov -
cur_gappiv * ie * (r - 1));
2025-10-15 13:22:41 +08:00
c->master_mfact_per = mfact;
}
2025-12-11 15:44:08 +08:00
// wlr_log(WLR_ERROR, "stack_inner_per: %f", c->stack_inner_per);
2025-10-15 13:22:41 +08:00
resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + ty,
.width = m->w.width - mw - 2 * cur_gappoh,
.height = h},
0);
ty += c->geom.height + cur_gappiv * ie;
}
i++;
}
}
void // 17
monocle(Monitor *m) {
Client *c = NULL;
2025-09-29 12:24:22 +08:00
struct wlr_box geom;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
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;
2025-09-29 12:24:22 +08:00
resize(c, geom, 0);
}
if ((c = focustop(m)))
wlr_scene_node_raise_to_top(&c->scene->node);
2026-05-16 08:23:48 +08:00
}
void 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;
// 计算最佳列数 cols = ceil(sqrt(n))
int32_t cols;
for (cols = 0; cols <= n; cols++) {
if (cols * cols >= n)
break;
}
int32_t base_rows = n / cols; // 每列的基础行数
int32_t remainder = n % cols; // 多出来的窗口,分配给前 remainder 列
// 计算标准列宽
int32_t col_width =
(m->w.width - 2 * cur_gappoh - (cols - 1) * cur_gappih) / cols;
i = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
int32_t col_idx, row_idx, rows_in_this_col;
// 判断当前窗口属于哪一列、哪一行
if (i < remainder * (base_rows + 1)) {
col_idx = i / (base_rows + 1);
row_idx = i % (base_rows + 1);
rows_in_this_col = base_rows + 1;
} else {
int32_t offset = i - remainder * (base_rows + 1);
col_idx = remainder + offset / base_rows;
row_idx = offset % base_rows;
rows_in_this_col = base_rows;
}
// 计算 X 坐标和宽度 (最后一列吃掉剩余像素,防止缝隙)
int32_t cx = m->w.x + cur_gappoh + col_idx * (col_width + cur_gappih);
int32_t cw = (col_idx == cols - 1)
? (m->w.width - 2 * cur_gappoh -
col_idx * (col_width + cur_gappih))
: col_width;
// 计算 Y 坐标和高度 (最后一行吃掉剩余像素)
int32_t base_ch = (m->w.height - 2 * cur_gappov -
(rows_in_this_col - 1) * cur_gappiv) /
rows_in_this_col;
int32_t cy = m->w.y + cur_gappov + row_idx * (base_ch + cur_gappiv);
int32_t ch = (row_idx == rows_in_this_col - 1)
? (m->w.height - 2 * cur_gappov -
row_idx * (base_ch + cur_gappiv))
: base_ch;
resize(c, (struct wlr_box){.x = cx, .y = cy, .width = cw, .height = ch},
0);
i++;
}
2026-05-09 22:07:21 +08:00
}