Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Implement status bar module-specific snapping, vertical centering, and persistent layout config saving
Cargo.toml | 1 +
src/server/cursor.rs | 169 +++++++++++++++++++++++++++++++++----------
src/server/output.rs | 2 +-
src/server/output_manager.rs | 2 +-
src/server/seat.rs | 137 +++++++++++++++++++++++++----------
src/server/window.rs | 49 ++++++++++++-
src/server/window_manager.rs | 63 +++++++++-------
7 files changed, 314 insertions(+), 109 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index a0cb603..64e944a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
doctest = false
[dependencies]
+cce-ui = { path = "../cce-ui" }
xkbcommon = "0.7"
serde = { version = "1", features = ["derive"] }
nix = { version = "0.29", features = ["signal", "process", "fs", "poll", "resource"] }
diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index 78b3138..ac4cd9b 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -1067,14 +1067,16 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
if (*(*seat).server).wm.adjust_position_mode && !op.window_ptr.is_null() && (*op.window_ptr).is_status_bar() && (*event).button == 0x110 {
let win = op.window_ptr;
- let mut closest_edge = crate::window::StatusEdge::Top;
+ let mut closest_edge = crate::window::StatusEdge::TopLeft;
let mut min_dist = f64::MAX;
let app_id = (*win).get_app_id_string().unwrap_or_default();
log::info!("[StatusRelease] Released status window: app_id={}, lx={}, ly={}", app_id, lx, ly);
let outputs_list = &mut (*server).om.outputs as *mut ffi::wl_list as *mut WlList;
let mut curr_out = (*outputs_list).next;
- let mut found_out = false;
+ let mut best_output: *mut crate::output::Output = std::ptr::null_mut();
+ let mut min_output_dist = f64::MAX;
+
while curr_out != outputs_list {
let output = crate::container_of!(curr_out, crate::output::Output, link);
if (*output).sent.state == crate::output::OutputStateValue::Enabled {
@@ -1084,56 +1086,145 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
let ow = wlr_box.width as f64;
let oh = wlr_box.height as f64;
- log::info!("[StatusRelease] Checking output: box_geom=({}, {}, {}, {})", ox, oy, ow, oh);
- if lx >= ox && lx <= ox + ow && ly >= oy && ly <= oy + oh {
- found_out = true;
- let dt = ly - oy;
- let db = (oy + oh) - ly;
- let dl = lx - ox;
- let dr = (ox + ow) - lx;
-
- log::info!("[StatusRelease] Distances: top={}, bottom={}, left={}, right={}", dt, db, dl, dr);
- enum EdgeBasic { Top, Bottom, Left, Right }
- let mut edge = EdgeBasic::Top;
- if dt < min_dist { min_dist = dt; edge = EdgeBasic::Top; }
- if db < min_dist { min_dist = db; edge = EdgeBasic::Bottom; }
- if dl < min_dist { min_dist = dl; edge = EdgeBasic::Left; }
- if dr < min_dist { min_dist = dr; edge = EdgeBasic::Right; }
-
- match edge {
- EdgeBasic::Top => {
- if lx < ox + ow / 3.0 {
- closest_edge = crate::window::StatusEdge::TopLeft;
- } else if lx > ox + 2.0 * ow / 3.0 {
- closest_edge = crate::window::StatusEdge::TopRight;
- } else {
- closest_edge = crate::window::StatusEdge::TopCenter;
- }
+ let clamp = |val: f64, min: f64, max: f64| {
+ if val < min { min } else if val > max { max } else { val }
+ };
+ let cx = clamp(lx, ox, ox + ow);
+ let cy = clamp(ly, oy, oy + oh);
+ let dx = lx - cx;
+ let dy = ly - cy;
+ let dist = dx * dx + dy * dy;
+ if dist < min_output_dist {
+ min_output_dist = dist;
+ best_output = output;
+ }
+ }
+ curr_out = (*curr_out).next;
+ }
+
+ let mut found_out = false;
+ if !best_output.is_null() {
+ found_out = true;
+ let wlr_box = (*best_output).sent.box_layout();
+ let ox = wlr_box.x as f64;
+ let oy = wlr_box.y as f64;
+ let ow = wlr_box.width as f64;
+ let oh = wlr_box.height as f64;
+
+ log::info!("[StatusRelease] Checking best output: box_geom=({}, {}, {}, {})", ox, oy, ow, oh);
+
+ let dt = ly - oy;
+ let db = (oy + oh) - ly;
+ let dl = lx - ox;
+ let dr = (ox + ow) - lx;
+
+ log::info!("[StatusRelease] Distances: top={}, bottom={}, left={}, right={}", dt, db, dl, dr);
+ enum EdgeBasic { Top, Bottom, Left, Right }
+ let mut edge = EdgeBasic::Top;
+ if dt < min_dist { min_dist = dt; edge = EdgeBasic::Top; }
+ if db < min_dist { min_dist = db; edge = EdgeBasic::Bottom; }
+ if dl < min_dist { min_dist = dl; edge = EdgeBasic::Left; }
+ if dr < min_dist { min_dist = dr; edge = EdgeBasic::Right; }
+
+ let corner_threshold = 120.0;
+ let is_near_top = ly < oy + corner_threshold;
+ let is_near_bottom = ly > oy + oh - corner_threshold;
+ let is_near_left = lx < ox + corner_threshold;
+ let is_near_right = lx > ox + ow - corner_threshold;
+
+ let semicircle_centers = [
+ (crate::window::StatusEdge::TopLeft, ox + 60.0, oy + 0.0),
+ (crate::window::StatusEdge::TopCenter, ox + ow / 2.0, oy + 0.0),
+ (crate::window::StatusEdge::TopRight, ox + ow - 60.0, oy + 0.0),
+ (crate::window::StatusEdge::BottomLeft, ox + 60.0, oy + oh),
+ (crate::window::StatusEdge::BottomCenter, ox + ow / 2.0, oy + oh),
+ (crate::window::StatusEdge::BottomRight, ox + ow - 60.0, oy + oh),
+ (crate::window::StatusEdge::Left, ox + 0.0, oy + oh / 2.0),
+ (crate::window::StatusEdge::Right, ox + ow, oy + oh / 2.0),
+ ];
+
+ let mut snapped_to_semicircle = false;
+ for (edge_type, cx, cy) in semicircle_centers {
+ let dx = lx - cx;
+ let dy = ly - cy;
+ if dx * dx + dy * dy <= 60.0 * 60.0 {
+ closest_edge = edge_type;
+ snapped_to_semicircle = true;
+ break;
+ }
+ }
+
+ if !snapped_to_semicircle {
+ match edge {
+ EdgeBasic::Top => {
+ if is_near_left {
+ closest_edge = crate::window::StatusEdge::TopLeft;
+ } else if is_near_right {
+ closest_edge = crate::window::StatusEdge::TopRight;
+ } else {
+ closest_edge = crate::window::StatusEdge::TopCenter;
}
- EdgeBasic::Bottom => {
- if lx < ox + ow / 3.0 {
- closest_edge = crate::window::StatusEdge::BottomLeft;
- } else if lx > ox + 2.0 * ow / 3.0 {
- closest_edge = crate::window::StatusEdge::BottomRight;
- } else {
- closest_edge = crate::window::StatusEdge::BottomCenter;
- }
+ }
+ EdgeBasic::Bottom => {
+ if is_near_left {
+ closest_edge = crate::window::StatusEdge::BottomLeft;
+ } else if is_near_right {
+ closest_edge = crate::window::StatusEdge::BottomRight;
+ } else {
+ closest_edge = crate::window::StatusEdge::BottomCenter;
}
- EdgeBasic::Left => {
+ }
+ EdgeBasic::Left => {
+ if is_near_top {
+ closest_edge = crate::window::StatusEdge::TopLeft;
+ } else if is_near_bottom {
+ closest_edge = crate::window::StatusEdge::BottomLeft;
+ } else {
closest_edge = crate::window::StatusEdge::Left;
}
- EdgeBasic::Right => {
+ }
+ EdgeBasic::Right => {
+ if is_near_top {
+ closest_edge = crate::window::StatusEdge::TopRight;
+ } else if is_near_bottom {
+ closest_edge = crate::window::StatusEdge::BottomRight;
+ } else {
closest_edge = crate::window::StatusEdge::Right;
}
}
- break;
}
}
- curr_out = (*curr_out).next;
}
log::info!("[StatusRelease] Snapping app_id={} closest_edge={:?}, found_out={}", app_id, closest_edge, found_out);
(*win).status_edge = closest_edge;
+
+ let name = if let Some(stripped) = app_id.strip_prefix("cce-status-left-") {
+ stripped
+ } else if let Some(stripped) = app_id.strip_prefix("cce-status-right-") {
+ stripped
+ } else {
+ &app_id
+ };
+ let edge_str = match closest_edge {
+ crate::window::StatusEdge::Left => "left",
+ crate::window::StatusEdge::Right => "right",
+ crate::window::StatusEdge::TopLeft => "top-left",
+ crate::window::StatusEdge::TopCenter => "top-center",
+ crate::window::StatusEdge::TopRight => "top-right",
+ crate::window::StatusEdge::BottomLeft => "bottom-left",
+ crate::window::StatusEdge::BottomCenter => "bottom-center",
+ crate::window::StatusEdge::BottomRight => "bottom-right",
+ _ => "top-left",
+ };
+ let key_path = format!("layout.status_bar.{}", name);
+ cce_ui::config::write_config_value(
+ &cce_ui::config::get_config_path().to_string_lossy(),
+ &key_path,
+ &format!("\"{}\"", edge_str),
+ "layout"
+ );
+
seat.op_end();
cursor.pressed.remove(&(*event).button);
(*server).wm.dirty_windowing();
diff --git a/src/server/output.rs b/src/server/output.rs
index 050bd1b..5fc9671 100644
--- a/src/server/output.rs
+++ b/src/server/output.rs
@@ -585,7 +585,7 @@ impl Output {
// Enable the overlay tree.
ffi::wlr_scene_node_set_enabled(self.adjust_tree as *mut ffi::wlr_scene_node, true);
- ffi::wlr_scene_node_raise_to_top(self.adjust_tree as *mut ffi::wlr_scene_node);
+ ffi::wlr_scene_node_lower_to_bottom(self.adjust_tree as *mut ffi::wlr_scene_node);
let (viewport_w, viewport_h) = self.current.dimensions();
let w = viewport_w;
diff --git a/src/server/output_manager.rs b/src/server/output_manager.rs
index e072c8d..9da7b7b 100644
--- a/src/server/output_manager.rs
+++ b/src/server/output_manager.rs
@@ -240,7 +240,7 @@ impl OutputManager {
}
if output.adjust_tree.is_null() {
- output.adjust_tree = ffi::wlr_scene_tree_create((*server).scene.layers.overlay);
+ output.adjust_tree = ffi::wlr_scene_tree_create((*server).scene.layers.top);
}
if !output.adjust_tree.is_null() {
ffi::wlr_scene_node_set_position(
diff --git a/src/server/seat.rs b/src/server/seat.rs
index 633ae07..e51f839 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -973,12 +973,14 @@ impl Seat {
// Dynamically update orientation during drag
let lx = x as f64;
let ly = y as f64;
- let mut closest_edge = crate::window::StatusEdge::Top;
+ let mut closest_edge = crate::window::StatusEdge::TopLeft;
let mut min_dist = f64::MAX;
let outputs_list = &mut (*self.server).om.outputs as *mut ffi::wl_list as *mut WlList;
let mut curr_out = (*outputs_list).next;
- let mut found_out = false;
+ let mut best_output: *mut crate::output::Output = std::ptr::null_mut();
+ let mut min_output_dist = f64::MAX;
+
while curr_out != outputs_list {
let output = crate::container_of!(curr_out, crate::output::Output, link);
if (*output).sent.state == crate::output::OutputStateValue::Enabled {
@@ -987,51 +989,112 @@ impl Seat {
let oy = wlr_box.y as f64;
let ow = wlr_box.width as f64;
let oh = wlr_box.height as f64;
+
+ let clamp = |val: f64, min: f64, max: f64| {
+ if val < min { min } else if val > max { max } else { val }
+ };
+ let cx = clamp(lx, ox, ox + ow);
+ let cy = clamp(ly, oy, oy + oh);
+ let dx = lx - cx;
+ let dy = ly - cy;
+ let dist = dx * dx + dy * dy;
+ if dist < min_output_dist {
+ min_output_dist = dist;
+ best_output = output;
+ }
+ }
+ curr_out = (*curr_out).next;
+ }
+
+ let mut found_out = false;
+ if !best_output.is_null() {
+ found_out = true;
+ let wlr_box = (*best_output).sent.box_layout();
+ let ox = wlr_box.x as f64;
+ let oy = wlr_box.y as f64;
+ let ow = wlr_box.width as f64;
+ let oh = wlr_box.height as f64;
+
+ let dt = ly - oy;
+ let db = (oy + oh) - ly;
+ let dl = lx - ox;
+ let dr = (ox + ow) - lx;
+
+ enum EdgeBasic { Top, Bottom, Left, Right }
+ let mut edge = EdgeBasic::Top;
+ if dt < min_dist { min_dist = dt; edge = EdgeBasic::Top; }
+ if db < min_dist { min_dist = db; edge = EdgeBasic::Bottom; }
+ if dl < min_dist { min_dist = dl; edge = EdgeBasic::Left; }
+ if dr < min_dist { min_dist = dr; edge = EdgeBasic::Right; }
+
+ let corner_threshold = 120.0;
+ let is_near_top = ly < oy + corner_threshold;
+ let is_near_bottom = ly > oy + oh - corner_threshold;
+ let is_near_left = lx < ox + corner_threshold;
+ let is_near_right = lx > ox + ow - corner_threshold;
+
+ let semicircle_centers = [
+ (crate::window::StatusEdge::TopLeft, ox + 60.0, oy + 0.0),
+ (crate::window::StatusEdge::TopCenter, ox + ow / 2.0, oy + 0.0),
+ (crate::window::StatusEdge::TopRight, ox + ow - 60.0, oy + 0.0),
+ (crate::window::StatusEdge::BottomLeft, ox + 60.0, oy + oh),
+ (crate::window::StatusEdge::BottomCenter, ox + ow / 2.0, oy + oh),
+ (crate::window::StatusEdge::BottomRight, ox + ow - 60.0, oy + oh),
+ (crate::window::StatusEdge::Left, ox + 0.0, oy + oh / 2.0),
+ (crate::window::StatusEdge::Right, ox + ow, oy + oh / 2.0),
+ ];
+
+ let mut snapped_to_semicircle = false;
+ for (edge_type, cx, cy) in semicircle_centers {
+ let dx = lx - cx;
+ let dy = ly - cy;
+ if dx * dx + dy * dy <= 60.0 * 60.0 {
+ closest_edge = edge_type;
+ snapped_to_semicircle = true;
+ break;
+ }
+ }
- if lx >= ox && lx <= ox + ow && ly >= oy && ly <= oy + oh {
- found_out = true;
- let dt = ly - oy;
- let db = (oy + oh) - ly;
- let dl = lx - ox;
- let dr = (ox + ow) - lx;
-
- enum EdgeBasic { Top, Bottom, Left, Right }
- let mut edge = EdgeBasic::Top;
- if dt < min_dist { min_dist = dt; edge = EdgeBasic::Top; }
- if db < min_dist { min_dist = db; edge = EdgeBasic::Bottom; }
- if dl < min_dist { min_dist = dl; edge = EdgeBasic::Left; }
- if dr < min_dist { min_dist = dr; edge = EdgeBasic::Right; }
-
- match edge {
- EdgeBasic::Top => {
- if lx < ox + ow / 3.0 {
- closest_edge = crate::window::StatusEdge::TopLeft;
- } else if lx > ox + 2.0 * ow / 3.0 {
- closest_edge = crate::window::StatusEdge::TopRight;
- } else {
- closest_edge = crate::window::StatusEdge::TopCenter;
- }
+ if !snapped_to_semicircle {
+ match edge {
+ EdgeBasic::Top => {
+ if is_near_left {
+ closest_edge = crate::window::StatusEdge::TopLeft;
+ } else if is_near_right {
+ closest_edge = crate::window::StatusEdge::TopRight;
+ } else {
+ closest_edge = crate::window::StatusEdge::TopCenter;
}
- EdgeBasic::Bottom => {
- if lx < ox + ow / 3.0 {
- closest_edge = crate::window::StatusEdge::BottomLeft;
- } else if lx > ox + 2.0 * ow / 3.0 {
- closest_edge = crate::window::StatusEdge::BottomRight;
- } else {
- closest_edge = crate::window::StatusEdge::BottomCenter;
- }
+ }
+ EdgeBasic::Bottom => {
+ if is_near_left {
+ closest_edge = crate::window::StatusEdge::BottomLeft;
+ } else if is_near_right {
+ closest_edge = crate::window::StatusEdge::BottomRight;
+ } else {
+ closest_edge = crate::window::StatusEdge::BottomCenter;
}
- EdgeBasic::Left => {
+ }
+ EdgeBasic::Left => {
+ if is_near_top {
+ closest_edge = crate::window::StatusEdge::TopLeft;
+ } else if is_near_bottom {
+ closest_edge = crate::window::StatusEdge::BottomLeft;
+ } else {
closest_edge = crate::window::StatusEdge::Left;
}
- EdgeBasic::Right => {
+ }
+ EdgeBasic::Right => {
+ if is_near_top {
+ closest_edge = crate::window::StatusEdge::TopRight;
+ } else if is_near_bottom {
+ closest_edge = crate::window::StatusEdge::BottomRight;
+ } else {
closest_edge = crate::window::StatusEdge::Right;
}
}
- break;
}
}
- curr_out = (*curr_out).next;
}
if found_out {
diff --git a/src/server/window.rs b/src/server/window.rs
index 02af0c8..a25b0b2 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -263,8 +263,7 @@ pub struct Window {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatusEdge {
- Top,
- Bottom,
+ Unspecified,
TopLeft,
TopCenter,
TopRight,
@@ -482,7 +481,7 @@ impl Window {
foreign_toplevel_handle: std::ptr::null_mut(),
wlr_toplevel_handle: std::ptr::null_mut(),
csd_buffer_size_bug: false,
- status_edge: StatusEdge::Top,
+ status_edge: StatusEdge::Unspecified,
});
ffi::wl_list_init(&mut window.decorations_below);
@@ -740,6 +739,50 @@ impl Window {
if is_status_bar || is_wallpaper {
self.tiling_mode = crate::tiling::TilingMode::Status;
+ if is_status_bar && self.status_edge == StatusEdge::Unspecified {
+ let app_id = std::ffi::CStr::from_ptr(app_id_ptr).to_string_lossy();
+ let name = if let Some(stripped) = app_id.strip_prefix("cce-status-left-") {
+ stripped
+ } else if let Some(stripped) = app_id.strip_prefix("cce-status-right-") {
+ stripped
+ } else {
+ &app_id
+ };
+ let mut loaded_edge = None;
+ if let Ok(content) = std::fs::read_to_string(cce_ui::config::get_config_path()) {
+ let val = cce_ui::config::parse_kdl_to_json(&content);
+ if let Some(layout_obj) = val.get("layout") {
+ if let Some(status_bar_obj) = layout_obj.get("status_bar") {
+ if let Some(edge_val) = status_bar_obj.get(name) {
+ if let Some(edge_str) = edge_val.as_str() {
+ loaded_edge = match edge_str.to_lowercase().as_str() {
+ "left" => Some(StatusEdge::Left),
+ "right" => Some(StatusEdge::Right),
+ "top-left" => Some(StatusEdge::TopLeft),
+ "top-center" => Some(StatusEdge::TopCenter),
+ "top-right" => Some(StatusEdge::TopRight),
+ "bottom-left" => Some(StatusEdge::BottomLeft),
+ "bottom-center" => Some(StatusEdge::BottomCenter),
+ "bottom-right" => Some(StatusEdge::BottomRight),
+ _ => None,
+ };
+ }
+ }
+ }
+ }
+ }
+ self.status_edge = if let Some(edge) = loaded_edge {
+ edge
+ } else {
+ if app_id.contains("viewport") {
+ StatusEdge::TopLeft
+ } else if app_id.contains("window") {
+ StatusEdge::TopCenter
+ } else {
+ StatusEdge::TopRight
+ }
+ };
+ }
} else {
let mut should_focus = true;
if self.restored {
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 6b00963..bebfc1b 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -1175,30 +1175,8 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
let resolve_edge = |win_ptr: *mut Window| {
let edge = (*win_ptr).status_edge;
- if edge == crate::window::StatusEdge::Top {
- if let Some(app_id) = (*win_ptr).get_app_id_string() {
- if app_id.contains("viewport") {
- crate::window::StatusEdge::TopLeft
- } else if app_id.contains("window") {
- crate::window::StatusEdge::TopCenter
- } else {
- crate::window::StatusEdge::TopRight
- }
- } else {
- crate::window::StatusEdge::TopLeft
- }
- } else if edge == crate::window::StatusEdge::Bottom {
- if let Some(app_id) = (*win_ptr).get_app_id_string() {
- if app_id.contains("viewport") {
- crate::window::StatusEdge::BottomLeft
- } else if app_id.contains("window") {
- crate::window::StatusEdge::BottomCenter
- } else {
- crate::window::StatusEdge::BottomRight
- }
- } else {
- crate::window::StatusEdge::BottomLeft
- }
+ if edge == crate::window::StatusEdge::Unspecified {
+ crate::window::StatusEdge::TopLeft
} else {
edge
}
@@ -1210,12 +1188,12 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
}
if (*win_ptr).is_status_bar() {
match resolve_edge(win_ptr) {
- crate::window::StatusEdge::Top | crate::window::StatusEdge::TopLeft | crate::window::StatusEdge::TopCenter | crate::window::StatusEdge::TopRight => {
+ crate::window::StatusEdge::Unspecified | crate::window::StatusEdge::TopLeft | crate::window::StatusEdge::TopCenter | crate::window::StatusEdge::TopRight => {
if !self.status_hide_mode {
has_top = true;
}
}
- crate::window::StatusEdge::Bottom | crate::window::StatusEdge::BottomLeft | crate::window::StatusEdge::BottomCenter | crate::window::StatusEdge::BottomRight => {
+ crate::window::StatusEdge::BottomLeft | crate::window::StatusEdge::BottomCenter | crate::window::StatusEdge::BottomRight => {
has_bottom = true;
}
crate::window::StatusEdge::Left => {
@@ -1884,7 +1862,17 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
}
// 3. Left Edge (Vertical stacking)
- let mut cur_left_y = wlr_box.y + margin;
+ let mut left_total_height = 0;
+ for &win_ptr in &left_side {
+ let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
+ let actual_h = if prev_len > 0 { prev_len as u32 } else { 100 };
+ left_total_height += actual_h as i32;
+ }
+ if !left_side.is_empty() {
+ left_total_height += (left_side.len() as i32 - 1) * spacing;
+ }
+ let mut cur_left_y = wlr_box.y + (wlr_box.height - left_total_height) / 2;
+
for win_ptr in left_side {
let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
let actual_h = if prev_len > 0 { prev_len as u32 } else { 100 };
@@ -1896,7 +1884,17 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
}
// 4. Right Edge (Vertical stacking)
- let mut cur_right_y = wlr_box.y + margin;
+ let mut right_total_height = 0;
+ for &win_ptr in &right_side {
+ let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
+ let actual_h = if prev_len > 0 { prev_len as u32 } else { 100 };
+ right_total_height += actual_h as i32;
+ }
+ if !right_side.is_empty() {
+ right_total_height += (right_side.len() as i32 - 1) * spacing;
+ }
+ let mut cur_right_y = wlr_box.y + (wlr_box.height - right_total_height) / 2;
+
for win_ptr in right_side {
let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
let actual_h = if prev_len > 0 { prev_len as u32 } else { 100 };
@@ -1906,6 +1904,15 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
(*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: bar_h, height: actual_h };
cur_right_y += actual_h as i32 + spacing;
}
+
+ // Force configure for all status bar windows on this output so they receive the new geometry immediately
+ for &win_ptr in self.windows.iter() {
+ if !win_ptr.is_null() && !(*win_ptr).closed && (*win_ptr).is_status_bar() {
+ if (*win_ptr).wm_requested.dimensions.is_some() {
+ (*win_ptr).manage_finish();
+ }
+ }
+ }
}
// If the focused window is no longer visible, refocus
let seats_list = &mut (*self.server).input_manager.seats as *mut ffi::wl_list as *mut WlList;