mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-11-10 20:45:05 +00:00
Added support for the UIScene life cycle on Apple platforms
Fixes https://github.com/libsdl-org/SDL/issues/12680
This commit is contained in:
@@ -97,6 +97,8 @@ typedef Uint32 SDL_WindowID;
|
||||
* uninitialized will either return the user provided value, if one was set
|
||||
* prior to initialization, or NULL. See docs/README-wayland.md for more
|
||||
* information.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER "SDL.video.wayland.wl_display"
|
||||
|
||||
|
||||
@@ -29,6 +29,15 @@
|
||||
|
||||
@end
|
||||
|
||||
API_AVAILABLE(ios(13.0))
|
||||
@interface SDLUIKitSceneDelegate : NSObject <UIApplicationDelegate, UIWindowSceneDelegate>
|
||||
|
||||
+ (NSString *)getSceneDelegateClassName;
|
||||
|
||||
- (void)hideLaunchScreen;
|
||||
|
||||
@end
|
||||
|
||||
@interface SDLUIKitDelegate : NSObject <UIApplicationDelegate>
|
||||
|
||||
+ (id)sharedAppDelegate;
|
||||
|
||||
@@ -59,7 +59,15 @@ int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserve
|
||||
|
||||
// Give over control to run loop, SDLUIKitDelegate will handle most things from here
|
||||
@autoreleasepool {
|
||||
UIApplicationMain(argc, argv, nil, [SDLUIKitDelegate getAppDelegateClassName]);
|
||||
NSString *name = nil;
|
||||
|
||||
if (@available(iOS 13.0, tvOS 13.0, *)) {
|
||||
name = [SDLUIKitSceneDelegate getSceneDelegateClassName];
|
||||
}
|
||||
if (!name) {
|
||||
name = [SDLUIKitDelegate getAppDelegateClassName];
|
||||
}
|
||||
UIApplicationMain(argc, argv, nil, name);
|
||||
}
|
||||
|
||||
// free the memory we used to hold copies of argc and argv
|
||||
@@ -162,6 +170,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
@end
|
||||
#endif // !SDL_PLATFORM_TVOS
|
||||
|
||||
|
||||
@interface SDLLaunchScreenController ()
|
||||
|
||||
#ifndef SDL_PLATFORM_TVOS
|
||||
@@ -343,7 +352,170 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
}
|
||||
#endif // !SDL_PLATFORM_TVOS
|
||||
|
||||
@end
|
||||
@end // SDLLaunchScreenController
|
||||
|
||||
|
||||
API_AVAILABLE(ios(13.0))
|
||||
@implementation SDLUIKitSceneDelegate
|
||||
{
|
||||
UIWindow *launchWindow;
|
||||
}
|
||||
|
||||
+ (NSString *)getSceneDelegateClassName
|
||||
{
|
||||
return @"SDLUIKitSceneDelegate";
|
||||
}
|
||||
|
||||
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
|
||||
{
|
||||
if (![scene isKindOfClass:[UIWindowScene class]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
windowScene.delegate = self;
|
||||
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
|
||||
#ifdef SDL_IPHONE_LAUNCHSCREEN
|
||||
UIViewController *vc = nil;
|
||||
NSString *screenname = nil;
|
||||
|
||||
#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS)
|
||||
screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
|
||||
|
||||
if (screenname) {
|
||||
@try {
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:screenname bundle:bundle];
|
||||
__auto_type storyboardVc = [storyboard instantiateInitialViewController];
|
||||
vc = [[SDLLaunchStoryboardViewController alloc] initWithStoryboardViewController:storyboardVc];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
// Do nothing (there's more code to execute below).
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vc == nil) {
|
||||
vc = [[SDLLaunchScreenController alloc] initWithNibName:screenname bundle:bundle];
|
||||
}
|
||||
|
||||
if (vc.view) {
|
||||
#ifdef SDL_PLATFORM_VISIONOS
|
||||
CGRect viewFrame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT);
|
||||
#else
|
||||
CGRect viewFrame = windowScene.coordinateSpace.bounds;
|
||||
#endif
|
||||
launchWindow = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
launchWindow.frame = viewFrame;
|
||||
|
||||
launchWindow.windowLevel = UIWindowLevelNormal + 1.0;
|
||||
launchWindow.hidden = NO;
|
||||
launchWindow.rootViewController = vc;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set working directory to resource path
|
||||
[[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
|
||||
|
||||
// Handle any connection options (like opening URLs)
|
||||
for (NSUserActivity *activity in connectionOptions.userActivities) {
|
||||
if (activity.webpageURL) {
|
||||
[self handleURL:activity.webpageURL];
|
||||
}
|
||||
}
|
||||
|
||||
for (UIOpenURLContext *urlContext in connectionOptions.URLContexts) {
|
||||
[self handleURL:urlContext.URL];
|
||||
}
|
||||
|
||||
SDL_SetMainReady();
|
||||
[self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:0.0];
|
||||
}
|
||||
|
||||
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
|
||||
{
|
||||
for (UIOpenURLContext *context in URLContexts) {
|
||||
[self handleURL:context.URL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sceneDidBecomeActive:(UIScene *)scene
|
||||
{
|
||||
SDL_OnApplicationDidEnterForeground();
|
||||
}
|
||||
|
||||
- (void)sceneWillResignActive:(UIScene *)scene
|
||||
{
|
||||
SDL_OnApplicationWillEnterBackground();
|
||||
}
|
||||
|
||||
- (void)sceneWillEnterForeground:(UIScene *)scene
|
||||
{
|
||||
SDL_OnApplicationWillEnterForeground();
|
||||
}
|
||||
|
||||
- (void)sceneDidEnterBackground:(UIScene *)scene
|
||||
{
|
||||
SDL_OnApplicationDidEnterBackground();
|
||||
}
|
||||
|
||||
- (void)handleURL:(NSURL *)url
|
||||
{
|
||||
const char *sourceApplicationCString = NULL;
|
||||
NSURL *fileURL = url.filePathURL;
|
||||
if (fileURL != nil) {
|
||||
SDL_SendDropFile(NULL, sourceApplicationCString, fileURL.path.UTF8String);
|
||||
} else {
|
||||
SDL_SendDropFile(NULL, sourceApplicationCString, url.absoluteString.UTF8String);
|
||||
}
|
||||
SDL_SendDropComplete(NULL);
|
||||
}
|
||||
|
||||
- (void)hideLaunchScreen
|
||||
{
|
||||
UIWindow *window = launchWindow;
|
||||
|
||||
if (!window || window.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
launchWindow = nil;
|
||||
|
||||
[UIView animateWithDuration:0.2
|
||||
animations:^{
|
||||
window.alpha = 0.0;
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
window.hidden = YES;
|
||||
UIKit_ForceUpdateHomeIndicator();
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)postFinishLaunch
|
||||
{
|
||||
[self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0];
|
||||
|
||||
SDL_SetiOSEventPump(true);
|
||||
exit_status = forward_main(forward_argc, forward_argv);
|
||||
SDL_SetiOSEventPump(false);
|
||||
|
||||
if (launchWindow) {
|
||||
launchWindow.hidden = YES;
|
||||
launchWindow = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0))
|
||||
{
|
||||
// This doesn't appear to be called, but it needs to be implemented to signal that we support the UIScene life cycle
|
||||
UISceneConfiguration *config = [[UISceneConfiguration alloc] initWithName:@"SDLSceneConfiguration" sessionRole:connectingSceneSession.role];
|
||||
config.delegateClass = [SDLUIKitSceneDelegate class];
|
||||
return config;
|
||||
}
|
||||
|
||||
@end // SDLUIKitSceneDelegate
|
||||
|
||||
|
||||
@implementation SDLUIKitDelegate
|
||||
{
|
||||
@@ -514,6 +686,6 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@end // SDLUIKitDelegate
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_UIKIT
|
||||
|
||||
@@ -152,6 +152,43 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow
|
||||
return true;
|
||||
}
|
||||
|
||||
API_AVAILABLE(ios(13.0))
|
||||
static UIWindowScene *GetActiveWindowScene(void)
|
||||
{
|
||||
if (@available(iOS 13.0, tvOS 13.0, *)) {
|
||||
NSSet<UIScene *> *connectedScenes = [UIApplication sharedApplication].connectedScenes;
|
||||
|
||||
// First, try to find an active foreground scene
|
||||
for (UIScene *scene in connectedScenes) {
|
||||
if ([scene isKindOfClass:[UIWindowScene class]]) {
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
if (windowScene.activationState == UISceneActivationStateForegroundActive) {
|
||||
return windowScene;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no active scene, return any foreground scene
|
||||
for (UIScene *scene in connectedScenes) {
|
||||
if ([scene isKindOfClass:[UIWindowScene class]]) {
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
if (windowScene.activationState == UISceneActivationStateForegroundInactive) {
|
||||
return windowScene;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort: return first window scene
|
||||
for (UIScene *scene in connectedScenes) {
|
||||
if ([scene isKindOfClass:[UIWindowScene class]]) {
|
||||
return (UIWindowScene *)scene;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
|
||||
{
|
||||
@autoreleasepool {
|
||||
@@ -197,13 +234,21 @@ bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti
|
||||
}
|
||||
#endif // !SDL_PLATFORM_TVOS
|
||||
|
||||
UIWindow *uiwindow = nil;
|
||||
if (@available(iOS 13.0, tvOS 13.0, *)) {
|
||||
UIWindowScene *scene = GetActiveWindowScene();
|
||||
if (scene) {
|
||||
uiwindow = [[SDL_uikitwindow alloc] initWithWindowScene:scene];
|
||||
}
|
||||
}
|
||||
if (!uiwindow) {
|
||||
// ignore the size user requested, and make a fullscreen window
|
||||
// !!! FIXME: can we have a smaller view?
|
||||
#ifdef SDL_PLATFORM_VISIONOS
|
||||
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:CGRectMake(window->x, window->y, window->w, window->h)];
|
||||
uiwindow = [[SDL_uikitwindow alloc] initWithFrame:CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT)];
|
||||
#else
|
||||
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
|
||||
uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
|
||||
#endif
|
||||
}
|
||||
|
||||
// put the window on an external display if appropriate.
|
||||
#ifndef SDL_PLATFORM_VISIONOS
|
||||
|
||||
Reference in New Issue
Block a user