macOS: the red close button sends the window to the Dock and the app keeps running (Dock click restores, Cmd+Q quits); a pane shown after being parked is shown before it is sized and told to re-lay out (X drew an empty timeline)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CRTkafa 2026-10-02 00:52:24 +07:00
parent e75465900b
commit 82d333e350
2 changed files with 39 additions and 4 deletions

View file

@ -1514,14 +1514,37 @@ impl App {
})
.build(context)
.unwrap_or_else(|error| panic!("Failed to launch {}: {error}", config.title))
.run(|_, event| log_run_event(&event));
.run(|app, event| on_run_event(app, &event));
}
}
/// Why the app is going away, for `--diag` ([`crate::diag`]): an exit request with its code (None is a
/// Run-loop events: the macOS close-hides rule, and why the app is going away for `--diag` ([`crate::diag`]): an exit request with its code (None is a
/// polite quit from outside: Cmd+Q, the Dock, or another app such as an auto-quitter closing the last
/// window), window close/destroy events and the final exit. Nothing is written without diagnostics.
fn log_run_event(event: &tauri::RunEvent) {
fn on_run_event(app: &AppHandle, event: &tauri::RunEvent) {
// macOS: the red close button sends the main window to the Dock (minimized, not hidden: an auto-quitter
// such as Swift Quit terminates an app whose window list goes empty, but not one with a minimized window)
// and the app keeps running; a Dock click shows it
// again; Cmd+Q still quits (an exit request, not a window close).
#[cfg(target_os = "macos")]
match event {
tauri::RunEvent::WindowEvent { label, event: tauri::WindowEvent::CloseRequested { api, .. }, .. } if label == policy::MAIN_LABEL => {
api.prevent_close();
if let Some(window) = app.get_window(policy::MAIN_LABEL) {
let _ = window.minimize();
}
}
tauri::RunEvent::Reopen { .. } => {
if let Some(window) = app.get_window(policy::MAIN_LABEL) {
let _ = window.unminimize();
let _ = window.show();
let _ = window.set_focus();
}
}
_ => {}
}
#[cfg(not(target_os = "macos"))]
let _ = app;
match event {
tauri::RunEvent::ExitRequested { code, .. } => crate::diag::log("host", &format!("exit requested code={code:?}")),
tauri::RunEvent::Exit => crate::diag::log("host", "exit"),

View file

@ -919,11 +919,23 @@ pub fn place_tab<R: Runtime>(webview: &Webview<R>, rect: crate::layout::Rect, vi
let was_visible = placed.was_visible(webview.label());
(placed.place(webview.label(), rect, visible), was_visible)
};
// macOS: a pane that comes back from hidden (parked at 1x1) and is resized while still hidden keeps
// the page's old viewport (X drew an empty timeline until the next real resize). Show it first, then
// size it, then tell the page its window changed.
#[cfg(target_os = "macos")]
let reveal = changed.visible && visible;
#[cfg(not(target_os = "macos"))]
let reveal = false;
if reveal {
set_tab_visible(webview, visible, parked, was_visible);
}
if changed.bounds {
let (x, y, width, height) = rect;
place_child(webview, x, y, width, height);
}
if changed.visible {
if reveal {
let _ = webview.eval("window.dispatchEvent(new Event('resize'));");
} else if changed.visible {
set_tab_visible(webview, visible, parked, was_visible);
} else {
set_memory_target(webview, visible, parked);