@@ -38,10 +38,10 @@ use bevy_utils::{
38
38
Duration , Instant ,
39
39
} ;
40
40
use bevy_window:: {
41
- exit_on_all_closed, CursorEntered , CursorLeft , CursorMoved , FileDragAndDrop , Ime ,
42
- ReceivedCharacter , RequestRedraw , Window , WindowBackendScaleFactorChanged ,
43
- WindowCloseRequested , WindowCreated , WindowDestroyed , WindowFocused , WindowMoved ,
44
- WindowResized , WindowScaleFactorChanged , WindowThemeChanged ,
41
+ exit_on_all_closed, ApplicationLifetime , CursorEntered , CursorLeft , CursorMoved ,
42
+ FileDragAndDrop , Ime , ReceivedCharacter , RequestRedraw , Window ,
43
+ WindowBackendScaleFactorChanged , WindowCloseRequested , WindowCreated , WindowDestroyed ,
44
+ WindowFocused , WindowMoved , WindowResized , WindowScaleFactorChanged , WindowThemeChanged ,
45
45
} ;
46
46
#[ cfg( target_os = "android" ) ]
47
47
use bevy_window:: { PrimaryWindow , RawHandleWrapper } ;
@@ -279,6 +279,7 @@ struct WindowAndInputEventWriters<'w> {
279
279
window_moved : EventWriter < ' w , WindowMoved > ,
280
280
window_theme_changed : EventWriter < ' w , WindowThemeChanged > ,
281
281
window_destroyed : EventWriter < ' w , WindowDestroyed > ,
282
+ lifetime : EventWriter < ' w , ApplicationLifetime > ,
282
283
keyboard_input : EventWriter < ' w , KeyboardInput > ,
283
284
character_input : EventWriter < ' w , ReceivedCharacter > ,
284
285
mouse_button_input : EventWriter < ' w , MouseButtonInput > ,
@@ -298,8 +299,8 @@ struct WindowAndInputEventWriters<'w> {
298
299
/// Persistent state that is used to run the [`App`] according to the current
299
300
/// [`UpdateMode`].
300
301
struct WinitAppRunnerState {
301
- /// Is `true` if the app is running and not suspended .
302
- is_active : bool ,
302
+ /// Current active state of the app.
303
+ active : ActiveState ,
303
304
/// Is `true` if a new [`WindowEvent`] has been received since the last update.
304
305
window_event_received : bool ,
305
306
/// Is `true` if the app has requested a redraw since the last update.
@@ -312,10 +313,28 @@ struct WinitAppRunnerState {
312
313
scheduled_update : Option < Instant > ,
313
314
}
314
315
316
+ #[ derive( PartialEq , Eq ) ]
317
+ enum ActiveState {
318
+ NotYetStarted ,
319
+ Active ,
320
+ Suspended ,
321
+ WillSuspend ,
322
+ }
323
+
324
+ impl ActiveState {
325
+ #[ inline]
326
+ fn should_run ( & self ) -> bool {
327
+ match self {
328
+ ActiveState :: NotYetStarted | ActiveState :: Suspended => false ,
329
+ ActiveState :: Active | ActiveState :: WillSuspend => true ,
330
+ }
331
+ }
332
+ }
333
+
315
334
impl Default for WinitAppRunnerState {
316
335
fn default ( ) -> Self {
317
336
Self {
318
- is_active : false ,
337
+ active : ActiveState :: NotYetStarted ,
319
338
window_event_received : false ,
320
339
redraw_requested : false ,
321
340
wait_elapsed : false ,
@@ -700,19 +719,23 @@ pub fn winit_runner(mut app: App) {
700
719
} ) ;
701
720
}
702
721
event:: Event :: Suspended => {
703
- runner_state. is_active = false ;
704
- #[ cfg( target_os = "android" ) ]
705
- {
706
- // Remove the `RawHandleWrapper` from the primary window.
707
- // This will trigger the surface destruction.
708
- let mut query = app. world . query_filtered :: < Entity , With < PrimaryWindow > > ( ) ;
709
- let entity = query. single ( & app. world ) ;
710
- app. world . entity_mut ( entity) . remove :: < RawHandleWrapper > ( ) ;
711
- * control_flow = ControlFlow :: Wait ;
712
- }
722
+ let ( mut event_writers, _, _) = event_writer_system_state. get_mut ( & mut app. world ) ;
723
+ event_writers. lifetime . send ( ApplicationLifetime :: Suspended ) ;
724
+ // Mark the state as `WillSuspend`. This will let the schedule run one last time
725
+ // before actually suspending to let the application react
726
+ runner_state. active = ActiveState :: WillSuspend ;
713
727
}
714
728
event:: Event :: Resumed => {
715
- runner_state. is_active = true ;
729
+ let ( mut event_writers, _, _) = event_writer_system_state. get_mut ( & mut app. world ) ;
730
+ match runner_state. active {
731
+ ActiveState :: NotYetStarted => {
732
+ event_writers. lifetime . send ( ApplicationLifetime :: Started ) ;
733
+ }
734
+ _ => {
735
+ event_writers. lifetime . send ( ApplicationLifetime :: Resumed ) ;
736
+ }
737
+ }
738
+ runner_state. active = ActiveState :: Active ;
716
739
#[ cfg( target_os = "android" ) ]
717
740
{
718
741
// Get windows that are cached but without raw handles. Those window were already created, but got their
@@ -754,7 +777,20 @@ pub fn winit_runner(mut app: App) {
754
777
}
755
778
}
756
779
event:: Event :: MainEventsCleared => {
757
- if runner_state. is_active {
780
+ if runner_state. active . should_run ( ) {
781
+ if runner_state. active == ActiveState :: WillSuspend {
782
+ runner_state. active = ActiveState :: Suspended ;
783
+ #[ cfg( target_os = "android" ) ]
784
+ {
785
+ // Remove the `RawHandleWrapper` from the primary window.
786
+ // This will trigger the surface destruction.
787
+ let mut query =
788
+ app. world . query_filtered :: < Entity , With < PrimaryWindow > > ( ) ;
789
+ let entity = query. single ( & app. world ) ;
790
+ app. world . entity_mut ( entity) . remove :: < RawHandleWrapper > ( ) ;
791
+ * control_flow = ControlFlow :: Wait ;
792
+ }
793
+ }
758
794
let ( config, windows) = focused_windows_state. get ( & app. world ) ;
759
795
let focused = windows. iter ( ) . any ( |window| window. focused ) ;
760
796
let should_update = match config. update_mode ( focused) {
0 commit comments