docs(windows): clarify restore policy support

This commit is contained in:
Chris Tate
2026-08-17 17:33:51 -05:00
parent 7379550a27
commit bb97110886
5 changed files with 10 additions and 8 deletions
+1 -1
View File
@@ -484,7 +484,7 @@ For timestamps, the facade owns the clocks (Zig 0.16 puts `std.time` behind `std
## Secondary windows
In a default TypeScript app, export `windows(model): readonly WindowDescriptor[]` and put each possible window's markup at `src/windows/<label>.native`; the generated launcher compiles those files, maps descriptor labels to them, and includes shared components they import from nested paths under `src/windows/`. Construct descriptors with `windowDescriptor`. `restorePolicy: "center_on_primary"` centers a fresh descriptor with no `x`/`y`; the default is `"clamp_to_visible_screen"`. `closePolicy: "quit"` routes `onCloseCommand` through `commandMsg`; `"hide"` retains the window and dispatches no close command. `titlebar` includes `"chromeless"` for fully skinned windows. `examples/system-monitor-ts` is the complete default-path reference.
In a default TypeScript app, export `windows(model): readonly WindowDescriptor[]` and put each possible window's markup at `src/windows/<label>.native`; the generated launcher compiles those files, maps descriptor labels to them, and includes shared components they import from nested paths under `src/windows/`. Construct descriptors with `windowDescriptor`. `restorePolicy: "center_on_primary"` centers a fresh descriptor with no `x`/`y` on macOS; Windows and Linux currently keep their native default placement. The default policy is `"clamp_to_visible_screen"`. `closePolicy: "quit"` routes `onCloseCommand` through `commandMsg`; `"hide"` retains the window and dispatches no close command. `titlebar` includes `"chromeless"` for fully skinned windows. `examples/system-monitor-ts` is the complete default-path reference.
In Zig cores and custom wiring, windows are model-declared exactly like the tray: `Options.windows_fn` returns the window descriptors that should exist right now (presence IS liveness), and `Options.window_view` builds each declared window's whole canvas tree, keyed by the descriptor's window label. After every dispatched Msg the runtime reconciles: windows the model started declaring are created (a source-less native window wearing one `gpu_surface` view with the descriptor's `canvas_label`, inheriting the main canvas's gpu options), windows it stopped declaring close, and every open window's view rebuilds from the same model — a theme picked in the settings window restyles the main window on the same dispatch. There is no `visible` flag: transient visibility is host state changed through `hideWindow`/`showWindow` or a `.hide` close policy; stop declaring a window to really close it and release its retained views.
+1 -1
View File
@@ -482,7 +482,7 @@ Export `windows(model): readonly WindowDescriptor[]` to derive the live secondar
`closePolicy` accepts `"quit"` (the default) or `"hide"`. A `"quit"` user close routes `onCloseCommand` through `commandMsg`, where the app maps it to the Msg that clears its open flag. A `"hide"` close retains the same native window and view and dispatches no close command; `Cmd.showWindow(label)` reveals it. Model-declared secondary windows are desktop-only. See `examples/system-monitor-ts`.
`restorePolicy` accepts `"clamp_to_visible_screen"` (the default) or `"center_on_primary"`. Model-declared windows do not restore persisted frames, so `"center_on_primary"` centers a fresh descriptor with no authored `x`/`y` during native creation.
`restorePolicy` accepts `"clamp_to_visible_screen"` (the default) or `"center_on_primary"`. Model-declared windows do not restore persisted frames. On macOS, `"center_on_primary"` centers a fresh descriptor with no authored `x`/`y`; Windows and Linux currently keep their native default placement.
`titlebar` accepts `"standard"`, `"hidden_inset"`, `"hidden_inset_tall"`, or `"chromeless"`. Transparent Windows windows require `"chromeless"`; because that removes the system buttons, fully skinned windows must draw working close/minimize controls.
+2 -2
View File
@@ -878,7 +878,7 @@ The `.wake` platform event is how live platforms marshal worker completions onto
## Secondary windows
In the default TypeScript path, export `windows(model): readonly WindowDescriptor[]` and put each possible window's Native markup at `src/windows/<label>.native`. Spell each constructor identity as a literal `label: asciiBytes("<label>")`; `native check` and every build reject dynamic labels and missing roots. Those roots may import shared components nested under `src/windows/`; the generated launcher compiles and hot-reloads the full closure. Use `windowDescriptor` from `@native-sdk/core`; its `restorePolicy` field accepts `"clamp_to_visible_screen"` or `"center_on_primary"`, `closePolicy` accepts `"quit"` or `"hide"`, and `titlebar` includes `"chromeless"`. A `"quit"` user close routes `onCloseCommand` through `commandMsg`; a `"hide"` close preserves the window and view and dispatches no close command. The `ts-core` skill has the complete descriptor and example.
In the default TypeScript path, export `windows(model): readonly WindowDescriptor[]` and put each possible window's Native markup at `src/windows/<label>.native`. Spell each constructor identity as a literal `label: asciiBytes("<label>")`; `native check` and every build reject dynamic labels and missing roots. Those roots may import shared components nested under `src/windows/`; the generated launcher compiles and hot-reloads the full closure. Use `windowDescriptor` from `@native-sdk/core`; its `restorePolicy` field accepts `"clamp_to_visible_screen"` or `"center_on_primary"` (centering is currently macOS-only), `closePolicy` accepts `"quit"` or `"hide"`, and `titlebar` includes `"chromeless"`. A `"quit"` user close routes `onCloseCommand` through `commandMsg`; a `"hide"` close preserves the window and view and dispatches no close command. The `ts-core` skill has the complete descriptor and example.
### Zig cores: `windows_fn` + `window_view`
@@ -905,7 +905,7 @@ fn windowView(ui: *App.Ui, model: *const Model, window_label: []const u8) App.Ui
Rules that matter:
- **Every canvas label must be unique across the app** (main + declared windows); input routes back by it, and automation verbs (`widget-click <canvas-label> <id>`, `screenshot`) address any window's canvas the same way.
- **Close policy**: `WindowDescriptor.close_policy` is `.quit` by default; a user close really closes and dispatches `on_close` (the dismissal precedent), so clear the open flag in `update` — or keep declaring the window and the next rebuild brings it back (source wins). `.hide` keeps the same window, slot, and views alive, dispatches no `on_close`, and `showWindow(label)` reveals it. A close the model itself initiated never echoes a Msg. Existing platform safeguards still apply: unsupported hosts refuse `.hide` rather than strand an unreachable window.
- **Restore policy**: `WindowDescriptor.restore_policy` is `.clamp_to_visible_screen` by default; `.center_on_primary` centers a fresh descriptor with no authored `x`/`y`. Model-declared windows deliberately do not restore persisted frames.
- **Restore policy**: `WindowDescriptor.restore_policy` is `.clamp_to_visible_screen` by default. On macOS, `.center_on_primary` centers a fresh descriptor with no authored `x`/`y`; Windows and Linux currently keep their native default placement. Model-declared windows deliberately do not restore persisted frames.
- **Budget**: at most `UiApp.max_ui_windows` (4) declared windows; excess warns and is ignored. Every dispatched Msg rebuilds every open window's view.
- **Present-before-show**: canvas windows (any `gpu_surface` view — startup, scene, and declared windows alike) are created ordered-out and become visible only after their first canvas frame presents, so opening one never flashes blank. Automatic (`WindowOptions.show = .on_first_present`, derived from the views); webview windows show immediately. The null platform records `window_show`, `window_visible`, and present/shown sequence numbers for ordering assertions; `NATIVE_SDK_WINDOW_TIMING=1` logs create→show latency on macOS.
- **Markup binds ONE window's content** — there is no `window` element in the closed grammar. A markup-authored secondary window is a `canvas.CompiledMarkupView` whose `build` `window_view` calls for that label.
+1 -1
View File
@@ -241,7 +241,7 @@ export function windows(model: Model): readonly WindowDescriptor[] {
`closePolicy` is `"quit"` by default. Under `"quit"`, a user close really closes the window and routes `onCloseCommand` through `commandMsg`; map it to the Msg that clears the model's open flag. If the model keeps declaring the label, source wins and the next reconciliation recreates it. Under `"hide"`, the same native window and view stay alive, no close command fires, and `Cmd.showWindow("settings")` reveals it. Stopping the declaration always performs a real reconcile close. The platform safeguards for `hide` are the same as manifest windows. Model-declared secondary windows are desktop-only.
`restorePolicy` accepts `"clamp_to_visible_screen"` (the default) or `"center_on_primary"`. Model-declared windows do not restore persisted frames, so the latter centers a fresh descriptor with no `x`/`y` directly at native creation time.
`restorePolicy` accepts `"clamp_to_visible_screen"` (the default) or `"center_on_primary"`. Model-declared windows do not restore persisted frames. On macOS, the latter centers a fresh descriptor with no `x`/`y` directly at native creation time; Windows and Linux currently keep their native default placement.
`titlebar` accepts `"standard"`, `"hidden_inset"`, `"hidden_inset_tall"`, and `"chromeless"`. The last removes all OS chrome and is required when a transparent model-declared window targets Windows; provide working app-drawn close/minimize controls for that fully skinned shape.
+5 -3
View File
@@ -370,9 +370,11 @@ pub fn UiAppWithFeatures(comptime ModelT: type, comptime MsgT: type, comptime fe
x: ?f32 = null,
y: ?f32 = null,
resizable: bool = true,
/// Placement policy applied by the host when creating this
/// fresh, non-restored window. `.center_on_primary` centers a
/// descriptor without an authored origin on the primary screen.
/// Placement policy passed to the host when creating this
/// fresh, non-restored window. On macOS,
/// `.center_on_primary` centers a descriptor without an authored
/// origin on the primary screen; other hosts currently retain
/// their native default placement.
restore_policy: app_manifest.WindowRestorePolicy = .clamp_to_visible_screen,
/// Content min-size floor the WINDOW enforces (macOS
/// `contentMinSize`): the user's resize stops at the floor