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

commitadb181e598df30ae954498ccb22678e3f7bfbb65
parent448525d5eb
authorLucas Galante <[email protected]>
date2026-06-29 19:51
Rename desktop_background to desktop_background_color

 src/server/config.rs             |  22 ++---
 src/server/output.rs             |   2 +-
 src/server/window.rs             | 182 +++++++++++++++++++++++++++++++++++----
 src/server/window_manager.rs     |   4 +-
 src/server/wlroots_log_wrapper.c |  27 +++++-
 wrapper.h                        |   2 +
 6 files changed, 202 insertions(+), 37 deletions(-)

diff --git a/src/server/config.rs b/src/server/config.rs
index be37f70..a3f7d2e 100644
--- a/src/server/config.rs
+++ b/src/server/config.rs
@@ -37,7 +37,7 @@ pub struct Layout {
     pub overlay_position: String,
     pub overlay_border_gap: i32,
     pub status_normal_color: String,
-    pub desktop_background: String,
+    pub desktop_background_color: String,
     pub transparency_opacity: f32,
     pub window_opacity: bool,
     pub desktop_grid_color: [f32; 4],
@@ -78,7 +78,7 @@ impl Default for Layout {
             overlay_position: "left".to_string(),
             overlay_border_gap: 0,
             status_normal_color: "#ccccd8".to_string(),
-            desktop_background: "#000000".to_string(),
+            desktop_background_color: "#000000".to_string(),
             transparency_opacity: 0.9,
             window_opacity: true,
             desktop_grid_color: [1.0, 1.0, 1.0, 0.05],
@@ -239,8 +239,8 @@ pub struct TransparencyConfig {
 
 #[derive(Debug, Deserialize, Clone)]
 pub struct SurfacesConfig {
-    #[serde(default = "default_desktop_background")]
-    pub desktop_background: String,
+    #[serde(default = "default_desktop_background_color")]
+    pub desktop_background_color: String,
     #[serde(default = "default_desktop_grid_color")]
     pub desktop_grid_color: String,
     #[serde(default = "default_desktop_grid_scale")]
@@ -252,7 +252,7 @@ pub struct SurfacesConfig {
 impl Default for SurfacesConfig {
     fn default() -> Self {
         Self {
-            desktop_background: default_desktop_background(),
+            desktop_background_color: default_desktop_background_color(),
             desktop_grid_color: default_desktop_grid_color(),
             desktop_grid_scale: default_desktop_grid_scale(),
             desktop_line_width: default_desktop_line_width(),
@@ -260,7 +260,7 @@ impl Default for SurfacesConfig {
     }
 }
 
-fn default_desktop_background() -> String {
+fn default_desktop_background_color() -> String {
     "#000000".to_string()
 }
 
@@ -1077,9 +1077,9 @@ fn parse_kdl_config(content: &str) -> Result<Config, String> {
                         for entry in desktop_node.entries() {
                             if let Some(id) = entry.name() {
                                 match id.value() {
-                                    "background" => {
+                                    "background_color" => {
                                         if let Some(val) = entry.value().as_string() {
-                                            surfaces.desktop_background = val.to_string();
+                                            surfaces.desktop_background_color = val.to_string();
                                         }
                                     }
                                     "grid_color" => {
@@ -1103,7 +1103,7 @@ fn parse_kdl_config(content: &str) -> Result<Config, String> {
     }
     if !found_nested {
         if let Some(node) = doc.nodes().iter().find(|n| n.name().value() == "surfaces") {
-            surfaces.desktop_background = get_child_arg_string(node, "desktop_background", &default_desktop_background());
+            surfaces.desktop_background_color = get_child_arg_string(node, "desktop_background_color", &default_desktop_background_color());
             surfaces.desktop_grid_color = get_child_arg_string(node, "desktop_grid_color", &default_desktop_grid_color());
             surfaces.desktop_grid_scale = get_child_arg_i64(node, "desktop_grid_scale", default_desktop_grid_scale());
             surfaces.desktop_line_width = get_child_arg_i64(node, "desktop_line_width", default_desktop_line_width());
@@ -1157,8 +1157,8 @@ pub fn parse_config(path: &str, state: &mut crate::window_manager::WindowManager
     state.layout.border_b = 0x3E3E3E3E;
     state.layout.border_a = 0xFFFFFFFF;
 
-    let desktop_background_str = config.surfaces.desktop_background.clone();
-    state.layout.desktop_background = desktop_background_str.clone();
+    let desktop_background_str = config.surfaces.desktop_background_color.clone();
+    state.layout.desktop_background_color = desktop_background_str.clone();
 
     let background_color_val = parse_hex_color(&desktop_background_str);
     state.layout.background_r = ((background_color_val >> 16) & 0xFF) * 0x01010101;
diff --git a/src/server/output.rs b/src/server/output.rs
index a08ae7f..ec1960f 100644
--- a/src/server/output.rs
+++ b/src/server/output.rs
@@ -460,7 +460,7 @@ impl Output {
         let wm = &(*self.server).wm;
         for &window in wm.windows.iter() {
             if !window.is_null() && (*window).scale != 1.0 {
-                (*window).render_finish();
+                (*window).scale_only_render_finish();
             }
         }
 
diff --git a/src/server/window.rs b/src/server/window.rs
index 3772eba..2c01ef5 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -843,9 +843,8 @@ impl Window {
         if self.wm_sent.dimensions_hint != hint {
             if matches!(self.tiling_mode, crate::tiling::TilingMode::Floating | crate::tiling::TilingMode::Popup | crate::tiling::TilingMode::Status) {
                 (*self.server).wm.dirty_windowing();
-            } else {
-                self.wm_sent.dimensions_hint = hint;
             }
+            self.wm_sent.dimensions_hint = hint;
         }
     }
 
@@ -864,6 +863,7 @@ impl Window {
         self.wm_scheduled.decoration_hint = hint;
         if hint != self.wm_sent.decoration_hint {
             (*self.server).wm.dirty_windowing();
+            self.wm_sent.decoration_hint = hint;
         }
     }
 
@@ -1549,24 +1549,9 @@ impl Window {
                 0
             };
 
-            unsafe extern "C" fn set_corner_radius_iterator(
-                buffer: *mut ffi::wlr_scene_buffer,
-                _sx: i32,
-                _sy: i32,
-                user_data: *mut std::ffi::c_void,
-            ) {
-                let radius = *(user_data as *const i32);
-                ffi::wlr_scene_buffer_set_corner_radius(
-                    buffer,
-                    radius,
-                    ffi::corner_location_CORNER_LOCATION_ALL,
-                );
-            }
-
-            ffi::wlr_scene_node_for_each_buffer(
+            ffi::river_scene_node_set_corner_radius(
                 self.surfaces.tree as *mut ffi::wlr_scene_node,
-                Some(set_corner_radius_iterator),
-                &radius as *const i32 as *mut std::ffi::c_void,
+                radius,
             );
 
             struct ScaleData {
@@ -1749,6 +1734,94 @@ impl Window {
         }
     }
 
+    pub unsafe fn scale_only_render_finish(&mut self) {
+        if self.scale == 1.0 {
+            return;
+        }
+
+        struct ScaleData {
+            scale: f64,
+            ancestor: *mut ffi::wlr_scene_node,
+        }
+
+        unsafe extern "C" fn set_expose_scale_iterator(
+            buffer: *mut ffi::wlr_scene_buffer,
+            sx: i32,
+            sy: i32,
+            user_data: *mut std::ffi::c_void,
+        ) {
+            let data = &*(user_data as *const ScaleData);
+            let node = buffer as *mut ffi::wlr_scene_node;
+
+            let surface = ffi::river_scene_node_get_surface(node);
+            if !surface.is_null() {
+                let w = ffi::river_wlr_surface_get_width(surface);
+                let h = ffi::river_wlr_surface_get_height(surface);
+                if data.scale == 1.0 {
+                    ffi::river_scene_buffer_set_dest_size_if_changed(buffer, w, h);
+                    ffi::river_scene_node_set_position_if_changed(node, 0, 0);
+                } else {
+                    let dest_w = (w as f64 * data.scale) as i32;
+                    let dest_h = (h as f64 * data.scale) as i32;
+                    ffi::river_scene_buffer_set_dest_size_if_changed(buffer, dest_w, dest_h);
+
+                    let (px, py) = get_parent_position_relative_to(node, data.ancestor);
+                    let dest_x = (px as f64 * (data.scale - 1.0)) as i32;
+                    let dest_y = (py as f64 * (data.scale - 1.0)) as i32;
+                    ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
+                }
+            } else if data.scale == 1.0 {
+                ffi::river_scene_buffer_set_dest_size_if_changed(buffer, 0, 0);
+                ffi::river_scene_node_set_position_if_changed(node, sx, sy);
+            } else {
+                let w = ffi::river_scene_buffer_get_width(buffer);
+                let h = ffi::river_scene_buffer_get_height(buffer);
+                let dest_w = (w as f64 * data.scale) as i32;
+                let dest_h = (h as f64 * data.scale) as i32;
+                ffi::river_scene_buffer_set_dest_size_if_changed(buffer, dest_w, dest_h);
+
+                let (px, py) = get_parent_position_relative_to(node, data.ancestor);
+                let dest_x = (px as f64 * (data.scale - 1.0)) as i32;
+                let dest_y = (py as f64 * (data.scale - 1.0)) as i32;
+                ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
+            }
+        }
+
+        let scale_data_surfaces = ScaleData { scale: self.scale, ancestor: self.surfaces.tree as *mut ffi::wlr_scene_node };
+        ffi::wlr_scene_node_for_each_buffer(
+            self.surfaces.tree as *mut ffi::wlr_scene_node,
+            Some(set_expose_scale_iterator),
+            &scale_data_surfaces as *const ScaleData as *mut std::ffi::c_void,
+        );
+
+        if self.surfaces.saved {
+            let scale_data_saved = ScaleData { scale: self.scale, ancestor: self.surfaces.saved_tree as *mut ffi::wlr_scene_node };
+            ffi::wlr_scene_node_for_each_buffer(
+                self.surfaces.saved_tree as *mut ffi::wlr_scene_node,
+                Some(set_expose_scale_iterator),
+                &scale_data_saved as *const ScaleData as *mut std::ffi::c_void,
+            );
+        }
+
+        let scale_data_popup = ScaleData { scale: self.scale, ancestor: self.popup_tree as *mut ffi::wlr_scene_node };
+        ffi::wlr_scene_node_for_each_buffer(
+            self.popup_tree as *mut ffi::wlr_scene_node,
+            Some(set_expose_scale_iterator),
+            &scale_data_popup as *const ScaleData as *mut std::ffi::c_void,
+        );
+
+        for decorations in [&mut self.decorations_above as *mut ffi::wl_list, &mut self.decorations_below as *mut ffi::wl_list] {
+            let list_head = decorations as *mut WlList;
+            let mut curr = (*list_head).next;
+            while curr != list_head {
+                let next = (*curr).next;
+                let dec = crate::container_of!(curr, Decoration, link);
+                (*dec).scale_only_render_finish();
+                curr = next;
+            }
+        }
+    }
+
     pub unsafe fn draw_borders(&mut self) {
         let requested = &self.rendering_requested;
 
@@ -2746,6 +2819,77 @@ impl Decoration {
             ffi::wlr_scene_subsurface_tree_set_clip(self.surfaces.tree as *mut ffi::wlr_scene_node, std::ptr::null());
         }
     }
+
+    pub unsafe fn scale_only_render_finish(&mut self) {
+        let scale = (*self.window).scale;
+        if scale == 1.0 {
+            return;
+        }
+
+        struct ScaleData {
+            scale: f64,
+            ancestor: *mut ffi::wlr_scene_node,
+        }
+
+        unsafe extern "C" fn set_expose_scale_iterator(
+            buffer: *mut ffi::wlr_scene_buffer,
+            sx: i32,
+            sy: i32,
+            user_data: *mut std::ffi::c_void,
+        ) {
+            let data = &*(user_data as *const ScaleData);
+            let node = buffer as *mut ffi::wlr_scene_node;
+
+            let surface = ffi::river_scene_node_get_surface(node);
+            if !surface.is_null() {
+                let w = ffi::river_wlr_surface_get_width(surface);
+                let h = ffi::river_wlr_surface_get_height(surface);
+                if data.scale == 1.0 {
+                    ffi::river_scene_buffer_set_dest_size_if_changed(buffer, w, h);
+                    ffi::river_scene_node_set_position_if_changed(node, 0, 0);
+                } else {
+                    let dest_w = (w as f64 * data.scale) as i32;
+                    let dest_h = (h as f64 * data.scale) as i32;
+                    ffi::river_scene_buffer_set_dest_size_if_changed(buffer, dest_w, dest_h);
+
+                    let (px, py) = get_parent_position_relative_to(node, data.ancestor);
+                    let dest_x = (px as f64 * (data.scale - 1.0)) as i32;
+                    let dest_y = (py as f64 * (data.scale - 1.0)) as i32;
+                    ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
+                }
+            } else if data.scale == 1.0 {
+                ffi::river_scene_buffer_set_dest_size_if_changed(buffer, 0, 0);
+                ffi::river_scene_node_set_position_if_changed(node, sx, sy);
+            } else {
+                let w = ffi::river_scene_buffer_get_width(buffer);
+                let h = ffi::river_scene_buffer_get_height(buffer);
+                let dest_w = (w as f64 * data.scale) as i32;
+                let dest_h = (h as f64 * data.scale) as i32;
+                ffi::river_scene_buffer_set_dest_size_if_changed(buffer, dest_w, dest_h);
+
+                let (px, py) = get_parent_position_relative_to(node, data.ancestor);
+                let dest_x = (px as f64 * (data.scale - 1.0)) as i32;
+                let dest_y = (py as f64 * (data.scale - 1.0)) as i32;
+                ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
+            }
+        }
+
+        let scale_data = ScaleData { scale, ancestor: self.surfaces.tree as *mut ffi::wlr_scene_node };
+        ffi::wlr_scene_node_for_each_buffer(
+            self.surfaces.tree as *mut ffi::wlr_scene_node,
+            Some(set_expose_scale_iterator),
+            &scale_data as *const ScaleData as *mut std::ffi::c_void,
+        );
+
+        if self.surfaces.saved {
+            let scale_data_saved = ScaleData { scale, ancestor: self.surfaces.saved_tree as *mut ffi::wlr_scene_node };
+            ffi::wlr_scene_node_for_each_buffer(
+                self.surfaces.saved_tree as *mut ffi::wlr_scene_node,
+                Some(set_expose_scale_iterator),
+                &scale_data_saved as *const ScaleData as *mut std::ffi::c_void,
+            );
+        }
+    }
 }
 
 pub unsafe fn decoration_from_wlr_surface(surface: *mut ffi::wlr_surface) -> *mut Decoration {
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 4fd2a72..0651c18 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -2268,8 +2268,8 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                 let key = parts[1];
                 let val = parts[2];
                 match key {
-                    "desktop_background" => {
-                        self.layout.desktop_background = val.to_string();
+                    "desktop_background_color" => {
+                        self.layout.desktop_background_color = val.to_string();
                         let parsed_color = crate::config::parse_hex_color(val);
                         self.layout.background_r = ((parsed_color >> 16) & 0xFF) * 0x01010101;
                         self.layout.background_g = ((parsed_color >> 8) & 0xFF) * 0x01010101;
diff --git a/src/server/wlroots_log_wrapper.c b/src/server/wlroots_log_wrapper.c
index 6d7a13b..1cd1362 100644
--- a/src/server/wlroots_log_wrapper.c
+++ b/src/server/wlroots_log_wrapper.c
@@ -660,9 +660,13 @@ static void enable_blur_iterator(struct wlr_scene_buffer *buffer, int sx, int sy
 		return;
 	}
 	bool enabled = *(bool *)user_data;
-	wlr_scene_buffer_set_backdrop_blur(buffer, enabled);
-	wlr_scene_buffer_set_backdrop_blur_optimized(buffer, enabled);
-	wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, enabled);
+	if (buffer->backdrop_blur != enabled ||
+		buffer->backdrop_blur_optimized != enabled ||
+		buffer->backdrop_blur_ignore_transparent != enabled) {
+		wlr_scene_buffer_set_backdrop_blur(buffer, enabled);
+		wlr_scene_buffer_set_backdrop_blur_optimized(buffer, enabled);
+		wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, enabled);
+	}
 }
 
 void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled) {
@@ -673,13 +677,28 @@ static void set_opacity_iterator(struct wlr_scene_buffer *buffer, int sx, int sy
 	(void)sx;
 	(void)sy;
 	float opacity = *(float *)user_data;
-	wlr_scene_buffer_set_opacity(buffer, opacity);
+	if (buffer->opacity != opacity) {
+		wlr_scene_buffer_set_opacity(buffer, opacity);
+	}
 }
 
 void river_scene_node_set_opacity(struct wlr_scene_node *node, float opacity) {
 	wlr_scene_node_for_each_buffer(node, set_opacity_iterator, &opacity);
 }
 
+static void set_corner_radius_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
+	(void)sx;
+	(void)sy;
+	int radius = *(int *)user_data;
+	if (buffer->corner_radius != radius || buffer->corners != CORNER_LOCATION_ALL) {
+		wlr_scene_buffer_set_corner_radius(buffer, radius, CORNER_LOCATION_ALL);
+	}
+}
+
+void river_scene_node_set_corner_radius(struct wlr_scene_node *node, int radius) {
+	wlr_scene_node_for_each_buffer(node, set_corner_radius_iterator, &radius);
+}
+
 void river_scene_buffer_set_dest_size_if_changed(struct wlr_scene_buffer *scene_buffer, int width, int height) {
 	if (scene_buffer->dst_width != width || scene_buffer->dst_height != height) {
 		wlr_scene_buffer_set_dest_size(scene_buffer, width, height);
diff --git a/wrapper.h b/wrapper.h
index 715b85f..eb573c3 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -261,6 +261,8 @@ void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled);
 
 void river_scene_node_set_opacity(struct wlr_scene_node *node, float opacity);
 
+void river_scene_node_set_corner_radius(struct wlr_scene_node *node, int radius);
+
 void river_scene_buffer_set_dest_size_if_changed(struct wlr_scene_buffer *scene_buffer, int width, int height);
 int river_scene_buffer_get_width(struct wlr_scene_buffer *scene_buffer);
 int river_scene_buffer_get_height(struct wlr_scene_buffer *scene_buffer);