From efc55aa372c6e46d966c7dcb962aed22ce0ba5da Mon Sep 17 00:00:00 2001 From: nevaforget Date: Sat, 28 Mar 2026 23:15:47 +0100 Subject: [PATCH] fix: prevent edge darkening on GPU-blurred wallpaper (v0.7.1) GskBlurNode samples pixels outside texture bounds as transparent, causing visible darkening at wallpaper edges. Fix renders the texture with 3x-sigma padding before blur, then clips back to original size. --- CHANGELOG.md | 6 ++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- src/panel.rs | 25 +++++++++++++++++++------ 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3949bbe..c5a90fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. Format based on [Keep a Changelog](https://keepachangelog.com/). +## [0.7.1] - 2026-03-28 + +### Fixed + +- Fix edge darkening on blurred wallpaper — GskBlurNode sampled transparent pixels outside texture bounds, now renders with 3x-sigma padding and crops back + ## [0.7.0] - 2026-03-28 ### Added diff --git a/Cargo.lock b/Cargo.lock index f137b5d..4d56db5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -616,7 +616,7 @@ dependencies = [ [[package]] name = "moonset" -version = "0.7.0" +version = "0.7.1" dependencies = [ "dirs", "gdk-pixbuf", diff --git a/Cargo.toml b/Cargo.toml index 49337f5..a666247 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moonset" -version = "0.7.0" +version = "0.7.1" edition = "2024" description = "Wayland session power menu with GTK4 and Layer Shell" license = "MIT" diff --git a/src/panel.rs b/src/panel.rs index 58ce3ab..b73965e 100644 --- a/src/panel.rs +++ b/src/panel.rs @@ -104,6 +104,10 @@ pub fn load_background_texture(bg_path: Option<&Path>) -> Option { // -- GPU blur via GskBlurNode ------------------------------------------------- /// Render a blurred texture using the GPU via GskBlurNode. +/// +/// To avoid edge darkening (blur samples transparent pixels outside bounds), +/// the texture is rendered with padding equal to 3x the blur sigma. The blur +/// is applied to the padded area, then cropped back to the original size. fn render_blurred_texture( widget: &impl IsA, texture: &gdk::Texture, @@ -111,15 +115,24 @@ fn render_blurred_texture( ) -> Option { let native = widget.native()?; let renderer = native.renderer()?; + + let w = texture.width() as f32; + let h = texture.height() as f32; + // Padding must cover the blur kernel radius (typically ~3x sigma) + let pad = (sigma * 3.0).ceil(); + let snapshot = gtk::Snapshot::new(); - let bounds = graphene_rs::Rect::new( - 0.0, 0.0, texture.width() as f32, texture.height() as f32, - ); + // Clip output to original texture size + snapshot.push_clip(&graphene_rs::Rect::new(pad, pad, w, h)); snapshot.push_blur(sigma as f64); - snapshot.append_texture(texture, &bounds); - snapshot.pop(); + // Render texture with padding on all sides (edges repeat via oversized bounds) + snapshot.append_texture(texture, &graphene_rs::Rect::new(0.0, 0.0, w + 2.0 * pad, h + 2.0 * pad)); + snapshot.pop(); // blur + snapshot.pop(); // clip + let node = snapshot.to_node()?; - Some(renderer.render_texture(&node, None)) + let viewport = graphene_rs::Rect::new(pad, pad, w, h); + Some(renderer.render_texture(&node, Some(&viewport))) } /// Fade out all windows and quit the app after the CSS transition completes.