Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
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();
}