feat: fair layout
Some checks are pending
Sync website / sync-website (push) Waiting to run
Sync wiki / sync-wiki (push) Waiting to run

This commit is contained in:
DreamMaoMao 2026-05-16 08:23:48 +08:00
parent 4be9e80355
commit 58d989d218
5 changed files with 160 additions and 0 deletions

View file

@ -645,6 +645,7 @@ void client_set_drop_area(Client *c) {
bool should_swap =
(cur_layout->id == DECK || cur_layout->id == VERTICAL_DECK ||
cur_layout->id == MONOCLE || cur_layout->id == GRID ||
cur_layout->id == FAIR || cur_layout->id == VERTICAL_FAIR ||
cur_layout->id == VERTICAL_GRID) ||
((cur_layout->id == TILE || cur_layout->id == VERTICAL_TILE ||
cur_layout->id == CENTER_TILE || cur_layout->id == RIGHT_TILE) &&

View file

@ -33,6 +33,7 @@ void restore_size_per(Monitor *m, Client *c) {
if (current_layout->id == SCROLLER ||
current_layout->id == VERTICAL_SCROLLER || current_layout->id == GRID ||
current_layout->id == FAIR || current_layout->id == VERTICAL_FAIR ||
current_layout->id == VERTICAL_GRID || current_layout->id == DECK ||
current_layout->id == VERTICAL_DECK || current_layout->id == MONOCLE) {
return;

View file

@ -674,4 +674,80 @@ monocle(Monitor *m) {
}
if ((c = focustop(m)))
wlr_scene_node_raise_to_top(&c->scene->node);
}
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++;
}
}

View file

@ -12,6 +12,8 @@ static void vertical_grid(Monitor *m);
static void vertical_scroller(Monitor *m);
static void vertical_deck(Monitor *mon);
static void dwindle(Monitor *m);
static void fair(Monitor *m);
static void vertical_fair(Monitor *m);
/* layout(s) */
Layout overviewlayout = {"󰃇", overview, "overview"};
@ -29,6 +31,8 @@ enum {
VERTICAL_DECK,
RIGHT_TILE,
DWINDLE,
FAIR,
VERTICAL_FAIR,
};
Layout layouts[] = {
@ -47,4 +51,6 @@ Layout layouts[] = {
{"VG", vertical_grid, "vertical_grid", VERTICAL_GRID}, // 垂直格子布局
{"VK", vertical_deck, "vertical_deck", VERTICAL_DECK}, // 垂直卡片布局
{"DW", dwindle, "dwindle", DWINDLE},
{"F", fair, "fair", FAIR},
{"VF", vertical_fair, "vertical_fair", VERTICAL_FAIR},
};

View file

@ -281,4 +281,80 @@ void vertical_grid(Monitor *m) {
i++;
}
}
}
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++;
}
}