tauri-apps / tauri-apps/plugins-workspace
[window-state] Window grows by the decoration extent on every restart (Linux/GTK CSD): inner_size() is saved, set_size() restores
- Dominant language
- Rust
- Stars
- 1.8k
- Forks
- 602
- Avg merge
- 4d 14h
- Merged PRs (30d)
- 9
Description
### Summary
On a desktop with client-side decorations (GNOME/Wayland), a window restored by
`window-state` is **larger on every launch than it was when it closed**, growing by the
decoration extent each time and compounding without limit. After ten restarts it is roughly
+520 x +1090 physical px and walking off the screen.
The cause is that the two halves of the round trip do not measure the same thing:
- `update_state` saves **`Window::inner_size()`** (`plugins/window-state/src/lib.rs`)
- `restore_state` applies it with **`Window::set_size()`**
On GTK those differ. `set_size` sizes the window *excluding* the CSD shadow and titlebar,
while `inner_size()` reports the allocated surface *including* them. So a window restored to
saved size `S` settles at `S + E`, and `S + E` is what gets written back on close. Next
launch starts from `S + E` and settles at `S + 2E`.
Notably `inner_size()` and `outer_size()` return **identical** values here once the window is
mapped, so the difference is not observable through those two APIs — it only shows up as the
gap between what you *ask* for and what you are then *told* you have.
### Steps to reproduce
1. GNOME/Wayland, a plain Tauri app with `tauri_plugin_window_state::Builder::default().build()`.
2. Launch, resize the window, close it with the window button (so the `RunEvent::Exit` hook runs).
3. Note `width`/`height` in `~/.config//.window-state.json`.
4. Relaunch and close again **without touching the window**.
5. The saved size has grown. Repeat — it grows by the same amount every time.
### Measured
Seeding the state file by hand and closing without resizing, so nothing but the plugin moves
the numbers:
| Saved size going in | Saved size coming out | Delta |
|---|---|---|
| 960 x 640 (seeded) | 1012 x 749 | +52, +109 |
| 1012 x 749 | 1064 x 858 | +52, +109 |
| 2037 x 1309 | 2089 x 1418 | +52, +109 |
`E` = 52 x 109 physical px = 26px shadow per side horizontally; 57px titlebar plus the same
52px of shadow vertically. Instrumenting the app confirms the mechanism directly: with
`1064 x 858` in the state file, the window reports `1116 x 967` (= saved + E) once the restore
has settled, and that inflated value is what the exit hook writes.
Two further observations from the same instrumentation, in case they are useful:
- At `setup` the window is still at the size `tauri.conf.json` asked for — the restore lands
later, from the `on_window_ready` hook — so anything trying to correct this from `setup`
reads a pre-restore size.
- `outer_size()` returns `0 x 0` before the window is mapped.
### Environment
- `tauri-plugin-window-state` 2.4.1 (also present on `v2` HEAD at the time of writing)
- `tauri` 2.11.5, `wry` 0.55.1
- Ubuntu 24.04.4, GNOME Shell 46.0, Wayland, GTK 3.24.41, scale factor 1.0
### Suggested fix
Make the save and the restore measure the same thing. Either save `outer_size()` to match
what `set_size` consumes, or restore through an API that sets the inner size, so that
`set_size(x)` followed by `inner_size()` is the identity on every platform.
A no-op-elsewhere alternative, if the platform difference is hard to reach from here: after
restoring, compare the reported size against the value that was just applied and re-apply the
difference once. That is the shape of the workaround I am carrying downstream, and it costs
nothing on platforms where the two already agree.
### Related but distinct
- #3521 is macOS and multiplicative (scale factor), not an additive decoration extent.
- #251 was zero-valued metadata on first run, fixed long ago.
Contributor guide
Research direction
Start in plugins/window-state/src/lib.rs by tracing the update_state save path and the restore_state path invoked from on_window_ready, then compare the size APIs used on GTK CSD. Reproduce the restart cycle on Linux/Wayland and verify that restoring and saving the same window no longer increases the recorded dimensions on successive launches.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100