# DWM rewrite in Rust

The goal is a small X11 window manager with DWM's familiar behavior, implemented in readable, idiomatic Rust. Optimize for understanding ownership and behavior before minimizing line count. This is a rewrite guided by observable behavior, rather than a function-by-function translation.

The local C baseline is now DWM 6.8 in `reference/dwm-6.8/`, unpacked unchanged from the user-provided download and identified by archive and file checksums. No local AGENTS.md was found. Record any personal patches and configuration separately before implementation. No Rust-specific skill was found among the installed skills; the Rust API Guidelines are the design reference.

## 1. Scope and compatibility baseline

First release: X11, tagging, tiled/monocle/floating layouts, keyboard and mouse actions, rules, focus, fullscreen, multiple monitors, and a status bar. Preserve relevant ICCCM and EWMH behavior supported by the pinned baseline. Wayland, a plugin framework, runtime configuration reload, and arbitrary DWM patch compatibility are separate projects.

Write a compatibility matrix before coding. Cover startup with existing windows, transient/dialog handling, override-redirect windows, focus history, layout order, current/previous tag views, current/previous layouts, window size hints, fullscreen restoration, urgency, status text, bar clicks, spawning, and clean shutdown. Mark intentional changes explicitly.

DWM tags must remain sets: a client can belong to multiple tags and a monitor can show multiple tags. Do not replace this with one workspace per window. Record rule matching and precedence, geometry rounding, and focus behavior as examples that can become tests.

## 2. Architecture: one crate, a few explicit boundaries

Start with one Cargo package containing a library for testable policy and a thin executable. Avoid a workspace of tiny crates.

```text
src/
  main.rs          startup, diagnostics, exit handling
  wm.rs            event orchestration and cross-object operations
  model/           clients, monitors, tags, geometry, layouts
  x11/             connection, atoms, properties, protocol requests
  input.rs         bindings, modifier handling, pointer interaction
  config.rs        typed defaults, bindings, rules, validation
  bar.rs           bar content, geometry, hit testing, drawing
  process.rs       spawning and child reaping
```

The normal path should be easy to follow:

```text
X11 event → handler → policy/state update → X11 requests → flush
```

Keep X11-generated types near the protocol boundary. Extract typed window metadata before changing policy. Layout calculation should return placements without talking to X11. Introduce a small effects enum only if it makes event ordering and testing clearer; do not build an elaborate command bus.

Begin with a single-threaded synchronous event loop. A pointer drag is explicit interaction state processed by that loop, so window destruction and other events remain handled during a drag.

## 3. Types and the behavior they own

| Type | Responsibility and useful methods |
| --- | --- |
| `WindowId`, `ClientId`, `MonitorId` | Distinguish X11 resources, managed clients, and monitor identities. |
| `Tag`, `TagSet` | Validate configured tag bounds; `contains`, `intersects`, `union`, `toggle`. |
| `TagView` | Maintain current and previous nonempty selections; `select`, `toggle`, `restore_previous`. |
| `Rect`, `Size`, `BorderWidth` | Express geometry; `intersection_area`, `outer_size`, checked protocol conversion. |
| `SizeHints` | Apply base size, increments, aspect and min/max constraints through `constrain`. |
| `Client` | Own title, metadata, tags, placement and hints; `is_visible_on`, `enter_fullscreen`, `leave_fullscreen`. |
| `Monitor` | Own screen/work areas, client order, focus history, tag view and layout selection. |
| `Layout` | Closed enum for `Tile`, `Monocle`, `Floating`; `placements` returns computed geometry. |
| `MasterRatio` | Validate finite supported ratios; expose intentional adjustment behavior. |
| `Action` | Typed variants such as `ViewTags(TagSet)`, `Focus(Direction)`, `SetLayout(Layout)`, `Spawn(CommandSpec)`. |
| `Rule` | Match window metadata and describe intended changes. Preserve baseline rule combination semantics. |
| `X11Backend` | Own connection and protocol resources; query metadata, configure, focus, publish properties. |
| `WindowManager` | Coordinate `manage`, `unmanage`, `focus_client`, `move_client_to_monitor`, `dispatch_action`. |

Prefer methods when a type owns the behavior or invariant. A client may update its fullscreen state, but the manager coordinates resulting monitor layout and X11 requests. Free functions remain appropriate for stateless algorithms without a natural receiver.

Use descriptive names: `master_count`, `master_ratio`, `selected_client`, `work_area`. Replace the C `Arg` union and function-pointer bindings with `Action` variants carrying their actual argument types.

Use enums where alternatives exclude each other. Represent normal placement as tiled or floating and fullscreen as a state carrying the previous placement, geometry and border width. Keep independent facts such as urgency as independent fields. Do not combine unrelated flags into one enormous enum.

Keep fields private where mutation could break an invariant. Use `Option<ClientId>` for absent focus, rather than a zero identifier. Validate configuration at startup. A rule may have no tag override; a managed client and active view must have a nonempty valid tag set. Model DWM's zero-argument “previous view” operation as a distinct action.

Start with concrete types and exhaustive matches. Introduce a trait only for a real interchangeable behavior or a useful test boundary. A trait for every struct, broad `dyn` dispatch, or a generic backend threaded through every type would increase reading effort without a demonstrated benefit.

## 4. Ownership and collections

`WindowManager` owns the client store, monitor store and selected monitor. Monitors contain client IDs rather than references; clients identify their monitor by ID. Keep layout order and focus history as separate ID vectors, because they serve different behaviors.

Start with a typed ID and standard map plus a window-to-client lookup. Never use unordered map iteration to determine layout or focus. Allocate client IDs independently from reusable X11 window IDs. Add a generational arena only if stale references or complexity justify it.

Maintain these invariants through manager methods:

- Every managed client belongs to exactly one live monitor.
- Monitor orders contain no duplicate or missing client IDs.
- Removing a client removes all membership and focus-history entries.
- The selected client belongs to its monitor and is eligible under the focus policy.
- Removing a monitor migrates its clients before deleting its state.

Avoid self-referential structures, mutable globals, and routine `Rc<RefCell<_>>`. Resolve borrowing conflicts by splitting fields, narrowing borrow scopes, or collecting IDs before mutation. Copying a small ID or geometry value is reasonable; cloning the entire manager to bypass borrowing is not.

## 5. X11 and rendering decisions

Use `x11rb` with its pure-Rust `RustConnection` as the first backend candidate. Pin the dependency after a small startup/event-loop spike. Check extension availability and provide a single-monitor fallback. Begin with monitor discovery compatible with the chosen DWM baseline; treat RandR hotplug support as an explicit addition if it exceeds that baseline.

For the bar, time-box a rendering spike comparing retaining Xft behind a narrow FFI wrapper with Cairo/Pango rendering uploaded to the X11 bar window. Decide using Unicode rendering, fallback fonts, dependency footprint, and code readability. Do not promise pixel-identical text rendering before this spike. Keep unsafe code, if needed, contained and documented.

Classify errors deliberately: another window manager owning root redirection is a startup failure; a client disappearing during a request is an expected race; a broken X connection ends the session. Surface checked request errors and asynchronous errors. Validate property types, formats and lengths. Do not use blanket error suppression or `unwrap()` on external input.

Use explicit shutdown for restoring windows and best-effort cleanup. Resource wrappers can use `Drop` for local cleanup, but shutdown requests that can fail should have an explicit path. Spawn argument vectors without implicit shell interpolation, and reap children.

## 6. Implementation milestones

| Stage | Deliverable | Acceptance gate |
| --- | --- | --- |
| 0. Baseline | Pinned upstream source, patch inventory, compatibility matrix and design decisions. | Every required behavior has a scenario; scope differences are recorded. |
| 1. Model | Geometry, tags/views, client/monitor state, layouts and typed actions. | Pure tests cover invariants, tag transitions, layout ordering, borders and rounding. |
| 2. X11 lifecycle | Connect, claim root, scan existing windows, manage/map/unmanage, clean exit. | Nested X server scenarios pass; competing WM and disappearing clients are handled. |
| 3. Daily interaction | Focus, bindings, rules, spawning, tile/monocle/floating, size hints, dragging. | Deterministic scenarios match the pinned baseline; event handling continues during dragging. |
| 4. Protocol and monitors | Relevant ICCCM/EWMH behavior, fullscreen, transients, monitor transfer and topology updates. | Real applications, fullscreen restore, focus negotiation and monitor changes behave correctly. |
| 5. Bar and configuration | Unicode bar, status updates, click regions, validated typed config. | Drawing and hit testing agree; malformed configuration has useful diagnostics. |
| 6. Release candidate | Documentation, session entry, build instructions and compatibility report. | Required tests pass; extended nested and real-session trials reveal no outstanding critical failures. |

The first runnable milestone is startup → manage a terminal → tile it → focus it → close it → exit cleanly. Build that vertical slice before completing every abstraction.

Keep configuration in readable Rust initially: `Config::default()` plus explicit binding/rule constructors. Recompilation preserves DWM's customization approach. Add a file format only if users need it; keep policy and validation independent of the format.

## 7. Verification and readability gates

Use pure unit tests for tags, views, rules, fullscreen transitions, geometry and layouts. Add property tests where they catch meaningful invariant failures, such as arbitrary tag toggles or client removal sequences.

Run integration scenarios under Xephyr or Xvfb with small controlled X clients. Compare behavior with the pinned C baseline: window geometry, visibility, focus, stacking and published properties. Compare observable outcomes, not internal structures. Check hidden-window behavior carefully: changing visibility implementation can alter client lifecycle events.

Exercise real terminals, browsers, dialogs and fullscreen applications. Include keyboard mapping changes, lock modifiers, Unicode titles, rapid map/unmap/destroy sequences, negative monitor coordinates and a window disappearing during dragging.

Before accepting each milestone, run `cargo fmt --check`, appropriate tests and Clippy. Review readability separately: can a reader trace an event to its outcome, find who owns an invariant, and understand a public method without consulting distant global state? Explain protocol quirks in comments; avoid comments that merely restate the code.

Success means the agreed DWM behaviors pass the compatibility matrix, state invariants survive lifecycle races, and policy code can be understood without learning X11 request encoding. Performance should be measured for event handling and layout before adding caching or concurrency.

## References

- [Upstream DWM implementation](https://git.suckless.org/dwm/file/dwm.c.html)
- [DWM manual](https://git.suckless.org/dwm/file/dwm.1.html)
- [Default configuration](https://git.suckless.org/dwm/file/config.def.h.html)
- [DWM rendering implementation](https://git.suckless.org/dwm/file/drw.c.html)
- [x11rb RustConnection](https://docs.rs/x11rb/latest/x11rb/rust_connection/index.html)
- [Rust API Guidelines: checklist](https://rust-lang.github.io/api-guidelines/checklist.html)
- [Rust API Guidelines: type safety](https://rust-lang.github.io/api-guidelines/type-safety.html)

## Detailed design and validation

- [Types, ownership, and event-flow diagrams](docs/RUST_DESIGN.md).
- [Compilable Rust type and transition sketches](examples/type_sketch.rs).
- [Regression strategy and C test migration](docs/REGRESSION_PLAN.md).
- [Local C baseline and checksums](reference/README.md).

The detailed documents use the downloaded 6.8 source as the reference. The sketches demonstrate policy only; they are not a runnable window manager.
