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

commit0626bde99ad9e09d3d683cc9c58dd70da009027a
parentd9134ae75a
authorLucas Galante <[email protected]>
date2026-06-16 12:26
fix(cce): status interface tag visibility, focus updates, and window layout/size checks

 src/server/seat.rs           |  1 +
 src/server/window.rs         | 73 +++++++++++++++++++++++++++++++++-----------
 src/server/window_manager.rs | 18 ++++++++---
 src/server/xdg_toplevel.rs   | 35 ++++++++++-----------
 4 files changed, 87 insertions(+), 40 deletions(-)

diff --git a/src/server/seat.rs b/src/server/seat.rs
index fa3a312..2a2acb5 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -345,6 +345,7 @@ impl Seat {
         }
 
         self.focused = new_focus;
+        (*self.server).wm.update_status();
 
         match new_focus {
             Focus::None => {}
diff --git a/src/server/window.rs b/src/server/window.rs
index 0520007..20c076f 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -692,7 +692,11 @@ impl Window {
     pub unsafe fn set_dimensions_hint(&mut self, hint: DimensionsHint) {
         self.wm_scheduled.dimensions_hint = hint;
         if self.wm_sent.dimensions_hint != hint {
-            (*self.server).wm.dirty_windowing();
+            if matches!(self.tiling_mode, crate::tiling::TilingMode::Floating | crate::tiling::TilingMode::Popup) {
+                (*self.server).wm.dirty_windowing();
+            } else {
+                self.wm_sent.dimensions_hint = hint;
+            }
         }
     }
 
@@ -1333,6 +1337,7 @@ impl Window {
 
             struct ScaleData {
                 scale: f64,
+                ancestor: *mut ffi::wlr_scene_node,
             }
 
             unsafe extern "C" fn set_expose_scale_iterator(
@@ -1348,29 +1353,37 @@ impl Window {
                 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);
+                    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);
                 }
             }
 
-            let scale_data = ScaleData { scale: self.scale };
+            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 as *const ScaleData as *mut std::ffi::c_void,
+                &scale_data_surfaces 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 as *const ScaleData as *mut std::ffi::c_void,
+                &scale_data_popup as *const ScaleData as *mut std::ffi::c_void,
             );
         }
 
@@ -2386,6 +2399,7 @@ impl Decoration {
 
         struct ScaleData {
             scale: f64,
+            ancestor: *mut ffi::wlr_scene_node,
         }
 
         unsafe extern "C" fn set_expose_scale_iterator(
@@ -2401,20 +2415,26 @@ impl Decoration {
             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);
+                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 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);
+                    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);
             }
         }
 
-        let scale_data = ScaleData { scale };
+        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),
@@ -2563,6 +2583,23 @@ pub static mut DECORATION_ROLE: ffi::wlr_surface_role = ffi::wlr_surface_role {
     destroy: Some(dec_role_destroy),
 };
 
+unsafe fn get_parent_position_relative_to(
+    node: *mut ffi::wlr_scene_node,
+    ancestor: *mut ffi::wlr_scene_node,
+) -> (i32, i32) {
+    let mut x = 0;
+    let mut y = 0;
+    if !node.is_null() {
+        let mut curr = ffi::river_scene_node_get_parent(node) as *mut ffi::wlr_scene_node;
+        while !curr.is_null() && curr != ancestor {
+            x += ffi::river_scene_node_get_x(curr);
+            y += ffi::river_scene_node_get_y(curr);
+            curr = ffi::river_scene_node_get_parent(curr) as *mut ffi::wlr_scene_node;
+        }
+    }
+    (x, y)
+}
+
 unsafe fn wl_listener_remove_safe(listener: *mut ffi::wl_listener) {
     let prev = (*listener).link.prev;
     let next = (*listener).link.next;
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 27ef147..7938ed5 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -213,20 +213,22 @@ impl WindowManager {
     }
 
     pub unsafe fn dirty_windowing(&mut self) {
+        let bt = std::backtrace::Backtrace::force_capture();
+        log::info!("dirty_windowing called from backtrace:\n{}", bt);
         self.scheduled.dirty = true;
         self.add_dirty_idle();
     }
-
+ 
     pub unsafe fn dirty_windowing_lazy(&mut self) {
         self.scheduled.dirty_lazy = true;
         self.add_dirty_idle();
     }
-
+ 
     pub unsafe fn clean_windowing(&mut self) {
         self.scheduled.dirty = false;
         self.remove_dirty_idle();
     }
-
+ 
     pub unsafe fn dirty_rendering(&mut self) {
         self.rendering_scheduled.dirty = true;
         self.add_dirty_idle();
@@ -706,7 +708,9 @@ impl WindowManager {
                     continue;
                 }
 
-                let visible = ((*win_ptr).tags & self.active_tags) != 0;
+                let app_id = (*win_ptr).get_app_id_string();
+                let is_status_bar = app_id.as_deref() == Some("cce-status-interface");
+                let visible = is_status_bar || ((*win_ptr).tags & self.active_tags) != 0;
                 if !visible {
                     ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, false);
                     (*win_ptr).rendering_requested.hidden = true;
@@ -1125,7 +1129,11 @@ impl WindowManager {
         let mut next_focus: *mut Window = std::ptr::null_mut();
         for &w in self.windows.iter() {
             if !w.is_null() && !(*w).closed && !(*w).minimized && ((*w).tags & self.active_tags) != 0 {
-                next_focus = w;
+                let app_id = (*w).get_app_id_string();
+                let is_status_bar = app_id.as_deref() == Some("cce-status-interface");
+                if !is_status_bar {
+                    next_focus = w;
+                }
             }
         }
         if !next_focus.is_null() {
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index ba9323e..aa95e59 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -239,30 +239,25 @@ impl XdgToplevel {
 
         let width = if let Some(w) = scheduled.width {
             w
+        } else if let Some(w) = (*self.window).configure_sent.width {
+            w
         } else {
-            match self.configure_state {
-                ConfigureState::Idle => self.geometry.width as u32,
-                ConfigureState::Inflight(..)
-                | ConfigureState::Acked
-                | ConfigureState::Committed
-                | ConfigureState::TimedOut(..)
-                | ConfigureState::TimedOutAcked => (*self.window).configure_sent.width.unwrap_or(0),
-            }
+            self.geometry.width as u32
         };
 
         let height = if let Some(h) = scheduled.height {
             h
+        } else if let Some(h) = (*self.window).configure_sent.height {
+            h
         } else {
-            match self.configure_state {
-                ConfigureState::Idle => self.geometry.height as u32,
-                ConfigureState::Inflight(..)
-                | ConfigureState::Acked
-                | ConfigureState::Committed
-                | ConfigureState::TimedOut(..)
-                | ConfigureState::TimedOutAcked => (*self.window).configure_sent.height.unwrap_or(0),
-            }
+            self.geometry.height as u32
         };
 
+        log::info!(
+            "XdgToplevel::configure: sending size {}x{} (scheduled={:?}, sent={:?}, geometry={:?}) to client '{}'",
+            width, height, scheduled.width, sent.width, (self.geometry.width, self.geometry.height), (*self.window).get_title_string().unwrap_or_else(|| "None".to_string())
+        );
+
         let configure_serial = ffi::wlr_xdg_toplevel_set_size(self.wlr_toplevel, width as i32, height as i32);
 
         (*self.window).configure_sent = (*self.window).configure_scheduled.clone();
@@ -467,7 +462,13 @@ unsafe extern "C" fn handle_commit(listener: *mut ffi::wl_listener, _data: *mut
                     "client initiated size change: {}x{} -> {}x{}",
                     old_geometry.width, old_geometry.height, new_geometry.width, new_geometry.height
                 );
-                (*window).set_dimensions(new_geometry.width as u32, new_geometry.height as u32);
+                if matches!((*window).tiling_mode, crate::tiling::TilingMode::Floating | crate::tiling::TilingMode::Popup) {
+                    (*window).set_dimensions(new_geometry.width as u32, new_geometry.height as u32);
+                    (*window).configure_sent.width = Some(new_geometry.width as u32);
+                    (*window).configure_sent.height = Some(new_geometry.height as u32);
+                } else {
+                    (*window).render_finish();
+                }
             } else if old_geometry.x != new_geometry.x || old_geometry.y != new_geometry.y {
                 (*window).render_finish();
             }