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

commit43cea2d523de97c5b1e7c31bf6cbbe5e07405418
parentae01e2b00c
authorLucas Galante <[email protected]>
date2026-08-12 15:04
feat: geometric Tiled mode + live overview displacement (policy rework)

Mechanism half of the cce-window-manager Tiled/Floating rework:

- op_end geometric detection: a move/resize that lands every content
  edge on a visible grid cell edge promotes the window to Tiled (it then
  reports xdg maximized); landing off-grid demotes it to Floating in
  place, clearing was_tiled so the arrange Exit restore stays quiet.
- Drag start no longer restores pre-maximize geometry: a tiled window
  un-tiles for the drag but keeps its cell-quantized box, so dropping it
  grid-aligned re-tiles it.
- Overview moves call policy overview::displace on every motion event —
  windows the drag covers scoot live to the side the drag vacated.
- configure.maximized now follows tiling_mode == Tiled. Cascade/Grid are
  retired: parse_tiling_mode accepts "tiled" (and legacy "maximized");
  unknown/legacy layout names fall back to Floating. The global_layout
  field and saved-state entry are gone; the empty LayoutNext arm too.
- Renames: Action::Expose→Overview (IPC command "overview", "expose"
  kept as alias; ccectl help updated; migrate-input writes "overview"),
  set_expose_scale_iterator→set_overview_scale_iterator,
  was_maximized→was_tiled, saved_maximized_*→saved_floating_*.

Live verification pending a compositor restart.

Co-Authored-By: Claude Fable 5 <[email protected]>

 CLAUDE.md                           |   5 +-
 src/cce_ctl.rs                      |   4 +-
 src/migrate_input.rs                |   2 +-
 src/server/cce_window_management.rs |   2 +-
 src/server/config.rs                |  12 ++--
 src/server/cursor.rs                |  68 +++++---------------
 src/server/seat.rs                  | 124 +++++++++++++++++++++++++++++++++++-
 src/server/window.rs                |  54 ++++++++--------
 src/server/window_manager.rs        |  38 +++++------
 src/server/xdg_toplevel.rs          |   2 +-
 src/server/xwayland_window.rs       |   2 +-
 11 files changed, 198 insertions(+), 115 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 9ab19a9..b7c57ef 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -111,8 +111,9 @@ treats them as opaque.
 - **`window.rs`** (~3900 lines) — per-window model and rendering (borders, blur,
   viewport transforms).
 - **`crate::tiling`** (from `cce-window-manager`) — `TilingMode` enum: `Floating`,
-  `Cascade`, `Grid`, `Fullscreen`, `Popup`, `Overlay`, `Maximized`. Modes apply
-  per-window and per-viewport.
+  `Tiled` (grid-aligned; the window reports xdg maximized), `Fullscreen`,
+  `Popup`, `Overlay`, `Status`. Tiled-ness is geometric: the seat op's end
+  (`seat.rs::op_end`) promotes/demotes via `policy::snap::is_cell_aligned`.
 - Input stack: `input_manager.rs`, `seat.rs`, `cursor.rs`, `keyboard*.rs`,
   `xkb_*.rs`, `libinput_*.rs`, `pointer_*.rs`, `tablet*.rs`, `text_input.rs`,
   `input_relay.rs`/`input_popup.rs` (IME).
diff --git a/src/cce_ctl.rs b/src/cce_ctl.rs
index ad1f637..f26b883 100644
--- a/src/cce_ctl.rs
+++ b/src/cce_ctl.rs
@@ -54,7 +54,7 @@ fn usage(name: &str, to_stderr: bool) {
     print("  close-window <app_id|id> [title-substring]  # close a specific window");
     print("  center-window [<app_id>]   # pan focused/named window on-screen; replies x= y= w= h=");
     print("  place-next <app_id> <x> <y> # one-shot: next map of app_id lands near this layout pos");
-    print("  expose");
+    print("  overview");
     print("  windows [--json]           # list windows; --json emits one JSON object per line");
     print("  status-hide-mode [true|false]");
     print("  adjust-position-mode [true|false|query]");
@@ -74,7 +74,7 @@ fn usage(name: &str, to_stderr: bool) {
     print("  bind <mods> <keysym> <action> [args...]");
     print("  pbind <mods> <button> <action>");
     print("  retile");
-    print("  mode <cascade|grid|fullscreen|floating|popup|maximized|overlay> <app_id> [title]");
+    print("  mode <floating|tiled|fullscreen|popup|overlay> <app_id> [title]");
     print("  pointer-location");
     print("  pointer-move-to <x> <y>            (layout pixels)");
     print("  pointer-move-by <dx> <dy>");
diff --git a/src/migrate_input.rs b/src/migrate_input.rs
index 04875c2..33496d1 100644
--- a/src/migrate_input.rs
+++ b/src/migrate_input.rs
@@ -107,7 +107,7 @@ pub fn extract_from_config(content: &str) -> Result<Extracted, String> {
                 ("close_window", "close_window"),
                 ("toggle_fullscreen", "toggle_fullscreen"),
                 ("window_switcher", "window_switcher"),
-                ("toggle_overview", "expose"),
+                ("toggle_overview", "overview"),
             ] {
                 let Some(c) = child(children, prop) else { continue };
                 let Some(chord) = first_arg_string(c) else { continue };
diff --git a/src/server/cce_window_management.rs b/src/server/cce_window_management.rs
index e737729..3bd2ffd 100644
--- a/src/server/cce_window_management.rs
+++ b/src/server/cce_window_management.rs
@@ -160,7 +160,7 @@ unsafe extern "C" fn toplevel_set_maximized(
     let server = (*data).server;
     let window_key = (*data).window_key;
     if let Some(window) = resolve_window(server, window_key) {
-        (*window).tiling_mode = crate::tiling::TilingMode::Maximized;
+        (*window).tiling_mode = crate::tiling::TilingMode::Tiled;
         (*window).mode_locked = true;
         (*window).wm_scheduled.maximize_requested = crate::window::MaximizeRequest::Maximize;
         (*server).wm.dirty_windowing();
diff --git a/src/server/config.rs b/src/server/config.rs
index f298e95..e627eaa 100644
--- a/src/server/config.rs
+++ b/src/server/config.rs
@@ -775,15 +775,15 @@ pub fn parse_hex_color_rgba(hex_str: &str) -> [f32; 4] {
 
 pub fn parse_tiling_mode(s: &str) -> TilingMode {
     match s.to_lowercase().as_str() {
-        "floating" => TilingMode::Floating,
-        "cascade" => TilingMode::Cascade,
-        "grid" => TilingMode::Grid,
         "fullscreen" => TilingMode::Fullscreen,
         "popup" => TilingMode::Popup,
         "sidepanel" | "side_panel" | "side-panel" | "pinned" | "overlay" => TilingMode::Overlay,
         "status" => TilingMode::Status,
-        "maximized" => TilingMode::Maximized,
-        _ => TilingMode::Cascade,
+        // "maximized" is the retired name for grid-locked windows.
+        "tiled" | "maximized" => TilingMode::Tiled,
+        // Everything else — including the retired "cascade"/"grid" layout
+        // modes still present in old configs — is Floating.
+        _ => TilingMode::Floating,
     }
 }
 
@@ -2217,7 +2217,7 @@ pub fn parse_config(path: &str, state: &mut crate::window_manager::WindowManager
                         gesture_type: g_type.to_string(),
                         fingers,
                         direction: direction.clone(),
-                        action: Action::Expose,
+                        action: Action::Overview,
                         command: None,
                     });
                 }
diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index 8017da7..9323724 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -962,7 +962,7 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                 return;
             } else if !overview_win_valid {
                 cursor.left_click_on_bg_in_overview = true;
-                (*server).wm.execute_action(&crate::config::Action::Expose, None);
+                (*server).wm.execute_action(&crate::config::Action::Overview, None);
                 cursor.pressed.insert((*event).button, None);
                 return;
             }
@@ -1030,22 +1030,10 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                     && (*target_win).tiling_mode != crate::tiling::TilingMode::Fullscreen
                     && (*target_win).tiling_mode != crate::tiling::TilingMode::Overlay
                 {
-                    if (*target_win).was_maximized {
-                        (*target_win).box_geom.width = (*target_win).saved_maximized_width;
-                        (*target_win).box_geom.height = (*target_win).saved_maximized_height;
-                        (*target_win).virtual_x = (*target_win).saved_maximized_virtual_x;
-                        (*target_win).virtual_y = (*target_win).saved_maximized_virtual_y;
-                        (*target_win).was_maximized = false;
-                        
-                        (*target_win).wm_requested.dimensions = Some(crate::window::Dimensions {
-                            width: (*target_win).saved_maximized_width as u32,
-                            height: (*target_win).saved_maximized_height as u32,
-                        });
-                        (*target_win).wm_requested.bounds = crate::window::Dimensions {
-                            width: (*target_win).saved_maximized_width as u32,
-                            height: (*target_win).saved_maximized_height as u32,
-                        };
-                    }
+                    // A tiled window un-tiles for the drag but keeps its
+                    // cell-quantized geometry; landing grid-aligned re-tiles
+                    // it (op_end geometric detection).
+                    (*target_win).was_tiled = false;
                     (*target_win).tiling_mode = crate::tiling::TilingMode::Floating;
                     (*target_win).mode_locked = true;
                 }
@@ -1136,22 +1124,10 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                 BorderZone::Resize(edges) => {
                     if (*event).button == 0x110 { // BTN_LEFT
                         if initial_mode != crate::tiling::TilingMode::Floating {
-                            if (*border_target_win).was_maximized {
-                                (*border_target_win).box_geom.width = (*border_target_win).saved_maximized_width;
-                                (*border_target_win).box_geom.height = (*border_target_win).saved_maximized_height;
-                                (*border_target_win).virtual_x = (*border_target_win).saved_maximized_virtual_x;
-                                (*border_target_win).virtual_y = (*border_target_win).saved_maximized_virtual_y;
-                                (*border_target_win).was_maximized = false;
-                                
-                                (*border_target_win).wm_requested.dimensions = Some(crate::window::Dimensions {
-                                    width: (*border_target_win).saved_maximized_width as u32,
-                                    height: (*border_target_win).saved_maximized_height as u32,
-                                });
-                                (*border_target_win).wm_requested.bounds = crate::window::Dimensions {
-                                    width: (*border_target_win).saved_maximized_width as u32,
-                                    height: (*border_target_win).saved_maximized_height as u32,
-                                };
-                            }
+                            // A tiled window un-tiles for the drag but keeps its
+                            // cell-quantized geometry; landing grid-aligned re-tiles
+                            // it (op_end geometric detection).
+                            (*border_target_win).was_tiled = false;
                             (*border_target_win).tiling_mode = crate::tiling::TilingMode::Floating;
                             (*border_target_win).mode_locked = true;
                         }
@@ -1201,11 +1177,11 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                         cursor.last_click_window = border_target_win;
 
                         if is_double_click {
-                            if initial_mode == crate::tiling::TilingMode::Maximized {
+                            if initial_mode == crate::tiling::TilingMode::Tiled {
                                 (*border_target_win).tiling_mode = crate::tiling::TilingMode::Floating;
                                 (*border_target_win).mode_locked = true;
                             } else {
-                                (*border_target_win).tiling_mode = crate::tiling::TilingMode::Maximized;
+                                (*border_target_win).tiling_mode = crate::tiling::TilingMode::Tiled;
                                 (*border_target_win).mode_locked = true;
                             }
                             seat.focus(Focus::Window(border_target_win));
@@ -1218,22 +1194,10 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                         if initial_mode != crate::tiling::TilingMode::Floating
                             && initial_mode != crate::tiling::TilingMode::Overlay
                         {
-                            if (*border_target_win).was_maximized {
-                                (*border_target_win).box_geom.width = (*border_target_win).saved_maximized_width;
-                                (*border_target_win).box_geom.height = (*border_target_win).saved_maximized_height;
-                                (*border_target_win).virtual_x = (*border_target_win).saved_maximized_virtual_x;
-                                (*border_target_win).virtual_y = (*border_target_win).saved_maximized_virtual_y;
-                                (*border_target_win).was_maximized = false;
-                                
-                                (*border_target_win).wm_requested.dimensions = Some(crate::window::Dimensions {
-                                    width: (*border_target_win).saved_maximized_width as u32,
-                                    height: (*border_target_win).saved_maximized_height as u32,
-                                });
-                                (*border_target_win).wm_requested.bounds = crate::window::Dimensions {
-                                    width: (*border_target_win).saved_maximized_width as u32,
-                                    height: (*border_target_win).saved_maximized_height as u32,
-                                };
-                            }
+                            // A tiled window un-tiles for the drag but keeps its
+                            // cell-quantized geometry; landing grid-aligned re-tiles
+                            // it (op_end geometric detection).
+                            (*border_target_win).was_tiled = false;
                             (*border_target_win).tiling_mode = crate::tiling::TilingMode::Floating;
                             (*border_target_win).mode_locked = true;
                         }
@@ -2177,7 +2141,7 @@ unsafe extern "C" fn handle_swipe_update(listener: *mut ffi::wl_listener, data:
         log::info!("Swipe gesture matched action: {:?}", matched_action);
         cursor.gesture_triggered = true;
 
-        if matched_action == crate::config::Action::Expose && (*seat.server).wm.mode == crate::window_manager::WindowManagerMode::Overview {
+        if matched_action == crate::config::Action::Overview && (*seat.server).wm.mode == crate::window_manager::WindowManagerMode::Overview {
             let lx = cursor.x();
             let ly = cursor.y();
             let mut hovered_win: *mut crate::window::Window = std::ptr::null_mut();
diff --git a/src/server/seat.rs b/src/server/seat.rs
index d467e0f..8d254a9 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -803,7 +803,7 @@ impl Seat {
         if window.is_null()
             || !matches!(
                 (*window).tiling_mode,
-                crate::tiling::TilingMode::Floating | crate::tiling::TilingMode::Maximized
+                crate::tiling::TilingMode::Floating | crate::tiling::TilingMode::Tiled
             )
         {
             return;
@@ -1015,6 +1015,10 @@ impl Seat {
                 if (*win).tiling_mode != crate::tiling::TilingMode::Floating
                     && (*win).tiling_mode != crate::tiling::TilingMode::Overlay
                 {
+                    // Un-tile for the drag but KEEP the geometry (clearing
+                    // was_tiled suppresses the arrange Exit restore);
+                    // landing grid-aligned re-tiles it in op_end.
+                    (*win).was_tiled = false;
                     (*win).tiling_mode = crate::tiling::TilingMode::Floating;
                     (*win).mode_locked = true;
                     (*self.server).wm.raise_window(win);
@@ -1191,6 +1195,20 @@ impl Seat {
                             (*win).virtual_x = vx;
                             (*win).virtual_y = vy;
 
+                            // Overview moves displace what they cover: any
+                            // window the drag covers past the threshold
+                            // scoots to the side the drag vacated.
+                            if (*self.server).wm.mode
+                                == crate::window_manager::WindowManagerMode::Overview
+                            {
+                                displace_covered(
+                                    self.server,
+                                    win,
+                                    (virtual_dx, virtual_dy),
+                                    &sp,
+                                );
+                            }
+
                             let mut out_x = 0;
                             let mut out_y = 0;
                             let outputs_list = &mut (*(*self.server).wm.server).om.outputs as *mut ffi::wl_list as *mut WlList;
@@ -1353,6 +1371,49 @@ impl Seat {
                         (*self.server).wm.dirty_windowing();
                     }
                 }
+                // Geometric mode detection: a move/resize that lands every
+                // content edge on a visible desktop-grid cell edge makes the
+                // window Tiled (it then reports the maximized state to its
+                // client); landing off-grid makes it Floating, in place.
+                // Only windows resolving Floating/Tiled participate —
+                // Popup/Overlay/Status/Fullscreen are untouched.
+                let resolved = (*self.server).wm.get_mode_for_window(win);
+                if matches!(
+                    resolved,
+                    crate::tiling::TilingMode::Floating | crate::tiling::TilingMode::Tiled
+                ) {
+                    // Unscaled params: alignment classifies the resting
+                    // geometry, the zoom-aware grab distance is irrelevant.
+                    let sp = (*self.server).wm.layout.snap_params();
+                    let (w, h) = match (*win).wm_requested.dimensions {
+                        // A just-finished resize may not be acked into
+                        // box_geom yet; the requested size is what the
+                        // window is about to become.
+                        Some(d) => (d.width as f64, d.height as f64),
+                        None => ((*win).box_geom.width as f64, (*win).box_geom.height as f64),
+                    };
+                    let aligned = crate::policy::snap::is_cell_aligned(
+                        (*win).virtual_x,
+                        (*win).virtual_y,
+                        w,
+                        h,
+                        &sp,
+                        1.0,
+                    );
+                    if aligned && resolved != crate::tiling::TilingMode::Tiled {
+                        (*win).tiling_mode = crate::tiling::TilingMode::Tiled;
+                        (*win).mode_locked = true;
+                        (*self.server).wm.dirty_windowing();
+                    } else if !aligned && resolved == crate::tiling::TilingMode::Tiled {
+                        // Un-tile in place: clearing was_tiled keeps the
+                        // arrange Exit transition from restoring the old
+                        // floating geometry.
+                        (*win).was_tiled = false;
+                        (*win).tiling_mode = crate::tiling::TilingMode::Floating;
+                        (*win).mode_locked = true;
+                        (*self.server).wm.dirty_windowing();
+                    }
+                }
                 // A border TAP — press+release without meaningful motion —
                 // is a click, not a drag. The press focused the window and
                 // killed any focus-follow pan (drag protection), which left
@@ -1376,6 +1437,67 @@ impl Seat {
     }
 }
 
+/// Live overview displacement for one motion step of a move op: every
+/// mapped, visible Floating/Tiled window the drag covers past the policy
+/// threshold relocates to the side the drag vacated
+/// (`crate::policy::overview::displace`). Single-level on purpose — a
+/// displaced window does not cascade into a third.
+unsafe fn displace_covered(
+    server: *mut Server,
+    win: *mut crate::window::Window,
+    drag_delta: (f64, f64),
+    sp: &crate::policy::snap::SnapParams,
+) {
+    let wm = &mut (*server).wm;
+    let moved = (
+        (*win).virtual_x,
+        (*win).virtual_y,
+        (*win).box_geom.width as f64,
+        (*win).box_geom.height as f64,
+    );
+    let mut ptrs: Vec<*mut crate::window::Window> = Vec::new();
+    let mut cands: Vec<crate::policy::overview::DisplaceCandidate> = Vec::new();
+    for &w in wm.windows.iter() {
+        if w.is_null() || w == win || (*w).closed || (*w).minimized {
+            continue;
+        }
+        if !matches!((*w).state, crate::window::WindowState::Mapped) {
+            continue;
+        }
+        if (*w).is_status_bar() || (*w).is_wallpaper() {
+            continue;
+        }
+        let mode = wm.get_mode_for_window(w);
+        if mode != crate::tiling::TilingMode::Floating
+            && mode != crate::tiling::TilingMode::Tiled
+        {
+            continue;
+        }
+        ptrs.push(w);
+        cands.push(crate::policy::overview::DisplaceCandidate {
+            x: (*w).virtual_x,
+            y: (*w).virtual_y,
+            w: (*w).box_geom.width as f64,
+            h: (*w).box_geom.height as f64,
+            tiled: mode == crate::tiling::TilingMode::Tiled,
+        });
+    }
+    if cands.is_empty() {
+        return;
+    }
+    let moves =
+        crate::policy::overview::displace(moved, drag_delta, &cands, sp, sp.gap_width);
+    if moves.is_empty() {
+        return;
+    }
+    for (idx, (nx, ny)) in moves {
+        let w = ptrs[idx];
+        (*w).virtual_x = nx;
+        (*w).virtual_y = ny;
+    }
+    wm.dirty_windowing();
+}
+
 unsafe extern "C" fn handle_request_set_cursor(
     listener: *mut ffi::wl_listener,
     data: *mut std::ffi::c_void,
diff --git a/src/server/window.rs b/src/server/window.rs
index 21a3b51..14bc19e 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -420,11 +420,11 @@ pub struct Window {
     pub saved_height: i32,
     pub saved_virtual_x: f64,
     pub saved_virtual_y: f64,
-    pub was_maximized: bool,
-    pub saved_maximized_width: i32,
-    pub saved_maximized_height: i32,
-    pub saved_maximized_virtual_x: f64,
-    pub saved_maximized_virtual_y: f64,
+    pub was_tiled: bool,
+    pub saved_floating_width: i32,
+    pub saved_floating_height: i32,
+    pub saved_floating_virtual_x: f64,
+    pub saved_floating_virtual_y: f64,
 
     pub wm_scheduled: WmScheduledState,
     pub wm_sent: WmSentState,
@@ -625,11 +625,11 @@ impl Window {
             saved_height: 0,
             saved_virtual_x: 0.0,
             saved_virtual_y: 0.0,
-            was_maximized: false,
-            saved_maximized_width: 0,
-            saved_maximized_height: 0,
-            saved_maximized_virtual_x: 0.0,
-            saved_maximized_virtual_y: 0.0,
+            was_tiled: false,
+            saved_floating_width: 0,
+            saved_floating_height: 0,
+            saved_floating_virtual_x: 0.0,
+            saved_floating_virtual_y: 0.0,
             wm_scheduled: WmScheduledState {
                 dimensions_hint: DimensionsHint { min_width: 0, min_height: 0, max_width: 0, max_height: 0 },
                 decoration_hint: ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
@@ -1824,9 +1824,9 @@ impl Window {
         };
         self.wm_requested.dimensions = None;
 
-        let is_maximized_layout = self.tiling_mode == crate::tiling::TilingMode::Cascade
-            || self.tiling_mode == crate::tiling::TilingMode::Grid
-            || self.tiling_mode == crate::tiling::TilingMode::Maximized;
+        // A tiled window thinks it is maximized: the xdg maximized state
+        // follows the mode.
+        let is_maximized_layout = self.tiling_mode == crate::tiling::TilingMode::Tiled;
         self.configure_scheduled = Configure {
             width,
             height,
@@ -2131,7 +2131,7 @@ impl Window {
                 ancestor: *mut ffi::wlr_scene_node,
             }
 
-            unsafe extern "C" fn set_expose_scale_iterator(
+            unsafe extern "C" fn set_overview_scale_iterator(
                 buffer: *mut ffi::wlr_scene_buffer,
                 sx: i32,
                 sy: i32,
@@ -2178,7 +2178,7 @@ impl Window {
             let scale_data_surfaces = ScaleData { scale_x, scale_y, ancestor: self.surfaces.tree as *mut ffi::wlr_scene_node };
             ffi::wlr_scene_node_for_each_buffer(
                 self.surfaces.tree as *mut ffi::wlr_scene_node,
-                Some(set_expose_scale_iterator),
+                Some(set_overview_scale_iterator),
                 &scale_data_surfaces as *const ScaleData as *mut std::ffi::c_void,
             );
 
@@ -2186,7 +2186,7 @@ impl Window {
                 let scale_data_saved = ScaleData { scale_x, scale_y, ancestor: self.surfaces.saved_tree as *mut ffi::wlr_scene_node };
                 ffi::wlr_scene_node_for_each_buffer(
                     self.surfaces.saved_tree as *mut ffi::wlr_scene_node,
-                    Some(set_expose_scale_iterator),
+                    Some(set_overview_scale_iterator),
                     &scale_data_saved as *const ScaleData as *mut std::ffi::c_void,
                 );
             }
@@ -2194,7 +2194,7 @@ impl Window {
             let scale_data_popup = ScaleData { scale_x, scale_y, ancestor: self.popup_tree as *mut ffi::wlr_scene_node };
             ffi::wlr_scene_node_for_each_buffer(
                 self.popup_tree as *mut ffi::wlr_scene_node,
-                Some(set_expose_scale_iterator),
+                Some(set_overview_scale_iterator),
                 &scale_data_popup as *const ScaleData as *mut std::ffi::c_void,
             );
             self.last_applied_scale = self.scale;
@@ -2379,7 +2379,7 @@ impl Window {
             ancestor: *mut ffi::wlr_scene_node,
         }
 
-        unsafe extern "C" fn set_expose_scale_iterator(
+        unsafe extern "C" fn set_overview_scale_iterator(
             buffer: *mut ffi::wlr_scene_buffer,
             sx: i32,
             sy: i32,
@@ -2424,7 +2424,7 @@ impl Window {
         let scale_data_surfaces = ScaleData { scale: self.scale, ancestor: self.surfaces.tree as *mut ffi::wlr_scene_node };
         ffi::wlr_scene_node_for_each_buffer(
             self.surfaces.tree as *mut ffi::wlr_scene_node,
-            Some(set_expose_scale_iterator),
+            Some(set_overview_scale_iterator),
             &scale_data_surfaces as *const ScaleData as *mut std::ffi::c_void,
         );
 
@@ -2432,7 +2432,7 @@ impl Window {
             let scale_data_saved = ScaleData { scale: self.scale, ancestor: self.surfaces.saved_tree as *mut ffi::wlr_scene_node };
             ffi::wlr_scene_node_for_each_buffer(
                 self.surfaces.saved_tree as *mut ffi::wlr_scene_node,
-                Some(set_expose_scale_iterator),
+                Some(set_overview_scale_iterator),
                 &scale_data_saved as *const ScaleData as *mut std::ffi::c_void,
             );
         }
@@ -2440,7 +2440,7 @@ impl Window {
         let scale_data_popup = ScaleData { scale: self.scale, ancestor: self.popup_tree as *mut ffi::wlr_scene_node };
         ffi::wlr_scene_node_for_each_buffer(
             self.popup_tree as *mut ffi::wlr_scene_node,
-            Some(set_expose_scale_iterator),
+            Some(set_overview_scale_iterator),
             &scale_data_popup as *const ScaleData as *mut std::ffi::c_void,
         );
 
@@ -3900,7 +3900,7 @@ impl Decoration {
             ancestor: *mut ffi::wlr_scene_node,
         }
 
-        unsafe extern "C" fn set_expose_scale_iterator(
+        unsafe extern "C" fn set_overview_scale_iterator(
             buffer: *mut ffi::wlr_scene_buffer,
             sx: i32,
             sy: i32,
@@ -3945,7 +3945,7 @@ impl Decoration {
         let scale_data = ScaleData { scale, ancestor: self.surfaces.tree as *mut ffi::wlr_scene_node };
         ffi::wlr_scene_node_for_each_buffer(
             self.surfaces.tree as *mut ffi::wlr_scene_node,
-            Some(set_expose_scale_iterator),
+            Some(set_overview_scale_iterator),
             &scale_data as *const ScaleData as *mut std::ffi::c_void,
         );
 
@@ -3953,7 +3953,7 @@ impl Decoration {
             let scale_data_saved = ScaleData { scale, ancestor: self.surfaces.saved_tree as *mut ffi::wlr_scene_node };
             ffi::wlr_scene_node_for_each_buffer(
                 self.surfaces.saved_tree as *mut ffi::wlr_scene_node,
-                Some(set_expose_scale_iterator),
+                Some(set_overview_scale_iterator),
                 &scale_data_saved as *const ScaleData as *mut std::ffi::c_void,
             );
         }
@@ -3975,7 +3975,7 @@ impl Decoration {
             ancestor: *mut ffi::wlr_scene_node,
         }
 
-        unsafe extern "C" fn set_expose_scale_iterator(
+        unsafe extern "C" fn set_overview_scale_iterator(
             buffer: *mut ffi::wlr_scene_buffer,
             sx: i32,
             sy: i32,
@@ -4020,7 +4020,7 @@ impl Decoration {
         let scale_data = ScaleData { scale, ancestor: self.surfaces.tree as *mut ffi::wlr_scene_node };
         ffi::wlr_scene_node_for_each_buffer(
             self.surfaces.tree as *mut ffi::wlr_scene_node,
-            Some(set_expose_scale_iterator),
+            Some(set_overview_scale_iterator),
             &scale_data as *const ScaleData as *mut std::ffi::c_void,
         );
 
@@ -4028,7 +4028,7 @@ impl Decoration {
             let scale_data_saved = ScaleData { scale, ancestor: self.surfaces.saved_tree as *mut ffi::wlr_scene_node };
             ffi::wlr_scene_node_for_each_buffer(
                 self.surfaces.saved_tree as *mut ffi::wlr_scene_node,
-                Some(set_expose_scale_iterator),
+                Some(set_overview_scale_iterator),
                 &scale_data_saved as *const ScaleData as *mut std::ffi::c_void,
             );
         }
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 5bf12c9..1ab11f9 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -81,7 +81,6 @@ pub struct WindowManager {
     pub desk_pan_y: f64,
     pub desk_zoom: f64,
     pub mode: WindowManagerMode,
-    pub global_layout: crate::tiling::TilingMode,
     pub layout: crate::config::Layout,
     pub mode_rules: Vec<crate::config::ModeRule>,
     pub keybinds: Vec<crate::config::Keybind>,
@@ -231,7 +230,6 @@ impl WindowManager {
         self.desk_zoom = 1.0;
         self.pending_screenshot = None;
         self.mode = WindowManagerMode::Normal;
-        self.global_layout = crate::tiling::TilingMode::Cascade;
         self.restore_queue = Vec::new();
         self.last_window_states = Vec::new();
         self.pending_placements = Vec::new();
@@ -349,7 +347,6 @@ impl WindowManager {
                 self.desk_pan_y = state.desk_pan_y;
                 self.desk_zoom = state.desk_zoom;
                 self.mode = if (state.desk_zoom - 1.0).abs() > 0.001 { WindowManagerMode::Overview } else { WindowManagerMode::Normal };
-                self.global_layout = state.global_layout;
                 self.restore_queue = state.windows;
                 self.last_window_states = state.last_window_states;
                 self.has_restored_focused_window = self.restore_queue.iter().any(|w| w.focused);
@@ -680,7 +677,6 @@ impl WindowManager {
             desk_pan_x: self.desk_pan_x,
             desk_pan_y: self.desk_pan_y,
             desk_zoom: self.desk_zoom,
-            global_layout: self.global_layout,
             windows: saved_wins,
             last_window_states: self.last_window_states.clone(),
         };
@@ -1051,7 +1047,7 @@ impl WindowManager {
             let is_wallpaper = app_id.as_deref() == Some("cce-wallpaper");
             let visible = !matches!((*w).state, crate::window::WindowState::Closing | crate::window::WindowState::Init);
             let resolved_mode = self.get_mode_for_window(w);
-            let expose_eligible = !(*w).minimized
+            let overview_eligible = !(*w).minimized
                 && !is_status
                 && !is_wallpaper
                 && visible
@@ -1075,7 +1071,7 @@ impl WindowManager {
                 resolved_mode,
                 visible,
                 focus_cyclable,
-                expose_eligible,
+                overview_eligible,
             });
         }
 
@@ -1844,9 +1840,9 @@ impl WindowManager {
                 active_resize: self.get_active_resize_dimensions(win_ptr),
                 ssd: (*win_ptr).wm_requested.ssd,
                 decorations_size: (*win_ptr).measure_decorations(),
-                was_maximized: (*win_ptr).was_maximized,
-                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),
+                was_tiled: (*win_ptr).was_tiled,
+                saved_floating_size: ((*win_ptr).saved_floating_width, (*win_ptr).saved_floating_height),
+                saved_floating_virtual: ((*win_ptr).saved_floating_virtual_x, (*win_ptr).saved_floating_virtual_y),
             });
             win_ptrs.push(win_ptr);
         }
@@ -1946,14 +1942,14 @@ impl WindowManager {
             if let Some(opacity) = wp.opacity {
                 (*win_ptr).rendering_requested.opacity = opacity;
             }
-            if let Some(((width, height), (vx, vy))) = wp.saved_maximized {
-                (*win_ptr).saved_maximized_width = width;
-                (*win_ptr).saved_maximized_height = height;
-                (*win_ptr).saved_maximized_virtual_x = vx;
-                (*win_ptr).saved_maximized_virtual_y = vy;
+            if let Some(((width, height), (vx, vy))) = wp.saved_floating {
+                (*win_ptr).saved_floating_width = width;
+                (*win_ptr).saved_floating_height = height;
+                (*win_ptr).saved_floating_virtual_x = vx;
+                (*win_ptr).saved_floating_virtual_y = vy;
             }
-            if let Some(was_maximized) = wp.was_maximized {
-                (*win_ptr).was_maximized = was_maximized;
+            if let Some(was_tiled) = wp.was_tiled {
+                (*win_ptr).was_tiled = was_tiled;
             }
         }
 
@@ -2558,7 +2554,6 @@ impl WindowManager {
                 log::info!("monolithic execute_action: Exit requested");
                 self.start_clean_exit();
             }
-            Action::LayoutNext => {}
             _ => {}
         }
     }
@@ -2897,8 +2892,9 @@ impl WindowManager {
                 self.execute_action(&crate::config::Action::Close, None);
                 "ok\n".to_string()
             }
-            "expose" => {
-                self.execute_action(&crate::config::Action::Expose, None);
+            // "expose" is the retired name for the overview toggle.
+            "overview" | "expose" => {
+                self.execute_action(&crate::config::Action::Overview, None);
                 "ok\n".to_string()
             }
             "wm-mode" => {
@@ -2908,12 +2904,12 @@ impl WindowManager {
                 let target = parts[1].to_lowercase();
                 if target == "normal" {
                     if self.mode == WindowManagerMode::Overview {
-                        self.execute_action(&crate::config::Action::Expose, None);
+                        self.execute_action(&crate::config::Action::Overview, None);
                     }
                     return "ok\n".to_string();
                 } else if target == "overview" {
                     if self.mode == WindowManagerMode::Normal {
-                        self.execute_action(&crate::config::Action::Expose, None);
+                        self.execute_action(&crate::config::Action::Overview, None);
                     }
                     return "ok\n".to_string();
                 }
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index 7d68c87..9b2a4ad 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -894,7 +894,7 @@ unsafe extern "C" fn handle_request_maximize(listener: *mut ffi::wl_listener, _d
     let window = (*toplevel).window;
 
     if ffi::river_wlr_xdg_toplevel_get_requested_maximized((*toplevel).wlr_toplevel) {
-        (*window).tiling_mode = crate::tiling::TilingMode::Maximized;
+        (*window).tiling_mode = crate::tiling::TilingMode::Tiled;
         (*window).mode_locked = true;
         (*window).wm_scheduled.maximize_requested = crate::window::MaximizeRequest::Maximize;
     } else {
diff --git a/src/server/xwayland_window.rs b/src/server/xwayland_window.rs
index 563152d..e5f4bc4 100644
--- a/src/server/xwayland_window.rs
+++ b/src/server/xwayland_window.rs
@@ -548,7 +548,7 @@ unsafe extern "C" fn handle_request_maximize(listener: *mut ffi::wl_listener, _d
     let maximized = (*(*xwindow).xsurface).maximized_vert || (*(*xwindow).xsurface).maximized_horz;
     let window = (*xwindow).window;
     if maximized {
-        (*window).tiling_mode = crate::tiling::TilingMode::Maximized;
+        (*window).tiling_mode = crate::tiling::TilingMode::Tiled;
         (*window).mode_locked = true;
     } else {
         (*window).tiling_mode = crate::tiling::TilingMode::Floating;