fix(window): don't save the geometry of a minimised window

Windows parks a minimised window at -32000,-32000 with a stub size and reports
it as not-maximised, so closing OpsLog from the taskbar while minimised stored
exactly that. Seen in a log: "window: saving -32000,-32000 237x39
maximised=false".

The restore side already rejects both the impossible corner and the
below-minimum size, so nothing opened off-screen — but it fell back to the
default placement, and the operator silently lost the size, the position and the
maximised state they had set.

saveWindowState now keeps what was already stored when the window is minimised.
Two tests for that: the Wails flag, and the -32000 corner, because a window that
is mid-close can sit at that corner with the flag already cleared. A poisoned
window.json repairs itself on the next close of an on-screen window.
This commit is contained in:
2026-08-09 01:47:45 +02:00
parent 44cf5954fd
commit 59135d55ab
3 changed files with 39 additions and 4 deletions
+30
View File
@@ -1800,6 +1800,24 @@ func writeWindowState(dataDir string, w windowState) {
}
}
// windowIsMinimised reports whether the window is currently minimised.
//
// Two tests rather than one: Wails answers the question directly, and the
// -32000 corner is Windows' own marker for a minimised window — a window that
// is mid-close or hidden can report that corner while the flag has already been
// cleared, and either way the geometry is not worth storing.
func (a *App) windowIsMinimised() bool {
if a.ctx == nil {
return false
}
if wruntime.WindowIsMinimised(a.ctx) {
return true
}
x, y := wruntime.WindowGetPosition(a.ctx)
const minimisedCorner = -32000
return x <= minimisedCorner || y <= minimisedCorner
}
// saveWindowState captures the current geometry. Called as the window closes.
// While in compact mode the window is pinned to a tiny fixed size, so we keep the
// previously-saved normal geometry rather than overwrite it with 1240×158 — only
@@ -1809,6 +1827,18 @@ func (a *App) saveWindowState() {
return
}
prev, _ := readWindowState(a.dataDir)
// A MINIMISED window has no usable geometry: Windows parks it at -32000,-32000
// with a stub size, and reports it as not-maximised. Closing OpsLog from the
// taskbar while minimised captured exactly that — "saving -32000,-32000 237x39
// maximised=false" — and window.json then held a position no monitor covers and
// a size below the minimum. The restore side rejects both and falls back to the
// default placement, so the operator silently lost the size, the position AND
// the maximised state they had. Keep what was already stored instead.
if a.windowIsMinimised() {
applog.Printf("window: minimised at close — keeping the stored geometry %d,%d %dx%d maximised=%v",
prev.X, prev.Y, prev.Width, prev.Height, prev.Maximised)
return
}
max := wruntime.WindowIsMaximised(a.ctx)
ws := prev
ws.Maximised = max