From d7286b0d8462bdff20c65b1dcec5ab0fad704928 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 7 Nov 2025 10:02:51 +0800 Subject: [PATCH 01/16] fix: adjust scenefx blur node feature --- src/animation/client.h | 12 +++++++++++ src/animation/common.h | 8 ++------ src/animation/layer.h | 4 ++++ src/mango.c | 46 +++++++++++++++++++++++++++--------------- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 90b664b55..e9459d55b 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -245,6 +245,13 @@ void buffer_set_effect(Client *c, BufferData data) { data.corner_location = CORNER_LOCATION_NONE; } + if (blur && !c->noblur) { + wlr_scene_blur_set_size(c->blur, c->animation.current.width - 2 * c->bw, + c->animation.current.height - 2 * c->bw); + + wlr_scene_blur_set_corner_radius(c->blur, border_radius, + data.corner_location); + } wlr_scene_node_for_each_buffer(&c->scene_surface->node, scene_buffer_apply_effect, &data); } @@ -535,6 +542,7 @@ void client_apply_clip(Client *c, float factor) { } 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}); @@ -987,6 +995,10 @@ void resize(Client *c, struct wlr_box geo, int interact) { apply_border(c); client_get_clip(c, &clip); wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); + if (blur && !c->noblur) + wlr_scene_blur_set_size(c->blur, + c->animation.current.width - 2 * c->bw, + c->animation.current.height - 2 * c->bw); return; } // 如果不是工作区切换时划出去的窗口,就让动画的结束位置,就是上面的真实位置和大小 diff --git a/src/animation/common.h b/src/animation/common.h index 06ffe1ab1..7079df867 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -158,12 +158,6 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly, scene_buffer->corner_radius, scene_buffer->corners); - // wlr_scene_buffer_set_backdrop_blur_optimized( - // snapshot_buffer, scene_buffer->backdrop_blur_optimized); - // wlr_scene_buffer_set_backdrop_blur_ignore_transparent( - // snapshot_buffer, scene_buffer->backdrop_blur_ignore_transparent); - wlr_scene_buffer_set_backdrop_blur(snapshot_buffer, false); - snapshot_buffer->node.data = scene_buffer->node.data; struct wlr_scene_surface *scene_surface = @@ -198,6 +192,8 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly, break; } + case WLR_SCENE_NODE_BLUR: + break; case WLR_SCENE_NODE_OPTIMIZED_BLUR: return true; } diff --git a/src/animation/layer.h b/src/animation/layer.h index 48ceb2118..80caec565 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -356,6 +356,10 @@ void layer_animation_next_tick(LayerSurface *l) { .height = height, }; + if (blur && blur_layer && !l->noblur && l->blur) + wlr_scene_blur_set_size(l->blur, l->animation.current.width, + l->animation.current.height); + if (animation_passed >= 1.0) { l->animation.running = false; l->need_output_flush = false; diff --git a/src/mango.c b/src/mango.c index 36cbbbfa7..69208d635 100644 --- a/src/mango.c +++ b/src/mango.c @@ -276,6 +276,7 @@ struct Client { struct wlr_scene_tree *scene; struct wlr_scene_rect *border; /* top, bottom, left, right */ struct wlr_scene_shadow *shadow; + struct wlr_scene_blur *blur; struct wlr_scene_tree *scene_surface; struct wl_list link; struct wl_list flink; @@ -405,6 +406,7 @@ typedef struct { struct wlr_scene_tree *scene; struct wlr_scene_tree *popups; struct wlr_scene_shadow *shadow; + struct wlr_scene_blur *blur; struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wl_list fadeout_link; @@ -2081,12 +2083,16 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, return; } - wlr_scene_buffer_set_backdrop_blur(buffer, true); - wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, true); + LayerSurface *l = (LayerSurface *)user_data; + + wlr_scene_node_set_enabled(&l->blur->node, true); + wlr_scene_blur_set_transparency_mask_source(l->blur, buffer); + wlr_scene_blur_set_size(l->blur, l->geom.width, l->geom.height); + if (blur_optimized) { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true); + wlr_scene_blur_set_should_only_blur_bottom_layer(l->blur, true); } else { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); + wlr_scene_blur_set_should_only_blur_bottom_layer(l->blur, false); } } @@ -2131,13 +2137,17 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { } // 初始化阴影 - if (layer_surface->current.exclusive_zone == 0 && - layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && + if (layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { - l->shadow = wlr_scene_shadow_create(l->scene, 0, 0, border_radius, - shadows_blur, shadowscolor); - wlr_scene_node_lower_to_bottom(&l->shadow->node); - wlr_scene_node_set_enabled(&l->shadow->node, true); + if (layer_surface->current.exclusive_zone == 0) { + l->shadow = wlr_scene_shadow_create(l->scene, 0, 0, border_radius, + shadows_blur, shadowscolor); + wlr_scene_node_lower_to_bottom(&l->shadow->node); + wlr_scene_node_set_enabled(&l->shadow->node, true); + } + + l->blur = wlr_scene_blur_create(l->scene, 0, 0); + wlr_scene_node_lower_to_bottom(&l->blur->node); } // 初始化动画 @@ -2194,7 +2204,8 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { if (!l->noblur && layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && layer_surface->current.layer != - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND && + l->blur) { wlr_scene_node_for_each_buffer(&l->scene->node, iter_layer_scene_buffers, l); @@ -3521,15 +3532,15 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, return; if (blur && c && !c->noblur) { - wlr_scene_buffer_set_backdrop_blur(buffer, true); - wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, false); + wlr_scene_node_set_enabled(&c->blur->node, true); + // wlr_scene_blur_set_transparency_mask_source(c->blur, buffer); if (blur_optimized) { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true); + wlr_scene_blur_set_should_only_blur_bottom_layer(c->blur, true); } else { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); + wlr_scene_blur_set_should_only_blur_bottom_layer(c->blur, false); } } else { - wlr_scene_buffer_set_backdrop_blur(buffer, false); + wlr_scene_node_set_enabled(&c->blur->node, false); } } @@ -3642,6 +3653,9 @@ mapnotify(struct wl_listener *listener, void *data) { c->shadow = wlr_scene_shadow_create(c->scene, 0, 0, border_radius, shadows_blur, shadowscolor); + c->blur = wlr_scene_blur_create(c->scene_surface, 0, 0); + wlr_scene_node_lower_to_bottom(&c->blur->node); + wlr_scene_node_lower_to_bottom(&c->shadow->node); wlr_scene_node_set_enabled(&c->shadow->node, true); From 358591f16a876a5b6d252d2e44b6faa09f703e47 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 19:59:05 +0800 Subject: [PATCH 02/16] fix: blur node size and position are wrong --- src/animation/client.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index e9459d55b..3792358d4 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -246,9 +246,6 @@ void buffer_set_effect(Client *c, BufferData data) { } if (blur && !c->noblur) { - wlr_scene_blur_set_size(c->blur, c->animation.current.width - 2 * c->bw, - c->animation.current.height - 2 * c->bw); - wlr_scene_blur_set_corner_radius(c->blur, border_radius, data.corner_location); } @@ -352,6 +349,14 @@ void client_draw_shadow(Client *c) { wlr_scene_shadow_set_clipped_region(c->shadow, clipped_region); } +void client_draw_blur(Client *c, struct wlr_box clip_box, struct ivec2 offset) { + if (blur && !c->noblur) { + wlr_scene_node_set_position(&c->blur->node, offset.x, offset.y); + wlr_scene_blur_set_size(c->blur, clip_box.width - c->bw, + clip_box.height - c->bw); + } +} + void apply_border(Client *c) { if (!c || c->iskilling || !client_surface(c)->mapped) return; @@ -536,6 +541,7 @@ void client_apply_clip(Client *c, float factor) { apply_border(c); client_draw_shadow(c); + client_draw_blur(c, clip_box, offset); if (clip_box.width <= 0 || clip_box.height <= 0) { return; @@ -574,6 +580,7 @@ void client_apply_clip(Client *c, float factor) { // 应用窗口装饰 apply_border(c); client_draw_shadow(c); + client_draw_blur(c, clip_box, offset); // 如果窗口剪切区域已经剪切到0,则不渲染窗口表面 if (clip_box.width <= 0 || clip_box.height <= 0) { From d8583b1224a7fbb7f6b5a97839683c54985917b4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 19 Nov 2025 11:10:05 +0800 Subject: [PATCH 03/16] fix: Fix blur lag --- src/mango.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 69208d635..80ad2415a 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2086,7 +2086,8 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, LayerSurface *l = (LayerSurface *)user_data; wlr_scene_node_set_enabled(&l->blur->node, true); - wlr_scene_blur_set_transparency_mask_source(l->blur, buffer); + wlr_scene_blur_set_mask_source(l->blur, &buffer->node, + BLUR_MASK_IGNORE_TRANSPARENCY); wlr_scene_blur_set_size(l->blur, l->geom.width, l->geom.height); if (blur_optimized) { @@ -3533,7 +3534,6 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, if (blur && c && !c->noblur) { wlr_scene_node_set_enabled(&c->blur->node, true); - // wlr_scene_blur_set_transparency_mask_source(c->blur, buffer); if (blur_optimized) { wlr_scene_blur_set_should_only_blur_bottom_layer(c->blur, true); } else { From fc677558f88a51d55e37f2805e291ccb30729209 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 19 Nov 2025 11:36:38 +0800 Subject: [PATCH 04/16] opt: set fadein blur to no blur_optimize --- src/animation/client.h | 10 ++++++++++ src/animation/layer.h | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/animation/client.h b/src/animation/client.h index 3792358d4..56bf43287 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1137,6 +1137,16 @@ bool client_apply_focus_opacity(Client *c) { target_opacity = opacity; } client_set_opacity(c, target_opacity); + if (blur && !c->noblur && !blur_optimized) { + wlr_scene_blur_set_strength( + c->blur, MIN(percent * (1.0 - fadein_begin_opacity) + + fadein_begin_opacity, + 1.0)); + wlr_scene_blur_set_alpha( + c->blur, MIN(percent * (1.0 - fadein_begin_opacity) + + fadein_begin_opacity, + 1.0)); + } } else if (animations && c->opacity_animation.running) { struct timespec now; diff --git a/src/animation/layer.h b/src/animation/layer.h index 80caec565..aa9f0479d 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -326,9 +326,14 @@ void layer_animation_next_tick(LayerSurface *l) { animation_passed * (1.0 - fadein_begin_opacity), 1.0f); - if (animation_fade_in) + if (animation_fade_in) { + if (blur && !l->noblur && !blur_optimized) { + wlr_scene_blur_set_strength(l->blur, opacity); + wlr_scene_blur_set_alpha(l->blur, opacity); + } wlr_scene_node_for_each_buffer(&l->scene->node, scene_buffer_apply_opacity, &opacity); + } wlr_scene_node_set_position(&l->scene->node, x, y); From c934afcd4a7eb0c5669b1335cb059506d954d43c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 09:54:45 +0800 Subject: [PATCH 05/16] chase: chase scenefx api change --- src/animation/client.h | 44 +++++++++++++++++++++--------------------- src/animation/common.h | 5 ++--- src/animation/layer.h | 3 +-- src/config/preset.h | 1 - src/mango.c | 11 +++++------ 5 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 56bf43287..c1382a1b1 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -8,22 +8,27 @@ void set_rect_size(struct wlr_scene_rect *rect, int width, int height) { wlr_scene_rect_set_size(rect, GEZERO(width), GEZERO(height)); } -enum corner_location set_client_corner_location(Client *c) { - enum corner_location current_corner_location = CORNER_LOCATION_ALL; +struct fx_corner_radii set_client_corner_location(Client *c) { + struct fx_corner_radii current_corner_location = + corner_radii_all(border_radius); struct wlr_box target_geom = animations ? c->animation.current : c->geom; if (target_geom.x + border_radius <= c->mon->m.x) { - current_corner_location &= ~CORNER_LOCATION_LEFT; // 清除左标志位 + current_corner_location.top_left = 0; // 清除左标志位 + current_corner_location.bottom_left = 0; // 清除左标志位 } if (target_geom.x + target_geom.width - border_radius >= c->mon->m.x + c->mon->m.width) { - current_corner_location &= ~CORNER_LOCATION_RIGHT; // 清除右标志位 + current_corner_location.top_right = 0; // 清除右标志位 + current_corner_location.bottom_right = 0; // 清除右标志位 } if (target_geom.y + border_radius <= c->mon->m.y) { - current_corner_location &= ~CORNER_LOCATION_TOP; // 清除上标志位 + current_corner_location.top_left = 0; // 清除上标志位 + current_corner_location.top_right = 0; // 清除上标志位 } if (target_geom.y + target_geom.height - border_radius >= c->mon->m.y + c->mon->m.height) { - current_corner_location &= ~CORNER_LOCATION_BOTTOM; // 清除下标志位 + current_corner_location.bottom_left = 0; // 清除下标志位 + current_corner_location.bottom_right = 0; // 清除下标志位 } return current_corner_location; } @@ -223,8 +228,7 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy, if (wlr_xdg_popup_try_from_wlr_surface(surface) != NULL) return; - wlr_scene_buffer_set_corner_radius(buffer, border_radius, - buffer_data->corner_location); + wlr_scene_buffer_set_corner_radii(buffer, buffer_data->corner_location); } void buffer_set_effect(Client *c, BufferData data) { @@ -242,12 +246,11 @@ void buffer_set_effect(Client *c, BufferData data) { if (c->isfullscreen || (no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1)) { - data.corner_location = CORNER_LOCATION_NONE; + data.corner_location = corner_radii_none(); } if (blur && !c->noblur) { - wlr_scene_blur_set_corner_radius(c->blur, border_radius, - data.corner_location); + wlr_scene_blur_set_corner_radii(c->blur, data.corner_location); } wlr_scene_node_for_each_buffer(&c->scene_surface->node, scene_buffer_apply_effect, &data); @@ -264,11 +267,11 @@ void client_draw_shadow(Client *c) { } bool hit_no_border = check_hit_no_border(c); - enum corner_location current_corner_location = + struct fx_corner_radii current_corner_location = c->isfullscreen || (no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1) - ? CORNER_LOCATION_NONE - : CORNER_LOCATION_ALL; + ? corner_radii_none() + : set_client_corner_location(c); unsigned int bwoffset = c->bw != 0 && hit_no_border ? c->bw : 0; @@ -301,7 +304,6 @@ void client_draw_shadow(Client *c) { struct clipped_region clipped_region = { .area = intersection_box, - .corner_radius = border_radius, .corners = current_corner_location, }; @@ -362,11 +364,11 @@ void apply_border(Client *c) { return; bool hit_no_border = check_hit_no_border(c); - enum corner_location current_corner_location = + struct fx_corner_radii current_corner_location = c->isfullscreen || (no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1) - ? CORNER_LOCATION_NONE - : CORNER_LOCATION_ALL; + ? corner_radii_none() + : set_client_corner_location(c); // Handle no-border cases if (hit_no_border && smartgaps) { @@ -438,15 +440,13 @@ void apply_border(Client *c) { struct clipped_region clipped_region = { .area = {inner_surface_x, inner_surface_y, inner_surface_width, inner_surface_height}, - .corner_radius = border_radius, .corners = current_corner_location, }; wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); wlr_scene_rect_set_size(c->border, rect_width, rect_height); wlr_scene_node_set_position(&c->border->node, rect_x, rect_y); - wlr_scene_rect_set_corner_radius(c->border, border_radius, - current_corner_location); + wlr_scene_rect_set_corner_radii(c->border, current_corner_location); wlr_scene_rect_set_clipped_region(c->border, clipped_region); } @@ -524,7 +524,7 @@ void client_apply_clip(Client *c, float factor) { struct ivec2 offset; BufferData buffer_data; - enum corner_location current_corner_location = + struct fx_corner_radii current_corner_location = set_client_corner_location(c); int bw = (int)c->bw; diff --git a/src/animation/common.h b/src/animation/common.h index 7079df867..8f15010f3 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -154,9 +154,8 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly, // Effects wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity); - wlr_scene_buffer_set_corner_radius(snapshot_buffer, - scene_buffer->corner_radius, - scene_buffer->corners); + wlr_scene_buffer_set_corner_radii(snapshot_buffer, + scene_buffer->corners); snapshot_buffer->node.data = scene_buffer->node.data; diff --git a/src/animation/layer.h b/src/animation/layer.h index aa9f0479d..e21924bf8 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -191,8 +191,7 @@ void layer_draw_shadow(LayerSurface *l) { struct clipped_region clipped_region = { .area = intersection_box, - .corner_radius = border_radius, - .corners = border_radius_location_default, + .corners = corner_radii_all(border_radius), }; wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y); diff --git a/src/config/preset.h b/src/config/preset.h index 2f994ec17..bbeaf3079 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -204,7 +204,6 @@ float focused_opacity = 1.0; float unfocused_opacity = 1.0; int border_radius = 0; -int border_radius_location_default = CORNER_LOCATION_ALL; int blur = 0; int blur_layer = 0; int blur_optimized = 1; diff --git a/src/mango.c b/src/mango.c index 80ad2415a..f8021be7e 100644 --- a/src/mango.c +++ b/src/mango.c @@ -262,7 +262,7 @@ typedef struct { float height_scale; int width; int height; - enum corner_location corner_location; + struct fx_corner_radii corner_location; bool should_scale; } BufferData; @@ -369,6 +369,7 @@ struct Client { bool isleftstack; int tearing_hint; int force_tearing; + int border_radius; }; typedef struct { @@ -694,7 +695,7 @@ static double find_animation_curve_at(double t, int type); static void apply_opacity_to_rect_nodes(Client *c, struct wlr_scene_node *node, double animation_passed); -static enum corner_location set_client_corner_location(Client *c); +static struct fx_corner_radii set_client_corner_location(Client *c); static double all_output_frame_duration_ms(); static struct wlr_scene_tree * wlr_scene_tree_snapshot(struct wlr_scene_node *node, @@ -2086,8 +2087,7 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, LayerSurface *l = (LayerSurface *)user_data; wlr_scene_node_set_enabled(&l->blur->node, true); - wlr_scene_blur_set_mask_source(l->blur, &buffer->node, - BLUR_MASK_IGNORE_TRANSPARENCY); + wlr_scene_blur_set_transparency_mask_source(l->blur, buffer); wlr_scene_blur_set_size(l->blur, l->geom.width, l->geom.height); if (blur_optimized) { @@ -3646,8 +3646,7 @@ mapnotify(struct wl_listener *listener, void *data) { c->isurgent ? urgentcolor : bordercolor); wlr_scene_node_lower_to_bottom(&c->border->node); wlr_scene_node_set_position(&c->border->node, 0, 0); - wlr_scene_rect_set_corner_radius(c->border, border_radius, - border_radius_location_default); + wlr_scene_rect_set_corner_radii(c->border, corner_radii_all(border_radius)); wlr_scene_node_set_enabled(&c->border->node, true); c->shadow = wlr_scene_shadow_create(c->scene, 0, 0, border_radius, From 6c166387538bd953095986b12166d6a127d173af Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 11:06:12 +0800 Subject: [PATCH 06/16] opt: flush the blur background cache when unmap a background layer --- src/mango.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/mango.c b/src/mango.c index d53df0c6a..d3400d583 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2281,6 +2281,19 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, } } +void layer_flush_blur_background(LayerSurface *l) { + if (!blur) + return; + + // 如果背景层发生变化,标记优化的模糊背景缓存需要更新 + if (l->layer_surface->current.layer == + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { + if (l->mon) { + wlr_scene_optimized_blur_mark_dirty(l->mon->blur); + } + } +} + void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, map); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; @@ -2413,15 +2426,7 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { } } - if (blur) { - // 如果背景层发生变化,标记优化的模糊背景缓存需要更新 - if (layer_surface->current.layer == - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { - if (l->mon) { - wlr_scene_optimized_blur_mark_dirty(l->mon->blur); - } - } - } + layer_flush_blur_background(l); if (layer_surface == exclusive_focus && layer_surface->current.keyboard_interactive != @@ -5655,6 +5660,7 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); l->being_unmapped = false; + layer_flush_blur_background(l); wlr_scene_node_destroy(&l->shadow->node); l->shadow = NULL; } From 4f3e6545bf6a15bb684afc58e72acf83eae1e826 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 11:11:46 +0800 Subject: [PATCH 07/16] fix: remove the useless code --- src/mango.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index d3400d583..c96c2357b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include From 3b535d4005b0486d918913b3128554e56dd154a5 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 13:16:57 +0800 Subject: [PATCH 08/16] mix: add window share and fix xcursor,text-input,ext-workspace --- meson.build | 5 +- src/ext-protocol/ext-workspace.h | 108 ++- src/ext-protocol/text-input.h | 22 +- src/ext-protocol/wlr_ext_workspace_v1.c | 997 ------------------------ src/ext-protocol/wlr_ext_workspace_v1.h | 106 --- src/fetch/monitor.h | 9 + src/mango.c | 86 +- 7 files changed, 163 insertions(+), 1170 deletions(-) delete mode 100644 src/ext-protocol/wlr_ext_workspace_v1.c delete mode 100644 src/ext-protocol/wlr_ext_workspace_v1.h diff --git a/meson.build b/meson.build index 478ef0e6b..f6f6d6f91 100644 --- a/meson.build +++ b/meson.build @@ -33,12 +33,12 @@ libm = cc.find_library('m') xcb = dependency('xcb', required : get_option('xwayland')) xlibs = dependency('xcb-icccm', required : get_option('xwayland')) wayland_server_dep = dependency('wayland-server',version: '>=1.23.1') -wlroots_dep = dependency('wlroots-0.19',version: '>=0.19.0') +wlroots_dep = dependency('wlroots-0.20',version: '>=0.20.0') xkbcommon_dep = dependency('xkbcommon') libinput_dep = dependency('libinput',version: '>=1.27.1') libwayland_client_dep = dependency('wayland-client') pcre2_dep = dependency('libpcre2-8') -libscenefx_dep = dependency('scenefx-0.4',version: '>=0.4.1') +libscenefx_dep = dependency('scenefx-0.5',version: '>=0.5.0') # 获取版本信息 @@ -97,7 +97,6 @@ endif executable('mango', 'src/mango.c', 'src/common/util.c', - 'src/ext-protocol/wlr_ext_workspace_v1.c', wayland_sources, dependencies : [ libm, diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 28aaeeeb7..82b7ef1f2 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -1,4 +1,4 @@ -#include "wlr_ext_workspace_v1.h" +#include #define EXT_WORKSPACE_ENABLE_CAPS \ EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ACTIVATE | \ @@ -7,20 +7,20 @@ typedef struct Monitor Monitor; struct workspace { - struct wl_list link; // Link in global workspaces list - uint32_t tag; // Numeric identifier (1-9, 0=overview) - Monitor *m; // Associated monitor - struct wlr_ext_workspace_handle_v1 *ext_workspace; // Protocol object - /* Event listeners */ - struct wl_listener activate; - struct wl_listener deactivate; - struct wl_listener assign; - struct wl_listener remove; + struct wl_list link; + uint32_t tag; + Monitor *m; + struct wlr_ext_workspace_handle_v1 *ext_workspace; + struct wl_listener commit; }; struct wlr_ext_workspace_manager_v1 *ext_manager; struct wl_list workspaces; +static void handle_ext_commit(struct wl_listener *listener, void *data); +static struct wl_listener ext_manager_commit_listener = {.notify = + handle_ext_commit}; + void goto_workspace(struct workspace *target) { uint32_t tag; tag = 1 << (target->tag - 1); @@ -43,30 +43,60 @@ void toggle_workspace(struct workspace *target) { } } -static void handle_ext_workspace_activate(struct wl_listener *listener, - void *data) { - struct workspace *workspace = - wl_container_of(listener, workspace, activate); +static void handle_ext_commit(struct wl_listener *listener, void *data) { + struct wlr_ext_workspace_v1_commit_event *event = data; + struct wlr_ext_workspace_v1_request *request; - if (workspace->m->isoverview) { - return; - } + wl_list_for_each(request, event->requests, link) { + switch (request->type) { + case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE: { + if (!request->activate.workspace) { + break; + } - goto_workspace(workspace); - wlr_log(WLR_INFO, "ext activating workspace %d", workspace->tag); -} + struct workspace *workspace = NULL; + struct workspace *w; + wl_list_for_each(w, &workspaces, link) { + if (w->ext_workspace == request->activate.workspace) { + workspace = w; + break; + } + } -static void handle_ext_workspace_deactivate(struct wl_listener *listener, - void *data) { - struct workspace *workspace = - wl_container_of(listener, workspace, deactivate); + if (!workspace || workspace->m->isoverview) { + break; + } - if (workspace->m->isoverview) { - return; - } + goto_workspace(workspace); + wlr_log(WLR_INFO, "ext activating workspace %d", workspace->tag); + break; + } + case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE: { + if (!request->deactivate.workspace) { + break; + } - toggle_workspace(workspace); - wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag); + struct workspace *workspace = NULL; + struct workspace *w; + wl_list_for_each(w, &workspaces, link) { + if (w->ext_workspace == request->deactivate.workspace) { + workspace = w; + break; + } + } + + if (!workspace || workspace->m->isoverview) { + break; + } + + toggle_workspace(workspace); + wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag); + break; + } + default: + break; + } + } } static const char *get_name_from_tag(uint32_t tag) { @@ -76,8 +106,6 @@ static const char *get_name_from_tag(uint32_t tag) { } void destroy_workspace(struct workspace *workspace) { - wl_list_remove(&workspace->activate.link); - wl_list_remove(&workspace->deactivate.link); wlr_ext_workspace_handle_v1_destroy(workspace->ext_workspace); wl_list_remove(&workspace->link); free(workspace); @@ -112,17 +140,12 @@ static void add_workspace_by_tag(int32_t tag, Monitor *m) { workspace->m = m; workspace->ext_workspace = wlr_ext_workspace_handle_v1_create( ext_manager, name, EXT_WORKSPACE_ENABLE_CAPS); + + workspace->ext_workspace->data = workspace; + wlr_ext_workspace_handle_v1_set_group(workspace->ext_workspace, m->ext_group); wlr_ext_workspace_handle_v1_set_name(workspace->ext_workspace, name); - - workspace->activate.notify = handle_ext_workspace_activate; - wl_signal_add(&workspace->ext_workspace->events.activate, - &workspace->activate); - - workspace->deactivate.notify = handle_ext_workspace_deactivate; - wl_signal_add(&workspace->ext_workspace->events.deactivate, - &workspace->deactivate); } void dwl_ext_workspace_printstatus(Monitor *m) { @@ -165,10 +188,10 @@ void refresh_monitors_workspaces_status(Monitor *m) { int32_t i; if (m->isoverview) { + add_workspace_by_tag(0, m); for (i = 1; i <= LENGTH(tags); i++) { remove_workspace_by_tag(i, m); } - add_workspace_by_tag(0, m); } else { remove_workspace_by_tag(0, m); for (i = 1; i <= LENGTH(tags); i++) { @@ -180,8 +203,9 @@ void refresh_monitors_workspaces_status(Monitor *m) { } void workspaces_init() { - /* Create the global workspace manager with activation capability */ ext_manager = wlr_ext_workspace_manager_v1_create(dpy, 1); - /* Initialize the global workspaces list */ + wl_list_init(&workspaces); + + wl_signal_add(&ext_manager->events.commit, &ext_manager_commit_listener); } \ No newline at end of file diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index dbd97e11f..7b4e1a1fd 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -77,15 +77,6 @@ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) { return NULL; } -Monitor *output_nearest_to(int32_t lx, int32_t ly) { - double closest_x, closest_y; - wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, - &closest_y); - - return output_from_wlr_output( - wlr_output_layout_output_at(output_layout, closest_x, closest_y)); -} - bool output_is_usable(Monitor *m) { return m && m->wlr_output->enabled; } static bool @@ -255,7 +246,7 @@ static void update_popup_position(struct dwl_input_method_popup *popup) { cursor_rect = (struct wlr_box){0}; } - output = output_nearest_to(cursor_rect.x, cursor_rect.y); + output = get_monitor_nearest_to(cursor_rect.x, cursor_rect.y); if (!output_is_usable(output)) { return; } @@ -301,9 +292,8 @@ static void handle_input_method_commit(struct wl_listener *listener, void *data) { struct dwl_input_method_relay *relay = wl_container_of(listener, relay, input_method_commit); - struct wlr_input_method_v2 *input_method = data; struct text_input *text_input; - assert(relay->input_method == input_method); + struct wlr_input_method_v2 *input_method = relay->input_method; text_input = relay->active_text_input; if (!text_input) { @@ -333,7 +323,8 @@ static void handle_keyboard_grab_destroy(struct wl_listener *listener, void *data) { struct dwl_input_method_relay *relay = wl_container_of(listener, relay, keyboard_grab_destroy); - struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = + relay->input_method->keyboard_grab; wl_list_remove(&relay->keyboard_grab_destroy.link); if (keyboard_grab->keyboard) { @@ -365,7 +356,6 @@ static void handle_input_method_destroy(struct wl_listener *listener, void *data) { struct dwl_input_method_relay *relay = wl_container_of(listener, relay, input_method_destroy); - assert(relay->input_method == data); wl_list_remove(&relay->input_method_commit.link); wl_list_remove(&relay->input_method_grab_keyboard.link); wl_list_remove(&relay->input_method_new_popup_surface.link); @@ -571,11 +561,11 @@ struct dwl_input_method_relay *dwl_im_relay_create() { relay->popup_tree = wlr_scene_tree_create(&scene->tree); relay->new_text_input.notify = handle_new_text_input; - wl_signal_add(&text_input_manager->events.text_input, + wl_signal_add(&text_input_manager->events.new_text_input, &relay->new_text_input); relay->new_input_method.notify = handle_new_input_method; - wl_signal_add(&input_method_manager->events.input_method, + wl_signal_add(&input_method_manager->events.new_input_method, &relay->new_input_method); relay->focused_surface_destroy.notify = handle_focused_surface_destroy; diff --git a/src/ext-protocol/wlr_ext_workspace_v1.c b/src/ext-protocol/wlr_ext_workspace_v1.c deleted file mode 100644 index 2d781b346..000000000 --- a/src/ext-protocol/wlr_ext_workspace_v1.c +++ /dev/null @@ -1,997 +0,0 @@ -// bash on: https://gitlab.freedesktop.org/tokyo4j/wlroots/-/tree/ext-workspace -// TODO: remove this file -// refer: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5115 - -#include "wlr_ext_workspace_v1.h" -#include "ext-workspace-v1-protocol.h" -#include -#include -#include -#include - -#define EXT_WORKSPACE_V1_VERSION 1 - -enum wlr_ext_workspace_v1_request_type { - WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE, - WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE, - WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE, - WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN, - WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE, -}; - -struct wlr_ext_workspace_v1_request { - enum wlr_ext_workspace_v1_request_type type; - - // CREATE_WORKSPACE - char *name; - // CREATE_WORKSPACE / ASSIGN - struct wlr_ext_workspace_group_handle_v1 *group; - // ACTIVATE / DEACTIVATE / ASSIGN / REMOVE - struct wlr_ext_workspace_handle_v1 *workspace; - - struct wl_list link; // wlr_ext_workspace_manager_v1_resource.requests -}; - -struct wlr_ext_workspace_v1_group_output { - struct wlr_output *output; - struct wlr_ext_workspace_group_handle_v1 *group; - struct wl_listener output_bind; - struct wl_listener output_destroy; - struct wl_list link; -}; - -// These structs wrap wl_resource of each interface to access the request queue -// (wlr_ext_workspace_manager_v1_resource.requests) assigned per manager -// resource - -struct wlr_ext_workspace_manager_v1_resource { - struct wl_resource *resource; - struct wlr_ext_workspace_manager_v1 *manager; - struct wl_list requests; // wlr_ext_workspace_v1_request.link - struct wl_list workspace_resources; // wlr_ext_workspace_v1_resource.link - struct wl_list group_resources; // wlr_ext_workspace_group_v1_resource.link - struct wl_list link; // wlr_ext_workspace_manager_v1.resources -}; - -struct wlr_ext_workspace_group_v1_resource { - struct wl_resource *resource; - struct wlr_ext_workspace_group_handle_v1 *group; - struct wlr_ext_workspace_manager_v1_resource *manager; - struct wl_list link; // wlr_ext_workspace_group_v1.resources - struct wl_list - manager_resource_link; // wlr_ext_workspace_manager_v1_resource.group_resources -}; - -struct wlr_ext_workspace_v1_resource { - struct wl_resource *resource; - struct wlr_ext_workspace_handle_v1 *workspace; - struct wlr_ext_workspace_manager_v1_resource *manager; - struct wl_list link; // wlr_ext_workspace_v1.resources - struct wl_list - manager_resource_link; // wlr_ext_workspace_manager_v1_resource.workspace_resources -}; - -static const struct ext_workspace_group_handle_v1_interface group_impl; - -static struct wlr_ext_workspace_group_v1_resource * -group_resource_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of( - resource, &ext_workspace_group_handle_v1_interface, &group_impl)); - return wl_resource_get_user_data(resource); -} - -static const struct ext_workspace_handle_v1_interface workspace_impl; - -static struct wlr_ext_workspace_v1_resource * -workspace_resource_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &ext_workspace_handle_v1_interface, - &workspace_impl)); - return wl_resource_get_user_data(resource); -} - -static const struct ext_workspace_manager_v1_interface manager_impl; - -static struct wlr_ext_workspace_manager_v1_resource * -manager_resource_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of( - resource, &ext_workspace_manager_v1_interface, &manager_impl)); - return wl_resource_get_user_data(resource); -} - -static void workspace_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void workspace_handle_activate(struct wl_client *client, - struct wl_resource *workspace_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - if (!workspace_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE; - req->workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static void -workspace_handle_deactivate(struct wl_client *client, - struct wl_resource *workspace_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - if (!workspace_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE; - req->workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static void workspace_handle_assign(struct wl_client *client, - struct wl_resource *workspace_resource, - struct wl_resource *group_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - struct wlr_ext_workspace_group_v1_resource *group_res = - group_resource_from_resource(group_resource); - if (!workspace_res || !group_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN; - req->group = group_res->group; - req->workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static void workspace_handle_remove(struct wl_client *client, - struct wl_resource *workspace_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - if (!workspace_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE; - req->workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static const struct ext_workspace_handle_v1_interface workspace_impl = { - .destroy = workspace_handle_destroy, - .activate = workspace_handle_activate, - .deactivate = workspace_handle_deactivate, - .assign = workspace_handle_assign, - .remove = workspace_handle_remove, -}; - -static void group_handle_create_workspace(struct wl_client *client, - struct wl_resource *group_resource, - const char *name) { - struct wlr_ext_workspace_group_v1_resource *group_res = - group_resource_from_resource(group_resource); - if (!group_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(group_resource); - return; - } - req->name = strdup(name); - if (!req->name) { - free(req); - wl_resource_post_no_memory(group_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE; - req->group = group_res->group; - wl_list_insert(group_res->manager->requests.prev, &req->link); -} - -static void group_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static const struct ext_workspace_group_handle_v1_interface group_impl = { - .create_workspace = group_handle_create_workspace, - .destroy = group_handle_destroy, -}; - -static void destroy_workspace_resource( - struct wlr_ext_workspace_v1_resource *workspace_res) { - wl_list_remove(&workspace_res->link); - wl_list_remove(&workspace_res->manager_resource_link); - wl_resource_set_user_data(workspace_res->resource, NULL); - free(workspace_res); -} - -static void workspace_resource_destroy(struct wl_resource *resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(resource); - if (workspace_res) { - destroy_workspace_resource(workspace_res); - } -} - -static struct wlr_ext_workspace_v1_resource *create_workspace_resource( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_manager_v1_resource *manager_res) { - struct wlr_ext_workspace_v1_resource *workspace_res = - calloc(1, sizeof(*workspace_res)); - if (!workspace_res) { - return NULL; - } - - struct wl_client *client = wl_resource_get_client(manager_res->resource); - workspace_res->resource = - wl_resource_create(client, &ext_workspace_handle_v1_interface, - wl_resource_get_version(manager_res->resource), 0); - if (!workspace_res->resource) { - free(workspace_res); - return NULL; - } - wl_resource_set_implementation(workspace_res->resource, &workspace_impl, - workspace_res, workspace_resource_destroy); - - workspace_res->workspace = workspace; - workspace_res->manager = manager_res; - wl_list_insert(&workspace->resources, &workspace_res->link); - wl_list_insert(&manager_res->workspace_resources, - &workspace_res->manager_resource_link); - - return workspace_res; -} - -static void -destroy_group_resource(struct wlr_ext_workspace_group_v1_resource *group_res) { - wl_list_remove(&group_res->link); - wl_list_remove(&group_res->manager_resource_link); - wl_resource_set_user_data(group_res->resource, NULL); - free(group_res); -} - -static void group_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_ext_workspace_group_v1_resource *group_res = - group_resource_from_resource(resource); - if (group_res) { - destroy_group_resource(group_res); - } -} - -static struct wlr_ext_workspace_group_v1_resource *create_group_resource( - struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_ext_workspace_manager_v1_resource *manager_res) { - struct wlr_ext_workspace_group_v1_resource *group_res = - calloc(1, sizeof(*group_res)); - if (!group_res) { - return NULL; - } - - struct wl_client *client = wl_resource_get_client(manager_res->resource); - uint32_t version = wl_resource_get_version(manager_res->resource); - group_res->resource = wl_resource_create( - client, &ext_workspace_group_handle_v1_interface, version, 0); - if (group_res->resource == NULL) { - free(group_res); - return NULL; - } - wl_resource_set_implementation(group_res->resource, &group_impl, group_res, - group_handle_resource_destroy); - - group_res->group = group; - group_res->manager = manager_res; - wl_list_insert(&group->resources, &group_res->link); - wl_list_insert(&manager_res->group_resources, - &group_res->manager_resource_link); - - return group_res; -} - -static void destroy_request(struct wlr_ext_workspace_v1_request *req) { - wl_list_remove(&req->link); - free(req->name); - free(req); -} - -static void manager_handle_commit(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_ext_workspace_manager_v1_resource *manager_res = - manager_resource_from_resource(resource); - if (!manager_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req, *tmp; - wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { - switch (req->type) { - case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE:; - struct wlr_ext_workspace_group_handle_v1_create_workspace_event - event = { - .name = req->name, - }; - wl_signal_emit_mutable(&req->group->events.create_workspace, - &event); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE: - wl_signal_emit_mutable(&req->workspace->events.activate, NULL); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE: - wl_signal_emit_mutable(&req->workspace->events.deactivate, NULL); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN: - wl_signal_emit_mutable(&req->workspace->events.assign, req->group); - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE: - wl_signal_emit_mutable(&req->workspace->events.remove, NULL); - break; - } - destroy_request(req); - } -} - -static void handle_idle(void *data) { - struct wlr_ext_workspace_manager_v1 *manager = data; - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &manager->resources, link) { - ext_workspace_manager_v1_send_done(manager_res->resource); - } - manager->idle_source = NULL; -} - -static void -manager_schedule_done(struct wlr_ext_workspace_manager_v1 *manager) { - if (!manager->idle_source) { - manager->idle_source = - wl_event_loop_add_idle(manager->event_loop, handle_idle, manager); - } -} - -static void -workspace_send_details(struct wlr_ext_workspace_v1_resource *workspace_res) { - struct wlr_ext_workspace_handle_v1 *workspace = workspace_res->workspace; - struct wl_resource *resource = workspace_res->resource; - - ext_workspace_handle_v1_send_capabilities(resource, workspace->caps); - if (workspace->coordinates.size > 0) { - ext_workspace_handle_v1_send_coordinates(resource, - &workspace->coordinates); - } - if (workspace->name) { - ext_workspace_handle_v1_send_name(resource, workspace->name); - } - if (workspace->id) { - ext_workspace_handle_v1_send_id(resource, workspace->id); - } - ext_workspace_handle_v1_send_state(resource, workspace->state); - manager_schedule_done(workspace->manager); -} - -static void manager_handle_stop(struct wl_client *client, - struct wl_resource *resource) { - ext_workspace_manager_v1_send_finished(resource); - wl_resource_destroy(resource); -} - -static const struct ext_workspace_manager_v1_interface manager_impl = { - .commit = manager_handle_commit, - .stop = manager_handle_stop, -}; - -static void destroy_manager_resource( - struct wlr_ext_workspace_manager_v1_resource *manager_res) { - struct wlr_ext_workspace_v1_request *req, *tmp; - wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { - destroy_request(req); - } - struct wlr_ext_workspace_v1_resource *workspace_res, *tmp2; - wl_list_for_each_safe(workspace_res, tmp2, - &manager_res->workspace_resources, - manager_resource_link) { - destroy_workspace_resource(workspace_res); - } - struct wlr_ext_workspace_group_v1_resource *group_res, *tmp3; - wl_list_for_each_safe(group_res, tmp3, &manager_res->group_resources, - manager_resource_link) { - destroy_group_resource(group_res); - } - - wl_list_remove(&manager_res->link); - wl_resource_set_user_data(manager_res->resource, NULL); - free(manager_res); -} - -static void manager_resource_destroy(struct wl_resource *resource) { - struct wlr_ext_workspace_manager_v1_resource *manager_res = - manager_resource_from_resource(resource); - if (manager_res) { - destroy_manager_resource(manager_res); - } -} - -static void -group_send_details(struct wlr_ext_workspace_group_v1_resource *group_res) { - struct wlr_ext_workspace_group_handle_v1 *group = group_res->group; - struct wl_resource *resource = group_res->resource; - struct wl_client *client = wl_resource_get_client(resource); - - ext_workspace_group_handle_v1_send_capabilities(resource, group->caps); - - struct wlr_ext_workspace_v1_group_output *group_output; - wl_list_for_each(group_output, &group->outputs, link) { - struct wl_resource *output_resource; - wl_resource_for_each(output_resource, - &group_output->output->resources) { - if (wl_resource_get_client(output_resource) == client) { - ext_workspace_group_handle_v1_send_output_enter( - resource, output_resource); - } - } - } - - manager_schedule_done(group->manager); -} - -static void manager_bind(struct wl_client *client, void *data, uint32_t version, - uint32_t id) { - struct wlr_ext_workspace_manager_v1 *manager = data; - - struct wlr_ext_workspace_manager_v1_resource *manager_res = - calloc(1, sizeof(*manager_res)); - if (!manager_res) { - wl_client_post_no_memory(client); - return; - } - - manager_res->manager = manager; - wl_list_init(&manager_res->requests); - wl_list_init(&manager_res->workspace_resources); - wl_list_init(&manager_res->group_resources); - - manager_res->resource = wl_resource_create( - client, &ext_workspace_manager_v1_interface, version, id); - if (!manager_res->resource) { - free(manager_res); - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(manager_res->resource, &manager_impl, - manager_res, manager_resource_destroy); - wl_list_insert(&manager->resources, &manager_res->link); - - struct wlr_ext_workspace_group_handle_v1 *group; - wl_list_for_each(group, &manager->groups, link) { - struct wlr_ext_workspace_group_v1_resource *group_res = - create_group_resource(group, manager_res); - if (!group_res) { - wl_resource_post_no_memory(manager_res->resource); - continue; - } - ext_workspace_manager_v1_send_workspace_group(manager_res->resource, - group_res->resource); - group_send_details(group_res); - } - - struct wlr_ext_workspace_handle_v1 *workspace; - wl_list_for_each(workspace, &manager->workspaces, link) { - struct wlr_ext_workspace_v1_resource *workspace_res = - create_workspace_resource(workspace, manager_res); - if (!workspace_res) { - wl_resource_post_no_memory(manager_res->resource); - continue; - } - ext_workspace_manager_v1_send_workspace(manager_res->resource, - workspace_res->resource); - workspace_send_details(workspace_res); - - if (!workspace->group) { - continue; - } - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &workspace->group->resources, link) { - if (group_res->manager == manager_res) { - ext_workspace_group_handle_v1_send_workspace_enter( - group_res->resource, workspace_res->resource); - } - } - } - - ext_workspace_manager_v1_send_done(manager_res->resource); -} - -static void manager_handle_display_destroy(struct wl_listener *listener, - void *data) { - struct wlr_ext_workspace_manager_v1 *manager = - wl_container_of(listener, manager, display_destroy); - - wl_signal_emit_mutable(&manager->events.destroy, NULL); - assert(wl_list_empty(&manager->events.destroy.listener_list)); - - struct wlr_ext_workspace_group_handle_v1 *group, *tmp; - wl_list_for_each_safe(group, tmp, &manager->groups, link) { - wlr_ext_workspace_group_handle_v1_destroy(group); - } - - struct wlr_ext_workspace_handle_v1 *workspace, *tmp2; - wl_list_for_each_safe(workspace, tmp2, &manager->workspaces, link) { - wlr_ext_workspace_handle_v1_destroy(workspace); - } - - struct wlr_ext_workspace_manager_v1_resource *manager_res, *tmp3; - wl_list_for_each_safe(manager_res, tmp3, &manager->resources, link) { - destroy_manager_resource(manager_res); - } - - if (manager->idle_source) { - wl_event_source_remove(manager->idle_source); - } - - wl_list_remove(&manager->display_destroy.link); - wl_global_destroy(manager->global); - free(manager); -} - -struct wlr_ext_workspace_manager_v1 * -wlr_ext_workspace_manager_v1_create(struct wl_display *display, - uint32_t version) { - assert(version <= EXT_WORKSPACE_V1_VERSION); - - struct wlr_ext_workspace_manager_v1 *manager = calloc(1, sizeof(*manager)); - if (!manager) { - return NULL; - } - - manager->global = - wl_global_create(display, &ext_workspace_manager_v1_interface, version, - manager, manager_bind); - if (!manager->global) { - free(manager); - return NULL; - } - - manager->event_loop = wl_display_get_event_loop(display); - - manager->display_destroy.notify = manager_handle_display_destroy; - wl_display_add_destroy_listener(display, &manager->display_destroy); - - wl_list_init(&manager->groups); - wl_list_init(&manager->workspaces); - wl_list_init(&manager->resources); - wl_signal_init(&manager->events.destroy); - - return manager; -} - -struct wlr_ext_workspace_group_handle_v1 * -wlr_ext_workspace_group_handle_v1_create( - struct wlr_ext_workspace_manager_v1 *manager, uint32_t caps) { - struct wlr_ext_workspace_group_handle_v1 *group = calloc(1, sizeof(*group)); - if (!group) { - return NULL; - } - - group->manager = manager; - group->caps = caps; - - wl_list_init(&group->outputs); - wl_list_init(&group->resources); - wl_signal_init(&group->events.create_workspace); - wl_signal_init(&group->events.destroy); - - wl_list_insert(manager->groups.prev, &group->link); - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &manager->resources, link) { - struct wlr_ext_workspace_group_v1_resource *group_res = - create_group_resource(group, manager_res); - if (!group_res) { - continue; - } - ext_workspace_manager_v1_send_workspace_group(manager_res->resource, - group_res->resource); - group_send_details(group_res); - } - - manager_schedule_done(manager); - - return group; -} - -static void -workspace_send_group(struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_group_handle_v1 *group, - bool enter) { - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &group->resources, link) { - if (group_res->manager != workspace_res->manager) { - continue; - } - if (enter) { - ext_workspace_group_handle_v1_send_workspace_enter( - group_res->resource, workspace_res->resource); - } else { - ext_workspace_group_handle_v1_send_workspace_leave( - group_res->resource, workspace_res->resource); - } - } - } - - manager_schedule_done(workspace->manager); -} - -static void -destroy_group_output(struct wlr_ext_workspace_v1_group_output *group_output) { - wl_list_remove(&group_output->output_bind.link); - wl_list_remove(&group_output->output_destroy.link); - wl_list_remove(&group_output->link); - free(group_output); -} - -static void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output, bool enter) { - - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &group->resources, link) { - struct wl_client *client = wl_resource_get_client(group_res->resource); - - struct wl_resource *output_resource; - wl_resource_for_each(output_resource, &output->resources) { - if (wl_resource_get_client(output_resource) != client) { - continue; - } - if (enter) { - ext_workspace_group_handle_v1_send_output_enter( - group_res->resource, output_resource); - } else { - ext_workspace_group_handle_v1_send_output_leave( - group_res->resource, output_resource); - } - } - } - - manager_schedule_done(group->manager); -} - -void wlr_ext_workspace_group_handle_v1_destroy( - struct wlr_ext_workspace_group_handle_v1 *group) { - if (!group) { - return; - } - - wl_signal_emit_mutable(&group->events.destroy, NULL); - - assert(wl_list_empty(&group->events.create_workspace.listener_list)); - assert(wl_list_empty(&group->events.destroy.listener_list)); - - struct wlr_ext_workspace_handle_v1 *workspace; - wl_list_for_each(workspace, &group->manager->workspaces, link) { - if (workspace->group == group) { - workspace_send_group(workspace, group, false); - workspace->group = NULL; - } - } - - struct wlr_ext_workspace_group_v1_resource *group_res, *tmp; - wl_list_for_each_safe(group_res, tmp, &group->resources, link) { - ext_workspace_group_handle_v1_send_removed(group_res->resource); - destroy_group_resource(group_res); - } - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &group->manager->resources, link) { - struct wlr_ext_workspace_v1_request *req, *tmp2; - wl_list_for_each_safe(req, tmp2, &manager_res->requests, link) { - if (req->group == group) { - destroy_request(req); - } - } - } - - struct wlr_ext_workspace_v1_group_output *group_output, *tmp3; - wl_list_for_each_safe(group_output, tmp3, &group->outputs, link) { - group_send_output(group, group_output->output, false); - destroy_group_output(group_output); - } - - manager_schedule_done(group->manager); - - wl_list_remove(&group->link); - free(group); -} - -static void handle_output_bind(struct wl_listener *listener, void *data) { - struct wlr_ext_workspace_v1_group_output *group_output = - wl_container_of(listener, group_output, output_bind); - struct wlr_output_event_bind *event = data; - struct wl_client *client = wl_resource_get_client(event->resource); - - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &group_output->group->resources, link) { - if (wl_resource_get_client(group_res->resource) == client) { - ext_workspace_group_handle_v1_send_output_enter(group_res->resource, - event->resource); - } - } - - manager_schedule_done(group_output->group->manager); -} - -static void handle_output_destroy(struct wl_listener *listener, void *data) { - struct wlr_ext_workspace_v1_group_output *group_output = - wl_container_of(listener, group_output, output_destroy); - group_send_output(group_output->group, group_output->output, false); - destroy_group_output(group_output); -} - -static struct wlr_ext_workspace_v1_group_output * -get_group_output(struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output) { - struct wlr_ext_workspace_v1_group_output *group_output; - wl_list_for_each(group_output, &group->outputs, link) { - if (group_output->output == output) { - return group_output; - } - } - return NULL; -} - -void wlr_ext_workspace_group_handle_v1_output_enter( - struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output) { - if (get_group_output(group, output)) { - return; - } - struct wlr_ext_workspace_v1_group_output *group_output = - calloc(1, sizeof(*group_output)); - if (!group_output) { - return; - } - group_output->output = output; - group_output->group = group; - wl_list_insert(&group->outputs, &group_output->link); - - group_output->output_bind.notify = handle_output_bind; - wl_signal_add(&output->events.bind, &group_output->output_bind); - group_output->output_destroy.notify = handle_output_destroy; - wl_signal_add(&output->events.destroy, &group_output->output_destroy); - - group_send_output(group, output, true); -} - -void wlr_ext_workspace_group_handle_v1_output_leave( - struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output) { - struct wlr_ext_workspace_v1_group_output *group_output = - get_group_output(group, output); - if (!group_output) { - return; - } - - group_send_output(group, output, false); - destroy_group_output(group_output); -} - -struct wlr_ext_workspace_handle_v1 * -wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, - const char *id, uint32_t caps) { - struct wlr_ext_workspace_handle_v1 *workspace = - calloc(1, sizeof(*workspace)); - if (!workspace) { - return NULL; - } - - workspace->manager = manager; - workspace->caps = caps; - - if (id) { - workspace->id = strdup(id); - if (!workspace->id) { - free(workspace); - return NULL; - } - } - - wl_list_init(&workspace->resources); - wl_array_init(&workspace->coordinates); - wl_signal_init(&workspace->events.activate); - wl_signal_init(&workspace->events.deactivate); - wl_signal_init(&workspace->events.remove); - wl_signal_init(&workspace->events.assign); - wl_signal_init(&workspace->events.destroy); - - wl_list_insert(&manager->workspaces, &workspace->link); - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &manager->resources, link) { - struct wlr_ext_workspace_v1_resource *workspace_res = - create_workspace_resource(workspace, manager_res); - if (!workspace_res) { - continue; - } - ext_workspace_manager_v1_send_workspace(manager_res->resource, - workspace_res->resource); - workspace_send_details(workspace_res); - } - - manager_schedule_done(manager); - - return workspace; -} - -void wlr_ext_workspace_handle_v1_destroy( - struct wlr_ext_workspace_handle_v1 *workspace) { - if (!workspace) { - return; - } - - wl_signal_emit_mutable(&workspace->events.destroy, NULL); - - assert(wl_list_empty(&workspace->events.activate.listener_list)); - assert(wl_list_empty(&workspace->events.deactivate.listener_list)); - assert(wl_list_empty(&workspace->events.remove.listener_list)); - assert(wl_list_empty(&workspace->events.assign.listener_list)); - assert(wl_list_empty(&workspace->events.destroy.listener_list)); - - if (workspace->group) { - workspace_send_group(workspace, workspace->group, false); - } - - struct wlr_ext_workspace_v1_resource *workspace_res, *tmp; - wl_list_for_each_safe(workspace_res, tmp, &workspace->resources, link) { - ext_workspace_handle_v1_send_removed(workspace_res->resource); - destroy_workspace_resource(workspace_res); - } - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &workspace->manager->resources, link) { - struct wlr_ext_workspace_v1_request *req, *tmp2; - wl_list_for_each_safe(req, tmp2, &manager_res->requests, link) { - if (req->workspace == workspace) { - destroy_request(req); - } - } - } - - manager_schedule_done(workspace->manager); - - wl_list_remove(&workspace->link); - wl_array_release(&workspace->coordinates); - free(workspace->id); - free(workspace->name); - free(workspace); -} - -void wlr_ext_workspace_handle_v1_set_group( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_group_handle_v1 *group) { - if (workspace->group == group) { - return; - } - - if (workspace->group) { - workspace_send_group(workspace, workspace->group, false); - } - workspace->group = group; - if (group) { - workspace_send_group(workspace, group, true); - } -} - -void wlr_ext_workspace_handle_v1_set_name( - struct wlr_ext_workspace_handle_v1 *workspace, const char *name) { - assert(name); - - if (workspace->name && strcmp(workspace->name, name) == 0) { - return; - } - - free(workspace->name); - workspace->name = strdup(name); - if (workspace->name == NULL) { - return; - } - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - ext_workspace_handle_v1_send_name(workspace_res->resource, - workspace->name); - } - - manager_schedule_done(workspace->manager); -} - -static bool array_equal(struct wl_array *a, struct wl_array *b) { - return (a->size == b->size) && - (a->size == 0 || memcmp(a->data, b->data, a->size) == 0); -} - -void wlr_ext_workspace_handle_v1_set_coordinates( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wl_array *coordinates) { - assert(coordinates); - - if (array_equal(&workspace->coordinates, coordinates)) { - return; - } - - wl_array_release(&workspace->coordinates); - wl_array_init(&workspace->coordinates); - wl_array_copy(&workspace->coordinates, coordinates); - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - ext_workspace_handle_v1_send_coordinates(workspace_res->resource, - &workspace->coordinates); - } - - manager_schedule_done(workspace->manager); -} - -static void workspace_set_state(struct wlr_ext_workspace_handle_v1 *workspace, - enum ext_workspace_handle_v1_state state, - bool enabled) { - uint32_t old_state = workspace->state; - if (enabled) { - workspace->state |= state; - } else { - workspace->state &= ~state; - } - if (old_state == workspace->state) { - return; - } - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - ext_workspace_handle_v1_send_state(workspace_res->resource, - workspace->state); - } - - manager_schedule_done(workspace->manager); -} - -void wlr_ext_workspace_handle_v1_set_active( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) { - workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE, - enabled); -} - -void wlr_ext_workspace_handle_v1_set_urgent( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) { - workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_URGENT, - enabled); -} - -void wlr_ext_workspace_handle_v1_set_hidden( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) { - workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN, - enabled); -} diff --git a/src/ext-protocol/wlr_ext_workspace_v1.h b/src/ext-protocol/wlr_ext_workspace_v1.h deleted file mode 100644 index a2a733b3b..000000000 --- a/src/ext-protocol/wlr_ext_workspace_v1.h +++ /dev/null @@ -1,106 +0,0 @@ -// bash on: https://gitlab.freedesktop.org/tokyo4j/wlroots/-/tree/ext-workspace -// TODO: remove this file -// refer: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5115 - -#include -#include - -struct wlr_output; - -struct wlr_ext_workspace_manager_v1 { - struct wl_global *global; - struct wl_list groups; // wlr_ext_workspace_group_handle_v1.link - struct wl_list workspaces; // wlr_ext_workspace_handle_v1.link - - struct { - struct wl_signal destroy; - } events; - - struct { - struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link - struct wl_event_source *idle_source; - struct wl_event_loop *event_loop; - struct wl_listener display_destroy; - }; -}; - -struct wlr_ext_workspace_group_handle_v1_create_workspace_event { - const char *name; -}; - -struct wlr_ext_workspace_group_handle_v1 { - struct wlr_ext_workspace_manager_v1 *manager; - uint32_t caps; // ext_workspace_group_handle_v1_group_capabilities - struct { - struct wl_signal - create_workspace; // wlr_ext_workspace_group_handle_v1_create_workspace_event - struct wl_signal destroy; - } events; - - struct wl_list link; // wlr_ext_workspace_manager_v1.groups - - struct { - struct wl_list outputs; // wlr_ext_workspace_v1_group_output.link - struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link - }; -}; - -struct wlr_ext_workspace_handle_v1 { - struct wlr_ext_workspace_manager_v1 *manager; - struct wlr_ext_workspace_group_handle_v1 *group; // May be NULL - char *id; - char *name; - struct wl_array coordinates; - uint32_t caps; // ext_workspace_handle_v1_workspace_capabilities - uint32_t state; // ext_workspace_handle_v1_state - - struct { - struct wl_signal activate; - struct wl_signal deactivate; - struct wl_signal remove; - struct wl_signal assign; // wlr_ext_workspace_group_handle_v1 - struct wl_signal destroy; - } events; - - struct wl_list link; // wlr_ext_workspace_manager_v1.workspaces - - struct { - struct wl_list resources; // wlr_ext_workspace_v1_resource.link - }; -}; - -struct wlr_ext_workspace_manager_v1 * -wlr_ext_workspace_manager_v1_create(struct wl_display *display, - uint32_t version); - -struct wlr_ext_workspace_group_handle_v1 * -wlr_ext_workspace_group_handle_v1_create( - struct wlr_ext_workspace_manager_v1 *manager, uint32_t caps); -void wlr_ext_workspace_group_handle_v1_destroy( - struct wlr_ext_workspace_group_handle_v1 *group); - -void wlr_ext_workspace_group_handle_v1_output_enter( - struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output); -void wlr_ext_workspace_group_handle_v1_output_leave( - struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output); - -struct wlr_ext_workspace_handle_v1 * -wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, - const char *id, uint32_t caps); -void wlr_ext_workspace_handle_v1_destroy( - struct wlr_ext_workspace_handle_v1 *workspace); - -void wlr_ext_workspace_handle_v1_set_group( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_group_handle_v1 *group); -void wlr_ext_workspace_handle_v1_set_name( - struct wlr_ext_workspace_handle_v1 *workspace, const char *name); -void wlr_ext_workspace_handle_v1_set_coordinates( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wl_array *coordinates); -void wlr_ext_workspace_handle_v1_set_active( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); -void wlr_ext_workspace_handle_v1_set_urgent( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); -void wlr_ext_workspace_handle_v1_set_hidden( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index 7a1ca4dc6..041a170b7 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -96,3 +96,12 @@ Monitor *xytomon(double x, double y) { struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); return o ? o->data : NULL; } + +Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly) { + double closest_x, closest_y; + wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, + &closest_y); + + return output_from_wlr_output( + wlr_output_layout_output_at(output_layout, closest_x, closest_y)); +} diff --git a/src/mango.c b/src/mango.c index c96c2357b..37a856daa 100644 --- a/src/mango.c +++ b/src/mango.c @@ -40,8 +40,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -316,6 +318,10 @@ struct Client { struct wlr_scene_shadow *shadow; struct wlr_scene_blur *blur; struct wlr_scene_tree *scene_surface; + struct wlr_scene_tree *image_capture_tree; + struct wlr_scene *image_capture_scene; + struct wlr_ext_image_capture_source_v1 *image_capture_source; + struct wlr_scene_surface *image_capture_scene_surface; struct wl_list link; struct wl_list flink; struct wl_list fadeout_link; @@ -407,6 +413,7 @@ struct Client { float unfocused_opacity; char oldmonname[128]; int32_t noblur; + struct wlr_ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel; double master_mfact_per, master_inner_per, stack_inner_per; double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; @@ -683,6 +690,7 @@ static void virtualkeyboard(struct wl_listener *listener, void *data); static void virtualpointer(struct wl_listener *listener, void *data); static void warp_cursor(const Client *c); static Monitor *xytomon(double x, double y); +static Monitor *get_monitor_nearest_to(int32_t x, int32_t y); static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void clear_fullscreen_flag(Client *c); @@ -845,7 +853,13 @@ static struct wl_list keyboard_shortcut_inhibitors; static uint32_t cursor_mode; static Client *grabc; static int32_t rzcorner; -static int32_t grabcx, grabcy; /* client-relative */ +static int32_t grabcx, grabcy; /* client-relative */ + +static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 + *ext_foreign_toplevel_image_capture_source_manager_v1; +static struct wl_listener new_foreign_toplevel_capture_request; +static struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list; + static int32_t drag_begin_cursorx, drag_begin_cursory; /* client-relative */ static bool start_drag_window = false; static int32_t last_apply_drap_time = 0; @@ -2147,6 +2161,7 @@ void cleanuplisteners(void) { wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); + wl_list_remove(&new_foreign_toplevel_capture_request.link); wl_list_remove(&tearing_new_object.link); wl_list_remove(&keyboard_shortcuts_inhibit_new_inhibitor.link); if (drm_lease_manager) { @@ -3933,6 +3948,18 @@ mapnotify(struct wl_listener *listener, void *data) { c->geom.width += 2 * c->bw; c->geom.height += 2 * c->bw; + struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = { + .app_id = client_get_appid(c), + .title = client_get_title(c), + }; + + c->image_capture_scene = wlr_scene_create(); + c->ext_foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create( + foreign_toplevel_list, &foreign_toplevel_state); + c->ext_foreign_toplevel->data = c; + c->image_capture_scene_surface = wlr_scene_surface_create( + &c->image_capture_scene->tree, client_surface(c)); + /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { @@ -4279,6 +4306,26 @@ void outputmgrapply(struct wl_listener *listener, void *data) { outputmgrapplyortest(config, 0); } +static void +handle_new_foreign_toplevel_capture_request(struct wl_listener *listener, + void *data) { + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request + *request = data; + Client *c = request->toplevel_handle->data; + + if (c->image_capture_source == NULL) { + c->image_capture_source = + wlr_ext_image_capture_source_v1_create_with_scene_node( + &c->image_capture_scene->tree.node, event_loop, alloc, drw); + if (c->image_capture_source == NULL) { + return; + } + } + + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept( + request, c->image_capture_source); +} + void // 0.7 custom outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test) { /* @@ -5285,6 +5332,7 @@ void setup(void) { wlr_subcompositor_create(dpy); wlr_alpha_modifier_v1_create(dpy); wlr_ext_data_control_manager_v1_create(dpy, 1); + wlr_fixes_create(dpy, 1); // 在 setup 函数中 wl_signal_init(&mango_print_status); @@ -5300,6 +5348,15 @@ void setup(void) { power_mgr = wlr_output_power_manager_v1_create(dpy); wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode); + foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create(dpy, 1); + ext_foreign_toplevel_image_capture_source_manager_v1 = + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(dpy, 1); + new_foreign_toplevel_capture_request.notify = + handle_new_foreign_toplevel_capture_request; + wl_signal_add(&ext_foreign_toplevel_image_capture_source_manager_v1->events + .new_request, + &new_foreign_toplevel_capture_request); + tearing_control = wlr_tearing_control_manager_v1_create(dpy, 1); tearing_new_object.notify = handle_tearing_new_object; wl_signal_add(&tearing_control->events.new_object, &tearing_new_object); @@ -5678,6 +5735,11 @@ void unmapnotify(struct wl_listener *listener, void *data) { (!c->mon || VISIBLEON(c, c->mon))) init_fadeout_client(c); + if (c->ext_foreign_toplevel) { + wlr_ext_foreign_toplevel_handle_v1_destroy(c->ext_foreign_toplevel); + c->ext_foreign_toplevel = NULL; + } + // If the client is in a stack, remove it from the stack if (c->swallowedby) { @@ -5762,6 +5824,8 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->next_in_stack = NULL; c->prev_in_stack = NULL; + wlr_scene_node_destroy(&c->image_capture_scene_surface->buffer->node); + wlr_scene_node_destroy(&c->image_capture_scene->tree.node); wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0, NULL, 0, 0, 0, 0); @@ -5911,6 +5975,14 @@ void updatetitle(struct wl_listener *listener, void *data) { title = client_get_title(c); if (title && c->foreign_toplevel) wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); + if (title && c->ext_foreign_toplevel) { + wlr_ext_foreign_toplevel_handle_v1_update_state( + c->ext_foreign_toplevel, + &(struct wlr_ext_foreign_toplevel_handle_v1_state){ + .title = title, + .app_id = c->ext_foreign_toplevel->app_id, + }); + } if (c == focustop(c->mon)) printstatus(); } @@ -6244,11 +6316,13 @@ void xwaylandready(struct wl_listener *listener, void *data) { wlr_xwayland_set_seat(xwayland, seat); /* Set the default XWayland cursor to match the rest of dwl. */ - if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) - wlr_xwayland_set_cursor( - xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, - xcursor->images[0]->width, xcursor->images[0]->height, - xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) { + struct wlr_xcursor_image *image = xcursor->images[0]; + struct wlr_buffer *buffer = wlr_xcursor_image_get_buffer(image); + wlr_xwayland_set_cursor(xwayland, buffer, xcursor->images[0]->hotspot_x, + xcursor->images[0]->hotspot_y); + } + /* xwayland can't auto sync the keymap, so we do it manually and we need to wait the xwayland completely inited */ From d11bc63802179ae0269619f305fb41afb94127dd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 13:47:04 +0800 Subject: [PATCH 09/16] feat: add shield_when_capture windowrule --- src/animation/client.h | 23 +++++++++++++ src/config/parse_config.h | 4 +++ src/mango.c | 72 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/src/animation/client.h b/src/animation/client.h index bb116cb0b..b60c07f55 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -355,6 +355,22 @@ void client_draw_shadow(Client *c) { wlr_scene_shadow_set_clipped_region(c->shadow, clipped_region); } +void apply_shield(Client *c, struct wlr_box clip_box) { + if (active_capture_count > 0 && c->shield_when_capture) { + wlr_scene_node_raise_to_top(&c->shield->node); + wlr_scene_node_set_position(&c->shield->node, clip_box.x, clip_box.y); + wlr_scene_rect_set_size(c->shield, clip_box.width, clip_box.height); + wlr_scene_node_set_enabled(&c->shield->node, true); + } else { + if (c->shield->node.enabled) { + wlr_scene_node_lower_to_bottom(&c->shield->node); + wlr_scene_rect_set_size(c->shield, c->animation.current.width, + c->animation.current.height); + wlr_scene_node_set_enabled(&c->shield->node, false); + } + } +} + void client_draw_blur(Client *c, struct wlr_box clip_box, struct ivec2 offset) { if (blur && !c->noblur) { wlr_scene_node_set_position(&c->blur->node, offset.x, offset.y); @@ -544,6 +560,7 @@ void client_apply_clip(Client *c, float factor) { apply_border(c); client_draw_shadow(c); + apply_shield(c, clip_box); client_draw_blur(c, clip_box, offset); if (clip_box.width <= 0 || clip_box.height <= 0) { @@ -583,6 +600,7 @@ void client_apply_clip(Client *c, float factor) { // 应用窗口装饰 apply_border(c); client_draw_shadow(c); + apply_shield(c, clip_box); client_draw_blur(c, clip_box, offset); // 如果窗口剪切区域已经剪切到0,则不渲染窗口表面 @@ -777,6 +795,10 @@ void init_fadeout_client(Client *c) { return; } + if (c->shield_when_capture && active_capture_count > 0) { + return; + } + if ((c->animation_type_close && strcmp(c->animation_type_close, "none") == 0) || (!c->animation_type_close && @@ -1011,6 +1033,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); client_draw_shadow(c); + apply_shield(c, clip); apply_border(c); client_get_clip(c, &clip); wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7e6db028b..74b0cdcf1 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -73,6 +73,7 @@ typedef struct { int32_t isunglobal; int32_t isglobal; int32_t isoverlay; + int32_t shield_when_capture; int32_t allow_shortcuts_inhibit; int32_t ignore_maximize; int32_t ignore_minimize; @@ -2005,6 +2006,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->isunglobal = -1; rule->isglobal = -1; rule->isoverlay = -1; + rule->shield_when_capture = -1; rule->allow_shortcuts_inhibit = -1; rule->ignore_maximize = -1; rule->ignore_minimize = -1; @@ -2111,6 +2113,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->focused_opacity = atof(val); } else if (strcmp(key, "isoverlay") == 0) { rule->isoverlay = atoi(val); + } else if (strcmp(key, "shield_when_capture") == 0) { + rule->shield_when_capture = atoi(val); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { rule->allow_shortcuts_inhibit = atoi(val); } else if (strcmp(key, "ignore_maximize") == 0) { diff --git a/src/mango.c b/src/mango.c index 37a856daa..4a0657aa1 100644 --- a/src/mango.c +++ b/src/mango.c @@ -316,6 +316,7 @@ struct Client { struct wlr_scene_tree *scene; struct wlr_scene_rect *border; /* top, bottom, left, right */ struct wlr_scene_shadow *shadow; + struct wlr_scene_rect *shield; struct wlr_scene_blur *blur; struct wlr_scene_tree *scene_surface; struct wlr_scene_tree *image_capture_tree; @@ -386,6 +387,7 @@ struct Client { int32_t iskilling; int32_t istagswitching; int32_t isnamedscratchpad; + int32_t shield_when_capture; bool is_pending_open_animation; bool is_restoring_from_ov; float scroller_proportion; @@ -548,6 +550,11 @@ typedef struct { struct wl_listener destroy; } SessionLock; +struct capture_session_tracker { + struct wl_listener session_destroy; + struct wlr_ext_image_copy_capture_session_v1 *session; +}; + /* function declarations */ static void applybounds( Client *c, @@ -691,6 +698,8 @@ static void virtualpointer(struct wl_listener *listener, void *data); static void warp_cursor(const Client *c); static Monitor *xytomon(double x, double y); static Monitor *get_monitor_nearest_to(int32_t x, int32_t y); +static void handle_iamge_copy_capture_new_session(struct wl_listener *listener, + void *data); static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void clear_fullscreen_flag(Client *c); @@ -827,6 +836,7 @@ static struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit; static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_output_power_manager_v1 *power_mgr; +static struct wlr_ext_image_copy_capture_manager_v1 *ext_image_copy_capture_mgr; static struct wlr_pointer_gestures_v1 *pointer_gestures; static struct wlr_drm_lease_v1_manager *drm_lease_manager; struct mango_print_status_manager *print_status_manager; @@ -896,6 +906,7 @@ static struct wl_event_source *hide_source; static bool cursor_hidden = false; static bool tag_combo = false; static const char *cli_config_path = NULL; +static int active_capture_count = 0; static KeyMode keymode = { .mode = {'d', 'e', 'f', 'a', 'u', 'l', 't', '\0'}, .isdefault = true, @@ -946,6 +957,8 @@ static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; static struct wl_listener output_power_mgr_set_mode = {.notify = powermgrsetmode}; +static struct wl_listener ext_image_copy_capture_mgr_new_session = { + .notify = handle_iamge_copy_capture_new_session}; static struct wl_listener request_activate = {.notify = urgent}; static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; @@ -1319,6 +1332,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isnamedscratchpad); APPLY_INT_PROP(c, r, isglobal); APPLY_INT_PROP(c, r, isoverlay); + APPLY_INT_PROP(c, r, shield_when_capture); APPLY_INT_PROP(c, r, ignore_maximize); APPLY_INT_PROP(c, r, ignore_minimize); APPLY_INT_PROP(c, r, isnosizehint); @@ -3997,6 +4011,12 @@ mapnotify(struct wl_listener *listener, void *data) { wlr_scene_node_lower_to_bottom(&c->shadow->node); wlr_scene_node_set_enabled(&c->shadow->node, true); + c->shield = wlr_scene_rect_create(c->scene_surface, 0, 0, + (float[4]){0, 0, 0, 0xff}); + c->shield->node.data = c; + wlr_scene_node_lower_to_bottom(&c->shield->node); + wlr_scene_node_set_enabled(&c->shield->node, false); + if (new_is_master && selmon && !is_scroller_layout(selmon)) // tile at the top wl_list_insert(&clients, &c->link); // 新窗口是master,头部入栈 @@ -4425,6 +4445,53 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, // 修改printstatus函数,接受掩码参数 void printstatus(void) { wl_signal_emit(&mango_print_status, NULL); } +// 会话销毁时的回调 +void handle_session_destroy(struct wl_listener *listener, void *data) { + struct capture_session_tracker *tracker = + wl_container_of(listener, tracker, session_destroy); + active_capture_count--; + wl_list_remove(&tracker->session_destroy.link); + + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + if (c->shield_when_capture && !c->iskilling && VISIBLEON(c, c->mon)) { + arrange(c->mon, false, false); + } + } + + wlr_log(WLR_DEBUG, "Capture session ended, active count: %d", + active_capture_count); + free(tracker); +} + +// 新会话创建时的回调 +void handle_iamge_copy_capture_new_session(struct wl_listener *listener, + void *data) { + struct wlr_ext_image_copy_capture_session_v1 *session = data; + + struct capture_session_tracker *tracker = calloc(1, sizeof(*tracker)); + if (!tracker) { + wlr_log(WLR_ERROR, "Failed to allocate capture session tracker"); + return; + } + tracker->session = session; + tracker->session_destroy.notify = handle_session_destroy; + // 监听会话的 destroy 信号,以便在会话结束时减少计数 + wl_signal_add(&session->events.destroy, &tracker->session_destroy); + + active_capture_count++; + + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + if (c->shield_when_capture && !c->iskilling && VISIBLEON(c, c->mon)) { + arrange(c->mon, false, false); + } + } + + wlr_log(WLR_DEBUG, "New capture session started, active count: %d", + active_capture_count); +} + void powermgrsetmode(struct wl_listener *listener, void *data) { struct wlr_output_power_v1_set_mode_event *event = data; struct wlr_output_state state = {0}; @@ -5338,6 +5405,11 @@ void setup(void) { wl_signal_init(&mango_print_status); wl_signal_add(&mango_print_status, &print_status_listener); + ext_image_copy_capture_mgr = + wlr_ext_image_copy_capture_manager_v1_create(dpy, 1); + wl_signal_add(&ext_image_copy_capture_mgr->events.new_session, + &ext_image_copy_capture_mgr_new_session); + /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); wl_signal_add(&activation->events.request_activate, &request_activate); From e9b551c87dcfebd161a91a3473c09aa2a98c8c2e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 14:18:25 +0800 Subject: [PATCH 10/16] fix: fix scenefx next --- src/animation/client.h | 56 +++++++++++++++++++++++++-------------- src/animation/layer.h | 4 +-- src/config/parse_config.h | 1 - src/mango.c | 26 +++++------------- 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 412daaaa1..12ef5f29c 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -12,7 +12,8 @@ void set_rect_size(struct wlr_scene_rect *rect, int32_t width, int32_t height) { struct fx_corner_radii set_client_corner_location(Client *c) { struct fx_corner_radii current_corner_location = corner_radii_all(config.border_radius); - struct wlr_box target_geom = config.animations ? c->animation.current : c->geom; + struct wlr_box target_geom = + config.animations ? c->animation.current : c->geom; if (target_geom.x + config.border_radius <= c->mon->m.x) { current_corner_location.top_left = 0; // 清除左标志位 current_corner_location.bottom_left = 0; // 清除左标志位 @@ -240,7 +241,6 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, return; wlr_scene_buffer_set_corner_radii(buffer, buffer_data->corner_location); - } void scene_buffer_apply_overview_effect(struct wlr_scene_buffer *buffer, @@ -288,7 +288,7 @@ void buffer_set_effect(Client *c, BufferData data) { if (c == grabc) data.should_scale = false; - if (c->isfullscreen || (no_radius_when_single && c->mon && + if (c->isfullscreen || (config.no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1)) { data.corner_location = corner_radii_none(); } @@ -420,10 +420,21 @@ void apply_shield(Client *c, struct wlr_box clip_box) { } void client_draw_blur(Client *c, struct wlr_box clip_box, struct ivec2 offset) { - if (blur && !c->noblur) { - wlr_scene_node_set_position(&c->blur->node, offset.x, offset.y); - wlr_scene_blur_set_size(c->blur, clip_box.width - c->bw, - clip_box.height - c->bw); + + if (c->isfullscreen) { + if (c->blur->node.enabled) { + wlr_scene_node_set_enabled(&c->blur->node, false); + } + return; + } else { + if (config.blur && !c->noblur) { + wlr_scene_node_set_enabled(&c->blur->node, true); + wlr_scene_node_set_position(&c->blur->node, offset.x, offset.y); + wlr_scene_blur_set_size(c->blur, clip_box.width - c->bw, + clip_box.height - c->bw); + } else { + wlr_scene_node_set_enabled(&c->blur->node, false); + } } } @@ -538,7 +549,8 @@ void apply_border(Client *c) { if (c->isfullscreen) { if (c->border->node.enabled) { - wlr_scene_node_set_position(&c->scene_surface->node, 0, 0); + wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false); + wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false); wlr_scene_node_set_enabled(&c->border->node, false); } return; @@ -552,7 +564,7 @@ void apply_border(Client *c) { apply_split_border(c, hit_no_border); struct fx_corner_radii current_corner_location = - c->isfullscreen || (no_radius_when_single && c->mon && + c->isfullscreen || (config.no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1) ? corner_radii_none() : set_client_corner_location(c); @@ -1320,7 +1332,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { return; struct wlr_box *bbox; - struct wlr_box clip; + struct wlr_box clip_box; if (!c->mon) return; @@ -1411,12 +1423,16 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->geom; wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); - client_draw_shadow(c); - apply_shield(c, clip); + struct ivec2 offset = clip_to_hide(c, &clip_box); + apply_border(c); - client_get_clip(c, &clip); - wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); - if (blur && !c->noblur) + client_draw_shadow(c); + apply_shield(c, clip_box); + client_draw_blur(c, clip_box, offset); + + client_get_clip(c, &clip_box); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); + if (config.blur && !c->noblur) wlr_scene_blur_set_size(c->blur, c->animation.current.width - 2 * c->bw, c->animation.current.height - 2 * c->bw); @@ -1549,14 +1565,14 @@ bool client_apply_focus_opacity(Client *c) { sizeof(c->opacity_animation.current_border_color)); c->opacity_animation.current_opacity = target_opacity; client_set_opacity(c, target_opacity); - if (blur && !c->noblur && !blur_optimized) { + if (config.blur && !c->noblur && !config.blur_optimized) { wlr_scene_blur_set_strength( - c->blur, MIN(percent * (1.0 - fadein_begin_opacity) + - fadein_begin_opacity, + c->blur, MIN(percent * (1.0 - config.fadein_begin_opacity) + + config.fadein_begin_opacity, 1.0)); wlr_scene_blur_set_alpha( - c->blur, MIN(percent * (1.0 - fadein_begin_opacity) + - fadein_begin_opacity, + c->blur, MIN(percent * (1.0 - config.fadein_begin_opacity) + + config.fadein_begin_opacity, 1.0)); } client_set_border_color(c, c->opacity_animation.target_border_color); diff --git a/src/animation/layer.h b/src/animation/layer.h index 3d8191b13..80d7e6ca6 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -328,7 +328,7 @@ void layer_animation_next_tick(LayerSurface *l) { 1.0f); if (config.animation_fade_in) { - if (blur && !l->noblur && !blur_optimized) { + if (config.blur && !l->noblur && !config.blur_optimized) { wlr_scene_blur_set_strength(l->blur, opacity); wlr_scene_blur_set_alpha(l->blur, opacity); } @@ -362,7 +362,7 @@ void layer_animation_next_tick(LayerSurface *l) { .height = height, }; - if (blur && blur_layer && !l->noblur && l->blur) + if (config.blur && config.blur_layer && !l->noblur && l->blur) wlr_scene_blur_set_size(l->blur, l->animation.current.width, l->animation.current.height); diff --git a/src/config/parse_config.h b/src/config/parse_config.h index d37a4ca4c..cbb629da7 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3742,7 +3742,6 @@ void set_value_default() { config.blur_layer = 0; config.blur_optimized = 1; config.border_radius = 0; - config.border_radius_location_default = CORNER_LOCATION_ALL; config.blur_params.num_passes = 1; config.blur_params.radius = 5; config.blur_params.noise = 0.02f; diff --git a/src/mango.c b/src/mango.c index c01fc59d6..6ec780c2d 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2743,19 +2743,6 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, } } -void layer_flush_blur_background(LayerSurface *l) { - if (!blur) - return; - - // 如果背景层发生变化,标记优化的模糊背景缓存需要更新 - if (l->layer_surface->current.layer == - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { - if (l->mon) { - wlr_scene_optimized_blur_mark_dirty(l->mon->blur); - } - } -} - void layer_flush_blur_background(LayerSurface *l) { if (!config.blur) return; @@ -2813,8 +2800,9 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { if (layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { if (layer_surface->current.exclusive_zone == 0) { - l->shadow = wlr_scene_shadow_create(l->scene, 0, 0, border_radius, - shadows_blur, shadowscolor); + l->shadow = wlr_scene_shadow_create( + l->scene, 0, 0, config.border_radius, config.shadows_blur, + config.shadowscolor); wlr_scene_node_lower_to_bottom(&l->shadow->node); wlr_scene_node_set_enabled(&l->shadow->node, true); } @@ -4459,14 +4447,11 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, return; if (config.blur && c && !c->noblur) { - wlr_scene_node_set_enabled(&c->blur->node, true); - if (blur_optimized) { + if (config.blur_optimized) { wlr_scene_blur_set_should_only_blur_bottom_layer(c->blur, true); } else { wlr_scene_blur_set_should_only_blur_bottom_layer(c->blur, false); } - } else { - wlr_scene_node_set_enabled(&c->blur->node, false); } } @@ -4656,7 +4641,8 @@ mapnotify(struct wl_listener *listener, void *data) { c->scene, 0, 0, c->isurgent ? config.urgentcolor : config.bordercolor); wlr_scene_node_lower_to_bottom(&c->border->node); wlr_scene_node_set_position(&c->border->node, 0, 0); - wlr_scene_rect_set_corner_radii(c->border, corner_radii_all(config.border_radius)); + wlr_scene_rect_set_corner_radii(c->border, + corner_radii_all(config.border_radius)); wlr_scene_node_set_enabled(&c->border->node, true); c->shadow = From 59a4df0a2b6fe089de83fd5b8ce262c747c541c4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 15:26:47 +0800 Subject: [PATCH 11/16] fix: window share shouldn't capture shield client --- src/animation/client.h | 12 ++++++++---- src/mango.c | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 12ef5f29c..1df141216 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -404,6 +404,11 @@ void client_draw_shadow(Client *c) { } void apply_shield(Client *c, struct wlr_box clip_box) { + + if (clip_box.width <= 0 || clip_box.height <= 0) { + return; + } + if (active_capture_count > 0 && c->shield_when_capture) { wlr_scene_node_raise_to_top(&c->shield->node); wlr_scene_node_set_position(&c->shield->node, clip_box.x, clip_box.y); @@ -933,8 +938,8 @@ void client_apply_clip(Client *c, float factor) { apply_border(c); client_draw_shadow(c); - apply_shield(c, clip_box); client_draw_blur(c, clip_box, offset); + apply_shield(c, clip_box); if (clip_box.width <= 0 || clip_box.height <= 0) { return; @@ -1426,11 +1431,10 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { struct ivec2 offset = clip_to_hide(c, &clip_box); apply_border(c); - client_draw_shadow(c); + client_get_clip(c, &clip_box); apply_shield(c, clip_box); + client_draw_shadow(c); client_draw_blur(c, clip_box, offset); - - client_get_clip(c, &clip_box); wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); if (config.blur && !c->noblur) wlr_scene_blur_set_size(c->blur, diff --git a/src/mango.c b/src/mango.c index 6ec780c2d..4176e251b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5013,6 +5013,9 @@ handle_new_foreign_toplevel_capture_request(struct wl_listener *listener, *request = data; Client *c = request->toplevel_handle->data; + if (c->shield_when_capture) + return; + if (c->image_capture_source == NULL) { c->image_capture_source = wlr_ext_image_capture_source_v1_create_with_scene_node( From a2b071b5fea0f8793adf3b0072768f1d56c66451 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 15:46:30 +0800 Subject: [PATCH 12/16] update docs --- docs/window-management/rules.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/window-management/rules.md b/docs/window-management/rules.md index b5ae81b14..5c97961c6 100644 --- a/docs/window-management/rules.md +++ b/docs/window-management/rules.md @@ -35,6 +35,8 @@ windowrule=Parameter:Values,Parameter:Values,appid:Values,title:Values | `single_scratchpad` | integer | `0` / `1` (default 1) | Only show one out of named scratchpads or the normal scratchpad | | `allow_shortcuts_inhibit` | integer | `0` / `1` (default 1) | Allow shortcuts to be inhibited by clients | | `idleinhibit_when_focus` | integer | `0` / `1` (default 0) | Automatically keep idle inhibit active when this window is focused | +| `shield_when_capture` | integer | `0` / `1` | Shield window when captured | + ### Geometry & Position From 6d535e2c1920d94db2fb30df7a0e88182dce66c0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 16:13:34 +0800 Subject: [PATCH 13/16] fix: shield and blur node in overview --- src/mango.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mango.c b/src/mango.c index 4176e251b..1bd38a068 100644 --- a/src/mango.c +++ b/src/mango.c @@ -6444,6 +6444,11 @@ void overview_backup_surface(Client *c) { 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); + + wlr_scene_node_reparent(&c->blur->node, c->scene_surface); + wlr_scene_node_lower_to_bottom(&c->blur->node); + wlr_scene_node_reparent(&c->shield->node, c->scene_surface); + wlr_scene_node_raise_to_top(&c->shield->node); } // 普通视图切换到overview时保存窗口的旧状态 @@ -6489,6 +6494,10 @@ void overview_restore(Client *c, const Arg *arg) { c->is_restoring_from_ov = (arg->ui & c->tags & TAGMASK) == 0 ? true : false; if (c->overview_scene_surface) { + wlr_scene_node_reparent(&c->blur->node, c->overview_scene_surface); + wlr_scene_node_lower_to_bottom(&c->blur->node); + wlr_scene_node_reparent(&c->shield->node, c->overview_scene_surface); + wlr_scene_node_raise_to_top(&c->shield->node); wlr_scene_node_destroy(&c->scene_surface->node); c->scene_surface = c->overview_scene_surface; c->overview_scene_surface = NULL; From 902806e16782b1b57111f07cde6e0d4c2c31f1e3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 17:15:05 +0800 Subject: [PATCH 14/16] opt: syncobj_enable default to 1 --- docs/configuration/miscellaneous.md | 2 +- src/config/parse_config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index cd8d167da..6fb5dc8f0 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -8,7 +8,7 @@ description: Advanced settings for XWayland, focus behavior, and system integrat | Setting | Default | Description | | :--- | :--- | :--- | | `xwayland_persistence` | `1` | Keep XWayland running even when no X11 apps are open (reduces startup lag). | -| `syncobj_enable` | `0` | Enable `drm_syncobj` timeline support (helps with gaming stutter/lag). **Requires restart.** | +| `syncobj_enable` | `1` | Enable `drm_syncobj` timeline support (helps with gaming stutter/lag). **Requires restart.** | | `allow_lock_transparent` | `0` | Allow the lock screen to be transparent. | | `allow_shortcuts_inhibit` | `1` | Allow shortcuts to be inhibited by clients. | | `vrr` | - | Set via [monitor rule](/docs/configuration/monitors#monitor-rules). | diff --git a/src/config/parse_config.h b/src/config/parse_config.h index cbb629da7..61a6da697 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3687,7 +3687,7 @@ void set_value_default() { config.view_current_to_back = 0; config.single_scratchpad = 1; config.xwayland_persistence = 1; - config.syncobj_enable = 0; + config.syncobj_enable = 1; config.tag_carousel = 0; config.drag_tile_refresh_interval = 8.0f; config.drag_floating_refresh_interval = 8.0f; From 3ab6e45220337f12f330bcf807d992b4a7c6acd2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 18:22:58 +0800 Subject: [PATCH 15/16] opt: make sure animaiton var init --- src/mango.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mango.c b/src/mango.c index 1bd38a068..1684f9fc4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4547,6 +4547,11 @@ void init_client_properties(Client *c) { sizeof(c->opacity_animation.current_border_color)); c->opacity_animation.initial_opacity = c->unfocused_opacity; c->opacity_animation.current_opacity = c->unfocused_opacity; + c->animation.tagining = false; + c->animation.running = false; + c->animation.overining = false; + c->animation.tagouting = false; + c->animation.tagouted = false; } void // old fix to 0.5 From 1ea7f88844d72b496f22453605e1a8ae898b1f18 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Jun 2026 19:25:10 +0800 Subject: [PATCH 16/16] fix: error clip box set for grabc client --- src/animation/client.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 1df141216..fb771da9b 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1337,7 +1337,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { return; struct wlr_box *bbox; - struct wlr_box clip_box; + struct wlr_box clip; if (!c->mon) return; @@ -1428,14 +1428,11 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->geom; wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); - struct ivec2 offset = clip_to_hide(c, &clip_box); - apply_border(c); - client_get_clip(c, &clip_box); - apply_shield(c, clip_box); + client_get_clip(c, &clip); + apply_shield(c, clip); client_draw_shadow(c); - client_draw_blur(c, clip_box, offset); - wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); if (config.blur && !c->noblur) wlr_scene_blur_set_size(c->blur, c->animation.current.width - 2 * c->bw,