From a6a765caff8f9c2988c13540e755648bbf516f5e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 19 May 2026 10:02:21 +0800 Subject: [PATCH] feat: dont resize client when in overview --- assets/config.conf | 1 + docs/window-management/overview.md | 2 + src/animation/client.h | 68 +++++-- src/config/parse_config.h | 13 +- src/dispatch/bind_define.h | 7 +- src/fetch/common.h | 36 +++- src/layout/horizontal.h | 114 ----------- src/layout/overview.h | 298 +++++++++++++++++++++++++++++ src/mango.c | 44 ++++- 9 files changed, 446 insertions(+), 137 deletions(-) create mode 100644 src/layout/overview.h diff --git a/assets/config.conf b/assets/config.conf index bc141e63..bb1ecfde 100644 --- a/assets/config.conf +++ b/assets/config.conf @@ -78,6 +78,7 @@ dwindle_preserve_split=0 hotarea_size=10 enable_hotarea=1 ov_tab_mode=0 +ov_no_resize=0 overviewgappi=5 overviewgappo=30 diff --git a/docs/window-management/overview.md b/docs/window-management/overview.md index 7da6e690..98f99c15 100644 --- a/docs/window-management/overview.md +++ b/docs/window-management/overview.md @@ -13,6 +13,7 @@ description: Configure the overview mode for window navigation. | `ov_tab_mode` | integer | `0` | Overview tab mode (0: disable, 1: enable). | | `overviewgappi` | integer | `5` | Inner gap in overview mode. | | `overviewgappo` | integer | `30` | Outer gap in overview mode. | +| `ov_no_resize` | integer | `0` | Disable window resizing in overview mode. | ### Setting Descriptions @@ -20,6 +21,7 @@ description: Configure the overview mode for window navigation. - `hotarea_size` — Size of the hot area trigger zone in pixels. - `hotarea_corner` — Corner that triggers the hot area (0: top-left, 1: top-right, 2: bottom-left, 3: bottom-right). - `ov_tab_mode` — Circles focus through windows in overview; releasing the mod key exits overview. +- `ov_no_resize` — Disables resizing of windows in overview mode(use snap to display). ### Mouse Interaction in Overview diff --git a/src/animation/client.h b/src/animation/client.h index 5a83a11e..4d408484 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -73,6 +73,14 @@ int32_t is_special_animation_rule(Client *c) { } } +void set_overview_enter_animation(Client *c) { + struct wlr_box geo = c->geom; + c->animainit_geom.width = geo.width * 1.2; + c->animainit_geom.height = geo.height * 1.2; + c->animainit_geom.x = geo.x + (geo.width - c->animainit_geom.width) / 2; + c->animainit_geom.y = geo.y + (geo.height - c->animainit_geom.height) / 2; +} + void set_client_open_animation(Client *c, struct wlr_box geo) { int32_t slide_direction; int32_t horizontal, horizontal_value; @@ -231,6 +239,19 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, buffer_data->corner_location); } +void scene_buffer_apply_overview_effect(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *data) { + BufferData *buffer_data = (BufferData *)data; + + if (buffer_data->width > 0 && buffer_data->height > 0) { + wlr_scene_buffer_set_dest_size(buffer, buffer_data->width, + buffer_data->height); + } + + wlr_scene_buffer_set_corner_radius(buffer, config.border_radius, + buffer_data->corner_location); +} + void buffer_set_effect(Client *c, BufferData data) { if (!c || c->iskilling) @@ -250,8 +271,13 @@ void buffer_set_effect(Client *c, BufferData data) { data.corner_location = CORNER_LOCATION_NONE; } - wlr_scene_node_for_each_buffer(&c->scene_surface->node, - scene_buffer_apply_effect, &data); + if (c->mon->isoverview && config.ov_no_resize) { + wlr_scene_node_for_each_buffer( + &c->scene_surface->node, scene_buffer_apply_overview_effect, &data); + } else { + wlr_scene_node_for_each_buffer(&c->scene_surface->node, + scene_buffer_apply_effect, &data); + } } void client_draw_shadow(Client *c) { @@ -793,7 +819,11 @@ void client_apply_clip(Client *c, float factor) { return; } - wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); + if (!c->mon->isoverview || !config.ov_no_resize) { + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, + &clip_box); + } + buffer_set_effect(c, (BufferData){1.0f, 1.0f, clip_box.width, clip_box.height, current_corner_location, true}); @@ -841,7 +871,9 @@ void client_apply_clip(Client *c, float factor) { } // 应用窗口表面剪切 - wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); + if (!c->mon->isoverview || !config.ov_no_resize) { + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); + } // 获取剪切后的表面的实际大小用于计算缩放 int32_t acutal_surface_width = geometry.width - offset.x - offset.width; @@ -987,6 +1019,7 @@ void client_animation_next_tick(Client *c) { c->animation.tagining = false; c->animation.running = false; + c->animation.overining = false; if (c->animation.tagouting) { c->animation.tagouting = false; @@ -1125,9 +1158,8 @@ void client_set_pending_state(Client *c) { c->animation.should_animate = false; } else if (config.animations && c->animation.tagining) { c->animation.should_animate = true; - } else if (!config.animations || c == grabc || - (!c->is_pending_open_animation && - wlr_box_equal(&c->current, &c->pending))) { + } else if (c == grabc || (!c->is_pending_open_animation && + wlr_box_equal(&c->current, &c->pending))) { c->animation.should_animate = false; } else { c->animation.should_animate = true; @@ -1201,8 +1233,11 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->animation.begin_fade_in = false; } - if (c->animation.action == OPEN && !c->animation.tagining && - !c->animation.tagouting && wlr_box_equal(&c->geom, &c->current)) { + if (c->animation.overining) { + c->animation.action = OVERVIEW; + } else if (c->animation.action == OPEN && !c->animation.tagining && + !c->animation.tagouting && + wlr_box_equal(&c->geom, &c->current)) { c->animation.action = c->animation.action; } else if (c->animation.tagouting) { c->animation.duration = config.animation_duration_tag; @@ -1241,8 +1276,10 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { } // c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局 - c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, - c->geom.height - 2 * c->bw); + if (!c->mon->isoverview || !config.ov_no_resize) { + c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, + c->geom.height - 2 * c->bw); + } if (c->configure_serial != 0) { c->mon->resizing_count_pending++; @@ -1285,6 +1322,15 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->animainit_geom = c->geom; } + if (config.animations && config.ov_no_resize && c->mon->isoverview && + c != c->mon->sel && c->animation.action == OVERVIEW) { + set_overview_enter_animation(c); + } + + if (!config.animations && config.ov_no_resize && c->mon->isoverview) { + c->animainit_geom = c->geom; + } + // 开始应用动画设置 client_set_pending_state(c); diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 9b82d81b..7c0000cb 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -252,10 +252,11 @@ typedef struct { int32_t dwindle_manual_split; float dwindle_split_ratio; - uint32_t hotarea_size; - uint32_t hotarea_corner; - uint32_t enable_hotarea; - uint32_t ov_tab_mode; + int32_t hotarea_size; + int32_t hotarea_corner; + int32_t enable_hotarea; + int32_t ov_tab_mode; + int32_t ov_no_resize; int32_t overviewgappi; int32_t overviewgappo; uint32_t cursor_hide_timeout; @@ -1655,6 +1656,8 @@ bool parse_option(Config *config, char *key, char *value) { config->enable_hotarea = atoi(value); } else if (strcmp(key, "ov_tab_mode") == 0) { config->ov_tab_mode = atoi(value); + } else if (strcmp(key, "ov_no_resize") == 0) { + config->ov_no_resize = atoi(value); } else if (strcmp(key, "overviewgappi") == 0) { config->overviewgappi = atoi(value); } else if (strcmp(key, "overviewgappo") == 0) { @@ -3237,6 +3240,7 @@ void override_config(void) { config.hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3); config.enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1); config.ov_tab_mode = CLAMP_INT(config.ov_tab_mode, 0, 1); + config.ov_no_resize = CLAMP_INT(config.ov_no_resize, 0, 1); config.overviewgappi = CLAMP_INT(config.overviewgappi, 0, 1000); config.overviewgappo = CLAMP_INT(config.overviewgappo, 0, 1000); config.xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1); @@ -3386,6 +3390,7 @@ void set_value_default() { config.capslock = 0; config.ov_tab_mode = 0; + config.ov_no_resize = 0; config.hotarea_size = 10; config.hotarea_corner = BOTTOM_LEFT; config.enable_hotarea = 1; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 2161f39b..60ebf915 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1743,15 +1743,18 @@ int32_t toggleoverview(const Arg *arg) { wl_list_for_each(c, &clients, link) { if (c && c->mon == selmon && !client_is_unmanaged(c) && - !client_is_x11_popup(c) && !c->isunglobal) + !client_is_x11_popup(c) && !c->isunglobal) { + c->animation.overining = true; overview_backup(c); + } } } else { wl_list_for_each(c, &clients, link) { if (c && c->mon == selmon && !c->iskilling && !client_is_unmanaged(c) && !c->isunglobal && - !client_is_x11_popup(c) && client_surface(c)->mapped) + !client_is_x11_popup(c) && client_surface(c)->mapped) { overview_restore(c, &(Arg){.ui = target}); + } } } diff --git a/src/fetch/common.h b/src/fetch/common.h index 57a1a8e6..aa3ae6ff 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -77,6 +77,19 @@ void get_layout_abbr(char *abbr, const char *full_name) { } } +Client *xytoclient(double x, double y) { + Client *c = NULL, *tmp = NULL; + wl_list_for_each_safe(c, tmp, &clients, link) { + if (VISIBLEON(c, c->mon) && c->animation.current.x <= x && + c->animation.current.y <= y && + c->animation.current.x + c->animation.current.width >= x && + c->animation.current.y + c->animation.current.height >= y) { + return c; + } + } + return NULL; +} + void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny) { struct wlr_scene_node *node, *pnode; @@ -84,6 +97,7 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, Client *c = NULL; LayerSurface *l = NULL; int32_t layer; + Client *ovc = NULL; for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { @@ -96,10 +110,16 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, if (!node->enabled) continue; - if (node->type == WLR_SCENE_NODE_BUFFER) - surface = wlr_scene_surface_try_from_buffer( - wlr_scene_buffer_from_node(node)) - ->surface; + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_try_from_buffer( + wlr_scene_buffer_from_node(node)); + if (scene_surface) { + surface = scene_surface->surface; + } else { + continue; + } + } /* start from the topmost layer, find a sureface that can be focused by pointer, @@ -130,4 +150,12 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, *pc = c; if (pl) *pl = l; + + if (selmon && selmon->isoverview && !l) { + ovc = xytoclient(x, y); + if (pc) + *pc = ovc; + if (psurface && ovc) + *psurface = client_surface(ovc); + } } \ No newline at end of file diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 00bea0e0..87fe2a96 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -1,117 +1,3 @@ - -// 网格布局窗口大小和位置计算 -void overview(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; - 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 && - ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(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 && - ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(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; - c->geom.width = cw; - c->geom.height = ch; - resize(c, c->geom, 0); - } 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 && - ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(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 deck(Monitor *m) { int32_t mw, my; int32_t i, n = 0; diff --git a/src/layout/overview.h b/src/layout/overview.h new file mode 100644 index 00000000..72544251 --- /dev/null +++ b/src/layout/overview.h @@ -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); + } +} \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 0ae7d3d9..7128c908 100644 --- a/src/mango.c +++ b/src/mango.c @@ -175,7 +175,7 @@ enum { }; /* EWMH atoms */ #endif enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */ -enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT }; +enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT, OVERVIEW }; enum { UNFOLD, FOLD, INVALIDFOLD }; enum { PREV, NEXT }; enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED }; @@ -279,6 +279,7 @@ struct dwl_animation { bool tagouting; bool begin_fade_in; bool tag_from_rule; + bool overining; uint32_t time_started; uint32_t duration; struct wlr_box initial; @@ -320,6 +321,7 @@ struct Client { struct wlr_scene_rect *splitindicator[4]; struct wlr_scene_shadow *shadow; struct wlr_scene_tree *scene_surface; + struct wlr_scene_tree *overview_scene_surface; struct wl_list link; struct wl_list flink; struct wl_list fadeout_link; @@ -873,6 +875,7 @@ scroller_node_create(struct TagScrollerState *st, Client *c); static void update_scroller_state(Monitor *m); Client *scroll_get_stack_tail_client(Client *c); static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c); +static void overview_backup_surface(Client *c); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -1078,6 +1081,7 @@ static struct wl_event_source *sync_keymap; #include "layout/arrange.h" #include "layout/dwindle.h" #include "layout/horizontal.h" +#include "layout/overview.h" #include "layout/scroll.h" #include "layout/vertical.h" @@ -4279,6 +4283,7 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, void init_client_properties(Client *c) { c->grid_col_per = 1.0f; c->grid_row_per = 1.0f; + c->overview_scene_surface = NULL; c->drop_direction = UNDIR; c->enable_drop_area_draw = false; c->isfocusing = false; @@ -4399,6 +4404,7 @@ mapnotify(struct wl_listener *listener, void *data) { // init client geom c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; + c->overview_backup_geom = c->geom; /* Handle unmanaged clients first so we can return prior create borders */ @@ -4484,10 +4490,15 @@ mapnotify(struct wl_listener *listener, void *data) { // apply buffer effects of client wlr_scene_node_for_each_buffer(&c->scene_surface->node, iter_xdg_scene_buffers, c); + wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); // set border color setborder_color(c); + if (c->mon->isoverview && config.ov_no_resize) { + overview_backup_surface(c); + } + // make sure the animation is open type c->is_pending_open_animation = true; resize(c, c->geom, 0); @@ -4854,7 +4865,8 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, if (config.sloppyfocus && !start_drag_window && c && time && c->scene && c->scene->node.enabled && !c->animation.tagining && - (surface != seat->pointer_state.focused_surface) && + (surface != seat->pointer_state.focused_surface || + (selmon && selmon->isoverview && selmon->sel != c)) && !client_is_unmanaged(c) && VISIBLEON(c, c->mon)) focusclient(c, 0); @@ -6061,6 +6073,23 @@ uint32_t want_restore_fullscreen(Client *target_client) { return 1; } +void overview_backup_surface(Client *c) { + struct wlr_box clip_box; + clip_box.x = 0; + clip_box.y = 0; + clip_box.width = c->geom.width - 2 * config.borderpx; + clip_box.height = c->geom.height - 2 * config.borderpx; + + c->overview_scene_surface = c->scene_surface; + wlr_scene_node_set_enabled(&c->scene_surface->node, true); + wlr_scene_node_set_position(&c->scene_surface->node, 0, 0); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); + c->scene_surface = + wlr_scene_tree_snapshot(&c->scene_surface->node, c->scene); + wlr_scene_node_set_enabled(&c->overview_scene_surface->node, false); + wlr_scene_node_set_enabled(&c->scene_surface->node, true); +} + // 普通视图切换到overview时保存窗口的旧状态 void overview_backup(Client *c) { c->overview_isfloatingbak = c->isfloating; @@ -6075,6 +6104,11 @@ void overview_backup(Client *c) { if (c->isfloating) { c->isfloating = 0; } + + if (config.ov_no_resize) { + overview_backup_surface(c); + } + if (c->isfullscreen || c->ismaximizescreen) { client_pending_fullscreen_state(c, 0); // 清除窗口全屏标志 client_pending_maximized_state(c, 0); @@ -6098,6 +6132,12 @@ void overview_restore(Client *c, const Arg *arg) { c->animation.tagining = false; c->is_restoring_from_ov = (arg->ui & c->tags & TAGMASK) == 0 ? true : false; + if (c->overview_scene_surface) { + wlr_scene_node_destroy(&c->scene_surface->node); + c->scene_surface = c->overview_scene_surface; + c->overview_scene_surface = NULL; + } + if (c->isfloating) { // XRaiseWindow(dpy, c->win); // 提升悬浮窗口到顶层 resize(c, c->overview_backup_geom, 0);