diff --git a/crates/bevy_winit/src/system.rs b/crates/bevy_winit/src/system.rs index 84975bf1e3e62..48b0a5ef6e40f 100644 --- a/crates/bevy_winit/src/system.rs +++ b/crates/bevy_winit/src/system.rs @@ -15,6 +15,8 @@ use bevy_window::{ use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; use winit::event_loop::ActiveEventLoop; +use bevy_app::AppExit; +use bevy_ecs::prelude::EventReader; use bevy_ecs::query::With; #[cfg(target_os = "ios")] use winit::platform::ios::WindowExtIOS; @@ -116,14 +118,16 @@ pub fn create_windows( } } +#[allow(clippy::too_many_arguments)] pub(crate) fn despawn_windows( closing: Query>, mut closed: RemovedComponents, - window_entities: Query<&Window>, + window_entities: Query>, mut closing_events: EventWriter, mut closed_events: EventWriter, mut winit_windows: NonSendMut, mut windows_to_drop: Local>>, + mut exit_events: EventReader, ) { // Drop all the windows that are waiting to be closed windows_to_drop.clear(); @@ -146,6 +150,15 @@ pub(crate) fn despawn_windows( closed_events.send(WindowClosed { window }); } } + + // On macOS, when exiting, we need to tell the rendering thread the windows are about to + // close to ensure that they are dropped on the main thread. Otherwise, the app will hang. + if !exit_events.is_empty() { + exit_events.clear(); + for window in window_entities.iter() { + closing_events.send(WindowClosing { window }); + } + } } /// The cached state of the window so we can check which properties were changed from within the app.