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
|
* uninitialized will either return the user provided value, if one was set
|
||||||
* prior to initialization, or NULL. See docs/README-wayland.md for more
|
* prior to initialization, or NULL. See docs/README-wayland.md for more
|
||||||
* information.
|
* 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"
|
#define SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER "SDL.video.wayland.wl_display"
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,15 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
API_AVAILABLE(ios(13.0))
|
||||||
|
@interface SDLUIKitSceneDelegate : NSObject <UIApplicationDelegate, UIWindowSceneDelegate>
|
||||||
|
|
||||||
|
+ (NSString *)getSceneDelegateClassName;
|
||||||
|
|
||||||
|
- (void)hideLaunchScreen;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface SDLUIKitDelegate : NSObject <UIApplicationDelegate>
|
@interface SDLUIKitDelegate : NSObject <UIApplicationDelegate>
|
||||||
|
|
||||||
+ (id)sharedAppDelegate;
|
+ (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
|
// Give over control to run loop, SDLUIKitDelegate will handle most things from here
|
||||||
@autoreleasepool {
|
@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
|
// 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
|
@end
|
||||||
#endif // !SDL_PLATFORM_TVOS
|
#endif // !SDL_PLATFORM_TVOS
|
||||||
|
|
||||||
|
|
||||||
@interface SDLLaunchScreenController ()
|
@interface SDLLaunchScreenController ()
|
||||||
|
|
||||||
#ifndef SDL_PLATFORM_TVOS
|
#ifndef SDL_PLATFORM_TVOS
|
||||||
@@ -343,7 +352,170 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
|||||||
}
|
}
|
||||||
#endif // !SDL_PLATFORM_TVOS
|
#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
|
@implementation SDLUIKitDelegate
|
||||||
{
|
{
|
||||||
@@ -514,6 +686,6 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end // SDLUIKitDelegate
|
||||||
|
|
||||||
#endif // SDL_VIDEO_DRIVER_UIKIT
|
#endif // SDL_VIDEO_DRIVER_UIKIT
|
||||||
|
|||||||
@@ -152,6 +152,43 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow
|
|||||||
return true;
|
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)
|
bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
@@ -197,13 +234,21 @@ bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti
|
|||||||
}
|
}
|
||||||
#endif // !SDL_PLATFORM_TVOS
|
#endif // !SDL_PLATFORM_TVOS
|
||||||
|
|
||||||
// ignore the size user requested, and make a fullscreen window
|
UIWindow *uiwindow = nil;
|
||||||
// !!! FIXME: can we have a smaller view?
|
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
|
||||||
#ifdef SDL_PLATFORM_VISIONOS
|
#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
|
#else
|
||||||
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
|
uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// put the window on an external display if appropriate.
|
// put the window on an external display if appropriate.
|
||||||
#ifndef SDL_PLATFORM_VISIONOS
|
#ifndef SDL_PLATFORM_VISIONOS
|
||||||
|
|||||||
Reference in New Issue
Block a user