fix(window): persist window geometry on normal quit, not just restart (#4810) (#4817)

This commit is contained in:
Mega Mind
2026-07-13 20:09:08 +04:00
committed by GitHub
parent e1914d209b
commit 59cb250e99
2 changed files with 47 additions and 0 deletions
+25
View File
@@ -3946,6 +3946,19 @@ pub fn run() {
"[window] close requested on main window — hiding to tray"
);
api.prevent_close();
// Persist geometry now, while the window handle is still
// reachable. On Windows the hide below is a raw SW_HIDE on the
// OS frame, after which `get_webview_window("main")` returns
// `None` until the window is shown again (#1607). If the user
// then picks tray "Quit" while hidden, the ExitRequested save
// finds no window and nothing is persisted, so the next launch
// falls back to the default geometry (#4810). Saving here
// captures the last on-screen size/position before it becomes
// unreachable; ExitRequested still saves for the shown-window
// quit paths (`save_main` is best-effort and idempotent).
if let Some(window) = app_handle.get_webview_window("main") {
window_state::save_main(&window);
}
// Hide the OS top-level Chrome_WidgetWin_1 frame via
// EnumWindows + SW_HIDE — full hide-to-tray as PR #1548
// intended. `window.hide()` and `window.minimize()` through
@@ -3966,6 +3979,18 @@ pub fn run() {
}
}
RunEvent::ExitRequested { .. } => {
// Persist the main window's geometry on every clean quit
// (Cmd+Q, tray "Quit", dock quit, or the frontend
// `app_quit` command) so the next launch restores the
// user's size + position. Previously `save_main` ran only
// on the identity-flip `restart_app` path (#900): a normal
// quit never saved, so the window always reopened at the
// default small centered size (#4810). `save_main` is
// best-effort and idempotent — safe to also run here even
// though `restart_app` saves before it triggers exit.
if let Some(window) = app_handle.get_webview_window("main") {
window_state::save_main(&window);
}
// Run our cleanup BEFORE CEF's own Exit handler does
// `close_all_windows() → cef::shutdown()`. Doing this in
// RunEvent::Exit instead races CEF's teardown and the
+22
View File
@@ -378,6 +378,28 @@ fn clamp_to_work_area(
mod tests {
use super::*;
#[test]
fn window_state_toml_roundtrips() {
// `save_main` serializes this record to `window_state.toml` and
// `restore_main` parses it back on the next launch. The whole
// save-on-quit → restore-on-launch feature (#4810) hinges on this
// record surviving the round trip byte-for-byte, including a
// negative x from a monitor left of the primary. Guards the
// on-disk contract against an accidental serde/rename change.
let state = WindowState {
x: -1920,
y: 100,
width: 1280,
height: 800,
};
let raw = toml::to_string_pretty(&state).expect("serialize");
let parsed: WindowState = toml::from_str(&raw).expect("parse");
assert_eq!(
(parsed.x, parsed.y, parsed.width, parsed.height),
(state.x, state.y, state.width, state.height)
);
}
fn wa(x: i32, y: i32, width: u32, height: u32) -> WorkArea {
WorkArea {
x,