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:
@@ -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.
|
// 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
|
// 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
|
// previously-saved normal geometry rather than overwrite it with 1240×158 — only
|
||||||
@@ -1809,6 +1827,18 @@ func (a *App) saveWindowState() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
prev, _ := readWindowState(a.dataDir)
|
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)
|
max := wruntime.WindowIsMaximised(a.ctx)
|
||||||
ws := prev
|
ws := prev
|
||||||
ws.Maximised = max
|
ws.Maximised = max
|
||||||
|
|||||||
+4
-2
@@ -5,12 +5,14 @@
|
|||||||
"en": [
|
"en": [
|
||||||
"Worked before: an operator's portable callsigns now count as the same station. Typing RK3DWA finds the RK3DWA/3, /P and /MM contacts too, and the other way round — before, the history only appeared if you typed the exact form. Can be turned off in Settings → General; contest dupe checking is unaffected and stays exact.",
|
"Worked before: an operator's portable callsigns now count as the same station. Typing RK3DWA finds the RK3DWA/3, /P and /MM contacts too, and the other way round — before, the history only appeared if you typed the exact form. Can be turned off in Settings → General; contest dupe checking is unaffected and stays exact.",
|
||||||
"QSO editor: the OpsLog card now appears with the other confirmations. It has its own Sent / Received row in the QSL Info table, next to QSL, LoTW, eQSL and the rest, and the \"QSL received\" tick moved there from Contact's details — with its PSE QSL / TNX indicator, which is unchanged. Sent stays read-only: OpsLog stamps it when the card actually goes out.",
|
"QSO editor: the OpsLog card now appears with the other confirmations. It has its own Sent / Received row in the QSL Info table, next to QSL, LoTW, eQSL and the rest, and the \"QSL received\" tick moved there from Contact's details — with its PSE QSL / TNX indicator, which is unchanged. Sent stays read-only: OpsLog stamps it when the card actually goes out.",
|
||||||
"QSL card: the {qso.pse_tnx} stamp now prints \"TNX QSL\" instead of just \"TNX\", to read as the counterpart of \"PSE QSL\"."
|
"QSL card: the {qso.pse_tnx} stamp now prints \"TNX QSL\" instead of just \"TNX\", to read as the counterpart of \"PSE QSL\".",
|
||||||
|
"Window: closing OpsLog while it is minimised no longer loses its size and position. Windows parks a minimised window at -32000,-32000 with a stub size, and that was what got saved — so the next launch found geometry no screen could hold, discarded it, and reopened at the default place. The stored geometry is now kept instead; it repairs itself the first time you close a window that is on screen."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Déjà contacté : les indicatifs portables d'un opérateur comptent désormais comme la même station. Taper RK3DWA retrouve aussi les QSO en RK3DWA/3, /P et /MM, et inversement — avant, l'historique n'apparaissait que si tu tapais la forme exacte. Désactivable dans Réglages → Général ; le contrôle de doublon en concours n'est pas touché et reste strict.",
|
"Déjà contacté : les indicatifs portables d'un opérateur comptent désormais comme la même station. Taper RK3DWA retrouve aussi les QSO en RK3DWA/3, /P et /MM, et inversement — avant, l'historique n'apparaissait que si tu tapais la forme exacte. Désactivable dans Réglages → Général ; le contrôle de doublon en concours n'est pas touché et reste strict.",
|
||||||
"Éditeur de QSO : la carte OpsLog rejoint les autres confirmations. Elle a sa propre ligne Envoyée / Reçue dans le tableau de l'onglet QSL Info, à côté de QSL, LoTW, eQSL et les autres, et la case « QSL reçue » y a été déplacée depuis Détails du contact — avec son indicateur PSE QSL / TNX, inchangé. « Envoyée » reste en lecture seule : OpsLog l'inscrit quand la carte part réellement.",
|
"Éditeur de QSO : la carte OpsLog rejoint les autres confirmations. Elle a sa propre ligne Envoyée / Reçue dans le tableau de l'onglet QSL Info, à côté de QSL, LoTW, eQSL et les autres, et la case « QSL reçue » y a été déplacée depuis Détails du contact — avec son indicateur PSE QSL / TNX, inchangé. « Envoyée » reste en lecture seule : OpsLog l'inscrit quand la carte part réellement.",
|
||||||
"Carte QSL : le tampon {qso.pse_tnx} imprime désormais « TNX QSL » et non plus « TNX » seul, pour répondre à « PSE QSL »."
|
"Carte QSL : le tampon {qso.pse_tnx} imprime désormais « TNX QSL » et non plus « TNX » seul, pour répondre à « PSE QSL ».",
|
||||||
|
"Fenêtre : fermer OpsLog alors qu'il est réduit ne fait plus perdre sa taille et sa position. Windows range une fenêtre réduite en -32000,-32000 avec une taille factice, et c'est cela qui était enregistré — au lancement suivant, OpsLog trouvait une géométrie qu'aucun écran ne peut contenir, la rejetait et rouvrait à l'emplacement par défaut. La géométrie déjà enregistrée est désormais conservée ; cela se répare tout seul à la première fermeture d'une fenêtre visible à l'écran."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,10 @@
|
|||||||
"match_by": "description"
|
"match_by": "description"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dxcc_filter": null,
|
"dxcc_filter": [
|
||||||
|
15,
|
||||||
|
54
|
||||||
|
],
|
||||||
"valid_bands": [
|
"valid_bands": [
|
||||||
"160m",
|
"160m",
|
||||||
"60m",
|
"60m",
|
||||||
@@ -43,7 +46,7 @@
|
|||||||
],
|
],
|
||||||
"total": 0,
|
"total": 0,
|
||||||
"builtin": true,
|
"builtin": true,
|
||||||
"version": 1
|
"version": 2
|
||||||
},
|
},
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user