A rendering claim about iris was verified by hand from another checkout,
because the compositor script and the input replay lived in ai-app's
submodule and not here.
`scripts/run-headless.sh` starts a headless sway on its own socket, runs
an example against it and screenshots the result. `rig-input`'s
`replay-touch` drives a recorded gesture in through Wayland's virtual
pointer, since a headless compositor has no input device to move.
`iris::harness` gains the `.touch` parser, so a recording means the same
thing replayed into a harness as into a window rather than being read
twice by two parsers.
The ai-app copy's `--phone` became `--mode`, since which phone is not
iris's business; its `IRIS_SCALE` has nothing to hand a density to here,
so it waits for one.
Small, and disjoint from #12 — this touches `task.rs`, `harness.rs` and `render_state.rs`, none of which #12 goes near.
`Tasks` held an `Arc<Window>` only to call `request_redraw` when a task finished, which made the task queue, and so `DefaultRsc`, impossible to build without a window. It now takes an `Arc<dyn WakeTaskQueue>`, and `Window` implements it.
Waking also moves from *the task ended* to *an update was sent*, which is when there is actually something for the host to apply. A task that keeps running after sending one no longer holds it until it finishes, and a task that sends none no longer asks for a frame nothing needs.
`iris::harness` is what that buys. `UiRenderState` already does layout, hit testing and primitive building with no surface, so a test can build a tree, run frames, move a pointer and read back where widgets landed. `tests/harness.rs` covers span layout, resize relayout, press routing, hover start and end, wheel scrolling with its clamp, and a task update reaching the tree. None of them could be written before, since the only way into layout was a window.
It does not draw. A claim about pixels still needs a real surface — I checked this one against the rig rather than asserting it: `examples/task` under headless sway, centre pixel `ff0000` before the click and `0000ff` after, so the windowed path still applies task updates under the new wake.
The only core change is `UiRenderState::output_size()`, so that a host reading back the size it set does not have to keep a second copy.
---------
Co-authored-by: iris <2+iris@noreply.localhost>
Reviewed-on: iris/iris#15
Reviewed-by: iris <2+iris@noreply.localhost>
Co-authored-by: AIris <4+iris-ai@noreply.localhost>