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

commit4e9b9e03813c6c904f4c316d2f94edfec0043a78
parente3a34d5b81
authorLucas Galante <[email protected]>
date2026-07-14 22:03
refactor: extract pure window-management policy layer from arrange_views

First step of the compositor/window-manager split: new src/server/policy/
module holds FFI-free policy code, seeded with the Policy/Compositor trait
boundary (api.rs) and the pure logic carved out of window_manager.rs:

- tiling.rs moved into policy/ (re-exported as crate::tiling)
- SavedState/SavedWindowState moved to policy/state.rs (same serde format)
- policy/arrange.rs: status-bar nine-region layout engine, usable-area
  computation, window classification, overlay placement, the Maximized
  enter/exit state machine, per-mode placement (popup/fullscreen/
  maximized grid-snap/pannable), offscreen culling, opacity policy
- WindowRole::from_app_id centralizes the "cce-wallpaper"/"cce-status"
  app_id conventions; Window::is_wallpaper/is_status_bar delegate to it
- StatusEdge moved to policy (re-exported via window.rs)

arrange_views drops from ~870 to ~460 lines and now only builds plain-data
snapshots and applies returned plans to the scene graph. Behavior-identical
by construction: persistent state writes (box_geom, virtual pos, saved
maximized geometry) are explicit plan fields, and loop order (including
multi-output last-wins and overlay demotion) is preserved. 14 new unit
tests pin grid snapping, bar layout, transitions, and culling.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014qnNdSob3VnZC9yGyiuGMA

 src/lib.rs                        |    5 +-
 src/server/policy/api.rs          |  142 ++++++
 src/server/policy/arrange.rs      | 1014 +++++++++++++++++++++++++++++++++++++
 src/server/policy/mod.rs          |   20 +
 src/server/policy/state.rs        |   32 ++
 src/server/{ => policy}/tiling.rs |    0
 src/server/window.rs              |   21 +-
 src/server/window_manager.rs      |  930 +++++++++-------------------------
 8 files changed, 1466 insertions(+), 698 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 1a98484..e2cb64d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,8 +21,9 @@ pub mod xkb_bindings;
 pub mod layer_shell;
 #[path = "server/scene.rs"]
 pub mod scene;
-#[path = "server/tiling.rs"]
-pub mod tiling;
+#[path = "server/policy/mod.rs"]
+pub mod policy;
+pub use policy::tiling;
 #[path = "server/config.rs"]
 pub mod config;
 #[path = "server/ipc_server.rs"]
diff --git a/src/server/policy/api.rs b/src/server/policy/api.rs
new file mode 100644
index 0000000..99e222d
--- /dev/null
+++ b/src/server/policy/api.rs
@@ -0,0 +1,142 @@
+// The Policy / Compositor trait boundary.
+//
+// `Policy` is implemented by the window-management side: it receives events
+// and decides placement, focus, decoration, and background — using only the
+// plain-data types in this file, never FFI. `Compositor` is implemented by
+// the mechanism side (`window_manager.rs` and friends): it executes those
+// decisions against the wlroots/scenefx scene graph.
+//
+// Skeleton status: nothing implements these traits yet. The migration plan is
+// to split `arrange_views()` into a policy half (compute placements) and a
+// mechanism half (apply to scene), then route window lifecycle, input actions,
+// and the animation tick through `Policy`. Effects are declarative on purpose:
+// new scenefx capabilities extend `EffectSpec` without changing either trait.
+
+use super::state::SavedState;
+
+/// Opaque handle to a window. Wraps the `SlotMap` key that the mechanism side
+/// uses internally; policy code never sees a pointer.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct WindowId(pub crate::slotmap::Key);
+
+/// What a surface is for. Assigned once at map time, this replaces scattered
+/// app_id string-matching (`"cce-wallpaper"`, `"cce-status*"`) in mechanism code.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WindowRole {
+    Normal,
+    StatusBar,
+    Background,
+    Overlay,
+}
+
+impl WindowRole {
+    /// The single place the special app_id conventions are interpreted.
+    /// `Overlay` is never derived from an app_id — it comes from tiling mode.
+    pub fn from_app_id(app_id: Option<&str>) -> Self {
+        match app_id {
+            Some("cce-wallpaper") => WindowRole::Background,
+            Some(id) if id.starts_with("cce-status") => WindowRole::StatusBar,
+            _ => WindowRole::Normal,
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct WindowInfo {
+    pub app_id: String,
+    pub title: String,
+    pub role: WindowRole,
+    pub cmdline: String,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct Rect {
+    pub x: i32,
+    pub y: i32,
+    pub width: i32,
+    pub height: i32,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct Rgba(pub [f32; 4]);
+
+/// Server-side decoration for one window: borders now, titlebars later.
+#[derive(Debug, Clone, PartialEq)]
+pub struct DecorationSpec {
+    pub border_width: i32,
+    pub border_color: Rgba,
+    pub corner_radius: i32,
+}
+
+/// Declarative per-window scenefx effects.
+#[derive(Debug, Clone, PartialEq)]
+pub struct EffectSpec {
+    pub opacity: f32,
+    pub blur: bool,
+    pub shadow: Option<ShadowSpec>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct ShadowSpec {
+    pub color: Rgba,
+    pub blur_sigma: f32,
+}
+
+/// What the background layer shows. Absorbs cce-wallpaper (Solid) and the
+/// grid_tree drawing in `output.rs` (Grid).
+#[derive(Debug, Clone, PartialEq)]
+pub enum BackgroundSpec {
+    Solid(Rgba),
+    Grid(GridSpec),
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct GridSpec {
+    pub background: Rgba,
+    pub line_color: Rgba,
+    pub cell_size: i32,
+    pub line_width: i32,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct OutputInfo {
+    pub width: i32,
+    pub height: i32,
+    pub scale: f32,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum PointerEvent {
+    Press { window: Option<WindowId>, x: f64, y: f64, button: u32 },
+    Release { window: Option<WindowId>, x: f64, y: f64, button: u32 },
+    Motion { x: f64, y: f64 },
+}
+
+/// Commands from policy to mechanism. Implemented by the compositor side;
+/// every method maps onto existing `WindowManager` / scene operations.
+pub trait Compositor {
+    fn place(&mut self, window: WindowId, rect: Rect);
+    fn focus(&mut self, window: Option<WindowId>);
+    fn raise(&mut self, window: WindowId);
+    fn close(&mut self, window: WindowId);
+    /// Pans/zooms windows and the background in the same frame.
+    fn set_viewport(&mut self, pan_x: f64, pan_y: f64, zoom: f64);
+    fn set_decoration(&mut self, window: WindowId, spec: DecorationSpec);
+    fn set_effects(&mut self, window: WindowId, spec: EffectSpec);
+    fn set_background(&mut self, spec: BackgroundSpec);
+    fn spawn(&mut self, cmdline: &str);
+}
+
+/// Events from mechanism to policy. Implemented by the window-management side.
+pub trait Policy {
+    fn window_mapped(&mut self, c: &mut dyn Compositor, window: WindowId, info: &WindowInfo);
+    fn window_unmapped(&mut self, c: &mut dyn Compositor, window: WindowId);
+    fn window_meta_changed(&mut self, c: &mut dyn Compositor, window: WindowId, info: &WindowInfo);
+    fn action(&mut self, c: &mut dyn Compositor, action: &crate::config::Action, arg: Option<&str>);
+    fn pointer(&mut self, c: &mut dyn Compositor, event: PointerEvent);
+    fn output_changed(&mut self, c: &mut dyn Compositor, outputs: &[OutputInfo]);
+    /// Animation driver: easing for pan/zoom targets, effect transitions.
+    fn tick(&mut self, c: &mut dyn Compositor, dt: f64);
+    fn save_state(&self) -> SavedState;
+    fn restore_state(&mut self, c: &mut dyn Compositor, state: SavedState);
+}
diff --git a/src/server/policy/arrange.rs b/src/server/policy/arrange.rs
new file mode 100644
index 0000000..67dd7f9
--- /dev/null
+++ b/src/server/policy/arrange.rs
@@ -0,0 +1,1014 @@
+// Pure layout computation extracted from `WindowManager::arrange_views()`.
+//
+// Functions here take plain-data snapshots and return placement plans; the
+// mechanism side (`window_manager.rs`) builds the snapshots from FFI state and
+// applies the plans to the scene graph. Extraction happens section by section;
+// currently covers the status-bar layout engine.
+
+use super::api::{Rect, WindowRole};
+use super::tiling::TilingMode;
+
+/// Which screen edge/region a status-bar window docks to.
+/// Set from the app_id suffix or config; `Unspecified` resolves to `TopLeft`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum StatusEdge {
+    Unspecified,
+    TopLeft,
+    TopCenter,
+    TopRight,
+    BottomLeft,
+    BottomCenter,
+    BottomRight,
+    Left,
+    Right,
+}
+
+/// Snapshot of one status-bar window, in `self.windows` iteration order.
+/// Windows being interactively dragged are excluded before layout.
+pub struct StatusBarItem {
+    pub app_id: String,
+    pub edge: StatusEdge,
+    /// max(box_geom.width, box_geom.height) — the bar's previous major length.
+    pub prev_len: i32,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct StatusBarPlacement {
+    pub x: i32,
+    pub y: i32,
+    pub width: u32,
+    pub height: u32,
+}
+
+pub struct StatusBarLayoutParams {
+    /// The output's layout box.
+    pub output: Rect,
+    pub bar_height: u32,
+    pub hide_mode: bool,
+    /// Pixels of bar left peeking when hide_mode pushes top bars offscreen.
+    pub hide_mode_preview: i32,
+}
+
+/// The usable (tileable) area of an output: the layout box, shrunk by the
+/// layer-shell non-exclusive area and by one bar-height per screen edge that
+/// has a status bar docked to it. Top bars reserve no space in hide mode.
+///
+/// `non_exclusive` is relative to the output box; a zero-sized rect means no
+/// layer-shell exclusion. `status_edges` holds the raw edge of every live
+/// status-bar window (`Unspecified` resolves to `TopLeft`).
+pub fn compute_usable_area(
+    output: Rect,
+    non_exclusive: Rect,
+    bar_height: i32,
+    status_hide_mode: bool,
+    status_edges: &[StatusEdge],
+) -> Rect {
+    let mut usable = output;
+
+    if non_exclusive.width > 0 && non_exclusive.height > 0 {
+        usable.x = output.x + non_exclusive.x;
+        usable.y = output.y + non_exclusive.y;
+        usable.width = non_exclusive.width;
+        usable.height = non_exclusive.height;
+    }
+
+    let mut has_top = false;
+    let mut has_bottom = false;
+    let mut has_left = false;
+    let mut has_right = false;
+
+    for &edge in status_edges {
+        let edge = if edge == StatusEdge::Unspecified { StatusEdge::TopLeft } else { edge };
+        match edge {
+            StatusEdge::Unspecified | StatusEdge::TopLeft | StatusEdge::TopCenter | StatusEdge::TopRight => {
+                if !status_hide_mode {
+                    has_top = true;
+                }
+            }
+            StatusEdge::BottomLeft | StatusEdge::BottomCenter | StatusEdge::BottomRight => {
+                has_bottom = true;
+            }
+            StatusEdge::Left => {
+                has_left = true;
+            }
+            StatusEdge::Right => {
+                has_right = true;
+            }
+        }
+    }
+
+    if has_top {
+        usable.y += bar_height;
+        usable.height -= bar_height;
+    }
+    if has_bottom {
+        usable.height -= bar_height;
+    }
+    if has_left {
+        usable.x += bar_height;
+        usable.width -= bar_height;
+    }
+    if has_right {
+        usable.width -= bar_height;
+    }
+
+    usable
+}
+
+/// How `arrange_views` treats a window this frame. `Background`/`StatusBar`
+/// windows get fixed geometry regardless of visibility; `Hidden` windows are
+/// disabled in the scene; `Overlay` windows get the overlay slot unless they
+/// are mid-drag (then they arrange as `Normal`).
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WindowClass {
+    Background,
+    StatusBar,
+    Hidden,
+    Overlay,
+    Normal,
+}
+
+pub fn classify_window(
+    role: WindowRole,
+    minimized: bool,
+    closing_or_init: bool,
+    mode: TilingMode,
+    is_moving: bool,
+) -> WindowClass {
+    match role {
+        WindowRole::Background => WindowClass::Background,
+        WindowRole::StatusBar => WindowClass::StatusBar,
+        _ => {
+            if minimized || closing_or_init {
+                WindowClass::Hidden
+            } else if mode == TilingMode::Overlay && !is_moving {
+                WindowClass::Overlay
+            } else {
+                WindowClass::Normal
+            }
+        }
+    }
+}
+
+/// Legacy border width, baked into the overlay geometry formulas.
+const BW: i32 = 0;
+
+/// Overlay windows keep 16px clear above for decorations.
+const OVERLAY_DEC_H: i32 = 16;
+
+/// Windows further than this many pixels outside the output are culled.
+const OFFSCREEN_MARGIN: f64 = 50.0;
+
+pub const OVERLAY_UNFOCUSED_OPACITY: f32 = 0.85;
+pub const NORMAL_UNFOCUSED_OPACITY: f32 = 0.90;
+
+pub fn window_opacity(is_focused: bool, opacity_enabled: bool, unfocused: f32) -> f32 {
+    if is_focused || !opacity_enabled { 1.0 } else { unfocused }
+}
+
+/// Per-output placement context: the physical box, the usable area from
+/// `compute_usable_area`, and the desktop viewport (pan/zoom).
+pub struct PlacementCtx {
+    pub phys: Rect,
+    pub usable: Rect,
+    pub pan_x: f64,
+    pub pan_y: f64,
+    pub zoom: f64,
+}
+
+impl PlacementCtx {
+    fn virtual_to_screen(&self, vx: f64, vy: f64) -> (i32, i32) {
+        (
+            self.phys.x + ((vx - self.pan_x) * self.zoom) as i32,
+            self.phys.y + ((vy - self.pan_y) * self.zoom) as i32,
+        )
+    }
+
+    fn is_offscreen(&self, x: i32, y: i32, scaled_w: f64, scaled_h: f64) -> bool {
+        let viewport_w = self.phys.width as f64;
+        let viewport_h = self.phys.height as f64;
+        (x as f64 + scaled_w + OFFSCREEN_MARGIN) < self.phys.x as f64
+            || (x as f64 - OFFSCREEN_MARGIN) > (self.phys.x as f64 + viewport_w)
+            || (y as f64 + scaled_h + OFFSCREEN_MARGIN) < self.phys.y as f64
+            || (y as f64 - OFFSCREEN_MARGIN) > (self.phys.y as f64 + viewport_h)
+    }
+}
+
+pub struct OverlaySnapshot {
+    pub box_geom: Rect,
+    pub min_width: i32,
+    pub is_cloud: bool,
+    pub ssd: bool,
+    pub decorations_size: (i32, i32),
+}
+
+pub struct OverlayParams {
+    pub overlay_width: i32,
+    pub border_gap: i32,
+    pub position_right: bool,
+    pub cloud_position_default: Option<[i32; 2]>,
+}
+
+pub struct OverlayPlacement {
+    pub pos: (i32, i32),
+    /// Persistent geometry to store back on the window, if placement chose it.
+    pub box_geom_write: Option<Rect>,
+    pub virtual_pos: (f64, f64),
+    pub size: (u32, u32),
+}
+
+/// Place the primary overlay window: fresh windows get the configured overlay
+/// slot (left or right edge, full usable height); cloud windows snap to their
+/// configured default position; anything else keeps its stored geometry.
+pub fn place_overlay_window(
+    snap: &OverlaySnapshot,
+    p: &OverlayParams,
+    ctx: &PlacementCtx,
+) -> OverlayPlacement {
+    let bw = BW;
+    let g = p.border_gap;
+    let dec_h = std::cmp::max(bw, OVERLAY_DEC_H);
+
+    let mut sp_x = snap.box_geom.x;
+    let mut sp_y = snap.box_geom.y;
+    let mut sp_w = snap.box_geom.width;
+    let mut sp_h = snap.box_geom.height;
+    let mut box_geom_write = None;
+
+    if sp_w == 0 || sp_h == 0 {
+        sp_w = if snap.min_width > 32 {
+            std::cmp::max(p.overlay_width, snap.min_width)
+        } else {
+            p.overlay_width
+        };
+        sp_h = (ctx.usable.height - (dec_h + bw) - 2 * g).max(1);
+
+        sp_x = if p.position_right {
+            ctx.usable.x + ctx.usable.width - sp_w - g + bw
+        } else {
+            ctx.usable.x + g + bw
+        };
+        sp_y = ctx.usable.y + dec_h + g;
+
+        box_geom_write = Some(Rect { x: sp_x, y: sp_y, width: sp_w, height: sp_h });
+    } else if snap.is_cloud {
+        if let Some(pos) = p.cloud_position_default {
+            sp_x = ctx.usable.x + pos[0];
+            sp_y = ctx.usable.y + pos[1];
+            box_geom_write = Some(Rect { x: sp_x, y: sp_y, width: sp_w, height: sp_h });
+        }
+    }
+
+    let vx = ctx.pan_x + (sp_x - ctx.phys.x) as f64 / ctx.zoom;
+    let vy = ctx.pan_y + (sp_y - ctx.phys.y) as f64 / ctx.zoom;
+
+    let mut target_w = sp_w;
+    let mut target_h = sp_h;
+    if !snap.ssd {
+        let (dec_w, dec_h) = snap.decorations_size;
+        target_w = (sp_w - dec_w).max(1);
+        target_h = (sp_h - dec_h).max(1);
+    }
+
+    OverlayPlacement {
+        pos: (sp_x, sp_y),
+        box_geom_write,
+        virtual_pos: (vx, vy),
+        size: (target_w as u32, target_h as u32),
+    }
+}
+
+/// State-machine step for entering/leaving Maximized mode. `Enter` tells the
+/// mechanism to save the given restore size (plus the window's current virtual
+/// position) and set `was_maximized`; `Exit` restores the saved geometry.
+/// Leaving with an invalid saved size does nothing (`was_maximized` stays set).
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum MaximizedTransition {
+    Enter { width: i32, height: i32 },
+    Exit { width: i32, height: i32, virtual_x: f64, virtual_y: f64 },
+}
+
+pub fn maximized_transition(
+    is_maximized_mode: bool,
+    was_maximized: bool,
+    box_size: (i32, i32),
+    min_size: (i32, i32),
+    saved_size: (i32, i32),
+    saved_virtual: (f64, f64),
+) -> Option<MaximizedTransition> {
+    if is_maximized_mode && !was_maximized {
+        let mut w = box_size.0;
+        let mut h = box_size.1;
+        if w <= 0 {
+            w = if min_size.0 > 32 { min_size.0 } else { 800 };
+        }
+        if h <= 0 {
+            h = if min_size.1 > 32 { min_size.1 } else { 600 };
+        }
+        Some(MaximizedTransition::Enter { width: w, height: h })
+    } else if !is_maximized_mode && was_maximized {
+        if saved_size.0 > 0 && saved_size.1 > 0 {
+            Some(MaximizedTransition::Exit {
+                width: saved_size.0,
+                height: saved_size.1,
+                virtual_x: saved_virtual.0,
+                virtual_y: saved_virtual.1,
+            })
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+
+pub struct NormalSnapshot {
+    pub mode: TilingMode,
+    pub box_geom: Rect,
+    pub min_size: (i32, i32),
+    pub virtual_pos: (f64, f64),
+    /// Live interactive-resize dimensions, if a resize op is in progress.
+    pub active_resize: Option<(u32, u32)>,
+    pub is_cloud: bool,
+    pub saved_maximized_size: (i32, i32),
+    pub saved_maximized_virtual: (f64, f64),
+}
+
+pub struct NormalParams {
+    pub gap_right: i32,
+    pub gap_top: i32,
+    pub cloud_position_default: Option<[i32; 2]>,
+    pub desktop_grid_scale: f64,
+}
+
+pub struct NormalPlacement {
+    pub pos: (i32, i32),
+    pub scale: f64,
+    pub size: (u32, u32),
+    /// Fullscreen windows report all edges tiled to the client.
+    pub tiled_all_edges: bool,
+    /// Offscreen-culling result; `None` leaves the window's flag untouched.
+    pub hidden: Option<bool>,
+    /// Maximized grid-snap moves the window's virtual position.
+    pub virtual_write: Option<(f64, f64)>,
+}
+
+/// Place a non-overlay window according to its tiling mode: `Popup` docks to
+/// the usable area's top-right (or the cloud default position), `Fullscreen`
+/// covers the physical output, `Maximized` snaps to cover every desktop-grid
+/// cell its saved geometry touches, and everything else pans on the virtual
+/// surface under the current viewport.
+pub fn place_normal_window(
+    snap: &NormalSnapshot,
+    p: &NormalParams,
+    ctx: &PlacementCtx,
+) -> NormalPlacement {
+    match snap.mode {
+        TilingMode::Popup => {
+            let fw = if snap.box_geom.width > 0 {
+                snap.box_geom.width
+            } else if snap.min_size.0 > 32 {
+                snap.min_size.0
+            } else {
+                360
+            };
+            let fh = if snap.box_geom.height > 0 {
+                snap.box_geom.height
+            } else if snap.min_size.1 > 32 {
+                snap.min_size.1
+            } else {
+                100
+            };
+
+            let (fx, fy) = if snap.is_cloud && p.cloud_position_default.is_some() {
+                let pos = p.cloud_position_default.unwrap();
+                (ctx.usable.x + pos[0], ctx.usable.y + pos[1])
+            } else {
+                (ctx.usable.x + ctx.usable.width - fw - p.gap_right, ctx.usable.y + p.gap_top)
+            };
+
+            NormalPlacement {
+                pos: (fx, fy),
+                scale: 1.0,
+                size: (fw as u32, fh as u32),
+                tiled_all_edges: false,
+                hidden: None,
+                virtual_write: None,
+            }
+        }
+        TilingMode::Fullscreen => NormalPlacement {
+            pos: (ctx.phys.x, ctx.phys.y),
+            scale: 1.0,
+            size: (ctx.phys.width as u32, ctx.phys.height as u32),
+            tiled_all_edges: true,
+            hidden: None,
+            virtual_write: None,
+        },
+        TilingMode::Maximized => {
+            // Resize to fully fill all desktop-grid cells the saved geometry
+            // is fully/partially inside of.
+            let scale = p.desktop_grid_scale;
+
+            let x1 = snap.saved_maximized_virtual.0;
+            let y1 = snap.saved_maximized_virtual.1;
+            let w = snap.saved_maximized_size.0 as f64;
+            let h = snap.saved_maximized_size.1 as f64;
+            let x2 = x1 + w;
+            let y2 = y1 + h;
+
+            let col_min = (x1 / scale).floor() as i32;
+            let col_max = ((x2 / scale).ceil() as i32 - 1).max(col_min);
+            let row_min = (y1 / scale).floor() as i32;
+            let row_max = ((y2 / scale).ceil() as i32 - 1).max(row_min);
+
+            let snapped_x1 = col_min as f64 * scale;
+            let snapped_x2 = (col_max + 1) as f64 * scale;
+            let snapped_y1 = row_min as f64 * scale;
+            let snapped_y2 = (row_max + 1) as f64 * scale;
+
+            let fw = snapped_x2 - snapped_x1;
+            let fh = snapped_y2 - snapped_y1;
+
+            let (final_x, final_y) = ctx.virtual_to_screen(snapped_x1, snapped_y1);
+
+            NormalPlacement {
+                pos: (final_x, final_y),
+                scale: ctx.zoom,
+                size: (fw as u32, fh as u32),
+                tiled_all_edges: false,
+                hidden: Some(ctx.is_offscreen(final_x, final_y, fw * ctx.zoom, fh * ctx.zoom)),
+                virtual_write: Some((snapped_x1, snapped_y1)),
+            }
+        }
+        _ => {
+            // Regular pannable window on the virtual surface.
+            let fw = if let Some(resize_size) = snap.active_resize {
+                resize_size.0 as i32
+            } else if snap.box_geom.width > 0 {
+                snap.box_geom.width
+            } else if snap.min_size.0 > 32 {
+                snap.min_size.0
+            } else {
+                800
+            };
+            let fh = if let Some(resize_size) = snap.active_resize {
+                resize_size.1 as i32
+            } else if snap.box_geom.height > 0 {
+                snap.box_geom.height
+            } else if snap.min_size.1 > 32 {
+                snap.min_size.1
+            } else {
+                600
+            };
+
+            let (final_x, final_y) = ctx.virtual_to_screen(snap.virtual_pos.0, snap.virtual_pos.1);
+
+            NormalPlacement {
+                pos: (final_x, final_y),
+                scale: ctx.zoom,
+                size: (fw as u32, fh as u32),
+                tiled_all_edges: false,
+                hidden: Some(ctx.is_offscreen(final_x, final_y, fw as f64 * ctx.zoom, fh as f64 * ctx.zoom)),
+                virtual_write: None,
+            }
+        }
+    }
+}
+
+const SPACING: i32 = 12;
+const MARGIN: i32 = 12;
+
+const LEFT_ORDER: &[&str] = &["viewport", "window"];
+const RIGHT_ORDER: &[&str] = &["tray", "cpu", "memory", "brightness", "volume", "battery", "clock"];
+
+fn left_sort_key(app_id: &str) -> usize {
+    let name = app_id.strip_prefix("cce-status-interface-left-")
+        .or_else(|| app_id.strip_prefix("cce-status-left-"))
+        .unwrap_or(app_id);
+    LEFT_ORDER.iter().position(|&m| m == name).unwrap_or(99)
+}
+
+fn right_sort_key(app_id: &str) -> usize {
+    let name = app_id.strip_prefix("cce-status-interface-right-")
+        .or_else(|| app_id.strip_prefix("cce-status-right-"))
+        .unwrap_or(app_id);
+    RIGHT_ORDER.iter().position(|&m| m == name).unwrap_or(99)
+}
+
+/// Bar length to use: previous major length, or 100 for a fresh bar.
+fn bar_len(prev_len: i32) -> u32 {
+    if prev_len > 0 { prev_len as u32 } else { 100 }
+}
+
+/// Lay out status-bar windows on one output: horizontal groups on the top and
+/// bottom edges (left/center/right within each), vertical stacks on the left
+/// and right edges, and full-width bars across the top.
+///
+/// Returns one placement per item, index-aligned with `items`.
+pub fn layout_status_bars(
+    items: &[StatusBarItem],
+    p: &StatusBarLayoutParams,
+) -> Vec<Option<StatusBarPlacement>> {
+    let wlr_box = p.output;
+    let bar_h = p.bar_height;
+    let spacing = SPACING;
+    let margin = MARGIN;
+
+    let mut top_left: Vec<usize> = Vec::new();
+    let mut top_center: Vec<usize> = Vec::new();
+    let mut top_right: Vec<usize> = Vec::new();
+    let mut bottom_left: Vec<usize> = Vec::new();
+    let mut bottom_center: Vec<usize> = Vec::new();
+    let mut bottom_right: Vec<usize> = Vec::new();
+    let mut left_side: Vec<usize> = Vec::new();
+    let mut right_side: Vec<usize> = Vec::new();
+    let mut full_top: Vec<usize> = Vec::new();
+
+    for (idx, item) in items.iter().enumerate() {
+        let edge = if item.edge == StatusEdge::Unspecified {
+            StatusEdge::TopLeft
+        } else {
+            item.edge
+        };
+        match edge {
+            StatusEdge::TopLeft => top_left.push(idx),
+            StatusEdge::TopCenter => top_center.push(idx),
+            StatusEdge::TopRight => top_right.push(idx),
+            StatusEdge::BottomLeft => bottom_left.push(idx),
+            StatusEdge::BottomCenter => bottom_center.push(idx),
+            StatusEdge::BottomRight => bottom_right.push(idx),
+            StatusEdge::Left => left_side.push(idx),
+            StatusEdge::Right => right_side.push(idx),
+            _ => full_top.push(idx),
+        }
+    }
+
+    log::info!("[ArrangeStatus] top_left_len={}, top_center_len={}, top_right_len={}, left_side_len={}", top_left.len(), top_center.len(), top_right.len(), left_side.len());
+
+    let sort_left = |list: &mut Vec<usize>| {
+        list.sort_by_key(|&i| left_sort_key(&items[i].app_id));
+    };
+    let sort_right = |list: &mut Vec<usize>| {
+        list.sort_by_key(|&i| right_sort_key(&items[i].app_id));
+    };
+
+    sort_left(&mut top_left);
+    sort_left(&mut top_center);
+    sort_right(&mut top_right);
+    sort_left(&mut bottom_left);
+    sort_left(&mut bottom_center);
+    sort_right(&mut bottom_right);
+
+    let mut placements: Vec<Option<StatusBarPlacement>> = vec![None; items.len()];
+
+    // 1. Top Edge
+    let status_y_top = if p.hide_mode {
+        wlr_box.y - (bar_h as i32 - p.hide_mode_preview)
+    } else {
+        wlr_box.y
+    };
+
+    let mut top_right_width_needed = 0;
+    for &i in &top_right {
+        let w = bar_len(items[i].prev_len);
+        top_right_width_needed += w as i32 + spacing;
+    }
+    let top_right_boundary = wlr_box.x + wlr_box.width - margin - top_right_width_needed;
+
+    // 1a. Left Group (TopLeft / nw)
+    let mut cur_left_x = wlr_box.x + margin;
+    for &i in &top_left {
+        let mut w = bar_len(items[i].prev_len);
+        let max_allowed_w = top_right_boundary - cur_left_x - spacing;
+        if w as i32 > max_allowed_w {
+            w = std::cmp::max(max_allowed_w, 20) as u32;
+        }
+        log::info!("[TopLeftLayout] app_id={} x={}, w={}", items[i].app_id, cur_left_x, w);
+        placements[i] = Some(StatusBarPlacement { x: cur_left_x, y: status_y_top, width: w, height: bar_h });
+        cur_left_x += w as i32 + spacing;
+    }
+
+    // 1b. Center Group (TopCenter / n)
+    let mut top_center_width_needed = 0;
+    for &i in &top_center {
+        let w = bar_len(items[i].prev_len);
+        top_center_width_needed += w as i32 + spacing;
+    }
+    if top_center_width_needed > 0 {
+        top_center_width_needed -= spacing;
+    }
+    let center_start_x = wlr_box.x + (wlr_box.width - top_center_width_needed) / 2;
+    let mut cur_center_x = std::cmp::max(center_start_x, cur_left_x + spacing);
+
+    for &i in &top_center {
+        let mut w = bar_len(items[i].prev_len);
+        let max_allowed_w = top_right_boundary - cur_center_x - spacing;
+        if w as i32 > max_allowed_w {
+            w = std::cmp::max(max_allowed_w, 20) as u32;
+        }
+        log::info!("[TopCenterLayout] app_id={} x={}, w={}", items[i].app_id, cur_center_x, w);
+        placements[i] = Some(StatusBarPlacement { x: cur_center_x, y: status_y_top, width: w, height: bar_h });
+        cur_center_x += w as i32 + spacing;
+    }
+
+    // 1c. Right Group (TopRight / ne)
+    let mut cur_right_x = wlr_box.x + wlr_box.width - margin;
+    for &i in top_right.iter().rev() {
+        let w = bar_len(items[i].prev_len);
+        let x = cur_right_x - w as i32;
+        placements[i] = Some(StatusBarPlacement { x, y: status_y_top, width: w, height: bar_h });
+        cur_right_x = x - spacing;
+    }
+
+    for &i in &full_top {
+        placements[i] = Some(StatusBarPlacement { x: wlr_box.x, y: status_y_top, width: wlr_box.width as u32, height: bar_h });
+    }
+
+    // 2. Bottom Edge
+    let status_y_bottom = wlr_box.y + wlr_box.height - bar_h as i32;
+
+    let mut bottom_right_width_needed = 0;
+    for &i in &bottom_right {
+        let w = bar_len(items[i].prev_len);
+        bottom_right_width_needed += w as i32 + spacing;
+    }
+    let bottom_right_boundary = wlr_box.x + wlr_box.width - margin - bottom_right_width_needed;
+
+    // 2a. Left Group (BottomLeft / sw)
+    let mut cur_left_x = wlr_box.x + margin;
+    for &i in &bottom_left {
+        let mut w = bar_len(items[i].prev_len);
+        let max_allowed_w = bottom_right_boundary - cur_left_x - spacing;
+        if w as i32 > max_allowed_w {
+            w = std::cmp::max(max_allowed_w, 20) as u32;
+        }
+        placements[i] = Some(StatusBarPlacement { x: cur_left_x, y: status_y_bottom, width: w, height: bar_h });
+        cur_left_x += w as i32 + spacing;
+    }
+
+    // 2b. Center Group (BottomCenter / s)
+    let mut bottom_center_width_needed = 0;
+    for &i in &bottom_center {
+        let w = bar_len(items[i].prev_len);
+        bottom_center_width_needed += w as i32 + spacing;
+    }
+    if bottom_center_width_needed > 0 {
+        bottom_center_width_needed -= spacing;
+    }
+    let center_start_x = wlr_box.x + (wlr_box.width - bottom_center_width_needed) / 2;
+    let mut cur_center_x = std::cmp::max(center_start_x, cur_left_x + spacing);
+
+    for &i in &bottom_center {
+        let mut w = bar_len(items[i].prev_len);
+        let max_allowed_w = bottom_right_boundary - cur_center_x - spacing;
+        if w as i32 > max_allowed_w {
+            w = std::cmp::max(max_allowed_w, 20) as u32;
+        }
+        placements[i] = Some(StatusBarPlacement { x: cur_center_x, y: status_y_bottom, width: w, height: bar_h });
+        cur_center_x += w as i32 + spacing;
+    }
+
+    // 2c. Right Group (BottomRight / se)
+    let mut cur_right_x = wlr_box.x + wlr_box.width - margin;
+    for &i in bottom_right.iter().rev() {
+        let w = bar_len(items[i].prev_len);
+        let x = cur_right_x - w as i32;
+        placements[i] = Some(StatusBarPlacement { x, y: status_y_bottom, width: w, height: bar_h });
+        cur_right_x = x - spacing;
+    }
+
+    // 3. Left Edge (Vertical stacking)
+    let mut left_total_height = 0;
+    for &i in &left_side {
+        let actual_h = bar_len(items[i].prev_len);
+        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 &i in &left_side {
+        let actual_h = bar_len(items[i].prev_len);
+        placements[i] = Some(StatusBarPlacement { x: wlr_box.x, y: cur_left_y, width: bar_h, height: actual_h });
+        cur_left_y += actual_h as i32 + spacing;
+    }
+
+    // 4. Right Edge (Vertical stacking)
+    let mut right_total_height = 0;
+    for &i in &right_side {
+        let actual_h = bar_len(items[i].prev_len);
+        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 &i in &right_side {
+        let actual_h = bar_len(items[i].prev_len);
+        placements[i] = Some(StatusBarPlacement { x: wlr_box.x + wlr_box.width - bar_h as i32, y: cur_right_y, width: bar_h, height: actual_h });
+        cur_right_y += actual_h as i32 + spacing;
+    }
+
+    placements
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn params() -> StatusBarLayoutParams {
+        StatusBarLayoutParams {
+            output: Rect { x: 0, y: 0, width: 1920, height: 1080 },
+            bar_height: 30,
+            hide_mode: false,
+            hide_mode_preview: 5,
+        }
+    }
+
+    fn item(app_id: &str, edge: StatusEdge, prev_len: i32) -> StatusBarItem {
+        StatusBarItem { app_id: app_id.to_string(), edge, prev_len }
+    }
+
+    #[test]
+    fn top_groups_flow_from_edges() {
+        let items = vec![
+            item("cce-status-left-viewport", StatusEdge::TopLeft, 0),
+            item("cce-status-left-window", StatusEdge::TopLeft, 0),
+            item("cce-status-right-clock", StatusEdge::TopRight, 200),
+        ];
+        let p = layout_status_bars(&items, &params());
+        // Left group flows right from the margin; fresh bars default to width 100.
+        assert_eq!(p[0], Some(StatusBarPlacement { x: 12, y: 0, width: 100, height: 30 }));
+        assert_eq!(p[1], Some(StatusBarPlacement { x: 124, y: 0, width: 100, height: 30 }));
+        // Right group is placed from the right edge inward.
+        assert_eq!(p[2], Some(StatusBarPlacement { x: 1908 - 200, y: 0, width: 200, height: 30 }));
+    }
+
+    #[test]
+    fn right_group_sorted_by_module_order() {
+        let items = vec![
+            item("cce-status-right-clock", StatusEdge::TopRight, 100),
+            item("cce-status-right-battery", StatusEdge::TopRight, 100),
+        ];
+        let p = layout_status_bars(&items, &params());
+        // RIGHT_ORDER puts battery before clock left-to-right, so clock hugs the edge.
+        assert_eq!(p[0].unwrap().x, 1808);
+        assert_eq!(p[1].unwrap().x, 1808 - 12 - 100);
+    }
+
+    #[test]
+    fn hide_mode_pushes_top_bars_offscreen_with_preview() {
+        let mut prm = params();
+        prm.hide_mode = true;
+        let items = vec![item("cce-status-left-viewport", StatusEdge::Unspecified, 0)];
+        let p = layout_status_bars(&items, &prm);
+        // Unspecified resolves to TopLeft; y = 0 - (30 - 5).
+        assert_eq!(p[0].unwrap().y, -25);
+    }
+
+    #[test]
+    fn usable_area_reserves_bar_edges() {
+        let output = Rect { x: 0, y: 0, width: 1920, height: 1080 };
+        let no_excl = Rect { x: 0, y: 0, width: 0, height: 0 };
+
+        // No bars, no exclusion: the full output.
+        assert_eq!(compute_usable_area(output, no_excl, 30, false, &[]), output);
+
+        // Top + left bars each reserve one bar-height.
+        let edges = [StatusEdge::TopLeft, StatusEdge::Left];
+        assert_eq!(
+            compute_usable_area(output, no_excl, 30, false, &edges),
+            Rect { x: 30, y: 30, width: 1890, height: 1050 }
+        );
+
+        // Hide mode releases the top reservation but not the others.
+        assert_eq!(
+            compute_usable_area(output, no_excl, 30, true, &edges),
+            Rect { x: 30, y: 0, width: 1890, height: 1080 }
+        );
+
+        // Layer-shell non-exclusive area applies before bar reservations.
+        let excl = Rect { x: 10, y: 20, width: 1900, height: 1040 };
+        assert_eq!(
+            compute_usable_area(output, excl, 30, false, &[StatusEdge::BottomCenter]),
+            Rect { x: 10, y: 20, width: 1900, height: 1010 }
+        );
+    }
+
+    #[test]
+    fn window_roles_from_app_id() {
+        assert_eq!(WindowRole::from_app_id(Some("cce-wallpaper")), WindowRole::Background);
+        assert_eq!(WindowRole::from_app_id(Some("cce-status-interface-right-clock")), WindowRole::StatusBar);
+        assert_eq!(WindowRole::from_app_id(Some("firefox")), WindowRole::Normal);
+        assert_eq!(WindowRole::from_app_id(None), WindowRole::Normal);
+    }
+
+    #[test]
+    fn classification_precedence() {
+        // Role wins over visibility: a minimized wallpaper still arranges as background.
+        assert_eq!(
+            classify_window(WindowRole::Background, true, true, TilingMode::Floating, false),
+            WindowClass::Background
+        );
+        assert_eq!(
+            classify_window(WindowRole::StatusBar, false, false, TilingMode::Floating, false),
+            WindowClass::StatusBar
+        );
+        // Minimized or closing/init normal windows are hidden.
+        assert_eq!(
+            classify_window(WindowRole::Normal, true, false, TilingMode::Grid, false),
+            WindowClass::Hidden
+        );
+        // Overlay mode gets the overlay slot — unless mid-drag.
+        assert_eq!(
+            classify_window(WindowRole::Normal, false, false, TilingMode::Overlay, false),
+            WindowClass::Overlay
+        );
+        assert_eq!(
+            classify_window(WindowRole::Normal, false, false, TilingMode::Overlay, true),
+            WindowClass::Normal
+        );
+        assert_eq!(
+            classify_window(WindowRole::Normal, false, false, TilingMode::Cascade, false),
+            WindowClass::Normal
+        );
+    }
+
+    fn ctx() -> PlacementCtx {
+        PlacementCtx {
+            phys: Rect { x: 0, y: 0, width: 1920, height: 1080 },
+            usable: Rect { x: 0, y: 30, width: 1920, height: 1050 },
+            pan_x: 0.0,
+            pan_y: 0.0,
+            zoom: 1.0,
+        }
+    }
+
+    #[test]
+    fn fresh_overlay_gets_configured_slot() {
+        let placement = place_overlay_window(
+            &OverlaySnapshot {
+                box_geom: Rect { x: 0, y: 0, width: 0, height: 0 },
+                min_width: 0,
+                is_cloud: false,
+                ssd: true,
+                decorations_size: (0, 16),
+            },
+            &OverlayParams {
+                overlay_width: 400,
+                border_gap: 8,
+                position_right: true,
+                cloud_position_default: None,
+            },
+            &ctx(),
+        );
+        // Right slot: x = usable right edge - width - gap; height fills the
+        // usable area minus the 16px decoration strip and both gaps.
+        assert_eq!(placement.pos, (1512, 54));
+        assert_eq!(placement.size, (400, 1018));
+        assert_eq!(placement.box_geom_write, Some(Rect { x: 1512, y: 54, width: 400, height: 1018 }));
+        assert_eq!(placement.virtual_pos, (1512.0, 54.0));
+    }
+
+    #[test]
+    fn overlay_without_ssd_shrinks_by_decorations() {
+        let placement = place_overlay_window(
+            &OverlaySnapshot {
+                box_geom: Rect { x: 100, y: 100, width: 400, height: 500 },
+                min_width: 0,
+                is_cloud: false,
+                ssd: false,
+                decorations_size: (2, 18),
+            },
+            &OverlayParams { overlay_width: 400, border_gap: 8, position_right: false, cloud_position_default: None },
+            &ctx(),
+        );
+        // Existing geometry is kept; the client is sized minus decorations.
+        assert_eq!(placement.pos, (100, 100));
+        assert_eq!(placement.size, (398, 482));
+        assert_eq!(placement.box_geom_write, None);
+    }
+
+    #[test]
+    fn maximized_transitions() {
+        // Entering with no usable geometry falls back to 800x600.
+        assert_eq!(
+            maximized_transition(true, false, (0, 0), (0, 0), (0, 0), (0.0, 0.0)),
+            Some(MaximizedTransition::Enter { width: 800, height: 600 })
+        );
+        // Entering keeps real geometry.
+        assert_eq!(
+            maximized_transition(true, false, (640, 480), (0, 0), (0, 0), (0.0, 0.0)),
+            Some(MaximizedTransition::Enter { width: 640, height: 480 })
+        );
+        // Steady states do nothing.
+        assert_eq!(maximized_transition(true, true, (640, 480), (0, 0), (640, 480), (0.0, 0.0)), None);
+        assert_eq!(maximized_transition(false, false, (640, 480), (0, 0), (0, 0), (0.0, 0.0)), None);
+        // Exit restores the saved geometry; invalid saved size is a no-op.
+        assert_eq!(
+            maximized_transition(false, true, (0, 0), (0, 0), (640, 480), (10.0, 20.0)),
+            Some(MaximizedTransition::Exit { width: 640, height: 480, virtual_x: 10.0, virtual_y: 20.0 })
+        );
+        assert_eq!(maximized_transition(false, true, (0, 0), (0, 0), (0, 480), (10.0, 20.0)), None);
+    }
+
+    #[test]
+    fn maximized_snaps_to_grid_cells() {
+        let snap = NormalSnapshot {
+            mode: TilingMode::Maximized,
+            box_geom: Rect { x: 0, y: 0, width: 100, height: 50 },
+            min_size: (0, 0),
+            virtual_pos: (150.0, 120.0),
+            active_resize: None,
+            is_cloud: false,
+            saved_maximized_size: (100, 50),
+            saved_maximized_virtual: (150.0, 120.0),
+        };
+        let p = NormalParams { gap_right: 10, gap_top: 6, cloud_position_default: None, desktop_grid_scale: 100.0 };
+        let placement = place_normal_window(&snap, &p, &ctx());
+        // Saved geometry spans grid columns 1-2 and row 1 → snapped to
+        // (100,100) with size 200x100.
+        assert_eq!(placement.virtual_write, Some((100.0, 100.0)));
+        assert_eq!(placement.pos, (100, 100));
+        assert_eq!(placement.size, (200, 100));
+        assert_eq!(placement.hidden, Some(false));
+        assert_eq!(placement.scale, 1.0);
+    }
+
+    #[test]
+    fn popup_docks_top_right_of_usable_area() {
+        let snap = NormalSnapshot {
+            mode: TilingMode::Popup,
+            box_geom: Rect { x: 0, y: 0, width: 0, height: 0 },
+            min_size: (0, 0),
+            virtual_pos: (0.0, 0.0),
+            active_resize: None,
+            is_cloud: false,
+            saved_maximized_size: (0, 0),
+            saved_maximized_virtual: (0.0, 0.0),
+        };
+        let p = NormalParams { gap_right: 10, gap_top: 6, cloud_position_default: None, desktop_grid_scale: 100.0 };
+        let placement = place_normal_window(&snap, &p, &ctx());
+        // Defaults to 360x100, docked inside the usable area (below the bar).
+        assert_eq!(placement.pos, (1920 - 360 - 10, 30 + 6));
+        assert_eq!(placement.size, (360, 100));
+        assert_eq!(placement.hidden, None);
+    }
+
+    #[test]
+    fn pannable_window_follows_viewport() {
+        let snap = NormalSnapshot {
+            mode: TilingMode::Cascade,
+            box_geom: Rect { x: 0, y: 0, width: 640, height: 480 },
+            min_size: (0, 0),
+            virtual_pos: (100.0, 200.0),
+            active_resize: None,
+            is_cloud: false,
+            saved_maximized_size: (0, 0),
+            saved_maximized_virtual: (0.0, 0.0),
+        };
+        let p = NormalParams { gap_right: 10, gap_top: 6, cloud_position_default: None, desktop_grid_scale: 100.0 };
+        let mut c = ctx();
+        c.pan_x = 50.0;
+        c.pan_y = 100.0;
+        c.zoom = 2.0;
+        let placement = place_normal_window(&snap, &p, &c);
+        assert_eq!(placement.pos, (100, 200));
+        assert_eq!(placement.scale, 2.0);
+        assert_eq!(placement.size, (640, 480));
+        assert_eq!(placement.hidden, Some(false));
+
+        // Pan far enough away and the window is culled.
+        c.pan_x = 5000.0;
+        let placement = place_normal_window(&snap, &p, &c);
+        assert_eq!(placement.hidden, Some(true));
+
+        // Interactive resize dimensions override stored geometry.
+        let resizing = NormalSnapshot { active_resize: Some((800, 600)), ..snap };
+        c.pan_x = 50.0;
+        let placement = place_normal_window(&resizing, &p, &c);
+        assert_eq!(placement.size, (800, 600));
+    }
+
+    #[test]
+    fn opacity_policy() {
+        assert_eq!(window_opacity(true, true, OVERLAY_UNFOCUSED_OPACITY), 1.0);
+        assert_eq!(window_opacity(false, false, OVERLAY_UNFOCUSED_OPACITY), 1.0);
+        assert_eq!(window_opacity(false, true, OVERLAY_UNFOCUSED_OPACITY), 0.85);
+        assert_eq!(window_opacity(false, true, NORMAL_UNFOCUSED_OPACITY), 0.90);
+    }
+
+    #[test]
+    fn side_stacks_center_vertically() {
+        let items = vec![
+            item("cce-status-a", StatusEdge::Left, 200),
+            item("cce-status-b", StatusEdge::Left, 100),
+        ];
+        let p = layout_status_bars(&items, &params());
+        // Total stack: 200 + 12 + 100 = 312, centered in 1080 → starts at 384.
+        assert_eq!(p[0], Some(StatusBarPlacement { x: 0, y: 384, width: 30, height: 200 }));
+        assert_eq!(p[1], Some(StatusBarPlacement { x: 0, y: 596, width: 30, height: 100 }));
+    }
+}
diff --git a/src/server/policy/mod.rs b/src/server/policy/mod.rs
new file mode 100644
index 0000000..68e2e5e
--- /dev/null
+++ b/src/server/policy/mod.rs
@@ -0,0 +1,20 @@
+// The window-management policy layer.
+//
+// This module is the seam for the planned compositor / window-manager split:
+// everything under `policy/` is pure Rust — no FFI, no raw wlroots pointers —
+// and is intended to eventually move to a separate `cce-window-manager` crate.
+// The mechanism side (scene graph, seats, shells, sockets) stays in this crate
+// and talks to policy code only through the types in `api`.
+//
+// Migration status:
+//   - `tiling`: pure layout formulas (moved here from `src/server/tiling.rs`).
+//   - `state`: persisted session state (moved here from `window_manager.rs`).
+//   - `arrange`: pure pieces of `arrange_views()`; currently the status-bar
+//     layout engine. `StatusEdge` lives here (re-exported via `window.rs`).
+//   - `api`: the `Policy` / `Compositor` trait boundary. Skeleton — defined but
+//     not yet driven by `window_manager.rs`.
+
+pub mod api;
+pub mod arrange;
+pub mod state;
+pub mod tiling;
diff --git a/src/server/policy/state.rs b/src/server/policy/state.rs
new file mode 100644
index 0000000..7f677cd
--- /dev/null
+++ b/src/server/policy/state.rs
@@ -0,0 +1,32 @@
+// Persisted session state, saved to $XDG_STATE_HOME/cce/state.json on shutdown
+// and restored on startup. Pure data — serialization and matching logic only;
+// the save/load I/O lives in `window_manager.rs`.
+
+use super::tiling::TilingMode;
+
+#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
+pub struct SavedWindowState {
+    pub app_id: String,
+    pub title: String,
+    pub tiling_mode: TilingMode,
+    pub minimized: bool,
+    pub virtual_x: f64,
+    pub virtual_y: f64,
+    pub scale: f64,
+    pub width: u32,
+    pub height: u32,
+    pub cmdline: String,
+    #[serde(default)]
+    pub focused: bool,
+}
+
+#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
+pub struct SavedState {
+    pub desk_pan_x: f64,
+    pub desk_pan_y: f64,
+    pub desk_zoom: f64,
+    pub global_layout: TilingMode,
+    pub windows: Vec<SavedWindowState>,
+    #[serde(default)]
+    pub last_window_states: Vec<SavedWindowState>,
+}
diff --git a/src/server/tiling.rs b/src/server/policy/tiling.rs
similarity index 100%
rename from src/server/tiling.rs
rename to src/server/policy/tiling.rs
diff --git a/src/server/window.rs b/src/server/window.rs
index 438bd9f..ac7adfb 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -261,18 +261,7 @@ pub struct Window {
     pub status_edge: StatusEdge,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum StatusEdge {
-    Unspecified,
-    TopLeft,
-    TopCenter,
-    TopRight,
-    BottomLeft,
-    BottomCenter,
-    BottomRight,
-    Left,
-    Right,
-}
+pub use crate::policy::arrange::StatusEdge;
 
 impl Window {
     pub unsafe fn is_wine(&self) -> bool {
@@ -284,12 +273,16 @@ impl Window {
             || !self.wm_requested.fullscreen.is_null()
     }
 
+    pub unsafe fn role(&self) -> crate::policy::api::WindowRole {
+        crate::policy::api::WindowRole::from_app_id(self.get_app_id_string().as_deref())
+    }
+
     pub unsafe fn is_status_bar(&self) -> bool {
-        self.get_app_id_string().as_deref().map_or(false, |id| id.starts_with("cce-status"))
+        self.role() == crate::policy::api::WindowRole::StatusBar
     }
 
     pub unsafe fn is_wallpaper(&self) -> bool {
-        self.get_app_id_string().as_deref() == Some("cce-wallpaper")
+        self.role() == crate::policy::api::WindowRole::Background
     }
 
     pub unsafe fn is_linked(&self) -> bool {
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index e3854ac..476cbe4 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -47,32 +47,7 @@ pub struct WindowManagerRenderingRequested {
     pub order_hash: u64,
 }
 
-#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
-pub struct SavedWindowState {
-    pub app_id: String,
-    pub title: String,
-    pub tiling_mode: crate::tiling::TilingMode,
-    pub minimized: bool,
-    pub virtual_x: f64,
-    pub virtual_y: f64,
-    pub scale: f64,
-    pub width: u32,
-    pub height: u32,
-    pub cmdline: String,
-    #[serde(default)]
-    pub focused: bool,
-}
-
-#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
-pub struct SavedState {
-    pub desk_pan_x: f64,
-    pub desk_pan_y: f64,
-    pub desk_zoom: f64,
-    pub global_layout: crate::tiling::TilingMode,
-    pub windows: Vec<SavedWindowState>,
-    #[serde(default)]
-    pub last_window_states: Vec<SavedWindowState>,
-}
+pub use crate::policy::state::{SavedState, SavedWindowState};
 
 pub struct WindowManager {
     pub server: *mut Server,
@@ -844,7 +819,7 @@ impl WindowManager {
             }
         }
 
-        let has_wallpaper = self.windows.iter().any(|&w| !w.is_null() && !(*w).closed && (*w).get_app_id_string().as_deref() == Some("cce-wallpaper"));
+        let has_wallpaper = self.windows.iter().any(|&w| !w.is_null() && !(*w).closed && (*w).is_wallpaper());
         let outputs_list = &mut (*self.server).om.outputs as *mut ffi::wl_list as *mut WlList;
         let mut curr_out = (*outputs_list).next;
         while curr_out != outputs_list {
@@ -1140,7 +1115,7 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
             return;
         }
 
-        let has_wallpaper = self.windows.iter().any(|&w| !w.is_null() && !(*w).closed && (*w).get_app_id_string().as_deref() == Some("cce-wallpaper"));
+        let has_wallpaper = self.windows.iter().any(|&w| !w.is_null() && !(*w).closed && (*w).is_wallpaper());
         for &output in &active_outputs {
             if !(*output).background_rect.is_null() {
                 ffi::wlr_scene_node_set_enabled((*output).background_rect as *mut ffi::wlr_scene_node, !has_wallpaper);
@@ -1167,73 +1142,23 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
             let phys_w = wlr_box.width;
             let phys_h = wlr_box.height;
 
-            let mut usable_x = phys_x;
-            let mut usable_y = phys_y;
-            let mut usable_w = phys_w;
-            let mut usable_h = phys_h;
-
             let non_ex = (*output).layer_shell.scheduled.non_exclusive_area;
-            if non_ex.width > 0 && non_ex.height > 0 {
-                usable_x = phys_x + non_ex.x;
-                usable_y = phys_y + non_ex.y;
-                usable_w = non_ex.width;
-                usable_h = non_ex.height;
-            }
-
-            let bar_h = self.layout.bar_height as i32;
-            let mut has_top = false;
-            let mut has_bottom = false;
-            let mut has_left = false;
-            let mut has_right = false;
-
-            let resolve_edge = |win_ptr: *mut Window| {
-                let edge = (*win_ptr).status_edge;
-                if edge == crate::window::StatusEdge::Unspecified {
-                    crate::window::StatusEdge::TopLeft
-                } else {
-                    edge
-                }
-            };
-
+            let mut status_edges: Vec<crate::window::StatusEdge> = Vec::new();
             for &win_ptr in self.windows.iter() {
                 if win_ptr.is_null() || (*win_ptr).closed {
                     continue;
                 }
                 if (*win_ptr).is_status_bar() {
-                    match resolve_edge(win_ptr) {
-                        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::BottomLeft | crate::window::StatusEdge::BottomCenter | crate::window::StatusEdge::BottomRight => {
-                            has_bottom = true;
-                        }
-                        crate::window::StatusEdge::Left => {
-                            has_left = true;
-                        }
-                        crate::window::StatusEdge::Right => {
-                            has_right = true;
-                        }
-                    }
+                    status_edges.push((*win_ptr).status_edge);
                 }
             }
-
-            if has_top {
-                usable_y += bar_h;
-                usable_h -= bar_h;
-            }
-            if has_bottom {
-                usable_h -= bar_h;
-            }
-            if has_left {
-                usable_x += bar_h;
-                usable_w -= bar_h;
-            }
-            if has_right {
-                usable_w -= bar_h;
-            }
-
+            let usable = crate::policy::arrange::compute_usable_area(
+                crate::policy::api::Rect { x: phys_x, y: phys_y, width: phys_w, height: phys_h },
+                crate::policy::api::Rect { x: non_ex.x, y: non_ex.y, width: non_ex.width, height: non_ex.height },
+                self.layout.bar_height as i32,
+                self.status_hide_mode,
+                &status_edges,
+            );
             let viewport_w = wlr_box.width as f64;
             let viewport_h = wlr_box.height as f64;
             let camera_center_x = self.desk_pan_x + (viewport_w / 2.0) / self.desk_zoom;
@@ -1248,161 +1173,151 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                     continue;
                 }
 
-                let app_id = (*win_ptr).get_app_id_string();
-                let is_status_bar = app_id.as_deref().map_or(false, |id| id.starts_with("cce-status"));
-                let is_wallpaper = app_id.as_deref() == Some("cce-wallpaper");
-                
-                if is_wallpaper {
-                    (*win_ptr).tiling_mode = crate::tiling::TilingMode::Status;
-                    (*win_ptr).wm_requested.tiled = 0;
-                    (*win_ptr).wm_requested.ssd = false;
-                    (*win_ptr).scale = 1.0;
-                    ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, true);
-                    (*win_ptr).rendering_requested.hidden = false;
-                    (*win_ptr).rendering_requested.blur = false;
-                    (*win_ptr).rendering_requested.x = phys_x;
-                    (*win_ptr).rendering_requested.y = phys_y;
-                    (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
-                        width: phys_w as u32,
-                        height: phys_h as u32,
-                    });
-                    (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
-                        width: phys_w as u32,
-                        height: phys_h as u32,
-                    };
-                    continue;
-                }
-
-                if is_status_bar {
-                    (*win_ptr).tiling_mode = crate::tiling::TilingMode::Status;
-                    (*win_ptr).wm_requested.tiled = 0;
-                    (*win_ptr).wm_requested.ssd = false;
-                    (*win_ptr).scale = 1.0;
-                    ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, true);
-                    (*win_ptr).rendering_requested.hidden = false;
-                    (*win_ptr).rendering_requested.blur = self.layout.status_background_blur > 0.001;
-                    continue;
-                }
-
-                let visible = !(*win_ptr).minimized
-                    && !matches!((*win_ptr).state, crate::window::WindowState::Closing | crate::window::WindowState::Init);
-                if !visible {
-                    ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, false);
-                    (*win_ptr).rendering_requested.hidden = true;
-                    continue;
-                }
-
-                ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, true);
-                (*win_ptr).rendering_requested.hidden = false;
-
                 let mode = self.get_mode_for_window(win_ptr);
-                (*win_ptr).tiling_mode = mode;
+                let class = crate::policy::arrange::classify_window(
+                    (*win_ptr).role(),
+                    (*win_ptr).minimized,
+                    matches!((*win_ptr).state, crate::window::WindowState::Closing | crate::window::WindowState::Init),
+                    mode,
+                    self.is_window_being_moved(win_ptr),
+                );
 
-                if !(*win_ptr).mode_locked {
-                    if let Some(rule) = self.get_rule_for_window(win_ptr) {
-                        if let Some(rule_ssd) = rule.ssd {
-                            (*win_ptr).wm_requested.ssd = rule_ssd;
-                        }
+                match class {
+                    crate::policy::arrange::WindowClass::Background => {
+                        (*win_ptr).tiling_mode = crate::tiling::TilingMode::Status;
+                        (*win_ptr).wm_requested.tiled = 0;
+                        (*win_ptr).wm_requested.ssd = false;
+                        (*win_ptr).scale = 1.0;
+                        ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, true);
+                        (*win_ptr).rendering_requested.hidden = false;
+                        (*win_ptr).rendering_requested.blur = false;
+                        (*win_ptr).rendering_requested.x = phys_x;
+                        (*win_ptr).rendering_requested.y = phys_y;
+                        (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
+                            width: phys_w as u32,
+                            height: phys_h as u32,
+                        });
+                        (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
+                            width: phys_w as u32,
+                            height: phys_h as u32,
+                        };
                     }
-                }
+                    crate::policy::arrange::WindowClass::StatusBar => {
+                        (*win_ptr).tiling_mode = crate::tiling::TilingMode::Status;
+                        (*win_ptr).wm_requested.tiled = 0;
+                        (*win_ptr).wm_requested.ssd = false;
+                        (*win_ptr).scale = 1.0;
+                        ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, true);
+                        (*win_ptr).rendering_requested.hidden = false;
+                        (*win_ptr).rendering_requested.blur = self.layout.status_background_blur > 0.001;
+                    }
+                    crate::policy::arrange::WindowClass::Hidden => {
+                        ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, false);
+                        (*win_ptr).rendering_requested.hidden = true;
+                    }
+                    crate::policy::arrange::WindowClass::Overlay | crate::policy::arrange::WindowClass::Normal => {
+                        ffi::wlr_scene_node_set_enabled((*win_ptr).tree as *mut ffi::wlr_scene_node, true);
+                        (*win_ptr).rendering_requested.hidden = false;
+
+                        (*win_ptr).tiling_mode = mode;
+
+                        if !(*win_ptr).mode_locked {
+                            if let Some(rule) = self.get_rule_for_window(win_ptr) {
+                                if let Some(rule_ssd) = rule.ssd {
+                                    (*win_ptr).wm_requested.ssd = rule_ssd;
+                                }
+                            }
+                        }
 
-                let is_moving = self.is_window_being_moved(win_ptr);
-                if mode == crate::tiling::TilingMode::Overlay && !is_moving {
-                    overlay_windows.push(win_ptr);
-                } else {
-                    normal_windows.push(win_ptr);
+                        if class == crate::policy::arrange::WindowClass::Overlay {
+                            overlay_windows.push(win_ptr);
+                        } else {
+                            normal_windows.push(win_ptr);
+                        }
+                    }
                 }
             }
 
             let bw = 0;
 
-            let g = self.layout.overlay_border_gap;
-            let dec_h = std::cmp::max(bw, 16);
+            let overlay_params = crate::policy::arrange::OverlayParams {
+                overlay_width: self.layout.overlay_width,
+                border_gap: self.layout.overlay_border_gap,
+                position_right: self.layout.overlay_position == "right",
+                cloud_position_default: self.layout.cloud_position_default,
+            };
+            let normal_params = crate::policy::arrange::NormalParams {
+                gap_right: self.layout.gap_right,
+                gap_top: self.layout.gap_top,
+                cloud_position_default: self.layout.cloud_position_default,
+                desktop_grid_scale: self.layout.desktop_grid_scale,
+            };
+            let ctx = crate::policy::arrange::PlacementCtx {
+                phys: crate::policy::api::Rect { x: phys_x, y: phys_y, width: phys_w, height: phys_h },
+                usable,
+                pan_x: self.desk_pan_x,
+                pan_y: self.desk_pan_y,
+                zoom: self.desk_zoom,
+            };
+
             for (sp_idx, &win_ptr) in overlay_windows.iter().enumerate() {
                 if sp_idx == 0 {
                     let app_id = (*win_ptr).get_app_id_string();
                     let is_cce_cloud = app_id.as_deref().map_or(false, |id| id.starts_with("cce-cloud"));
 
-                    let mut sp_x = (*win_ptr).box_geom.x;
-                    let mut sp_y = (*win_ptr).box_geom.y;
-                    let mut sp_w = (*win_ptr).box_geom.width as i32;
-                    let mut sp_h = (*win_ptr).box_geom.height as i32;
-
-
-                    if sp_w == 0 || sp_h == 0 {
-                        sp_w = if (*win_ptr).wm_scheduled.dimensions_hint.min_width > 32 {
-                            std::cmp::max(self.layout.overlay_width, (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32)
-                        } else {
-                            self.layout.overlay_width
-                        };
-                        sp_h = (usable_h - (dec_h + bw) - 2 * g).max(1);
+                    let placement = crate::policy::arrange::place_overlay_window(
+                        &crate::policy::arrange::OverlaySnapshot {
+                            box_geom: crate::policy::api::Rect {
+                                x: (*win_ptr).box_geom.x,
+                                y: (*win_ptr).box_geom.y,
+                                width: (*win_ptr).box_geom.width,
+                                height: (*win_ptr).box_geom.height,
+                            },
+                            min_width: (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32,
+                            is_cloud: is_cce_cloud,
+                            ssd: (*win_ptr).wm_requested.ssd,
+                            decorations_size: (*win_ptr).get_decorations_size(),
+                        },
+                        &overlay_params,
+                        &ctx,
+                    );
 
-                        sp_x = if self.layout.overlay_position == "right" {
-                            usable_x + usable_w - sp_w - g + bw
-                        } else {
-                            usable_x + g + bw
-                        };
-                        sp_y = usable_y + dec_h + g;
-
-                        (*win_ptr).box_geom.x = sp_x;
-                        (*win_ptr).box_geom.y = sp_y;
-                        (*win_ptr).box_geom.width = sp_w;
-                        (*win_ptr).box_geom.height = sp_h;
-                    } else if is_cce_cloud {
-                        if let Some(pos) = self.layout.cloud_position_default {
-                            sp_x = usable_x + pos[0];
-                            sp_y = usable_y + pos[1];
-                            (*win_ptr).box_geom.x = sp_x;
-                            (*win_ptr).box_geom.y = sp_y;
-                        }
+                    if let Some(bg) = placement.box_geom_write {
+                        (*win_ptr).box_geom.x = bg.x;
+                        (*win_ptr).box_geom.y = bg.y;
+                        (*win_ptr).box_geom.width = bg.width;
+                        (*win_ptr).box_geom.height = bg.height;
                     }
-
-                    (*win_ptr).rendering_requested.x = sp_x;
-                    (*win_ptr).rendering_requested.y = sp_y;
+                    (*win_ptr).rendering_requested.x = placement.pos.0;
+                    (*win_ptr).rendering_requested.y = placement.pos.1;
                     (*win_ptr).scale = 1.0;
-
-
-
-                    let vx = self.desk_pan_x + (sp_x - phys_x) as f64 / self.desk_zoom;
-                    let vy = self.desk_pan_y + (sp_y - phys_y) as f64 / self.desk_zoom;
-                    (*win_ptr).virtual_x = vx;
-                    (*win_ptr).virtual_y = vy;
-                    
-                    let mut sp_target_w = sp_w;
-                    let mut sp_target_h = sp_h;
-                    if !(*win_ptr).wm_requested.ssd {
-                        let (dec_w, dec_h) = (*win_ptr).get_decorations_size();
-                        sp_target_w = (sp_w - dec_w).max(1);
-                        sp_target_h = (sp_h - dec_h).max(1);
-                    }
+                    (*win_ptr).virtual_x = placement.virtual_pos.0;
+                    (*win_ptr).virtual_y = placement.virtual_pos.1;
                     (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
-                        width: sp_target_w as u32,
-                        height: sp_target_h as u32,
+                        width: placement.size.0,
+                        height: placement.size.1,
                     });
                     (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
-                        width: sp_target_w as u32,
-                        height: sp_target_h as u32,
+                        width: placement.size.0,
+                        height: placement.size.1,
                     };
                     (*win_ptr).wm_requested.tiled = 1 | 2 | 4 | 8;
 
                     let is_focused = win_ptr == focused_window;
-                    let r = self.layout.border_r;
-                    let g_color = self.layout.border_g;
-                    let b = self.layout.border_b;
-                    let a = self.layout.border_a;
-
                     (*win_ptr).rendering_requested.border = crate::window::Border {
                         edges: crate::window::Edges { top: true, bottom: true, left: true, right: true },
                         width: bw as u32,
-                        r,
-                        g: g_color,
-                        b,
-                        a,
+                        r: self.layout.border_r,
+                        g: self.layout.border_g,
+                        b: self.layout.border_b,
+                        a: self.layout.border_a,
                     };
                     (*win_ptr).rendering_requested.blur = self.layout.window_blur;
-                    (*win_ptr).rendering_requested.opacity = if is_focused { 1.0f32 } else {
-                        if !self.layout.window_opacity { 1.0f32 } else { 0.85f32 }
-                    };
+                    (*win_ptr).rendering_requested.opacity = crate::policy::arrange::window_opacity(
+                        is_focused,
+                        self.layout.window_opacity,
+                        crate::policy::arrange::OVERLAY_UNFOCUSED_OPACITY,
+                    );
                 } else {
                     normal_windows.push(win_ptr);
                 }
@@ -1410,58 +1325,51 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
 
             // Manage entering/exiting Maximized state for normal windows
             for &win_ptr in &normal_windows {
-                let mode = (*win_ptr).tiling_mode;
-                if mode == crate::tiling::TilingMode::Maximized && !(*win_ptr).was_maximized {
-                    // Entering Maximized mode
-                    let mut w = (*win_ptr).box_geom.width;
-                    let mut h = (*win_ptr).box_geom.height;
-                    if w <= 0 {
-                        w = if (*win_ptr).wm_scheduled.dimensions_hint.min_width > 32 {
-                            (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32
-                        } else {
-                            800
-                        };
-                    }
-                    if h <= 0 {
-                        h = if (*win_ptr).wm_scheduled.dimensions_hint.min_height > 32 {
-                            (*win_ptr).wm_scheduled.dimensions_hint.min_height as i32
-                        } else {
-                            600
-                        };
+                let transition = crate::policy::arrange::maximized_transition(
+                    (*win_ptr).tiling_mode == crate::tiling::TilingMode::Maximized,
+                    (*win_ptr).was_maximized,
+                    ((*win_ptr).box_geom.width, (*win_ptr).box_geom.height),
+                    (
+                        (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32,
+                        (*win_ptr).wm_scheduled.dimensions_hint.min_height as i32,
+                    ),
+                    ((*win_ptr).saved_maximized_width, (*win_ptr).saved_maximized_height),
+                    ((*win_ptr).saved_maximized_virtual_x, (*win_ptr).saved_maximized_virtual_y),
+                );
+                match transition {
+                    Some(crate::policy::arrange::MaximizedTransition::Enter { width, height }) => {
+                        (*win_ptr).saved_maximized_width = width;
+                        (*win_ptr).saved_maximized_height = height;
+                        (*win_ptr).saved_maximized_virtual_x = (*win_ptr).virtual_x;
+                        (*win_ptr).saved_maximized_virtual_y = (*win_ptr).virtual_y;
+                        (*win_ptr).was_maximized = true;
+                        log::info!("[Maximized] Saved window {:?} geometry: {}x{} at ({}, {})", 
+                            (*win_ptr).get_title_string().as_deref().unwrap_or(""), 
+                            width, height, 
+                            (*win_ptr).saved_maximized_virtual_x, (*win_ptr).saved_maximized_virtual_y
+                        );
                     }
-                    (*win_ptr).saved_maximized_width = w;
-                    (*win_ptr).saved_maximized_height = h;
-                    (*win_ptr).saved_maximized_virtual_x = (*win_ptr).virtual_x;
-                    (*win_ptr).saved_maximized_virtual_y = (*win_ptr).virtual_y;
-                    (*win_ptr).was_maximized = true;
-                    log::info!("[Maximized] Saved window {:?} geometry: {}x{} at ({}, {})", 
-                        (*win_ptr).get_title_string().as_deref().unwrap_or(""), 
-                        (*win_ptr).saved_maximized_width, (*win_ptr).saved_maximized_height, 
-                        (*win_ptr).saved_maximized_virtual_x, (*win_ptr).saved_maximized_virtual_y
-                    );
-                } else if mode != crate::tiling::TilingMode::Maximized && (*win_ptr).was_maximized {
-                    // Exiting Maximized mode
-                    if (*win_ptr).saved_maximized_width > 0 && (*win_ptr).saved_maximized_height > 0 {
-                        (*win_ptr).box_geom.width = (*win_ptr).saved_maximized_width;
-                        (*win_ptr).box_geom.height = (*win_ptr).saved_maximized_height;
-                        (*win_ptr).virtual_x = (*win_ptr).saved_maximized_virtual_x;
-                        (*win_ptr).virtual_y = (*win_ptr).saved_maximized_virtual_y;
+                    Some(crate::policy::arrange::MaximizedTransition::Exit { width, height, virtual_x, virtual_y }) => {
+                        (*win_ptr).box_geom.width = width;
+                        (*win_ptr).box_geom.height = height;
+                        (*win_ptr).virtual_x = virtual_x;
+                        (*win_ptr).virtual_y = virtual_y;
                         (*win_ptr).was_maximized = false;
-                        
+
                         (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
-                            width: (*win_ptr).saved_maximized_width as u32,
-                            height: (*win_ptr).saved_maximized_height as u32,
+                            width: width as u32,
+                            height: height as u32,
                         });
                         (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
-                            width: (*win_ptr).saved_maximized_width as u32,
-                            height: (*win_ptr).saved_maximized_height as u32,
+                            width: width as u32,
+                            height: height as u32,
                         };
                         log::info!("[Maximized] Restored window {:?} geometry: {}x{} at ({}, {})", 
                             (*win_ptr).get_title_string().as_deref().unwrap_or(""), 
-                            (*win_ptr).saved_maximized_width, (*win_ptr).saved_maximized_height, 
-                            (*win_ptr).saved_maximized_virtual_x, (*win_ptr).saved_maximized_virtual_y
+                            width, height, virtual_x, virtual_y
                         );
                     }
+                    None => {}
                 }
             }
 
@@ -1469,191 +1377,75 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
             for &win_ptr in &normal_windows {
                 let mode = (*win_ptr).tiling_mode;
                 let is_focused = win_ptr == focused_window;
+                let app_id = (*win_ptr).get_app_id_string();
+                let is_cce_cloud = app_id.as_deref().map_or(false, |id| id.starts_with("cce-cloud"));
+
+                let placement = crate::policy::arrange::place_normal_window(
+                    &crate::policy::arrange::NormalSnapshot {
+                        mode,
+                        box_geom: crate::policy::api::Rect {
+                            x: (*win_ptr).box_geom.x,
+                            y: (*win_ptr).box_geom.y,
+                            width: (*win_ptr).box_geom.width,
+                            height: (*win_ptr).box_geom.height,
+                        },
+                        min_size: (
+                            (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32,
+                            (*win_ptr).wm_scheduled.dimensions_hint.min_height as i32,
+                        ),
+                        virtual_pos: ((*win_ptr).virtual_x, (*win_ptr).virtual_y),
+                        active_resize: self.get_active_resize_dimensions(win_ptr),
+                        is_cloud: is_cce_cloud,
+                        saved_maximized_size: ((*win_ptr).saved_maximized_width, (*win_ptr).saved_maximized_height),
+                        saved_maximized_virtual: ((*win_ptr).saved_maximized_virtual_x, (*win_ptr).saved_maximized_virtual_y),
+                    },
+                    &normal_params,
+                    &ctx,
+                );
 
-                if mode == crate::tiling::TilingMode::Popup {
-                    let hint_min_w = (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32;
-                    let hint_min_h = (*win_ptr).wm_scheduled.dimensions_hint.min_height as i32;
-                    let fw = if (*win_ptr).box_geom.width > 0 {
-                        (*win_ptr).box_geom.width as i32
-                    } else if hint_min_w > 32 {
-                        hint_min_w
-                    } else {
-                        360
-                    };
-                    let fh = if (*win_ptr).box_geom.height > 0 {
-                        (*win_ptr).box_geom.height as i32
-                    } else if hint_min_h > 32 {
-                        hint_min_h
-                    } else {
-                        100
-                    };
-                    let app_id = (*win_ptr).get_app_id_string();
-                    let is_cce_cloud = app_id.as_deref().map_or(false, |id| id.starts_with("cce-cloud"));
-
-                    let (fx, fy) = if is_cce_cloud && self.layout.cloud_position_default.is_some() {
-                        let pos = self.layout.cloud_position_default.unwrap();
-                        (usable_x + pos[0], usable_y + pos[1])
-                    } else {
-                        (usable_x + usable_w - fw - self.layout.gap_right, usable_y + self.layout.gap_top)
-                    };
-
-                    (*win_ptr).rendering_requested.x = fx;
-                    (*win_ptr).rendering_requested.y = fy;
-                    (*win_ptr).scale = 1.0;
-
-                    (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
-                        width: fw as u32,
-                        height: fh as u32,
-                    });
-                    (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
-                        width: fw as u32,
-                        height: fh as u32,
-                    };
-                } else if mode == crate::tiling::TilingMode::Fullscreen {
-                    (*win_ptr).rendering_requested.x = phys_x;
-                    (*win_ptr).rendering_requested.y = phys_y;
-                    (*win_ptr).scale = 1.0;
-                    (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
-                        width: phys_w as u32,
-                        height: phys_h as u32,
-                    });
-                    (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
-                        width: phys_w as u32,
-                        height: phys_h as u32,
-                    };
+                (*win_ptr).rendering_requested.x = placement.pos.0;
+                (*win_ptr).rendering_requested.y = placement.pos.1;
+                (*win_ptr).scale = placement.scale;
+                if let Some((vx, vy)) = placement.virtual_write {
+                    (*win_ptr).virtual_x = vx;
+                    (*win_ptr).virtual_y = vy;
+                }
+                if let Some(hidden) = placement.hidden {
+                    (*win_ptr).rendering_requested.hidden = hidden;
+                }
+                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
+                    width: placement.size.0,
+                    height: placement.size.1,
+                });
+                (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
+                    width: placement.size.0,
+                    height: placement.size.1,
+                };
+                if placement.tiled_all_edges {
                     (*win_ptr).wm_requested.tiled = 1 | 2 | 4 | 8;
-                } else if mode == crate::tiling::TilingMode::Maximized {
-                    // Maximized mode: Resizes to fully fill all cells of the desktop grid it is fully/partially inside of.
-                    let scale = self.layout.desktop_grid_scale;
-                    
-                    // Use saved maximized geometry for cell calculation
-                    let x1 = (*win_ptr).saved_maximized_virtual_x;
-                    let y1 = (*win_ptr).saved_maximized_virtual_y;
-                    let w = (*win_ptr).saved_maximized_width as f64;
-                    let h = (*win_ptr).saved_maximized_height as f64;
-                    let x2 = x1 + w;
-                    let y2 = y1 + h;
-                    
-                    let col_min = (x1 / scale).floor() as i32;
-                    let col_max = ((x2 / scale).ceil() as i32 - 1).max(col_min);
-                    let row_min = (y1 / scale).floor() as i32;
-                    let row_max = ((y2 / scale).ceil() as i32 - 1).max(row_min);
-                    
-                    let snapped_x1 = col_min as f64 * scale;
-                    let snapped_x2 = (col_max + 1) as f64 * scale;
-                    let snapped_y1 = row_min as f64 * scale;
-                    let snapped_y2 = (row_max + 1) as f64 * scale;
-                    
-                    let fw = snapped_x2 - snapped_x1;
-                    let fh = snapped_y2 - snapped_y1;
-                    
-                    // Update current virtual position for rendering
-                    (*win_ptr).virtual_x = snapped_x1;
-                    (*win_ptr).virtual_y = snapped_y1;
-                    
-                    let final_x = phys_x + (((*win_ptr).virtual_x - self.desk_pan_x) * self.desk_zoom) as i32;
-                    let final_y = phys_y + (((*win_ptr).virtual_y - self.desk_pan_y) * self.desk_zoom) as i32;
-
-                    (*win_ptr).rendering_requested.x = final_x;
-                    (*win_ptr).rendering_requested.y = final_y;
-                    (*win_ptr).scale = self.desk_zoom;
-
-                    // Offscreen check
-                    let scaled_w = fw * self.desk_zoom;
-                    let scaled_h = fh * self.desk_zoom;
-                    let is_offscreen = (final_x as f64 + scaled_w + 50.0) < phys_x as f64
-                        || (final_x as f64 - 50.0) > (phys_x as f64 + viewport_w)
-                        || (final_y as f64 + scaled_h + 50.0) < phys_y as f64
-                        || (final_y as f64 - 50.0) > (phys_y as f64 + viewport_h);
-                    (*win_ptr).rendering_requested.hidden = is_offscreen;
-
-                    (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
-                        width: fw as u32,
-                        height: fh as u32,
-                    });
-                    (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
-                        width: fw as u32,
-                        height: fh as u32,
-                    };
-                } else {
-                    // Regular pannable window on the virtual surface
-                    let fw = if let Some(resize_size) = self.get_active_resize_dimensions(win_ptr) {
-                        resize_size.0 as i32
-                    } else if (*win_ptr).box_geom.width > 0 {
-                        (*win_ptr).box_geom.width as i32
-                    } else if (*win_ptr).wm_scheduled.dimensions_hint.min_width > 32 {
-                        (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32
-                    } else {
-                        800
-                    };
-                    let fh = if let Some(resize_size) = self.get_active_resize_dimensions(win_ptr) {
-                        resize_size.1 as i32
-                    } else if (*win_ptr).box_geom.height > 0 {
-                        (*win_ptr).box_geom.height as i32
-                    } else if (*win_ptr).wm_scheduled.dimensions_hint.min_height > 32 {
-                        (*win_ptr).wm_scheduled.dimensions_hint.min_height as i32
-                    } else {
-                        600
-                    };
-
-                    let final_x = phys_x + (((*win_ptr).virtual_x - self.desk_pan_x) * self.desk_zoom) as i32;
-                    let final_y = phys_y + (((*win_ptr).virtual_y - self.desk_pan_y) * self.desk_zoom) as i32;
-
-                    (*win_ptr).rendering_requested.x = final_x;
-                    (*win_ptr).rendering_requested.y = final_y;
-                    (*win_ptr).scale = self.desk_zoom;
-
-                    // Offscreen check
-                    let scaled_w = fw as f64 * self.desk_zoom;
-                    let scaled_h = fh as f64 * self.desk_zoom;
-                    let is_offscreen = (final_x as f64 + scaled_w + 50.0) < phys_x as f64
-                        || (final_x as f64 - 50.0) > (phys_x as f64 + viewport_w)
-                        || (final_y as f64 + scaled_h + 50.0) < phys_y as f64
-                        || (final_y as f64 - 50.0) > (phys_y as f64 + viewport_h);
-                    (*win_ptr).rendering_requested.hidden = is_offscreen;
-
-                    (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions {
-                        width: fw as u32,
-                        height: fh as u32,
-                    });
-                    (*win_ptr).wm_requested.bounds = crate::window::Dimensions {
-                        width: fw as u32,
-                        height: fh as u32,
-                    };
                 }
 
                 // Apply borders, opacity, and blur to normal windows
-                let r = self.layout.border_r;
-                let g_val = self.layout.border_g;
-                let b = self.layout.border_b;
-                let a = self.layout.border_a;
-
                 (*win_ptr).rendering_requested.border = crate::window::Border {
                     edges: crate::window::Edges { top: true, bottom: true, left: true, right: true },
                     width: bw as u32,
-                    r,
-                    g: g_val,
-                    b,
-                    a,
-                };
-(*win_ptr).rendering_requested.blur = self.layout.window_blur;
-                (*win_ptr).rendering_requested.opacity = if is_focused { 1.0f32 } else {
-                    if !self.layout.window_opacity { 1.0f32 } else { 0.90f32 }
+                    r: self.layout.border_r,
+                    g: self.layout.border_g,
+                    b: self.layout.border_b,
+                    a: self.layout.border_a,
                 };
+                (*win_ptr).rendering_requested.blur = self.layout.window_blur;
+                (*win_ptr).rendering_requested.opacity = crate::policy::arrange::window_opacity(
+                    is_focused,
+                    self.layout.window_opacity,
+                    crate::policy::arrange::NORMAL_UNFOCUSED_OPACITY,
+                );
             }
-            // Position status bar windows on this output
-            let bar_h = self.layout.bar_height as u32;
-            let spacing = 12;
-            let margin = 12;
-            let mut top_left = Vec::new();
-            let mut top_center = Vec::new();
-            let mut top_right = Vec::new();
-            let mut bottom_left = Vec::new();
-            let mut bottom_center = Vec::new();
-            let mut bottom_right = Vec::new();
-            let mut left_side = Vec::new();
-            let mut right_side = Vec::new();
-            let mut full_top = Vec::new();
+            // Position status bar windows on this output.
+            // Snapshot the bars (excluding any being interactively dragged),
+            // lay them out in policy code, then apply the placements.
+            let mut status_items: Vec<crate::policy::arrange::StatusBarItem> = Vec::new();
+            let mut status_wins: Vec<*mut Window> = Vec::new();
 
             for &win_ptr in self.windows.iter() {
                 if win_ptr.is_null() || (*win_ptr).closed {
@@ -1682,265 +1474,39 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                             continue;
                         }
 
-                        let edge = resolve_edge(win_ptr);
-                        match edge {
-                            crate::window::StatusEdge::TopLeft => {
-                                top_left.push(win_ptr);
-                            }
-                            crate::window::StatusEdge::TopCenter => {
-                                top_center.push(win_ptr);
-                            }
-                            crate::window::StatusEdge::TopRight => {
-                                top_right.push(win_ptr);
-                            }
-                            crate::window::StatusEdge::BottomLeft => {
-                                bottom_left.push(win_ptr);
-                            }
-                            crate::window::StatusEdge::BottomCenter => {
-                                bottom_center.push(win_ptr);
-                            }
-                            crate::window::StatusEdge::BottomRight => {
-                                bottom_right.push(win_ptr);
-                            }
-                            crate::window::StatusEdge::Left => {
-                                left_side.push(win_ptr);
-                            }
-                            crate::window::StatusEdge::Right => {
-                                right_side.push(win_ptr);
-                            }
-                            _ => {
-                                full_top.push(win_ptr);
-                            }
-                        }
                         log::info!("[ArrangeStatus] app_id={} status_edge={:?}", app_id, (*win_ptr).status_edge);
+                        status_items.push(crate::policy::arrange::StatusBarItem {
+                            app_id,
+                            edge: (*win_ptr).status_edge,
+                            prev_len: std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height),
+                        });
+                        status_wins.push(win_ptr);
                     }
                 }
             }
 
-            log::info!("[ArrangeStatus] top_left_len={}, top_center_len={}, top_right_len={}, left_side_len={}", top_left.len(), top_center.len(), top_right.len(), left_side.len());
-
-            const LEFT_ORDER: &[&str] = &["viewport", "window"];
-            const RIGHT_ORDER: &[&str] = &["tray", "cpu", "memory", "brightness", "volume", "battery", "clock"];
+            let placements = crate::policy::arrange::layout_status_bars(
+                &status_items,
+                &crate::policy::arrange::StatusBarLayoutParams {
+                    output: crate::policy::api::Rect {
+                        x: wlr_box.x,
+                        y: wlr_box.y,
+                        width: wlr_box.width,
+                        height: wlr_box.height,
+                    },
+                    bar_height: self.layout.bar_height as u32,
+                    hide_mode: self.status_hide_mode,
+                    hide_mode_preview: self.layout.status_module_hide_mode_preview as i32,
+                },
+            );
 
-            let sort_left = |w_list: &mut Vec<*mut Window>| {
-                w_list.sort_by_key(|&w| unsafe {
-                    let app_id = (*w).get_app_id_string().unwrap_or_default();
-                    let name = app_id.strip_prefix("cce-status-interface-left-")
-                        .or_else(|| app_id.strip_prefix("cce-status-left-"))
-                        .unwrap_or(&app_id);
-                    LEFT_ORDER.iter().position(|&m| m == name).unwrap_or(99)
-                });
-            };
-
-            let sort_right = |w_list: &mut Vec<*mut Window>| {
-                w_list.sort_by_key(|&w| unsafe {
-                    let app_id = (*w).get_app_id_string().unwrap_or_default();
-                    let name = app_id.strip_prefix("cce-status-interface-right-")
-                        .or_else(|| app_id.strip_prefix("cce-status-right-"))
-                        .unwrap_or(&app_id);
-                    RIGHT_ORDER.iter().position(|&m| m == name).unwrap_or(99)
-                });
-            };
-
-            sort_left(&mut top_left);
-            sort_left(&mut top_center);
-            sort_right(&mut top_right);
-            sort_left(&mut bottom_left);
-            sort_left(&mut bottom_center);
-            sort_right(&mut bottom_right);
-
-            // 1. Top Edge
-            let status_y_top = if self.status_hide_mode {
-                let preview = self.layout.status_module_hide_mode_preview as i32;
-                wlr_box.y - (bar_h as i32 - preview)
-            } else {
-                wlr_box.y
-            };
-
-            let mut top_right_width_needed = 0;
-            for &win_ptr in &top_right {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                top_right_width_needed += w as i32 + spacing;
-            }
-            let top_right_boundary = wlr_box.x + wlr_box.width - margin - top_right_width_needed;
-
-            // 1a. Left Group (TopLeft / nw)
-            let mut cur_left_x = wlr_box.x + margin;
-            for &win_ptr in &top_left {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let mut w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                let max_allowed_w = top_right_boundary - cur_left_x - spacing;
-                if w as i32 > max_allowed_w {
-                    w = std::cmp::max(max_allowed_w, 20) as u32;
-                }
-                let app_id = (*win_ptr).get_app_id_string().unwrap_or_default();
-                log::info!("[TopLeftLayout] app_id={} x={}, w={}", app_id, cur_left_x, w);
-                (*win_ptr).rendering_requested.x = cur_left_x;
-                (*win_ptr).rendering_requested.y = status_y_top;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: w, height: bar_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: w, height: bar_h };
-                cur_left_x += w as i32 + spacing;
-            }
-
-            // 1b. Center Group (TopCenter / n)
-            let mut top_center_width_needed = 0;
-            for &win_ptr in &top_center {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                top_center_width_needed += w as i32 + spacing;
-            }
-            if top_center_width_needed > 0 {
-                top_center_width_needed -= spacing;
-            }
-            let center_start_x = wlr_box.x + (wlr_box.width - top_center_width_needed) / 2;
-            let mut cur_center_x = std::cmp::max(center_start_x, cur_left_x + spacing);
-
-            for &win_ptr in &top_center {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let mut w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                let max_allowed_w = top_right_boundary - cur_center_x - spacing;
-                if w as i32 > max_allowed_w {
-                    w = std::cmp::max(max_allowed_w, 20) as u32;
-                }
-                let app_id = (*win_ptr).get_app_id_string().unwrap_or_default();
-                log::info!("[TopCenterLayout] app_id={} x={}, w={}", app_id, cur_center_x, w);
-                (*win_ptr).rendering_requested.x = cur_center_x;
-                (*win_ptr).rendering_requested.y = status_y_top;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: w, height: bar_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: w, height: bar_h };
-                cur_center_x += w as i32 + spacing;
-            }
-
-            // 1c. Right Group (TopRight / ne)
-            let mut cur_right_x = wlr_box.x + wlr_box.width - margin;
-            for win_ptr in top_right.into_iter().rev() {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                let x = cur_right_x - w as i32;
-                (*win_ptr).rendering_requested.x = x;
-                (*win_ptr).rendering_requested.y = status_y_top;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: w, height: bar_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: w, height: bar_h };
-                cur_right_x = x - spacing;
-            }
-
-            for win_ptr in full_top {
-                (*win_ptr).rendering_requested.x = wlr_box.x;
-                (*win_ptr).rendering_requested.y = status_y_top;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: wlr_box.width as u32, height: bar_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: wlr_box.width as u32, height: bar_h };
-            }
-
-            // 2. Bottom Edge
-            let status_y_bottom = wlr_box.y + wlr_box.height - bar_h as i32;
-
-            let mut bottom_right_width_needed = 0;
-            for &win_ptr in &bottom_right {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                bottom_right_width_needed += w as i32 + spacing;
-            }
-            let bottom_right_boundary = wlr_box.x + wlr_box.width - margin - bottom_right_width_needed;
-
-            // 2a. Left Group (BottomLeft / sw)
-            let mut cur_left_x = wlr_box.x + margin;
-            for &win_ptr in &bottom_left {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let mut w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                let max_allowed_w = bottom_right_boundary - cur_left_x - spacing;
-                if w as i32 > max_allowed_w {
-                    w = std::cmp::max(max_allowed_w, 20) as u32;
-                }
-                (*win_ptr).rendering_requested.x = cur_left_x;
-                (*win_ptr).rendering_requested.y = status_y_bottom;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: w, height: bar_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: w, height: bar_h };
-                cur_left_x += w as i32 + spacing;
-            }
-
-            // 2b. Center Group (BottomCenter / s)
-            let mut bottom_center_width_needed = 0;
-            for &win_ptr in &bottom_center {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                bottom_center_width_needed += w as i32 + spacing;
-            }
-            if bottom_center_width_needed > 0 {
-                bottom_center_width_needed -= spacing;
-            }
-            let center_start_x = wlr_box.x + (wlr_box.width - bottom_center_width_needed) / 2;
-            let mut cur_center_x = std::cmp::max(center_start_x, cur_left_x + spacing);
-
-            for &win_ptr in &bottom_center {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let mut w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                let max_allowed_w = bottom_right_boundary - cur_center_x - spacing;
-                if w as i32 > max_allowed_w {
-                    w = std::cmp::max(max_allowed_w, 20) as u32;
+            for (&win_ptr, placement) in status_wins.iter().zip(placements.iter()) {
+                if let Some(pl) = placement {
+                    (*win_ptr).rendering_requested.x = pl.x;
+                    (*win_ptr).rendering_requested.y = pl.y;
+                    (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: pl.width, height: pl.height });
+                    (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: pl.width, height: pl.height };
                 }
-                (*win_ptr).rendering_requested.x = cur_center_x;
-                (*win_ptr).rendering_requested.y = status_y_bottom;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: w, height: bar_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: w, height: bar_h };
-                cur_center_x += w as i32 + spacing;
-            }
-
-            // 2c. Right Group (BottomRight / se)
-            let mut cur_right_x = wlr_box.x + wlr_box.width - margin;
-            for win_ptr in bottom_right.into_iter().rev() {
-                let prev_len = std::cmp::max((*win_ptr).box_geom.width, (*win_ptr).box_geom.height);
-                let w = if prev_len > 0 { prev_len as u32 } else { 100 };
-                let x = cur_right_x - w as i32;
-                (*win_ptr).rendering_requested.x = x;
-                (*win_ptr).rendering_requested.y = status_y_bottom;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: w, height: bar_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: w, height: bar_h };
-                cur_right_x = x - spacing;
-            }
-
-            // 3. Left Edge (Vertical stacking)
-            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 };
-                (*win_ptr).rendering_requested.x = wlr_box.x;
-                (*win_ptr).rendering_requested.y = cur_left_y;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: bar_h, height: actual_h });
-                (*win_ptr).wm_requested.bounds = crate::window::Dimensions { width: bar_h, height: actual_h };
-                cur_left_y += actual_h as i32 + spacing;
-            }
-
-            // 4. Right Edge (Vertical stacking)
-            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 };
-                (*win_ptr).rendering_requested.x = wlr_box.x + wlr_box.width - bar_h as i32;
-                (*win_ptr).rendering_requested.y = cur_right_y;
-                (*win_ptr).wm_requested.dimensions = Some(crate::window::Dimensions { width: bar_h, height: actual_h });
-                (*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