@@ -15,6 +15,8 @@ use bevy_window::{
1515use winit:: dpi:: { LogicalPosition , LogicalSize , PhysicalPosition , PhysicalSize } ;
1616use winit:: event_loop:: ActiveEventLoop ;
1717
18+ use bevy_app:: AppExit ;
19+ use bevy_ecs:: prelude:: EventReader ;
1820use bevy_ecs:: query:: With ;
1921#[ cfg( target_os = "ios" ) ]
2022use winit:: platform:: ios:: WindowExtIOS ;
@@ -116,14 +118,16 @@ pub fn create_windows<F: QueryFilter + 'static>(
116118 }
117119}
118120
121+ #[ allow( clippy:: too_many_arguments) ]
119122pub ( crate ) fn despawn_windows (
120123 closing : Query < Entity , With < ClosingWindow > > ,
121124 mut closed : RemovedComponents < Window > ,
122- window_entities : Query < & Window > ,
125+ window_entities : Query < Entity , With < Window > > ,
123126 mut closing_events : EventWriter < WindowClosing > ,
124127 mut closed_events : EventWriter < WindowClosed > ,
125128 mut winit_windows : NonSendMut < WinitWindows > ,
126129 mut windows_to_drop : Local < Vec < WindowWrapper < winit:: window:: Window > > > ,
130+ mut exit_events : EventReader < AppExit > ,
127131) {
128132 // Drop all the windows that are waiting to be closed
129133 windows_to_drop. clear ( ) ;
@@ -146,6 +150,15 @@ pub(crate) fn despawn_windows(
146150 closed_events. send ( WindowClosed { window } ) ;
147151 }
148152 }
153+
154+ // On macOS, when exiting, we need to tell the rendering thread the windows are about to
155+ // close to ensure that they are dropped on the main thread. Otherwise, the app will hang.
156+ if !exit_events. is_empty ( ) {
157+ exit_events. clear ( ) ;
158+ for window in window_entities. iter ( ) {
159+ closing_events. send ( WindowClosing { window } ) ;
160+ }
161+ }
149162}
150163
151164/// The cached state of the window so we can check which properties were changed from within the app.
0 commit comments