feat: dont resize client when in overview

This commit is contained in:
DreamMaoMao 2026-05-19 10:02:21 +08:00
parent 9e4fade55e
commit a6a765caff
9 changed files with 446 additions and 137 deletions

298
src/layout/overview.h Normal file
View file

@ -0,0 +1,298 @@
void overview_scale(Monitor *m) {
int32_t target_gappo = config.overviewgappo;
int32_t target_gappi = config.overviewgappi;
int orig_n = m->visible_clients;
if (orig_n == 0)
return;
size_t sz_c_arr = orig_n * sizeof(Client *);
size_t sz_aspects = orig_n * sizeof(float);
size_t sz_suffix_sums = (orig_n + 1) * sizeof(float);
size_t sz_best_items = orig_n * sizeof(int);
size_t sz_temp_items = orig_n * sizeof(int);
size_t sz_items = orig_n * sizeof(int);
size_t sz_A_sum = orig_n * sizeof(float);
size_t total_size = sz_c_arr + sz_aspects + sz_suffix_sums + sz_best_items +
sz_temp_items + sz_items + sz_A_sum;
void *buffer = malloc(total_size);
if (!buffer) {
return;
}
Client **c_arr = (Client **)buffer;
float *aspects = (float *)((char *)buffer + sz_c_arr);
float *suffix_sums = (float *)((char *)aspects + sz_aspects);
int *best_items_per_row = (int *)((char *)suffix_sums + sz_suffix_sums);
int *temp_items_per_row =
(int *)((char *)best_items_per_row + sz_best_items);
int *items_per_row = (int *)((char *)temp_items_per_row + sz_temp_items);
float *A_sum = (float *)((char *)items_per_row + sz_items);
int actual_n = 0;
Client *c = NULL;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal && !client_is_x11_popup(c)) {
c_arr[actual_n] = c;
float aspect = 1.0f;
if (c->overview_backup_geom.height > 0 &&
c->overview_backup_geom.width > 0) {
aspect = (float)c->overview_backup_geom.width /
c->overview_backup_geom.height;
}
if (aspect < 0.2f)
aspect = 0.2f;
if (aspect > 5.0f)
aspect = 5.0f;
aspects[actual_n] = aspect;
actual_n++;
}
}
int n = actual_n;
if (n == 0) {
free(buffer);
return;
}
suffix_sums[n] = 0.0f;
for (int i = n - 1; i >= 0; i--) {
suffix_sums[i] = suffix_sums[i + 1] + aspects[i];
}
float max_avail_w = m->w.width - 2 * target_gappo;
float max_avail_h = m->w.height - 2 * target_gappo;
if (max_avail_w < 10)
max_avail_w = 10;
if (max_avail_h < 10)
max_avail_h = 10;
int best_rows = 1;
float best_row_height = 0.0f;
best_items_per_row[0] = n;
for (int R = 1; R <= n; R++) {
int start_idx = 0;
for (int r = 0; r < R; r++) {
int rows_left = R - r;
float S_rem = suffix_sums[start_idx];
float target_sum = S_rem / rows_left;
float current_sum = 0;
int count = 0;
while (start_idx + count < n - (rows_left - 1)) {
float next_val = aspects[start_idx + count];
if (rows_left == 1) {
current_sum += next_val;
count++;
continue;
}
if (count > 0) {
float diff_without = fabs(current_sum - target_sum);
float diff_with = fabs(current_sum + next_val - target_sum);
if (diff_with > diff_without) {
break;
}
}
current_sum += next_val;
count++;
}
temp_items_per_row[r] = count;
start_idx += count;
}
float min_h_max_w = 999999.0f;
start_idx = 0;
for (int r = 0; r < R; r++) {
float row_A_sum = suffix_sums[start_idx] -
suffix_sums[start_idx + temp_items_per_row[r]];
start_idx += temp_items_per_row[r];
float gap_x_total = (temp_items_per_row[r] - 1) * target_gappi;
float w_avail = max_avail_w - gap_x_total;
if (w_avail < 1)
w_avail = 1;
float h_limit = w_avail / row_A_sum;
if (h_limit < min_h_max_w) {
min_h_max_w = h_limit;
}
}
float gap_y_total_temp = (R - 1) * target_gappi;
float h_avail = max_avail_h - gap_y_total_temp;
if (h_avail < 1)
h_avail = 1;
float h_max_h = h_avail / R;
float final_h = min_h_max_w < h_max_h ? min_h_max_w : h_max_h;
if (final_h > best_row_height) {
best_row_height = final_h;
best_rows = R;
for (int r = 0; r < R; r++) {
best_items_per_row[r] = temp_items_per_row[r];
}
}
}
int rows = best_rows;
float row_height = best_row_height;
int current_render_idx = 0;
for (int r = 0; r < rows; r++) {
items_per_row[r] = best_items_per_row[r];
A_sum[r] = suffix_sums[current_render_idx] -
suffix_sums[current_render_idx + items_per_row[r]];
current_render_idx += items_per_row[r];
}
float gap_y_total = (rows - 1) * target_gappi;
float total_layout_height = rows * row_height + gap_y_total;
float start_y = m->w.y + (m->w.height - total_layout_height) / 2.0f;
int current_idx = 0;
float current_y = start_y;
for (int r = 0; r < rows; r++) {
float row_width =
row_height * A_sum[r] + (items_per_row[r] - 1) * target_gappi;
float current_x = m->w.x + (m->w.width - row_width) / 2.0f;
for (int i = 0; i < items_per_row[r]; i++) {
Client *client = c_arr[current_idx];
float aspect = aspects[current_idx];
float client_width = row_height * aspect;
struct wlr_box client_geom;
client_geom.x = (int)(current_x + 0.5f);
client_geom.y = (int)(current_y + 0.5f);
float next_x = current_x + client_width;
client_geom.width = (int)(next_x + 0.5f) - client_geom.x;
float next_y = current_y + row_height;
client_geom.height = (int)(next_y + 0.5f) - client_geom.y;
resize(client, client_geom, 0);
current_x = next_x + target_gappi;
current_idx++;
}
current_y += row_height + target_gappi;
}
free(buffer);
}
void overview_resize(Monitor *m) {
int32_t i, n;
int32_t cx, cy, cw, ch;
int32_t dx;
int32_t cols, rows, overcols;
Client *c = NULL;
int32_t target_gappo = config.overviewgappo;
int32_t target_gappi = config.overviewgappi;
float single_width_ratio = 0.7;
float single_height_ratio = 0.8;
n = m->visible_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 && !client_is_x11_popup(c)) {
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;
c->geom.width = cw;
c->geom.height = ch;
resize(c, c->geom, 0);
return;
}
}
}
if (n == 2) {
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 && !client_is_x11_popup(c)) {
if (i == 0) {
c->geom.x = m->w.x + target_gappo;
c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
} else if (i == 1) {
c->geom.x = m->w.x + cw + target_gappo + target_gappi;
c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
}
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;
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) {
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;
if (VISIBLEON(c, m) && !c->isunglobal && !client_is_x11_popup(c)) {
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;
c->geom.x = cx + target_gappo;
c->geom.y = cy + target_gappo;
c->geom.width = cw;
c->geom.height = ch;
resize(c, c->geom, 0);
i++;
}
}
}
void overview(Monitor *m) {
if (config.ov_no_resize) {
overview_scale(m);
} else {
overview_resize(m);
}
}