WM v1 platform — what exists, what broke, what is next (Rex brief)¶
This document is the single place to answer “what happened after the windowing refactor” and what still has to be built for a real desktop stack around WM v1.
Warning
This roadmap is a historical WM-focused brief and is not the complete current platform contract.
For canonical current-state docs, use newdocs/README.md and:
newdocs/system-architecture.mdnewdocs/settings-control-pattern.mdnewdocs/game-engine-architecture.mdnewdocs/doom-renderer-roadmap.md
See also: Documentation map — which file owns which topic (WM close regressions → foundation-debt §5; client RGBA mmap → §5.3). · System architecture — full-stack diagram + §7 shell/terminal gaps & target wiring (ioctl, signals, job control, TERM). · Terminal stack — PTY wiring, gterm vs dps ownership, display sanitizer vs VT emulation. · PTY v1 design — kernel + userspace PTY contract, sys_read flags, Phase D status. · SDK/README.md — SDK layout (p1std, p1window, cstd).
Application SDK — UI policy (Apr 2026)¶
For compositor-backed WM v1 windows, use p1window{.external} (or the p1std{.external} umbrella). Use Window::open_decorated, present_rgba, and try_recv_event / WmEvent for the main loop — not raw p1_ipc_send + magic message_type values for those flows.
cstd::wm_v1is the wire layer (p1windowcalls it).Raw
cstd::p1uiis fine for bootstrap datagrams not wrapped yet (e.g. display query 6 / 7).
New apps should prefer one dependency: p1std{.external} (p1std::window + p1std::libc).
What WM v1 is today¶
Wire format:
apps/deskgui/src/api/window.rsdefinesmessage_typevalues,pack_*/unpack_*, and WM v1 create / present / geometry opcodes.Transport: Syscall 50 (
sys_ipc_send) with a userIpcMessage; kernel may remap present pointers into the compositor’s address space for types 2, 5, 18. Each sender owns a 16 MiB VA band in the compositor (0x6000_1000_0000 + sender_task_id * 0x1_000_000);num_pagesis clamped so map/teardown never crosses into the next band (seefoundation-debt.md§3.5.6).Recv: Syscall 51 is the canonical
sys_ipc_recv(syscall 31 is a duplicate handler in the kernel — user libc now uses 51 viaSDK/lib/cstd/src/p1ui.rs).Compositor:
apps/deskguidecodes datagrams, owns z-order, focus, title chrome, and blits client RGBA withWindowManager::render(client Y =window.y + WM_V1_TITLE_BAR_H).Clients (policy): Windowed apps use
p1window{.external} (orp1std{.external}) for create / present / input. Legacy code may still callwm_v1/p1uidirectly; new code should not add hand-rolled WM loops.
Bugs found and fixes landed (terminal / WM / exec)¶
1. Decorated window geometry vs. client buffer¶
Window::h is client height. The compositor draws title bar + client. Clamping win.y with ch - win.h allowed the outer frame to extend TITLE_H pixels past the work area or sit too high, so draw_external_frame skipped most source rows (final_y < clip_y). Symptom: almost black client, only a strip at the bottom (e.g. the > line).
Fix: clamp_window_with_rect uses outer height h + WM_V1_TITLE_BAR_H for vertical clamping, caps client height to ch - TITLE_H on snap, and Window::contains uses the same outer height. Constant: WM_V1_TITLE_BAR_H in api/window.rs.
2. sys_execve children did not inherit the parent’s FD table¶
spawn_task always installed a fresh fd_table (0→0, 1→1, …). That matches the global VFS singleton stdin/stdout only if the parent never diverged; more importantly, next_fd and any extra mappings were not inherited, so parent/child I/O behaviour could drift from Unix expectations.
Fix: spawn_task(..., inherit_fds_from: Option<usize>). sys_execve passes Some(current_task_idx) so the child clones the parent’s fd_table and next_fd. Boot paths (shell.rs init / helper spawn) pass None (unchanged bootstrap behaviour).
3. gterm ↔ DPS integration (PTY master / redraw)¶
PTY output:
poll_dps_outputdrains the PTY master in a loop withsys_read_with_flags(..., READ_FLAG_NONBLOCK_PTY)(see PTY v1 design §1.2) and feeds chunks toappend_pty_master_bytes(line splitting + display fold — notread(1)on a pipe).Lines: completed lines strip trailing
\rbefore fold + push; tail is folded each frame for the live prompt.UI noise: Removed the yellow
F:… K:…debug overlay (constant invalidation contributed to perceived flicker).
4. IPC recv syscall alignment¶
p1_ipc_recv now uses syscall 51, matching apps/init and avoiding confusion with the legacy duplicate 31.
5. Exec cost (ramdisk)¶
Previously documented: ramdisk_bytes_if_cached + single clone in sys_execve avoids double full-ELF clone for cached ramdisk ELFs. Remaining launch latency is dominated by ELF map / page tables / first run unless we add prelinking or keep warm workers.
6. Multi-window close / present map — root causes fixed (Apr 2026)¶
Several bugs stacked together so “close order” looked superstitious; none of them were “apps must depend on the first terminal.” Full write-up: foundation-debt.md §3, §5, §5.1, §5.2 (serial log signature for the “close front → survivor #PF” case), §5.3 (client RGBA mmap vs brk). Short list so nobody re-debugs from zero:
Failure mode |
What was wrong |
Where fixed |
|---|---|---|
Kill top terminal → #PF or hang on next |
|
|
Close order seemed to depend on “which band” / PID layout |
Uncapped |
|
Wrong window got clicks when frames overlapped |
Hit test used |
|
Blit raced teardown |
|
Remove rows before kill; |
Torn blit row alignment (wide buffers) |
|
|
Rainbow / garbage in client area when client buffer width > window width |
Present metadata carried window |
gterm: |
gterm |
Large ping-pong RGBA lived on the same |
|
Debt (not “fixed”, only mitigated): shared PML4[192] means user cleanup skips that subtree — leaks or manual compositor teardown may be needed when deskgui truly exits; Track B in this file (surface table + non-shared map identity) is still the structural fix.
6b. Desktop chrome follow-ups (Apr 2026)¶
Feature |
Behavior |
Where |
|---|---|---|
Task manager drag |
User can move the floating task manager by dragging its title bar (close button excluded); position clamped to the work area. |
|
Per-core CPU HUD |
Top bar / task manager footer can show “busy / online” logical cores using |
Kernel: |
These are WM/compositor concerns, not PTY logic, but they ship in the same desktop milestone as the terminal fixes.
What Rex asked for next — honest scope¶
Delivering all of the list below is multi-sprint OS work, not a single patch. This section is the agreed product breakdown so planning and reviews stay grounded.
1. Client library (p1window / p1std)¶
Shipped (Apr 2026): p1window at SDK/lib/p1window — typed WM v1 client. Consumers: gterm, Surf. p1std at SDK/lib/p1std re-exports p1window (as window) and cstd (as libc) plus SdkError.
Low layer: SDK/lib/cstd/src/wm_v1.rs + p1ui.rs — for p1window and bootstrap IPC; not the supported app-facing API for ordinary windows (see Application SDK — UI policy above).
Work: Harden p1window (resize helpers, more typed errors from compositor codes, optional RAII); migrate Wander / Settings / evnt; add small wrappers in p1std over time.
2. Real input system¶
Today: Compositor broadcasts type 3 (mouse) and 4 (keyboard, scancode + down flag) to one focused PID; no per-window queues, no repeat/keymap layer in WM.
Targets:
Per-surface mailbox or ring buffer in the broker (not a single global vec — see
src/sys/ipc.rsSystemBroker).Focus + capture (mouse relative / confine to client rect below title bar).
Wheel already has a field in gterm’s mouse
p3— wire it consistently from PS/2 / VirtIO.Optional cooked text path (layout → Unicode) vs raw scancodes (games).
3. Memory management¶
Today (Apr 2026): Kernel still remaps the sender’s physical pages into the compositor on each qualifying syscall 50 present. gterm allocates large client RGBA with p1_alloc_framebuffer → sys_mmap_anon (syscall 9), not by extending brk beside alloc — see foundation-debt.md §5.3. Ordinary heap may still use brk via GlobalAlloc until a general allocator lands.
Targets:
Capabilities: export a shm id from compositor, import in client, single mapping.
Damage rects in present (
dirtyset or RLE) to reduce memcpy.GPU path: deferred until a stable scanout / GL/Vulkan story exists.
4. Compositor features¶
Targets: Dirty-region compositing, fullscreen/modal layers, clip stack per window, vsync-gated present (or double-buffered GOP) to kill tearing.
5. Shell integration (DPS as first-class)¶
Today (Apr 2026) — PTY path is live for the dock terminal:
gterm (
apps/termd):sys_openpty→ childsys_pty_rebind_stdso dps stdin/stdout are the slave; gterm holds the master. Keystrokes go to the master withsys_write; output is read from the master viasys_read_with_flags(..., READ_FLAG_NONBLOCK_PTY)inpoll_dps_outputso the WM client never blocks on an empty PTY queue.dps (
apps/dps): blockingsys_readon fd 0 (slave) for readline;read == 0+ successfulTIOCGWINSZon fd 0 ⇒ treat as PTY EOF and exit; otherwise short sleep (non-PTY bootstrap).Prompt / output: dps is written for a dumb viewer: plain
PS1by default; gterm still folds CSI/OSC for safe pixels (see PTY v1 design §9).
Still “targets” (not done to POSIX bar):
Per-PTY foreground for
sys_signal_foreground(global PID today — see PTY v1 A.3).Full job control,
SIGWINCHdelivery after resize, optional kernel line discipline or sharedlibline.Init policy: only one interactive consumer of
/dev/consoleunless session multiplexing exists.
Suggested next implementation order¶
PTY correctness after the pair ships — A.3 per-PTY foreground +
sys_signal_foregroundscope; Phase CSIGWINCH+ WM bounds →TIOCSWINSZ(see PTY v1 design §2.0).libwindow— removes foot-guns from every app.Broker mailboxes per PID (or per surface) — removes head-of-line blocking across unrelated messages.
Damage + vsync present — user-visible quality win.
WM / compositor state — beyond Vec<Window> (planned)¶
Honest label: WindowManager today is a prototype: a Vec of window rows plus z-order and focus. That is not the same thing as a retained scene graph with reference-counted surfaces and a single lifecycle invariant between kernel present maps, IPC, and compositor rows. Closing a window that is not the last one surfaced bugs where teardown order, logging, and row lifetime were not jointly defined — patching one symptom at a time without locking invariants stays brittle.
The move is two tracks at once (not either/or):
Track A — Safe removal on the current shape (short horizon)¶
Goal: any delete leaves no dangling refs, defined stacking, idempotent purge.
Requirement |
Work |
|---|---|
No |
Drop WM row or zero |
Z-order + focus |
One documented rule after every remove: e.g. top = max |
Draw order |
Per-frame |
Observability |
Throttled |
Exit: open several terminals; close in arbitrary order; serial + UI show no compositor death and no frame where a row exists for an unmapped present band. Met in Apr 2026 only after PML4[192] cleanup skip, 16 MiB present clamp, translate-all present, deskgui topmost hit-test + kill ordering — see §6 above; run §5.1 in foundation-debt.md before declaring regressions “mysterious.”
Track B — Target compositor model (medium horizon)¶
Split Surface from Window (frame):
Surface: stablesurface_id,owner_pid, buffer metadata, explicit lifecycle (Attached/Detaching/ dead); compositor-owned surface table (not “whatever the Vec says”).Window/ frame chrome: placement, decoration, z-order, focus — referencessurface_id; does not solely own kernel map teardown.
Kernel: present-map registry moves from (receiver, sender) only toward (receiver, sender, surface_id) or a shm handle so multi-surface-per-PID and symmetric teardown are real (see §3 memory targets above).
Retained scene graph + damage (§4 compositor features): after Track A is green and Track B has a surface table — otherwise the graph inherits the same dangling lifetime bugs.
Ordering¶
Track A to green — stops embarrassing close-any-window death; proves removal semantics on today’s code.
Track B surface table + map identity — removes the structural class of “Vec row vs kernel map” drift.
Scene graph + damage + vsync — perf and polish; not a substitute for (1)(2).
Small Vec-level fixes remain fine when they cite an invariant from this section and add a manual or scripted close-order check.
Files touched in the latest integration pass¶
Area |
File(s) |
|---|---|
WM geometry / hit test / z-order / close |
|
WM destroy + present unmap |
|
Blit stride + present metadata (external buffers) |
|
Embedded UI using tight buffers |
e.g. |
Shared |
|
Syscall 50 present map + clamp + translate |
|
Present registry + teardown |
|
Exec FD inheritance |
|
IPC recv syscall |
|
Per-core CPU load |
|
Task manager drag + footer |
|
gterm I/O, fold, stride, present |
|
dps blocking stdin / PTY EOF |
|
Ramdisk exec fast path |
|
How to show Rex “what happened”¶
WM v1 is real — protocol in
api/window.rs, compositor decode incompositor.rs, clients on syscall 50/51.Two hard bugs — outer-frame clamp (black client) and exec FD inheritance (shell I/O).
The rest is roadmap — libwindow, full POSIX job control / per-PTY signals, damage, per-surface input queues: scoped above so nobody pretends the entire desktop shipped in one refactor (PTY pair + dock path did land — see §5).
When QEMU is rebuilt with these changes: expect visible line input, DPS output after Enter, correct RGBA blitting when the client buffer is wider than the window, draggable task manager, per-core busy hints in the HUD, and fewer “wrong offset” / escape-garbage artifacts in gterm. Tearing and multi-second cold launch still need the compositor / vsync / damage follow-ups above.
Follow-up (same week — concrete latency + IPC)¶
sys_execveuser stack: mapping 512 × 4 KiB pages per launch dominated dock latency. Default is now 96 pages (~384 KiB); paths whose bytes containsurf,doom, orwander(case-insensitive) still get 384 pages (~1.5 MiB) for heavy UI ELFs.p1_ipc_recv/p1_getpid/p1_ipc_sendinline asm:int 0x80can clobberrcx/r11; missinglateoutclobbers can corrupt caller state and break IPC handling in subtle ways. Clobbers were added;preserves_flagswas dropped on these paths.gterm IPC recv target: matches init/Surf —
p1_ipc_recv(0, …)so the kernel always resolves “receive for current task” the same way.
Doc maintenance (WM / multi-window)¶
Index of platform docs:
documentation-map.md.Before merging changes to
spawn_process_pml4,cleanup_user_page_tables, syscall 50 present arm,ipc_present_maps,draw_external_frame/ present stride, orwindow_managerclose/hit-test: runfoundation-debt.md§5.1 and skim §5.2 so serial traces stay interpretable.Do not revert the
PML4[192]skip or the 16 MiB page clamp without a replacement design recorded in this file + foundation-debt §3.5.6.PTY + terminal display contract: PTY v1 design and Terminal stack; keep aligned when changing
sys_readflags,fold_pty_*, or present stride.