Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 46 additions & 20 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ single Rust `.exe` with no installer and no required config. Core hooks:

- **Alt + left-drag** — move any window from anywhere on it (no title bar needed).
- **Alt + right-drag** — resize from the nearest corner (red bracket marker).
- **Tiling** — `dwindle` (spiral, default) or `master` layout.
- **Tiling** — `dwindle` (spiral, default), `master`, `columns`, `grid`,
`monocle`, or Niri-style `scrolling` (column strip, off-screen columns
parked outside the virtual screen, tabbed columns; `plan/scrolling.md`).
Layout is per monitor (`monitor_layouts`).
- **Up to 10 virtual workspaces**, shared or per-monitor.
- **Per-monitor status bar** (workspace pills, title, clock, CPU/RAM/battery).
- **Workspace-switch animation** — overlay compositor: off/slide/spring/fade.
- **Window glide** — windows animate to their tile slot on open/move/resize/
re-tile via a per-window snapshot overlay (off/glide).
re-tile/scroll via an overlay of live DWM thumbnails (off/glide).
- **App launcher** — Alt+Space opens a fuzzy app picker (Start Menu shortcuts),
hook-driven with no foreground focus. See `plan/launcher.md`.
- Coloured DWM borders, unfocused dimming, focus-follows-mouse, per-app rules,
Expand Down Expand Up @@ -49,7 +52,9 @@ cargo build # fast debug build of the whole workspace
cargo run -p astur # run the WM from source
```

Quit: `Ctrl+C` in the console (runs `restore_all_windows`), or kill the process.
Quit: tray Quit or `Ctrl+C` in the console (runs `restore_all_windows`: shows
hidden windows and unparks parked ones), or kill the process (the next launch's
crash rescue does the same from `~/.astur/rescue.lst`).

Config lives in `%USERPROFILE%\.astur\astur.conf` + `navbar.conf`, both created
on first run, fully commented, **hot-reloaded on save**.
Expand All @@ -58,10 +63,11 @@ on first run, fully commented, **hot-reloaded on save**.

| File | Lines (approx) | What |
|---|---|---|
| `crates/astur/src/main.rs` | ~5500 | Everything Win32: hooks, worker threads, manager, bar, animations, launcher, file search, system menu. One big file by design (single TU, fast build). |
| `crates/astur/src/layout.rs` | ~250 | `dwindle_layout` + `master_stack` geometry. `RECT` type only, no Win32 calls. |
| `crates/astur-config/src/lib.rs` | ~600 | `Config` struct, documented-default file templates, key/value parser. **No Win32** — pure data, shared with the settings GUI (aliased `config` in the WM). |
| `crates/astur-settings/` | stub | Settings GUI (egui, WIP). Separate process — a GUI crash can't touch the WM. |
| `crates/astur/src/main.rs` | ~23800 | Everything Win32: hooks, worker threads, manager, scrolling strip model, bar, tab bars, compositors, launcher, file search, system menu. One big file by preference (see CLAUDE.md; splitting would not change build time). |
| `crates/astur/src/layout.rs` | ~1300 | Pure tiling geometry (dwindle, master, columns, grid, monocle, scrolling strip: spans, offset clamp, peek/park `classify`, `park_spot`) + tests. `RECT` type only, no Win32 calls. |
| `crates/astur/src/yasb.rs` | ~800 | GlazeWM-compatible workspace WebSocket API for YASB (loopback only, off by default). |
| `crates/astur-config/src/lib.rs` | ~2900 | `Config` struct, `LAYOUTS` (the one list of layout names), documented-default file templates, key/value parser. **No Win32** — pure data, shared with the settings GUI (aliased `config` in the WM). |
| `crates/astur-settings/` | ~1400 | Settings GUI (egui), shipped. Separate process — a GUI crash can't touch the WM. |
| `Cargo.toml` (root) | — | `[workspace]` manifest + release profile. WM deps live in `crates/astur/Cargo.toml`. |

`main.rs` is large but sectioned with `// ====` banners. Use the function map
Expand All @@ -70,22 +76,38 @@ on first run, fully commented, **hot-reloaded on save**.
## Threads (mental model)

The process is a set of single-purpose threads talking over `Mutex`/`Condvar`
queues. Keep it that way — do not move work onto the hook threads.

- **Hook threads** (`mouse_proc`, `keyboard_proc`) — run inside `WH_MOUSE_LL` /
`WH_KEYBOARD_LL`. Must return fast. They push to queues; they do not do work.
`ANY_DRAG`/`ALT_DOWN` atomics let them early-out without locking.
- **Manager loop** (`manager_loop` / `Manager`) — owns all window/workspace state.
Drains the command queue (`CMDQ`). All `SetWindowPos`/tiling/switching here.
- **Position worker** (`position_worker`) — applies drag move/resize off the hook
so a slow app's `SetWindowPos` can't stall input.
queues. Keep it that way — do not move work onto the hooks (main thread).

- **Main thread** — installs and runs the hooks: `mouse_proc` / `keyboard_proc`
(`WH_MOUSE_LL` / `WH_KEYBOARD_LL`) and `win_event_proc` (out-of-context
WinEvents). Hooks must return fast: push a `Cmd`, do no work, no lock without
an atomic guard (`ANY_DRAG`/`ALT_DOWN`/`SCROLLMON_N` let them early-out).
Also owns the bar windows, the tray and the scrolling layout's tab-bar
windows (`astur_tabs`, synced from the manager's `TAB_SNAPSHOT` by
`tab_bars_sync`; clicks push `Cmd::TabClick`, nothing places windows).
- **Manager loop** (`manager_loop` / `Manager`) — owns all window/workspace/
strip state. Drains the command queue (`CMDQ`). All `SetWindowPos`/tiling/
switching/parking here, live Alt-drag placement included (`place_drag_frame`).
- **Transition worker** (`transition_worker` / `run_transition`) — owns the
workspace-switch overlay, pumps its own message loop, GDI-composites frames
(fade: DWM blends a second, layered overlay instead).
- **Glide worker** (`glide_worker` / `run_window_glide`) — same pattern for the
per-window move/open/close/resize glide overlay.
- **Motion worker** (`glide_worker` / `run_window_glide`, thread "glide") —
window motion overlay (move/open/close/reflow/scroll): live DWM thumbnails
of already-placed windows over the wallpaper, re-aimed in place while it
runs (`retarget_glide`). Owns its overlay, pump and every thumbnail.
- **Wallpaper capture** (`wallpaper_capture_worker`) — renders the wallpaper
backdrop for both compositors (PrintWindow of the wallpaper window only).
- **Cold-snapshot worker** (`cold_worker`) — PrintWindows cold parked tiles
(blank DWM surface: hidden, minimised, or never on screen since shown) into
the `COLD` cache so the motion can draw them. Besides the wallpaper capture,
the only thread that PrintWindows (never the manager, a compositor or a
hook). A hung app may block it; nothing waits on it.
- **Stats worker** (`stats_worker`) — polls CPU/RAM/battery ~2s for the bar.
- **Focus-follow worker**, **config watcher**, **bar windows** — as named.
- **Disk writers** (`state_worker`, `mru_worker`, `rescue_worker`) — the
manager only fills a latest-wins slot; the disk I/O (state, launcher MRU,
`rescue.lst`) runs here, so a slow disk never delays a command.
- **Focus-follow worker**, **config watcher**, **launcher**, **sysmenu**,
**icon/file-search workers**, **IPC**, **YASB**, **hook watchdog** — as named.

## Conventions

Expand All @@ -97,7 +119,9 @@ queues. Keep it that way — do not move work onto the hook threads.
- Cosmetic threads get bitmap/rect data by **single-owner hand-off, never
shared** — a handle the owner gives up, moved rather than copied (the
incoming workspace snapshot is taken out of the cache; the outgoing capture
goes to the transition worker and is handed back as the snapshot). Exactly
goes to the transition worker and is handed back as the snapshot; a cold
window's snapshot is taken out of its cache into the motion request and
freed by the glide worker). Exactly
one thread owns, and frees, each bitmap at any moment; the owned `Bmp` type
(no `Clone`) enforces it for snapshots. Deselect, then `GdiFlush`, before
every hand-off.
Expand All @@ -107,6 +131,8 @@ queues. Keep it that way — do not move work onto the hook threads.
## Where to go next

- `plan/architecture.md` — deeper component + data-flow notes.
- `plan/scrolling.md` — scrolling layout spec + contract: keys, config,
geometry, peek/park, safety, manual test checklist.
- `plan/animations.md` — animation design: desktop-switch modes (off/slide/spring/
fade) and the honest analysis of window open/close/move/resize animation.
- `plan/win32-reference.md` — APIs used, doc links, gotchas (slow/buggy calls).
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading