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

commit1b610a2471071cb9f5cc9814d5d49e09a5a8bb56
parent5a12486945
authorLucas Galante <[email protected]>
date2026-07-03 14:01
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;