Commit 8e37536
authored
Windows fixes: caption clearance, GUI subsystem, elision budget, dark titlebars (#122)
* Hand the full snap quantum back to the text wrap/elision budget
- Edge snapping rounds each frame edge independently, so an exact-fit text frame at a fractional position can lose up to a FULL device pixel of width — the old 0.5/scale hand-back plus the 0.125 elision slack under-covered it, and the TS scaffold's centered counter digit painted as "…" on Windows at scale 1
- textWrapMaxWidth now returns width + 1/scale with the epsilon policy documented at the seam; regression tests sweep fractional origins for every digit at scales 1/1.25/1.5/2 plus the exact centered-row scaffold shape
* Reserve the Windows caption cluster in drag-header layout
- A window-drag header that never consumed the chrome channel's trailing inset laid right-aligned content under the DWM min/max/close cluster; the caption punch-out then visibly truncated it (system-monitor-ts's header status)
- The runtime now runs a one-retry clearance pass: when the built layout leaves drag-header CONTENT under the platform-reported control cluster, it stamps the cluster into DesignTokens.window_controls and rebuilds once, and widget layout trims the drag row's content box on the cluster's side - apps that already pad (soundboard) never trigger and keep byte-identical layout
- Regression: engine tests for both cluster sides and the content-only trigger, plus runtime tests faking Windows-shaped chrome through the null platform for the naive and the contract header shapes
* Give Windows release exes the GUI subsystem and pin it at packaging
- Every app exe was console-subsystem (zig's default), so dev AND packaged apps flashed a terminal behind the window; the posture is now: Debug keeps the console (dev logs live there), release-shaped builds get /SUBSYSTEM:WINDOWS - redirected logging still works because only console AUTO-allocation is subsystem-gated
- native package reads the wrapped exe's PE subsystem (peSubsystem), warns with the rebuild teaching when it wraps a console binary, and reports it in PackageStats.windows_console_subsystem; tests pin the reader and both packaging outcomes over synthetic PE headers
- Verified on the Windows box: ReleaseFast ts-smoke.exe reads subsystem=2, launches headed with no console, automation and file-redirected logs intact
* Dark-mode titlebars on Windows and a kinder scaffold empty state
- Standard-chrome windows set DWMWA_USE_IMMERSIVE_DARK_MODE from the OS app scheme at creation (pre-show, no light-caption flash) and on appearance broadcasts; hidden-titlebar windows keep their pixel-sampled caption fidelity
- The TS scaffold's status bar branches on {stampedMs < 0} to say "press Stamp for a timestamp" instead of "stamped: -1ms"; fresh scaffold verified through native check and the ts-core e2e scaffold pins
* Emit the GUI-subsystem posture into the scaffold's standalone build.zig
- The web-frontend scaffold (Next/Vite/React/Svelte/Vue, native init --full) generates its own build.zig and never set exe.subsystem, so those apps still shipped console-subsystem Windows release exes - and the packaging warn had no remedy, since rebuilding can't fix a scaffold that never sets it
- The generated build.zig now carries the same release-only assignment as the SDK build graph (Debug keeps the console for dev logs), with the condensed rationale
- The Vite template test pins the emitted condition and assignment lines
* Resolve a drag header's anchored children against the cleared rect
- The collision scan counts anchored descendants of the drag header, but the remedy only trimmed the flow content box - an anchored floater triggered the one retry and then stayed under the caption cluster (retry paid, nothing moved)
- layoutWidgetDepth now passes the anchor base through windowControlsClearedContent for window_drag widgets only, covering both the trailing (Windows) and leading (macOS) clusters; non-drag widgets' anchored children are untouched by construction
- Engine test pins the anchored-only collision converging in one pass (scan fires, remedy moves it, re-scan stays quiet), the macOS mirror, and byte-identical non-drag anchoring under stamped tokens
* Run the window-control clearance retry in secondary windows too
- rebuildWindowSlot laid out exactly once, so a model-declared hidden-inset window's drag header still rendered content under the OS caption cluster; it now runs the same collision scan + one-retry pass as the main rebuild, stamping the cluster into a local copy of the slot's tokens.
- windowControlsReservation takes the canvas label so both rebuild paths share it, and the slot's build+layout pass is factored into buildWindowSlotPass (same arena reuse as the main path's buildLayoutPass retry).
- ui_app_window_tests: a colliding secondary drag header re-lays clear of the cluster while the main canvas stays unstamped, and a padded secondary header keeps its own layout.
* Read only the PE headers for the packaging subsystem check
- peIsConsoleSubsystem slurped the whole exe through readPath (capped at 128 MiB) and swallowed every error as false, so a console exe over the cap packaged without the promised warning and packaging allocated the entire binary to read 2 bytes.
- peSubsystemAtPath reads the 0x40-byte DOS header, bounds the rest to e_lfanew + 94 bytes through the existing pure peSubsystem parser, and rejects e_lfanew past a 1 MiB ceiling as not-a-real-PE; only genuinely-unreadable files still degrade to no-claim.
- Tests: a sparse console exe past the old cap still warns, and a bogus 8 MiB e_lfanew answers nothing under the failing allocator (no full-file or offset-sized allocation).
* Persist the subsystem verdict in the report and stats summary
- package-manifest.zon now carries .subsystem = "gui"/"console" whenever the posture check ran (a Windows package with a binary), threaded through writeReport like asset_count; other targets make no claim
- the stats summary prints "subsystem: gui" or "subsystem: console (a terminal window opens behind the app - rebuild with `native build`)" alongside the web-layer and signing verdicts
- PackageStats.windows_console_subsystem is now a ternary (?bool) so an unprobed package cannot pass for a GUI verdict; the synthetic-PE tests pin both report fields and the no-binary null
* Stop claiming a gui subsystem the PE parse never established
- Replace the bool verdict with WindowsSubsystem { gui, console, unknown }: gui and console only when the optional header said so, unknown for non-PE/truncated bytes, benign read errors, and unmodeled subsystem values; null still means the check never ran
- Diagnostic prints "subsystem: unknown (unrecognized executable format)" and the report writes .subsystem = "unknown" instead of affirming gui; console warning behavior and OutOfMemory propagation unchanged
- Pin unknown for a non-PE file, a truncated PE, and a native-subsystem exe; retarget the sparse-oversized and offset-ceiling probes onto the verdict helper
* Package a release-shaped exe from the web-frontend scaffold
- The emitted build.zig defaulted -Doptimize to Debug for everything, so the documented `zig build package` wrapped a Debug, console-subsystem exe; the package step now builds its own exe that defaults to ReleaseFast (mirroring `native build`) while an explicit -Doptimize or --release still pins both roles.
- Registers -Doptimize by hand instead of standardOptimizeOption so the graph can tell unset from explicit, the same optimizeMode split build/app.zig uses; the --optimize arg, the artifact name, and the Windows GUI-subsystem posture all key on the package exe's actual mode.
- Extends the Vite template pins to the package-exe shape and forbids the stale dev-exe wiring.
* Judge drag-header text by its painted bounds in the caption scan
- The collision scan intersected each candidate's full frame with the caption cluster, so a grow/stretch centered title spanning the header row false-positived while its glyphs sat clear — and the paid retry visibly shifted the title.
- Single-line text leaves now intersect their aligned painted bounds: measured width through the same tokens seam the layout ran with, capped at the frame, placed per text_alignment; controls keep the frame test, and span paragraphs or explicit newlines fall back to it conservatively.
- Threads tokens from both windowControlsReservation call sites, pins the centered-title no-retry case at engine and runtime level, and keeps the trailing true-positive, the macOS leading mirror, and post-remedy re-scan convergence green.1 parent 07b259f commit 8e37536
20 files changed
Lines changed: 1486 additions & 74 deletions
File tree
- build
- changelog.d
- src
- platform/windows
- primitives/canvas
- runtime
- tooling
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
388 | 388 | | |
389 | 389 | | |
390 | 390 | | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
391 | 403 | | |
392 | 404 | | |
393 | 405 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4480 | 4480 | | |
4481 | 4481 | | |
4482 | 4482 | | |
| 4483 | + | |
| 4484 | + | |
| 4485 | + | |
| 4486 | + | |
| 4487 | + | |
| 4488 | + | |
| 4489 | + | |
| 4490 | + | |
| 4491 | + | |
| 4492 | + | |
| 4493 | + | |
| 4494 | + | |
| 4495 | + | |
| 4496 | + | |
| 4497 | + | |
| 4498 | + | |
| 4499 | + | |
4483 | 4500 | | |
4484 | 4501 | | |
4485 | 4502 | | |
| |||
4500 | 4517 | | |
4501 | 4518 | | |
4502 | 4519 | | |
| 4520 | + | |
| 4521 | + | |
| 4522 | + | |
| 4523 | + | |
4503 | 4524 | | |
4504 | 4525 | | |
4505 | 4526 | | |
| |||
4967 | 4988 | | |
4968 | 4989 | | |
4969 | 4990 | | |
| 4991 | + | |
| 4992 | + | |
| 4993 | + | |
4970 | 4994 | | |
4971 | 4995 | | |
4972 | 4996 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
695 | 695 | | |
696 | 696 | | |
697 | 697 | | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
698 | 703 | | |
699 | 704 | | |
700 | 705 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
1521 | 1522 | | |
1522 | 1523 | | |
1523 | 1524 | | |
| 1525 | + | |
| 1526 | + | |
| 1527 | + | |
| 1528 | + | |
| 1529 | + | |
| 1530 | + | |
| 1531 | + | |
| 1532 | + | |
| 1533 | + | |
| 1534 | + | |
| 1535 | + | |
| 1536 | + | |
| 1537 | + | |
| 1538 | + | |
1524 | 1539 | | |
1525 | 1540 | | |
1526 | 1541 | | |
| |||
0 commit comments