SDL: Keep the lifecycle observer active while there are windows active

From 2c7b7d1d33748b6c27eaf57cc5d96ce6c4c64a87 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 14 Jan 2025 19:41:02 -0800
Subject: [PATCH] Keep the lifecycle observer active while there are windows
 active

Fixes https://github.com/libsdl-org/SDL/issues/11627
---
 src/video/SDL_video.c             | 12 ++++++++++++
 src/video/uikit/SDL_uikitevents.m | 13 +++++++++++--
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 3b5fa4d84d7fd..bbf99ecfa65fd 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -172,6 +172,10 @@ extern bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window);
 extern bool Cocoa_SetWindowFullscreenSpace(SDL_Window *window, bool state, bool blocking);
 #endif
 
+#ifdef SDL_VIDEO_DRIVER_UIKIT
+extern void SDL_UpdateLifecycleObserver(void);
+#endif
+
 static void SDL_CheckWindowDisplayChanged(SDL_Window *window);
 static void SDL_CheckWindowDisplayScaleChanged(SDL_Window *window);
 static void SDL_CheckWindowSafeAreaChanged(SDL_Window *window);
@@ -2467,6 +2471,10 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
     // Make sure window pixel size is up to date
     SDL_CheckWindowPixelSizeChanged(window);
 
+#ifdef SDL_VIDEO_DRIVER_UIKIT
+    SDL_UpdateLifecycleObserver();
+#endif
+
     SDL_ClearError();
 
     return window;
@@ -4198,6 +4206,10 @@ void SDL_DestroyWindow(SDL_Window *window)
     }
 
     SDL_free(window);
+
+#ifdef SDL_VIDEO_DRIVER_UIKIT
+    SDL_UpdateLifecycleObserver();
+#endif
 }
 
 bool SDL_ScreenSaverEnabled(void)
diff --git a/src/video/uikit/SDL_uikitevents.m b/src/video/uikit/SDL_uikitevents.m
index 8479b4f44163e..86224f7948b2a 100644
--- a/src/video/uikit/SDL_uikitevents.m
+++ b/src/video/uikit/SDL_uikitevents.m
@@ -44,7 +44,16 @@ @implementation SDL_LifecycleObserver
 - (void)update
 {
     NSNotificationCenter *notificationCenter = NSNotificationCenter.defaultCenter;
-    if ((UIKit_EventPumpEnabled || SDL_HasMainCallbacks()) && !self.isObservingNotifications) {
+    bool wants_observation = (UIKit_EventPumpEnabled || SDL_HasMainCallbacks());
+    if (!wants_observation) {
+        // Make sure no windows have active animation callbacks
+        int num_windows = 0;
+        SDL_free(SDL_GetWindows(&num_windows));
+        if (num_windows > 0) {
+            wants_observation = true;
+        }
+    }
+    if (wants_observation && !self.isObservingNotifications) {
         self.isObservingNotifications = YES;
         [notificationCenter addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
         [notificationCenter addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil];
@@ -58,7 +67,7 @@ - (void)update
                                    name:UIApplicationDidChangeStatusBarOrientationNotification
                                  object:nil];
 #endif
-    } else if (!UIKit_EventPumpEnabled && !SDL_HasMainCallbacks() && self.isObservingNotifications) {
+    } else if (!wants_observation && self.isObservingNotifications) {
         self.isObservingNotifications = NO;
         [notificationCenter removeObserver:self];
     }