Skip to content

Remember the window's size and position - #99

Merged
vmillet-dev merged 2 commits into
mainfrom
feat/window-remembers-its-geometry
Sep 13, 2026
Merged

vmillet-dev merged 2 commits into
mainfrom
feat/window-remembers-its-geometry

Conversation

@vmillet-dev

@vmillet-dev vmillet-dev commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Closes #11.

tauri-plugin-window-state — the plugin, not a hand-rolled persistence through PreferencesService. It brought one crate with it and no transitive dependency, which is well under "more than it is worth"; and doing it in the front end would mean restoring the geometry after Angular boots, so the window would visibly jump on every launch.

The flags are the whole ticket

The plugin's default is StateFlags::all(), and all() includes VISIBLE. With closeToTray on — which is the default — quitting from the tray saves a window that is hidden, and the next launch restores it hidden: an application that starts with nothing on screen and only a tray icon to be found by. That is the trap the ticket warns about, and taking the plugin's default would have walked straight into it.

So WINDOW_STATE_FLAGS is SIZE | POSITION | MAXIMIZED, named and commented, with a unit test that holds VISIBLE out — a comment cannot fail a build. DECORATIONS and FULLSCREEN are left out for the opposite reason: nothing in DevBox changes either, so saving them stores noise.

The other half of the ticket's warning needs nothing from us. A minimized window on Windows reports itself at -32000, and the plugin already guards it: both its Moved and its Resized handlers skip a minimized window, and update_state skips size and position when minimized or maximized. Confirmed by reading the plugin rather than by hoping.

Worth knowing: the file is written on RunEvent::Exit, not on every move. The tray's "Quitter" is app.exit(0), so it goes through; a force-kill writes nothing and leaves the previous geometry standing, which is the right answer for a crash.

First launch

tauri.conf.json is now only a first launch. 800×600 was the ticket's own complaint — narrow for a grid of minmax(220px, 1fr) cards — so it is 1100×720, with minWidth/minHeight of 640×480. The floor is not decoration: it is what stops a saved geometry, or a drag, from bringing the window back at a size nothing fits in.

Verified on the assembled application

This is not reachable from the e2e suite — reopenSession() is explicitly not a restart, the process hosts the WebDriver server and must stay up, so "quit and launch again" cannot be expressed there. Same reason 15-preferences-on-disk reads its file from Node. So it was checked by hand, against the real binary:

step result
fresh profile, first launch 1116×759 outer — the new 1100×720 client area
moved and resized to 980×640 at 240,130, then quit .window-state.json written: 964×601 at 240,130 (client area)
launched again 980×640 at 240,130 — identical
closed to the tray, then launched again 980×640 at 240,130 — unchanged, one process, revealed by single-instance
"visible": false forced into the state file, then launched window appears anyway — the flag is genuinely not consulted

That last row is the trap, demonstrated rather than argued.

Checked

  • cargo test — 169 + 34 + 83 + 14 + 10 passing, including the new flag guard. cargo clippy --all-targets -- -D warnings, cargo fmt --check — clean.
  • npm test — 937 passing. npm run lint — clean.
  • Full e2e — 15/15 green. Run deliberately, because the default window size changed and every spec's viewport with it.

docs/architecture.md gains a "Window geometry" section next to the tray; CLAUDE.md gains the VISIBLE trap.

`tauri-plugin-window-state`, with explicit flags rather than its default
`all()`: that set carries `VISIBLE`, and quitting from the tray saves a
hidden window — the next launch would restore it hidden, an application
that starts with nothing on screen. A unit test holds the flag out.

The size in `tauri.conf.json` is now only a first launch, and 800x600 was
narrow for a grid of cards: 1100x720, with a 640x480 floor so no saved
geometry can come back unusable.
The plugin restores the geometry from `on_webview_ready`, which runs
after the window is already on screen: it appeared at the config's size
and then jumped. Measured through startup, that was 1116x720 at +172 ms
and the remembered 900x600 at +359 ms.

The window is now created hidden and shown from `setup`, once the restore
has run — one rectangle, no jump. `backgroundColor` is the dark `--bg-0`
so the WebView's white does not take the flash's place.
@vmillet-dev
vmillet-dev force-pushed the feat/window-remembers-its-geometry branch from 5945dcb to b74cb29 Compare September 13, 2026 18:42
@vmillet-dev
vmillet-dev merged commit 295e0e5 into main Sep 13, 2026
10 of 11 checks passed
@vmillet-dev
vmillet-dev deleted the feat/window-remembers-its-geometry branch September 13, 2026 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The window forgets its size and position

1 participant