Files
danos/system/services/display-demo/display-demo.zig
T
daniel 5ab7263c9c display-demo: stop drawing a cursor and stop blocking on the mouse
Two real bugs visible in a normal `zig build run-x86-64` boot (but not in the
display-demo test, which spawns no input service):

  - Two cursors. The demo drew its own cursor layer while the display service
    now draws one too (its mouse-listener thread). The demo's went through the
    client IPC protocol and lagged; the service's is in-process and tracks
    tightly — "one responds better than the other."

  - Animation frozen until the mouse moves. The demo called a *blocking*
    `mouse.next()` (ipc_reply_wait) inside its animation loop, so the sliding
    box advanced only one frame per mouse event. In the display-demo test
    there is no input service, so subscribeMouse() returned null and the loop
    ran free on its 30ms timer — which is exactly why the test passed while
    the real boot was broken.

The compositor now owns the cursor (docs/display.md), so the demo should draw
none and read no input: it becomes a pure client-animation proof whose loop is
independent of the mouse. Removes its cursor layer, mouse subscription, and the
blocking read.

Also harden displayDemoTest to spawn the `input` service alongside the demo
(matching real boot): a client that blocks its animation loop on a mouse read
would now stall before `display-demo: ok` and fail the test, instead of
passing because no input service happened to be present.

Verified: display / display-service / display-demo / display-cursor all green.
2026-07-21 02:37:47 +01:00

64 lines
2.5 KiB
Zig

//! system/services/display-demo — a hardware-free client of the display service, the
//! `input-source` analog for the compositor. It creates a wallpaper and a rectangle it
//! slides each frame, then drives the compositor in a present loop — proof that a
//! *separate process* can compose a moving scene through the display service over IPC,
//! exercising the layer client API and damage-driven present end to end
//! (docs/display.md). It logs `display-demo: ok` once it has driven a run of frames.
//!
//! It draws no cursor and reads no input: the on-screen cursor is the display service's
//! own, tracked by the service's mouse-listener thread (docs/display.md). The demo's job
//! is only to prove client-driven animation, so its loop runs on its own frame timer and
//! is deliberately independent of the mouse.
const runtime = @import("runtime");
const display = runtime.display;
const system = runtime.system;
const time = runtime.time;
pub fn main() void {
const mode = display.info() orelse {
_ = system.write("display-demo: no display service\n");
return;
};
// A full-screen wallpaper under everything.
const wallpaper = display.createLayer(0, 0, mode.width, mode.height, 0) orelse return createFailed();
_ = wallpaper.fill(0, 0, mode.width, mode.height, display.color(0x10, 0x18, 0x28));
// A rectangle that slides back and forth.
const box_w: u32 = 140;
const box_h: u32 = 100;
const box_y: i32 = 200;
const box = display.createLayer(0, box_y, box_w, box_h, 1) orelse return createFailed();
_ = box.fill(0, 0, box_w, box_h, display.color(0xE0, 0x60, 0x40));
_ = display.present();
_ = system.write("display-demo: scene up; animating\n");
const span: i32 = @as(i32, @intCast(mode.width)) - @as(i32, @intCast(box_w));
var x: i32 = 0;
var dx: i32 = 8;
var frame: u32 = 0;
while (true) : (frame += 1) {
x += dx;
if (x <= 0) {
x = 0;
dx = -dx;
} else if (x >= span) {
x = span;
dx = -dx;
}
_ = box.configure(x, box_y, 1, true); // move it; the compositor repaints old + new
_ = display.present();
// A run of frames drawn through the compositor is the automated proof (the visible
// motion is a screenshot away via `zig build run-x86-64`).
if (frame == 20) _ = system.write("display-demo: ok\n");
time.sleep(time.Duration.fromMillis(30));
}
}
fn createFailed() void {
_ = system.write("display-demo: create failed\n");
}