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

commit95fdd04f406bea6ccc3029ca0e2333fe610f3f3d
parent275ceaf2cd
authorLucas Galante <[email protected]>
date2026-06-16 10:07
fix: resolve expose status updates feedback loop and HiDPI window scale restoration

 src/server/status_server.rs  |  2 +-
 src/server/window.rs         | 52 ++++++++++++++++++++------------------------
 src/server/window_manager.rs |  9 +++++++-
 3 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/src/server/status_server.rs b/src/server/status_server.rs
index a7cf54c..d875656 100644
--- a/src/server/status_server.rs
+++ b/src/server/status_server.rs
@@ -12,7 +12,7 @@ use std::os::unix::net::{UnixListener, UnixStream};
 use std::sync::mpsc;
 
 /// A status update sent from the main loop to the server thread.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct StatusUpdate {
     /// JSON string for tags module subscribers
     pub tags_json: String,
diff --git a/src/server/window.rs b/src/server/window.rs
index 691e82f..7cfbe1c 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -1333,22 +1333,20 @@ impl Window {
                 let data = &*(user_data as *const ScaleData);
                 let node = buffer as *mut ffi::wlr_scene_node;
 
-                if data.scale == 1.0 {
+                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);
+                    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 dest_x = (sx as f64 * data.scale) as i32;
+                    let dest_y = (sy as f64 * data.scale) 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 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);
-                        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 dest_x = (sx as f64 * data.scale) as i32;
-                        let dest_y = (sy as f64 * data.scale) as i32;
-                        ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
-                    }
                 }
             }
 
@@ -2388,22 +2386,20 @@ impl Decoration {
             let data = &*(user_data as *const ScaleData);
             let node = buffer as *mut ffi::wlr_scene_node;
 
-            if data.scale == 1.0 {
+            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);
+                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 dest_x = (sx as f64 * data.scale) as i32;
+                let dest_y = (sy as f64 * data.scale) 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 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);
-                    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 dest_x = (sx as f64 * data.scale) as i32;
-                    let dest_y = (sy as f64 * data.scale) as i32;
-                    ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
-                }
             }
         }
 
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 2dfda72..27ef147 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -71,6 +71,7 @@ pub struct WindowManager {
     pub input_rules: Vec<crate::config::InputDeviceConfigRule>,
     pub input_config: crate::config::InputConfig,
     pub expose_active: bool,
+    pub last_status_update: std::cell::RefCell<Option<crate::status_server::StatusUpdate>>,
 }
 
 impl WindowManager {
@@ -128,6 +129,7 @@ impl WindowManager {
         self.input_rules = Vec::new();
         self.input_config = crate::config::InputConfig::default();
         self.expose_active = false;
+        self.last_status_update = std::cell::RefCell::new(None);
 
         ffi::wl_list_init(&mut self.sent.outputs);
         ffi::wl_list_init(&mut self.sent.seats);
@@ -1100,7 +1102,12 @@ impl WindowManager {
 
     pub unsafe fn update_status(&self) {
         if let Some(ref sender) = self.status_sender {
-            sender.send(crate::status_server::build_status_update(self));
+            let update = crate::status_server::build_status_update(self);
+            let mut last = self.last_status_update.borrow_mut();
+            if last.as_ref() != Some(&update) {
+                sender.send(update.clone());
+                *last = Some(update);
+            }
         }
     }