From 8db4a9cc61df03b130b313eb9a297fa7a214e8c3 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 17 Mar 2025 11:29:53 +0100 Subject: [PATCH] macOS: Close windows automatically when exiting (#4154) This disallows carrying over open windows between calls of `run_app_on_demand` (which wasn't intended to be supported anyhow). --- src/changelog/unreleased.md | 1 + src/platform_impl/apple/appkit/app_state.rs | 6 ++++-- src/platform_impl/apple/appkit/event_loop.rs | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 792e5759..df1261cb 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -241,3 +241,4 @@ changelog entry. - On Windows, fixed ~500 ms pause when clicking the title bar during continuous redraw. - On macos, `WindowExtMacOS::set_simple_fullscreen` now honors `WindowExtMacOS::set_borderless_game` - On X11 and Wayland, fixed pump_events with `Some(Duration::Zero)` blocking with `Wait` polling mode +- On macOS, fixed `run_app_on_demand` returning without closing open windows. diff --git a/src/platform_impl/apple/appkit/app_state.rs b/src/platform_impl/apple/appkit/app_state.rs index e260ef49..f59bbab2 100644 --- a/src/platform_impl/apple/appkit/app_state.rs +++ b/src/platform_impl/apple/appkit/app_state.rs @@ -11,7 +11,7 @@ use objc2_foundation::NSNotification; use super::super::event_handler::EventHandler; use super::super::event_loop_proxy::EventLoopProxy; -use super::event_loop::{stop_app_immediately, ActiveEventLoop, PanicInfo}; +use super::event_loop::{notify_windows_of_exit, stop_app_immediately, ActiveEventLoop, PanicInfo}; use super::menu; use super::observer::{EventLoopWaker, RunLoop}; use crate::application::ApplicationHandler; @@ -156,7 +156,8 @@ impl AppState { pub fn will_terminate(self: &Rc, _notification: &NSNotification) { trace_scope!("NSApplicationWillTerminateNotification"); - // TODO: Notify every window that it will be destroyed, like done in iOS? + let app = NSApplication::sharedApplication(self.mtm); + notify_windows_of_exit(&app); self.event_handler.terminate(); self.internal_exit(); } @@ -365,6 +366,7 @@ impl AppState { if self.exiting() { let app = NSApplication::sharedApplication(self.mtm); stop_app_immediately(&app); + notify_windows_of_exit(&app); } if self.stop_before_wait.get() { diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index 5baecb7e..849e40a0 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -407,6 +407,22 @@ pub(super) fn stop_app_immediately(app: &NSApplication) { }); } +/// Tell all windows to close. +/// +/// This will synchronously trigger `WindowEvent::Destroyed` within +/// `windowWillClose:`, giving the application one last chance to handle +/// those events. It doesn't matter if the user also ends up closing the +/// windows in `Window`'s `Drop` impl, once a window has been closed once, it +/// stays closed. +/// +/// This ensures that no windows linger on after the event loop has exited, +/// see . +pub(super) fn notify_windows_of_exit(app: &NSApplication) { + for window in app.windows() { + window.close(); + } +} + /// Catches panics that happen inside `f` and when a panic /// happens, stops the `sharedApplication` #[inline]