summaryrefslogtreecommitdiff
path: root/source/3rd-party/SDL2/src/video/uikit/SDL_uikitappdelegate.m
diff options
context:
space:
mode:
Diffstat (limited to 'source/3rd-party/SDL2/src/video/uikit/SDL_uikitappdelegate.m')
-rw-r--r--source/3rd-party/SDL2/src/video/uikit/SDL_uikitappdelegate.m516
1 files changed, 516 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/video/uikit/SDL_uikitappdelegate.m b/source/3rd-party/SDL2/src/video/uikit/SDL_uikitappdelegate.m
new file mode 100644
index 0000000..15762d2
--- /dev/null
+++ b/source/3rd-party/SDL2/src/video/uikit/SDL_uikitappdelegate.m
@@ -0,0 +1,516 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_UIKIT
+
+#include "../SDL_sysvideo.h"
+#include "SDL_assert.h"
+#include "SDL_hints.h"
+#include "SDL_system.h"
+#include "SDL_main.h"
+
+#import "SDL_uikitappdelegate.h"
+#import "SDL_uikitmodes.h"
+#import "SDL_uikitwindow.h"
+
+#include "../../events/SDL_events_c.h"
+
+#ifdef main
+#undef main
+#endif
+
+static int forward_argc;
+static char **forward_argv;
+static int exit_status;
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ /* store arguments */
+ forward_argc = argc;
+ forward_argv = (char **)malloc((argc+1) * sizeof(char *));
+ for (i = 0; i < argc; i++) {
+ forward_argv[i] = malloc( (strlen(argv[i])+1) * sizeof(char));
+ strcpy(forward_argv[i], argv[i]);
+ }
+ forward_argv[i] = NULL;
+
+ /* Give over control to run loop, SDLUIKitDelegate will handle most things from here */
+ @autoreleasepool {
+ UIApplicationMain(argc, argv, nil, [SDLUIKitDelegate getAppDelegateClassName]);
+ }
+
+ /* free the memory we used to hold copies of argc and argv */
+ for (i = 0; i < forward_argc; i++) {
+ free(forward_argv[i]);
+ }
+ free(forward_argv);
+
+ return exit_status;
+}
+
+static void SDLCALL
+SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+ BOOL disable = (hint && *hint != '0');
+ [UIApplication sharedApplication].idleTimerDisabled = disable;
+}
+
+#if !TARGET_OS_TV
+/* Load a launch image using the old UILaunchImageFile-era naming rules. */
+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) {
+ /* The image name for the iPhone 5 uses its height as a suffix. */
+ image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]];
+ } else if (idiom == UIUserInterfaceIdiomPad) {
+ /* iPad apps can launch in any orientation. */
+ 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;
+}
+#endif /* !TARGET_OS_TV */
+
+@interface SDLLaunchScreenController ()
+
+#if !TARGET_OS_TV
+- (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;
+ BOOL atleastiOS8 = UIKit_IsSystemVersionAtLeast(8.0);
+
+ /* Launch screens were added in iOS 8. Otherwise we use launch images. */
+ if (screenname && atleastiOS8) {
+ @try {
+ self.view = [bundle loadNibNamed:screenname owner:self options:nil][0];
+ }
+ @catch (NSException *exception) {
+ /* If a launch screen name is specified but it fails to load, iOS
+ * displays a blank screen rather than falling back to an image. */
+ return nil;
+ }
+ }
+
+ if (!self.view) {
+ NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
+ NSString *imagename = nil;
+ UIImage *image = nil;
+
+ int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
+ int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
+
+#if !TARGET_OS_TV
+ UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
+
+ /* We always want portrait-oriented size, to match UILaunchImageSize. */
+ if (screenw > screenh) {
+ int width = screenw;
+ screenw = screenh;
+ screenh = width;
+ }
+#endif
+
+ /* Xcode 5 introduced a dictionary of launch images in Info.plist. */
+ if (launchimages) {
+ for (NSDictionary *dict in launchimages) {
+ NSString *minversion = dict[@"UILaunchImageMinimumOSVersion"];
+ NSString *sizestring = dict[@"UILaunchImageSize"];
+
+ /* Ignore this image if the current version is too low. */
+ if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) {
+ continue;
+ }
+
+ /* Ignore this image if the size doesn't match. */
+ if (sizestring) {
+ CGSize size = CGSizeFromString(sizestring);
+ if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) {
+ continue;
+ }
+ }
+
+#if !TARGET_OS_TV
+ 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;
+ }
+ }
+
+ /* Ignore this image if the orientation doesn't match. */
+ if ((orientmask & (1 << curorient)) == 0) {
+ continue;
+ }
+#endif
+
+ imagename = dict[@"UILaunchImageName"];
+ }
+
+ if (imagename) {
+ image = [UIImage imageNamed:imagename];
+ }
+ }
+#if !TARGET_OS_TV
+ else {
+ imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
+
+ if (imagename) {
+ image = SDL_LoadLaunchImageNamed(imagename, screenh);
+ }
+
+ if (!image) {
+ image = SDL_LoadLaunchImageNamed(@"Default", screenh);
+ }
+ }
+#endif
+
+ if (image) {
+ UIImageView *view = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
+ UIImageOrientation imageorient = UIImageOrientationUp;
+
+#if !TARGET_OS_TV
+ /* Bugs observed / workaround tested in iOS 8.3, 7.1, and 6.1. */
+ if (UIInterfaceOrientationIsLandscape(curorient)) {
+ if (atleastiOS8 && image.size.width < image.size.height) {
+ /* On iOS 8, portrait launch images displayed in forced-
+ * landscape mode (e.g. a standard Default.png on an iPhone
+ * when Info.plist only supports landscape orientations) need
+ * to be rotated to display in the expected orientation. */
+ if (curorient == UIInterfaceOrientationLandscapeLeft) {
+ imageorient = UIImageOrientationRight;
+ } else if (curorient == UIInterfaceOrientationLandscapeRight) {
+ imageorient = UIImageOrientationLeft;
+ }
+ } else if (!atleastiOS8 && image.size.width > image.size.height) {
+ /* On iOS 7 and below, landscape launch images displayed in
+ * landscape mode (e.g. landscape iPad launch images) need
+ * to be rotated to display in the expected orientation. */
+ if (curorient == UIInterfaceOrientationLandscapeLeft) {
+ imageorient = UIImageOrientationLeft;
+ } else if (curorient == UIInterfaceOrientationLandscapeRight) {
+ imageorient = UIImageOrientationRight;
+ }
+ }
+ }
+#endif
+
+ /* Create the properly oriented image. */
+ view.image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:imageorient];
+
+ self.view = view;
+ }
+ }
+
+ return self;
+}
+
+- (void)loadView
+{
+ /* Do nothing. */
+}
+
+#if !TARGET_OS_TV
+- (BOOL)shouldAutorotate
+{
+ /* If YES, the launch image will be incorrectly rotated in some cases. */
+ return NO;
+}
+
+- (NSUInteger)supportedInterfaceOrientations
+{
+ /* We keep the supported orientations unrestricted to avoid the case where
+ * there are no common orientations between the ones set in Info.plist and
+ * the ones set here (it will cause an exception in that case.) */
+ return UIInterfaceOrientationMaskAll;
+}
+#endif /* !TARGET_OS_TV */
+
+@end
+
+@implementation SDLUIKitDelegate {
+ UIWindow *launchWindow;
+}
+
+/* convenience method */
++ (id)sharedAppDelegate
+{
+ /* the delegate is set in UIApplicationMain(), which is guaranteed to be
+ * called before this method */
+ return [UIApplication sharedApplication].delegate;
+}
+
++ (NSString *)getAppDelegateClassName
+{
+ /* subclassing notice: when you subclass this appdelegate, make sure to add
+ * a category to override this method and return the actual name of the
+ * delegate */
+ return @"SDLUIKitDelegate";
+}
+
+- (void)hideLaunchScreen
+{
+ UIWindow *window = launchWindow;
+
+ if (!window || window.hidden) {
+ return;
+ }
+
+ launchWindow = nil;
+
+ /* Do a nice animated fade-out (roughly matches the real launch behavior.) */
+ [UIView animateWithDuration:0.2 animations:^{
+ window.alpha = 0.0;
+ } completion:^(BOOL finished) {
+ window.hidden = YES;
+ }];
+}
+
+- (void)postFinishLaunch
+{
+ /* Hide the launch screen the next time the run loop is run. SDL apps will
+ * have a chance to load resources while the launch screen is still up. */
+ [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0];
+
+ /* run the user's application, passing argc and argv */
+ SDL_iPhoneSetEventPump(SDL_TRUE);
+ exit_status = SDL_main(forward_argc, forward_argv);
+ SDL_iPhoneSetEventPump(SDL_FALSE);
+
+ if (launchWindow) {
+ launchWindow.hidden = YES;
+ launchWindow = nil;
+ }
+
+ /* exit, passing the return status from the user's application */
+ /* We don't actually exit to support applications that do setup in their
+ * main function and then allow the Cocoa event loop to run. */
+ /* exit(exit_status); */
+}
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ NSBundle *bundle = [NSBundle mainBundle];
+
+#if SDL_IPHONE_LAUNCHSCREEN
+ /* The normal launch screen is displayed until didFinishLaunching returns,
+ * but SDL_main is called after that happens and there may be a noticeable
+ * delay between the start of SDL_main and when the first real frame is
+ * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is
+ * called), so we show the launch screen programmatically until the first
+ * time events are pumped. */
+ UIViewController *vc = nil;
+ NSString *screenname = nil;
+
+ /* tvOS only uses a plain launch image. */
+#if !TARGET_OS_TV
+ screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
+
+ if (screenname && UIKit_IsSystemVersionAtLeast(8.0)) {
+ @try {
+ /* The launch storyboard is actually a nib in some older versions of
+ * Xcode. We'll try to load it as a storyboard first, as it's more
+ * modern. */
+ UIStoryboard *storyboard = [UIStoryboard storyboardWithName:screenname bundle:bundle];
+ vc = [storyboard instantiateInitialViewController];
+ }
+ @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) {
+ launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+
+ /* We don't want the launch window immediately hidden when a real SDL
+ * window is shown - we fade it out ourselves when we're ready. */
+ launchWindow.windowLevel = UIWindowLevelNormal + 1.0;
+
+ /* Show the window but don't make it key. Events should always go to
+ * other windows when possible. */
+ launchWindow.hidden = NO;
+
+ launchWindow.rootViewController = vc;
+ }
+#endif
+
+ /* Set working directory to resource path */
+ [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
+
+ /* register a callback for the idletimer hint */
+ SDL_AddHintCallback(SDL_HINT_IDLE_TIMER_DISABLED,
+ SDL_IdleTimerDisabledChanged, NULL);
+
+ 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_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
+ if (data != nil) {
+ return data.uiwindow;
+ }
+ }
+ }
+ return nil;
+}
+
+- (void)setWindow:(UIWindow *)window
+{
+ /* Do nothing. */
+}
+
+#if !TARGET_OS_TV
+- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
+{
+ SDL_OnApplicationDidChangeStatusBarOrientation();
+}
+#endif
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+ SDL_OnApplicationWillTerminate();
+}
+
+- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
+{
+ SDL_OnApplicationDidReceiveMemoryWarning();
+}
+
+- (void)applicationWillResignActive:(UIApplication*)application
+{
+ SDL_OnApplicationWillResignActive();
+}
+
+- (void)applicationDidEnterBackground:(UIApplication*)application
+{
+ SDL_OnApplicationDidEnterBackground();
+}
+
+- (void)applicationWillEnterForeground:(UIApplication*)application
+{
+ SDL_OnApplicationWillEnterForeground();
+}
+
+- (void)applicationDidBecomeActive:(UIApplication*)application
+{
+ SDL_OnApplicationDidBecomeActive();
+}
+
+- (void)sendDropFileForURL:(NSURL *)url
+{
+ NSURL *fileURL = url.filePathURL;
+ if (fileURL != nil) {
+ SDL_SendDropFile(NULL, fileURL.path.UTF8String);
+ } else {
+ SDL_SendDropFile(NULL, url.absoluteString.UTF8String);
+ }
+ SDL_SendDropComplete(NULL);
+}
+
+#if TARGET_OS_TV || (defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0)
+
+- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
+{
+ /* TODO: Handle options */
+ [self sendDropFileForURL:url];
+ return YES;
+}
+
+#else
+
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+{
+ [self sendDropFileForURL:url];
+ return YES;
+}
+
+#endif
+
+@end
+
+#endif /* SDL_VIDEO_DRIVER_UIKIT */
+
+/* vi: set ts=4 sw=4 expandtab: */