From 6556cde24676a7b78e509a5d1c4490929cb12baf 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 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/macos/app_state.rs | 7 +++++-- src/platform_impl/macos/event_loop.rs | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 01fc4c012..d0c6189e5 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -54,3 +54,4 @@ changelog entry. - On Wayland, fixed a crash when consequently calling `set_cursor_grab` without pointer focus. - On Wayland, ensure that external event loop is woken-up when using pump_events and integrating via `FD`. - On Wayland, apply fractional scaling to custom cursors. +- On macOS, fixed `run_app_on_demand` returning without closing open windows. diff --git a/src/platform_impl/macos/app_state.rs b/src/platform_impl/macos/app_state.rs index 35076b6d1..dd2ccd116 100644 --- a/src/platform_impl/macos/app_state.rs +++ b/src/platform_impl/macos/app_state.rs @@ -11,7 +11,7 @@ use objc2_app_kit::{ use objc2_foundation::{MainThreadMarker, NSNotification, NSObject, NSObjectProtocol}; use super::event_handler::EventHandler; -use super::event_loop::{stop_app_immediately, ActiveEventLoop, PanicInfo}; +use super::event_loop::{notify_windows_of_exit, stop_app_immediately, ActiveEventLoop, PanicInfo}; use super::observer::{EventLoopWaker, RunLoop}; use super::{menu, WindowId, DEVICE_ID}; use crate::event::{DeviceEvent, Event, StartCause, WindowEvent}; @@ -165,7 +165,9 @@ impl ApplicationDelegate { fn will_terminate(&self, _notification: &NSNotification) { trace_scope!("applicationWillTerminate:"); - // TODO: Notify every window that it will be destroyed, like done in iOS? + let mtm = MainThreadMarker::from(self); + let app = NSApplication::sharedApplication(mtm); + notify_windows_of_exit(&app); self.internal_exit(); } @@ -392,6 +394,7 @@ impl ApplicationDelegate { if self.exiting() { let app = NSApplication::sharedApplication(mtm); stop_app_immediately(&app); + notify_windows_of_exit(&app); } if self.ivars().stop_before_wait.get() { diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index cb0620ac9..8bc69f28c 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -421,6 +421,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]