#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_UIKIT
#include "../SDL_sysvideo.h"
#import "SDL_uikitappdelegate.h"
#import "SDL_uikitmodes.h"
#import "SDL_uikitwindow.h"
#include "../../events/SDL_events_c.h"
#include "../../main/SDL_main_callbacks.h"
#ifdef main
#undef main
#endif
static SDL_main_func forward_main;
static int forward_argc;
static char **forward_argv;
static int exit_status;
int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved)
{
forward_main = mainFunction;
forward_argc = argc;
forward_argv = argv;
@autoreleasepool {
NSString *name = nil;
if (@available(iOS 13.0, tvOS 13.0, *)) {
name = [SDLUIKitSceneDelegate getSceneDelegateClassName];
}
if (!name) {
name = [SDLUIKitDelegate getAppDelegateClassName];
}
UIApplicationMain(argc, argv, nil, name);
}
return exit_status;
}
#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS)
static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
{
UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom;
UIImage *image = nil;
if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) {
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]];
} else if (idiom == UIUserInterfaceIdiomPad) {
if (UIInterfaceOrientationIsLandscape(curorient)) {
if (curorient == UIInterfaceOrientationLandscapeLeft) {
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]];
} else {
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]];
}
if (!image) {
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]];
}
} else {
if (curorient == UIInterfaceOrientationPortraitUpsideDown) {
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]];
}
if (!image) {
image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]];
}
}
}
if (!image) {
image = [UIImage imageNamed:name];
}
return image;
}
@interface SDLLaunchStoryboardViewController : UIViewController
@property(nonatomic, strong) UIViewController *storyboardViewController;
- (instancetype)initWithStoryboardViewController:(UIViewController *)storyboardViewController;
@end
@implementation SDLLaunchStoryboardViewController
- (instancetype)initWithStoryboardViewController:(UIViewController *)storyboardViewController
{
self = [super init];
self.storyboardViewController = storyboardViewController;
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self addChildViewController:self.storyboardViewController];
[self.view addSubview:self.storyboardViewController.view];
self.storyboardViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.storyboardViewController.view.frame = self.view.bounds;
[self.storyboardViewController didMoveToParentViewController:self];
#ifndef SDL_PLATFORM_VISIONOS
UIApplication.sharedApplication.statusBarHidden = self.prefersStatusBarHidden;
UIApplication.sharedApplication.statusBarStyle = self.preferredStatusBarStyle;
#endif
}
- (BOOL)prefersStatusBarHidden
{
return [[NSBundle.mainBundle objectForInfoDictionaryKey:@"UIStatusBarHidden"] boolValue];
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
NSString *statusBarStyle = [NSBundle.mainBundle objectForInfoDictionaryKey:@"UIStatusBarStyle"];
if ([statusBarStyle isEqualToString:@"UIStatusBarStyleLightContent"]) {
return UIStatusBarStyleLightContent;
}
if (@available(iOS 13.0, *)) {
if ([statusBarStyle isEqualToString:@"UIStatusBarStyleDarkContent"]) {
return UIStatusBarStyleDarkContent;
}
}
return UIStatusBarStyleDefault;
}
@end
#endif
@interface SDLLaunchScreenController ()
#ifndef SDL_PLATFORM_TVOS
- (NSUInteger)supportedInterfaceOrientations;
#endif
@end
@implementation SDLLaunchScreenController
- (instancetype)init
{
return [self initWithNibName:nil bundle:[NSBundle mainBundle]];
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (!(self = [super initWithNibName:nil bundle:nil])) {
return nil;
}
NSString *screenname = nibNameOrNil;
NSBundle *bundle = nibBundleOrNil;
if (screenname) {
@try {
self.view = [bundle loadNibNamed:screenname owner:self options:nil][0];
}
@catch (NSException *exception) {
return nil;
}
}
if (!self.view) {
NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
NSString *imagename = nil;
UIImage *image = nil;
#ifdef SDL_PLATFORM_VISIONOS
int screenw = SDL_XR_SCREENWIDTH;
int screenh = SDL_XR_SCREENHEIGHT;
#else
int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
#endif
#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS)
UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
if (screenw > screenh) {
int width = screenw;
screenw = screenh;
screenh = width;
}
#endif
if (launchimages) {
for (NSDictionary *dict in launchimages) {
NSString *minversion = dict[@"UILaunchImageMinimumOSVersion"];
NSString *sizestring = dict[@"UILaunchImageSize"];
if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) {
continue;
}
if (sizestring) {
CGSize size = CGSizeFromString(sizestring);
if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) {
continue;
}
}
#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS)
UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
NSString *orientstring = dict[@"UILaunchImageOrientation"];
if (orientstring) {
if ([orientstring isEqualToString:@"PortraitUpsideDown"]) {
orientmask = UIInterfaceOrientationMaskPortraitUpsideDown;
} else if ([orientstring isEqualToString:@"Landscape"]) {
orientmask = UIInterfaceOrientationMaskLandscape;
} else if ([orientstring isEqualToString:@"LandscapeLeft"]) {
orientmask = UIInterfaceOrientationMaskLandscapeLeft;
} else if ([orientstring isEqualToString:@"LandscapeRight"]) {
orientmask = UIInterfaceOrientationMaskLandscapeRight;
}
}
if ((orientmask & (1 << curorient)) == 0) {
continue;
}
#endif
imagename = dict[@"UILaunchImageName"];
}
if (imagename) {
image = [UIImage imageNamed:imagename];
}
}
#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS)
else {
imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
if (imagename) {
image = SDL_LoadLaunchImageNamed(imagename, screenh);
}
if (!image) {
image = SDL_LoadLaunchImageNamed(@"Default", screenh);
}
}
#endif
if (image) {
#ifdef SDL_PLATFORM_VISIONOS
CGRect viewFrame = CGRectMake(0, 0, screenw, screenh);
#else
CGRect viewFrame = [UIScreen mainScreen].bounds;
#endif
UIImageView *view = [[UIImageView alloc] initWithFrame:viewFrame];
UIImageOrientation imageorient = UIImageOrientationUp;
#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS)
if (UIInterfaceOrientationIsLandscape(curorient)) {
if (image.size.width < image.size.height) {
if (curorient == UIInterfaceOrientationLandscapeLeft) {
imageorient = UIImageOrientationRight;
} else if (curorient == UIInterfaceOrientationLandscapeRight) {
imageorient = UIImageOrientationLeft;
}
}
}
#endif
view.image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:imageorient];
self.view = view;
}
}
return self;
}
- (void)loadView
{
}
#ifndef SDL_PLATFORM_TVOS
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
#endif
@end
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) {
}
}
#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
[[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
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 = SDL_CallMainFunction(forward_argc, forward_argv, forward_main);
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))
{
UISceneConfiguration *config = [[UISceneConfiguration alloc] initWithName:@"SDLSceneConfiguration" sessionRole:connectingSceneSession.role];
config.delegateClass = [SDLUIKitSceneDelegate class];
return config;
}
@end
@implementation SDLUIKitDelegate
{
UIWindow *launchWindow;
}
+ (id)sharedAppDelegate
{
return [UIApplication sharedApplication].delegate;
}
+ (NSString *)getAppDelegateClassName
{
return @"SDLUIKitDelegate";
}
- (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 = SDL_CallMainFunction(forward_argc, forward_argv, forward_main);
SDL_SetiOSEventPump(false);
if (launchWindow) {
launchWindow.hidden = YES;
launchWindow = nil;
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
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) {
}
}
#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 = [UIScreen mainScreen].bounds;
#endif
launchWindow = [[UIWindow alloc] initWithFrame:viewFrame];
launchWindow.windowLevel = UIWindowLevelNormal + 1.0;
launchWindow.hidden = NO;
launchWindow.rootViewController = vc;
}
#endif
[[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
SDL_SetMainReady();
[self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:0.0];
return YES;
}
- (UIWindow *)window
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this) {
SDL_Window *window = NULL;
for (window = _this->windows; window != NULL; window = window->next) {
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->internal;
if (data != nil) {
return data.uiwindow;
}
}
}
return nil;
}
- (void)setWindow:(UIWindow *)window
{
}
- (void)sendDropFileForURL:(NSURL *)url fromSourceApplication:(NSString *)sourceApplication
{
NSURL *fileURL = url.filePathURL;
const char *sourceApplicationCString = sourceApplication ? [sourceApplication UTF8String] : NULL;
if (fileURL != nil) {
SDL_SendDropFile(NULL, sourceApplicationCString, fileURL.path.UTF8String);
} else {
SDL_SendDropFile(NULL, sourceApplicationCString, url.absoluteString.UTF8String);
}
SDL_SendDropComplete(NULL);
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
[self sendDropFileForURL:url fromSourceApplication:NULL];
return YES;
}
@end
#endif