Platform × Feature Findings Matrix
The cross-platform grid for the windowing demo feature specs: one cell per platform per feature, each holding a verification-tier label, a one-line finding, and a link to the full findings doc. Empty cells are demos not yet landed.
Last reviewed: June 11, 2026
Legend: A = agent-verified (A[wine] = under Wine — Wine is a reimplementation, not Windows; A[ssh] = on mac-bsn over SSH — WindowServer-registration verified, on-screen compositing not), B = compiled-for-target only, C = manual run pending/done, — = N/A. Tier B/C expectations are [expected, unverified], never stated as fact.
| Feature | Wayland | X11 | Win32 | macOS |
|---|---|---|---|---|
| Scaffold: concepts-to-pixel / LOC | [A] 11 / 463 (findings) | [A] 9 / 412 (findings) | [A[wine]] 10 / 323 (findings) | [A[ssh]] 11 / 391 (findings) |
| F01 first pixel | [A] 11 concepts / 2 round-trips; ~2.2 ms client work, 11–19 ms to confirmed pixel (frame-clock-bound) (findings) | [A] ~1.4 ms, 5 round-trips dominate; no on-glass proof without Present; a WM adds ~3 ms (findings) | [A[wine]] 23.8 ms to first BitBlt, 13.1 ms = one-time session connect; 0 round-trips; first WM_SIZE in CreateWindowExW iff WS_VISIBLE (findings) | [A[ssh]] 130 ms cold → 100 ms warm; the delta is the three first-WindowServer-contact calls (findings) |
| F02 resize | [A] negotiation proven (serial-exact ack before every matching commit); --violate ⇒ fatal invalid_surface_state, connection killed (findings) | [A] notify-not-negotiate; ≥1 stale frame/resize structural; WM makes XResizeWindow deniable (findings) | [A[wine]] notification: all 14 SetWindowPos sizes granted verbatim; pure shrinks invalidate nothing; WM_SIZING unreachable programmatically (findings) | [A[ssh]] app-decided, synchronous setFrameSize:→windowDidResize:→drawRect:; pixels = points × 2.0 on all 14 events; live-resize never entered programmatically (findings) |
| F03 modal loop | [A] no modal loop exists to survive: max tick gap 17.06 ms through 12 transitions vs 16.80 ms calm; modal_enter unrepresentable (findings) | [A] no modal loop — ticks held ≤17.8 ms through 50-resize storms, bare + WM-mediated (findings) | [A[wine]] modal loop entered programmatically: no-fix freeze max gap 1.01 s vs SetTimer-fix 17 ms in-modal ticks; winewayland swallows SC_* entirely (findings) | [A[ssh]] common-modes timer ticks through nested tracking/modal modes (max gap 109.5 ms); default-mode timer starves completely (0 fires / 2.0 s gap) (findings) |
| F04 frame pacing | [A] wl_surface.frame: 16.52/16.67/16.75/16.87 ms over 600 frames (synthetic 60 Hz); minimized ⇒ callbacks stop dead, no client-side un-minimize (findings) | [A] Present is the only frame clock (real ust/msc); Xvfb advertises 1.2, synthetic 60 Hz; hidden windows never throttle (findings) | [A[wine]] DwmFlush is a non-blocking S_OK stub under Wine (forced pacing free-runs at p50 522 µs) → timer fallback ran 600 frames; no throttling while minimized (findings) | [A[ssh]] CADisplayLink silent under locked console despite unpaused/visible state — watchdog fell back to a 16 ms NSTimer; real cadence Tier C (findings) |
| F05 loop wakeup | [A] no protocol-level user event — cross-thread wakeup must be a client fd; eventfd median 11 µs via the prepare_read/poll loop (findings) | [A] native user event exists (ClientMessage, p50 71 µs, full round-trip) but fd-readiness is trivial and 4× faster (eventfd p50 17 µs) (findings) | [A[wine]] PostMessageW p50 60 µs vs PostThreadMessageW p50 506 µs; MsgWaitForMultipleObjectsEx is the "add an fd" story — capped at 63 handles (n=64 ⇒ err=87) (findings) | [A[ssh]] three mechanisms compared — fd via CFFileDescriptor fastest (p50 72 µs) vs postEvent: 319 µs / CFRunLoopSource 398 µs; raw fds only through CF/dispatch adapters, never poll()-style; ~75 ms cold-start tax on the first wakeup (findings) |
| F06 keyboard | [A] protocol ships only evdev codes; client owns sym/text, repeat (both cancellations proven), and compose — verified under sway headless + wtype (findings) | [A] same xkbcommon state machine as Wayland via xkbcommon-x11; server owns repeat (detectable opt-in); live setxkbmap rebuild + client-side compose proven (findings) | [A[wine]] full WM_KEYDOWN→TranslateMessage→WM_CHAR chain driven at scancode level; the layout switch is a lie under the null driver — the HKL changes, the tables don't (de-layout captures queued for real Windows) (findings) | [A[ssh]] three levels, three owners (keyCode / UCKeyTranslate / interpretKeyEvents:); synthetic NSEvent never composes dead keys, the layout engine does (é); repeat contract 250 ms delay / 33 ms interval with isARepeat (findings) |
| F07 text input | [A] full CJK round-trip headless: sway + fcitx5-pinyin drove zwp_text_input_v3 preedit→commit_string "你好", serial discipline proven; weston is v1-only (findings) | [A] XIM end-to-end incl. headless fcitx5 pinyin (你好 commit, destroy/restart callbacks, on-the-spot preedit deltas); the XFilterEvent gate is total (findings) | [A[wine]] IMM32 choreography fully verified headless (SCS_SETSTR echoes real WM_IME_*); TSF COM bring-up all-S_OK, blocked only by ITextStoreACP (findings) | [A[ssh]] full NSTextInputClient (runtime class_addProtocol!) flips composition on: option-e+e ⇒ setMarkedText:"´"→insertText:"é"; Esc commits-then-cancels; focus loss orphans the pre-edit (findings) |
| F08 dpi scaling | [A] both paths in one binary; live fractional rescale + cross-scale output move on sway; first commit is ALWAYS at scale 1 — post-map rescale guaranteed (findings) | [A] absence proven live: Xft.dpi 96→144→192 + xrandr --dpi deliver NOTHING to the window; only live channel = opt-in root PropertyNotify on RESOURCE_MANAGER (convention, not protocol) (findings) | [A[wine]] PMv2 surface complete (write-once err=5, thread granularity, virtualization captured); WM_DPICHANGED structurally unreachable — Wayland scale arrives as plain WM_SIZE at DPI 96 (findings) | [A[ssh]] all scale sources agree (2.0); convertRectToBacking: exact incl. fractional; headless drawRect: CTM is identity — rasterization claim Tier C; wrong-scale buffers fail silently (findings) |
| F09 outputs | [A] wl_output v4 + xdg-output logical/physical split; live hot-add/remove + the vanishing-occupied-output sequence captured; occupancy trails configures by ~200 ms (findings) | [A] both RandR views (1.5 monitors vs 1.2 wiring objects, they disagree on physical mm); occupancy derived, off-screen windows learn nothing; soft-unplug via non-desktop reachable (findings) | [A[wine]] live hotplug captured (sway output → \\.\DISPLAY2 in ~1 s) but Wine fires NONE of the three notify messages — only polling caught it; rcMonitor all at +0+0 under winewayland (findings) | [A[ssh]] dual enumeration (NSScreen + CG) + NSScreenNumber bridge + window.screen (AppKit answers occupancy itself); locked session empties the CG active list only; CGDisplayPixelsWide returns points (findings) |
| F10 pointer capture | [A] lock granted only on surface entry; oneshot/persistent lifecycles + hint-warp proven; only relative motion flows while locked; deactivation ONLY on focus change (sway) (findings) | [A] lock is assembled (grab+hide+warp; restore exact); confine_to modal but unenforced post-activation on Xvfb; XFixes barriers ambient + grab-proof; raw events DOUBLE during own grabs (findings) | [A[wine]] raw WM_INPUT + ClipCursor(1×1)+ShowCursor lock + confine all proven; Wine applies ballistics BEFORE the raw stream; focus loss doesn’t clear the clip (findings) | [A[ssh]] lock = 3 sync calls, no deny, no read-back getter; warp silent/fraction-truncating + 0.25 s suppression; NO public confine — warp-back leaks 1 out-of-bounds event per excursion (findings) |
| F11 scroll | [A] full v9 axis vocabulary frame-grouped; v120 = discrete×120 (15/detent libinput convention); axis_stop in its own frame; momentum is app-synthesized (findings) | [A] core vs XI2 delivered either/or per window (XI2 suppresses core); Xvfb has no XIScrollClass (CI = buttons 4/5 only); XIPointerEmulated=0 on XTest wheels — dedupe by capability, not flag (findings) | [A[wine]] wheelDelta verbatim at ±120/±40; carry-vs-truncate diffed (truncation loses AND fabricates detents); under-cursor routing while the routing SPI errors (findings) | [A[ssh]] one event, three representations; hasPreciseScrollingDeltas is the unit switch (lines vs px, 10 px/line); momentum routed statefully — sendEvent: drops synthetic momentum events (findings) |
| F12 cursors | [A] cursor-shape-v1 (sway yes / weston no — both mechanisms mandatory in 2026) + theme path with HiDPI reload; seat-capability lifecycle is fatal if mishandled (findings) | [A] font + themed + custom-ARGB + 60-frame SERVER-animated cursors; XCURSOR_* env all honored; themeless Xvfb resolves nothing, default size = min(dim)/48 (findings) | [A[wine]] resize vocabulary is 4 bidirectional shapes for 8 edges; class cursor silently overwrites SetCursor on DefWindowProc fall-through; WM_SETCURSOR storms per mouse move (findings) | [A[ssh]] 22-getter vocabulary probed — no public diagonal resize cursor pre-macOS 15 (frameResize… ×8 exercised); set rewrites the push/pop stack top; system cursors ship 1x+2x (arrow: 4 reps to 280 px) (findings) |
| F13 decorations | [A] SSD negotiated where offered (sway; weston has NO decoration protocol); hand-rolled CSD with real-serial move/resize grabs; geometry violation = disconnect; libdecor 295 vs 1061 LOC (findings) | — (N/A — SSD; hook notes in the Wayland F13 doc) | — | — |
| F14 window state | [A] full states-array choreography (v1 sees maximized where v5 sees tiled_*!); minimize is fire-and-forget by XML and measurement; close advisory, veto = ignore, EPIPE captured (findings) | [A] state changes are advisory ClientMessages (silence without a WM); echo = payload-less PropertyNotify requiring re-fetch; close veto = ignoring the message; no handshake ⇒ XKillClient (findings) | [A[wine]] states echo synchronously via WM_SIZE wParam; fullscreen is a geometry idiom that CORRUPTS the placement normal-rect; close veto is first-class (don’t forward WM_CLOSE) (findings) | [A[ssh]] three verbs, three temporal shapes: zoom: sync+animated (356 ms live-resize bracket), miniaturize: async (1.55 s), toggleFullScreen: FAILS locked; windowShouldClose: is a first-class once-veto — close skips the ask (findings) |
| F15 popup | [A] positioner solved COMPOSITOR-side (sway flips, not slides, at edges); outside click is uncapturable — only popup_done, topmost-first; stale grab serial silently granted grab-less (findings) | [A] popup = override-redirect + session-global grab (starves ALL other clients); placement and dismissal 100% app-side; one grab serves the submenu chain (findings) | [A[wine]] WS_POPUP+SetCapture; one capture slot + screen-coord hit-testing serves the chain; WM_CAPTURECHANGED is the silent grab-breaker; popups may exceed output bounds (findings) | [A[ssh]] borderless window @ level 101; placement/clamping 100% app math (off-screen frames accepted verbatim); local monitor sees only queued events; Esc via cancelOperation:; child window tracks parent exactly (findings) |
| F16 clipboard + DnD | [A] clipboard + DnD share one data_source/offer pipe-fd machinery; set_selection is DEAD without a real input serial (silently ignored); DnD action compositor-resolved (findings) | [A] clipboard + XDND are ONE selection mechanism; INCR proven both directions; full XDND v5 source+target by hand; delayed rendering is the only mode (findings) | [A[wine]] delayed rendering timed (WM_RENDERFORMAT only on demand); OLE DnD fully headless (hand-rolled COM to DRAGDROP_S_DROP); host bridging two-way on winex11, ABSENT on winewayland (findings) | [A[ssh]] eager+lazy NSPasteboard; changeCount polling is the ONLY change signal; promises die with the source; changeCount-in-ownership-callback recurses to stack overflow (findings) |
| F17 threading | [A] no main-thread rule at all; per-thread wl_event_queue + proxy wrapper is the designed routing model; a mispaired read_events silently wedges the connection forever (findings) | [A] no main-thread rule (affinity is per-Display); classic no-XInitThreads corruption EXTINCT on libX11 ≥ 1.8 (ELF-constructor self-arms); shared-Display reads starve one reader (findings) | [A[wine]] HWND queue affinity proven (main sees 0 of 10); SendMessage blocks on the receiver's pump; mutual-send defused by nonqueued processing, send-to-parked-thread DEADLOCKS; 100/100 cross-thread BitBlt (findings) | [A[ssh]] the strictest of all four: window off-main = deterministic NSInternalInconsistencyException crash (assert verbatim); direct cross-thread setNeedsDisplay: is a SILENT no-op (findings) |
The X11 and macOS F13 cells are "N/A — SSD" by design (see the F13 spec); their one-line customization-hook notes land in the Wayland F13 findings doc's comparison section.