window management library
git clone https://git.lucas.co/cce-window-manager.git
docs: document cells, spawn, ramp and query
The module lists in CLAUDE.md and lib.rs had not kept up with the modules
themselves: cells, spawn and ramp appeared in neither, query only in
lib.rs. Add all four, slotted by topic rather than appended — ramp beside
camera, whose transitions it drives; cells and spawn beside snap, which
they share their grid math with.
Two facts each entry records because getting them wrong is expensive:
cells must agree with snap.rs exactly or a tiled window fails to land on
a named square, and ramp's parser is mirrored from cce-ui rather than
shared, so the two have to move together.
Also refresh the stale test paragraph — 143 tests now, not 109, and they
live in every module except api.rs and state.rs, not just the three
originally named.
Co-Authored-By: Claude Opus 5 <[email protected]>
CLAUDE.md | 37 ++++++++++++++++++++++++++++++++++---
src/lib.rs | 9 +++++++++
2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 687a9f1..a9a8160 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -37,7 +37,7 @@ Commit here, not at the workspace root. The crate must **build standalone** —
```sh
cargo build # standalone build (fast; no compositor deps)
-cargo test # run all tests (~109 unit tests, all in-crate)
+cargo test # run all tests (~143 unit tests, all in-crate)
cargo test snap:: # tests in one module
cargo test -p cce-window-manager # same, from the workspace root
```
@@ -46,8 +46,9 @@ Because this crate is pure Rust, building/testing it never triggers the
compositor's native `build.rs` pipeline — prefer working here directly when the
change is policy-side.
-Tests live in `#[cfg(test)]` modules inside `arrange.rs`, `snap.rs`, and
-`slotmap.rs`. This crate is where the DE's testable logic is concentrated —
+Tests live in `#[cfg(test)]` modules at the bottom of the module they cover —
+every module has one except `api.rs` and `state.rs`, which are plain-data
+vocabulary. This crate is where the DE's testable logic is concentrated —
placement/snapping changes should come with unit tests (the existing test
modules show the style: small numeric scenarios with worked-out expectations in
comments).
@@ -138,11 +139,35 @@ The crate owns what a binding *means*; the compositor owns the physical half
backdrop extent, density-faded cell lattice with safety caps). The
compositor's `output.rs` keeps the scene rects/pool and scenefx encodings;
`Layout::background_spec()` builds the `api::GridSpec`.
+- `cells.rs` — chess-style addressing for desktop-grid squares: the origin
+ square is `A1`, letters run right and numbers run DOWN, both 1-based with
+ no zero (`-A1` is left of the origin, `A-1` above it, columns past Z carry
+ on Excel-style). Provides `square_label`/`parse_square`, `square_rect` /
+ `block_rect`, `window_span` (which squares a window covers) and
+ `remap_block` (re-tile a block across a grid-geometry change). Its grid
+ math must agree with `snap.rs` exactly — same virtual-surface content
+ coordinates, same period/inset — or a "tiled" window would not land on a
+ named square.
+- `spawn.rs` — where a window launched *at* a square should land, as opposed
+ to reopening where it last was. `place_at_cell` keeps the invocation square
+ as one of the block's corners and picks WHICH corner by growing away from
+ what is already there (top-left preferred, then the others, scored by
+ collisions first and off-screen area second); `nearest_free` then steps a
+ block off anything still occupying it. It never searches for somewhere
+ else to be, so the result stays predictable.
- `camera.rs` — viewport pan/zoom math (`Camera` = pan_x/pan_y/zoom):
`zoom_about_anchor` (wheel zoom at cursor, keyed zoom at viewport center),
`center_on`, `fit_bounds` (overview fit), `visible_fraction` +
`FOCUS_VISIBLE_THRESHOLD` (focus-follow panning), `is_overview`. The
mechanism owns the actual fields and animation; these are pure maps.
+- `ramp.rs` — speed-ramp evaluation for duration-based camera transitions.
+ `SpeedRamp::from_spec` parses the DE-wide ramp spec string cce-ui's Ramp
+ widget writes and integrates that SPEED profile into a cumulative
+ `progress(t)` curve normalized to end at exactly 1 (so any profile arrives
+ on target; zero-speed segments read as dwell, an all-zero ramp yields
+ `None` and callers fall back to their non-ramp animation). The parser and
+ interpolation are deliberately MIRRORED from cce-ui rather than shared —
+ this crate stays dependency-minimal — so the two must be kept in step.
- `focus.rs` — directional focus selection (`directional_focus` over window
center points in virtual coordinates; no wraparound, off-axis distance is
penalized). Consumed by the compositor's `FocusUp/Down/Left/Right` action
@@ -159,6 +184,12 @@ The crate owns what a binding *means*; the compositor owns the physical half
- `overview.rs` — overview-mode move rules: `displace` relocates windows a
drag covers (past an overlap threshold) to the side the drag vacated,
called by the mechanism on every motion event of an overview move.
+- `query.rs` — window-query resolution: how a user-supplied query string
+ (`ccectl focus-window` / `center-window`, window-stream subscriptions)
+ picks a window. An all-numeric query is tried as an exact window id first,
+ then matched case-insensitively against app_ids with exact beating
+ substring. The mechanism supplies the candidates (mapped windows, in
+ window order); this module owns only the matching rules.
- `state.rs` — `SavedState` / `SavedWindowState` serde types. New fields need
`#[serde(default)]` to keep old state files loadable.
- `slotmap.rs` — generational-index map (river-derived, 0BSD-licensed — keep the
diff --git a/src/lib.rs b/src/lib.rs
index 265cab6..23d8f7d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -22,6 +22,9 @@
// modulo tree shift, density fade, cell lattice with safety caps.
// - `camera`: viewport pan/zoom math — keyed/wheel zoom about an anchor,
// centering, overview fit, focus-follow visibility.
+// - `ramp`: speed-ramp evaluation for duration-based camera
+// transitions — parses the DE-wide ramp spec cce-ui's Ramp widget
+// writes, integrating it into a normalized progress curve.
// - `focus`: directional focus selection (which window is "up/left/…"
// of the focused one) over virtual-surface center points.
// - `tiling`: `TilingMode` — `Tiled`/`Floating` plus the internal roles.
@@ -31,6 +34,12 @@
// - `query`: window-query resolution (ccectl focus-window etc.) — numeric
// id first, then app_id with exact-beats-substring.
// - `snap`: magnetic grid snapping for interactive move/resize.
+// - `cells`: chess-style addressing for desktop-grid squares (A1, -B3)
+// — labels, parsing, square/block rects, and re-tiling a block across
+// a grid-geometry change. Its geometry must agree with `snap`'s.
+// - `spawn`: where a window launched AT a square should land — the block
+// grows away from whatever already occupies the square, then steps to
+// the nearest free spot.
// - `state`: persisted session state (serialization/matching only; the
// save/load I/O stays in the compositor).
// - `slotmap`: generational-index map (river-derived, 0BSD); `api::WindowId`