git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit28af0a9dde2301287d44a50bfb89267d3850a0aa
parent8346b5d07c
authorLucas Galante <[email protected]>
date2026-06-30 16:15
Pass explicit geometry bounds to river_scene_node_enable_blur to match window content

 src/server/layer_shell.rs        |  4 ++++
 src/server/window.rs             | 19 ++++++++++++++++---
 src/server/wlroots_log_wrapper.c | 19 +++++++++++++------
 src/server/xdg_toplevel.rs       |  8 ++++++++
 wrapper.h                        |  2 +-
 5 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/src/server/layer_shell.rs b/src/server/layer_shell.rs
index 9f7fe55..acd75b5 100644
--- a/src/server/layer_shell.rs
+++ b/src/server/layer_shell.rs
@@ -598,6 +598,10 @@ unsafe extern "C" fn handle_layer_surface_commit(listener: *mut ffi::wl_listener
             blur_enabled,
             (*server).wm.layout.scenefx_optimized_blur,
             ignore_transparent,
+            0,
+            0,
+            0,
+            0,
         );
     }
 
diff --git a/src/server/window.rs b/src/server/window.rs
index 733426b..c52c8b9 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -1539,7 +1539,20 @@ impl Window {
             if app_id.starts_with("cce-status") {
                 ignore_transparent = (*self.server).wm.layout.status_backdrop_blur_ignore_transparent;
             }
-            ffi::river_scene_node_enable_blur(self.surfaces.tree as *mut ffi::wlr_scene_node, blur_enabled, (*self.server).wm.layout.scenefx_optimized_blur, ignore_transparent);
+            let geom_x = self.rendering_requested.x;
+            let geom_y = self.rendering_requested.y;
+            let geom_w = self.rendering_sent.width as i32;
+            let geom_h = self.rendering_sent.height as i32;
+            ffi::river_scene_node_enable_blur(
+                self.surfaces.tree as *mut ffi::wlr_scene_node,
+                blur_enabled,
+                (*self.server).wm.layout.scenefx_optimized_blur,
+                ignore_transparent,
+                geom_x,
+                geom_y,
+                geom_w,
+                geom_h,
+            );
             ffi::river_scene_node_set_opacity(self.tree as *mut ffi::wlr_scene_node, requested.opacity);
 
             let radius = if requested.circular {
@@ -1845,7 +1858,7 @@ impl Window {
             ffi::river_scene_node_set_position_if_changed(self.popup_tree as *mut ffi::wlr_scene_node, self.box_geom.x, self.box_geom.y);
 
             // Disable backdrop blur during active viewport zoom/pan for maximum performance
-            ffi::river_scene_node_enable_blur(self.surfaces.tree as *mut ffi::wlr_scene_node, false, (*self.server).wm.layout.scenefx_optimized_blur, true);
+            ffi::river_scene_node_enable_blur(self.surfaces.tree as *mut ffi::wlr_scene_node, false, (*self.server).wm.layout.scenefx_optimized_blur, true, 0, 0, 0, 0);
 
             self.scale_only_render_finish();
             self.draw_borders();
@@ -2779,7 +2792,7 @@ impl Decoration {
         if app_id.starts_with("cce-status") {
             ignore_transparent = (*server).wm.layout.status_backdrop_blur_ignore_transparent;
         }
-        ffi::river_scene_node_enable_blur(self.surfaces.tree as *mut ffi::wlr_scene_node, self.rendering_requested.blur, (*server).wm.layout.scenefx_optimized_blur, ignore_transparent);
+        ffi::river_scene_node_enable_blur(self.surfaces.tree as *mut ffi::wlr_scene_node, self.rendering_requested.blur, (*server).wm.layout.scenefx_optimized_blur, ignore_transparent, 0, 0, 0, 0);
 
         let scale = (*self.window).scale;
         let scaled_x = (self.rendering_requested.offset_x as f64 * scale) as i32;
diff --git a/src/server/wlroots_log_wrapper.c b/src/server/wlroots_log_wrapper.c
index 15e605e..90e5734 100644
--- a/src/server/wlroots_log_wrapper.c
+++ b/src/server/wlroots_log_wrapper.c
@@ -670,7 +670,7 @@ static void get_size_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, v
 	if (buffer->dst_height > size[1]) size[1] = buffer->dst_height;
 }
 
-void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, bool optimized, bool ignore_transparent) {
+void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, bool optimized, bool ignore_transparent, int x, int y, int width, int height) {
 	(void)ignore_transparent;
 	if (node->type != WLR_SCENE_NODE_TREE) {
 		return;
@@ -685,11 +685,14 @@ void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, boo
 		return;
 	}
 
-	int width = 0, height = 0;
-	int size[2] = {0, 0};
-	wlr_scene_node_for_each_buffer(node, get_size_iterator, size);
-	width = size[0];
-	height = size[1];
+	if (width <= 0 || height <= 0) {
+		int size[2] = {0, 0};
+		wlr_scene_node_for_each_buffer(node, get_size_iterator, size);
+		width = size[0];
+		height = size[1];
+		x = 0;
+		y = 0;
+	}
 
 	if (width <= 0 || height <= 0) {
 		width = 1920; // Fallback defaults
@@ -725,6 +728,10 @@ void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, boo
 			wlr_scene_blur_set_size((struct wlr_scene_blur *)blur_node, width, height);
 		}
 	}
+
+	if (blur_node) {
+		wlr_scene_node_set_position(blur_node, x, y);
+	}
 }
 
 static void set_opacity_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index b8b7101..e6f8246 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -413,11 +413,19 @@ unsafe extern "C" fn handle_commit(listener: *mut ffi::wl_listener, _data: *mut
     if app_id.starts_with("cce-status") {
         ignore_transparent = (*(*window).server).wm.layout.status_backdrop_blur_ignore_transparent;
     }
+    let geom_x = (*window).rendering_requested.x;
+    let geom_y = (*window).rendering_requested.y;
+    let geom_w = (*window).rendering_sent.width as i32;
+    let geom_h = (*window).rendering_sent.height as i32;
     ffi::river_scene_node_enable_blur(
         (*window).surfaces.tree as *mut ffi::wlr_scene_node,
         (*window).rendering_requested.blur,
         (*(*window).server).wm.layout.scenefx_optimized_blur,
         ignore_transparent,
+        geom_x,
+        geom_y,
+        geom_w,
+        geom_h,
     );
 
     let capture_node = &mut (*(*window).capture_scene).tree as *mut ffi::wlr_scene_tree as *mut ffi::wlr_scene_node;
diff --git a/wrapper.h b/wrapper.h
index 4e6d132..7288e93 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -257,7 +257,7 @@ struct wlr_seat_client *river_wlr_drag_get_seat_client(struct wlr_drag *drag);
 
 void river_wlr_keyboard_init(struct wlr_keyboard *keyboard, void (*led_update)(struct wlr_keyboard *keyboard, uint32_t leds), const char *name);
 
-void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, bool optimized, bool ignore_transparent);
+void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, bool optimized, bool ignore_transparent, int x, int y, int width, int height);
 
 void river_scene_node_set_opacity(struct wlr_scene_node *node, float opacity);