Several improvements to the iOS backend: iOS-improvements
authorAlex Szpakowski <slime73@gmail.com>
Thu, 15 Jan 2015 01:06:14 -0400
branchiOS-improvements
changeset 9532318042c16b76
parent 9531 b7ad394978b1
child 9533 e5693e855338
Several improvements to the iOS backend:

- Added new custom launch screen code. It uses the launch screen nib when available on iOS 8+, the launch images dictionary if the launch screen nib isn't available, and the old standard image names if the launch image dictionary isn't in the plist.
The launch screen is now hidden during the first call to SDL_PumpEvents rather than SDL_CreateWindow so apps can have the launch screen still visible if they do time-consuming loading after creating their window. It also fades out in roughly the same way as the system launch screen behavior.
It can be disabled by setting the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h to 0.

- A blank UIView is now created and displayed when the window is first created. The old behavior was to defer creating any view until SDL_GL_CreateContext, which prevented rotation, touch events, and other windowing-related things from working until then. This also makes it easier to use SDL_GetWindowWMInfo after creating a window.

- Moved the keyboard and animation callback code from SDL's UIView subclasses to its UIViewController subclass, which lets them work properly in all cases when a SDL window is valid, even before SDL_GL_CreateContext is called and after SDL_GL_DeleteContext is called.

- SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext are more robust.

- Fixed some edge cases where SDL windows weren't rotating properly or their reported sizes were out of sync with their actual sizes.

- Removed all calls to [UIApplication setStatusBarOrientation:]. It doesn't seem to work as expected in all cases in recent iOS versions.

- Some code style cleanup.
include/SDL_config_iphoneos.h
premake/Xcode-iOS/SDL_config_premake.h
src/video/SDL_video.c
src/video/uikit/SDL_uikitappdelegate.h
src/video/uikit/SDL_uikitappdelegate.m
src/video/uikit/SDL_uikitmessagebox.m
src/video/uikit/SDL_uikitmodes.m
src/video/uikit/SDL_uikitopengles.m
src/video/uikit/SDL_uikitopenglview.h
src/video/uikit/SDL_uikitopenglview.m
src/video/uikit/SDL_uikitview.h
src/video/uikit/SDL_uikitview.m
src/video/uikit/SDL_uikitviewcontroller.h
src/video/uikit/SDL_uikitviewcontroller.m
src/video/uikit/SDL_uikitwindow.h
src/video/uikit/SDL_uikitwindow.m
     1.1 --- a/include/SDL_config_iphoneos.h	Tue Dec 02 02:52:45 2014 -0400
     1.2 +++ b/include/SDL_config_iphoneos.h	Thu Jan 15 01:06:14 2015 -0400
     1.3 @@ -145,6 +145,9 @@
     1.4  /* enable iPhone keyboard support */
     1.5  #define SDL_IPHONE_KEYBOARD 1
     1.6  
     1.7 +/* enable iOS extended launch screen */
     1.8 +#define SDL_IPHONE_LAUNCHSCREEN 1
     1.9 +
    1.10  /* enable joystick subsystem */
    1.11  #define SDL_JOYSTICK_DISABLED 0
    1.12  
     2.1 --- a/premake/Xcode-iOS/SDL_config_premake.h	Tue Dec 02 02:52:45 2014 -0400
     2.2 +++ b/premake/Xcode-iOS/SDL_config_premake.h	Thu Jan 15 01:06:14 2015 -0400
     2.3 @@ -126,6 +126,9 @@
     2.4  #ifndef SDL_IPHONE_KEYBOARD
     2.5  #define SDL_IPHONE_KEYBOARD 1
     2.6  #endif
     2.7 +#ifndef SDL_IPHONE_LAUNCHSCREEN
     2.8 +#define SDL_IPHONE_LAUNCHSCREEN 1
     2.9 +#endif
    2.10  #ifndef SDL_POWER_UIKIT
    2.11  #define SDL_POWER_UIKIT 1
    2.12  #endif
     3.1 --- a/src/video/SDL_video.c	Tue Dec 02 02:52:45 2014 -0400
     3.2 +++ b/src/video/SDL_video.c	Thu Jan 15 01:06:14 2015 -0400
     3.3 @@ -1100,22 +1100,22 @@
     3.4      }
     3.5  }
     3.6  
     3.7 -static void
     3.8 +static int
     3.9  SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
    3.10  {
    3.11      SDL_VideoDisplay *display;
    3.12      SDL_Window *other;
    3.13  
    3.14 -    CHECK_WINDOW_MAGIC(window,);
    3.15 +    CHECK_WINDOW_MAGIC(window,-1);
    3.16  
    3.17      /* if we are in the process of hiding don't go back to fullscreen */
    3.18      if ( window->is_hiding && fullscreen )
    3.19 -        return;
    3.20 +        return 0;
    3.21      
    3.22  #ifdef __MACOSX__
    3.23      if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
    3.24          window->last_fullscreen_flags = window->flags;
    3.25 -        return;
    3.26 +        return 0;
    3.27      }
    3.28  #endif
    3.29  
    3.30 @@ -1132,7 +1132,7 @@
    3.31      /* See if anything needs to be done now */
    3.32      if ((display->fullscreen_window == window) == fullscreen) {
    3.33          if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
    3.34 -            return;
    3.35 +            return 0;
    3.36          }
    3.37      }
    3.38  
    3.39 @@ -1161,9 +1161,13 @@
    3.40  
    3.41                  /* only do the mode change if we want exclusive fullscreen */
    3.42                  if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
    3.43 -                    SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
    3.44 +                    if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
    3.45 +                        return -1;
    3.46 +                    }
    3.47                  } else {
    3.48 -                    SDL_SetDisplayModeForDisplay(display, NULL);
    3.49 +                    if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
    3.50 +                        return -1;
    3.51 +                    }
    3.52                  }
    3.53  
    3.54                  if (_this->SetWindowFullscreen) {
    3.55 @@ -1182,7 +1186,7 @@
    3.56                  SDL_RestoreMousePosition(other);
    3.57  
    3.58                  window->last_fullscreen_flags = window->flags;
    3.59 -                return;
    3.60 +                return 0;
    3.61              }
    3.62          }
    3.63      }
    3.64 @@ -1202,6 +1206,7 @@
    3.65      SDL_RestoreMousePosition(window);
    3.66  
    3.67      window->last_fullscreen_flags = window->flags;
    3.68 +    return 0;
    3.69  }
    3.70  
    3.71  #define CREATE_FLAGS \
    3.72 @@ -1927,9 +1932,7 @@
    3.73      window->flags &= ~FULLSCREEN_MASK;
    3.74      window->flags |= flags;
    3.75  
    3.76 -    SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
    3.77 -
    3.78 -    return 0;
    3.79 +    return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
    3.80  }
    3.81  
    3.82  static SDL_Surface *
     4.1 --- a/src/video/uikit/SDL_uikitappdelegate.h	Tue Dec 02 02:52:45 2014 -0400
     4.2 +++ b/src/video/uikit/SDL_uikitappdelegate.h	Thu Jan 15 01:06:14 2015 -0400
     4.3 @@ -21,12 +21,22 @@
     4.4  
     4.5  #import <UIKit/UIKit.h>
     4.6  
     4.7 -@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate> {
     4.8 -}
     4.9 +@interface SDLLaunchScreenController : UIViewController
    4.10  
    4.11 -+ (id) sharedAppDelegate;
    4.12 +- (instancetype)init;
    4.13 +- (void)loadView;
    4.14 +- (BOOL)shouldAutorotate;
    4.15 +- (NSUInteger)supportedInterfaceOrientations;
    4.16 +
    4.17 +@end
    4.18 +
    4.19 +@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate>
    4.20 +
    4.21 ++ (id)sharedAppDelegate;
    4.22  + (NSString *)getAppDelegateClassName;
    4.23  
    4.24 +- (void)hideLaunchScreen;
    4.25 +
    4.26  @end
    4.27  
    4.28  /* vi: set ts=4 sw=4 expandtab: */
     5.1 --- a/src/video/uikit/SDL_uikitappdelegate.m	Tue Dec 02 02:52:45 2014 -0400
     5.2 +++ b/src/video/uikit/SDL_uikitappdelegate.m	Thu Jan 15 01:06:14 2015 -0400
     5.3 @@ -28,8 +28,10 @@
     5.4  #include "SDL_system.h"
     5.5  #include "SDL_main.h"
     5.6  
     5.7 -#include "SDL_uikitappdelegate.h"
     5.8 -#include "SDL_uikitmodes.h"
     5.9 +#import "SDL_uikitappdelegate.h"
    5.10 +#import "SDL_uikitmodes.h"
    5.11 +#import "SDL_uikitwindow.h"
    5.12 +
    5.13  #include "../../events/SDL_events_c.h"
    5.14  
    5.15  #ifdef main
    5.16 @@ -74,46 +76,256 @@
    5.17      [UIApplication sharedApplication].idleTimerDisabled = disable;
    5.18  }
    5.19  
    5.20 -@implementation SDLUIKitDelegate
    5.21 +/* Load a launch image using the old UILaunchImageFile-era naming rules. */
    5.22 +static UIImage *
    5.23 +SDL_LoadLaunchImageNamed(NSString *name, int screenh)
    5.24 +{
    5.25 +    UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
    5.26 +    UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom;
    5.27 +    UIImage *image = nil;
    5.28 +
    5.29 +    if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) {
    5.30 +        /* The image name for the iPhone 5 uses its height as a suffix. */
    5.31 +        image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]];
    5.32 +    } else if (idiom == UIUserInterfaceIdiomPad) {
    5.33 +        /* iPad apps can launch in any orientation. */
    5.34 +        if (UIInterfaceOrientationIsLandscape(curorient)) {
    5.35 +            if (curorient == UIInterfaceOrientationLandscapeLeft) {
    5.36 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]];
    5.37 +            } else {
    5.38 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]];
    5.39 +            }
    5.40 +            if (!image) {
    5.41 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]];
    5.42 +            }
    5.43 +        } else {
    5.44 +            if (curorient == UIInterfaceOrientationPortraitUpsideDown) {
    5.45 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]];
    5.46 +            }
    5.47 +            if (!image) {
    5.48 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]];
    5.49 +            }
    5.50 +        }
    5.51 +    }
    5.52 +
    5.53 +    if (!image) {
    5.54 +        image = [UIImage imageNamed:name];
    5.55 +    }
    5.56 +
    5.57 +    return image;
    5.58 +}
    5.59 +
    5.60 +@implementation SDLLaunchScreenController
    5.61 +
    5.62 +- (instancetype)init
    5.63 +{
    5.64 +    if (!(self = [super initWithNibName:nil bundle:nil])) {
    5.65 +        return nil;
    5.66 +    }
    5.67 +
    5.68 +    NSBundle *bundle = [NSBundle mainBundle];
    5.69 +    NSString *screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
    5.70 +
    5.71 +    /* Launch screens were added in iOS 8. Otherwise we use launch images. */
    5.72 +    if (screenname && UIKit_IsSystemVersionAtLeast(8.0)) {
    5.73 +        @try {
    5.74 +            self.view = [bundle loadNibNamed:screenname owner:self options:nil][0];
    5.75 +        }
    5.76 +        @catch (NSException *exception) {
    5.77 +            /* iOS displays a blank screen rather than falling back to an image,
    5.78 +             * if a launch screen name is specified but it fails to load. */
    5.79 +            return nil;
    5.80 +        }
    5.81 +    }
    5.82 +
    5.83 +    if (!self.view) {
    5.84 +        NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
    5.85 +        UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
    5.86 +        NSString *imagename = nil;
    5.87 +        UIImage *image = nil;
    5.88 +
    5.89 +        int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
    5.90 +        int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
    5.91 +
    5.92 +        /* We always want portrait-oriented size, to match UILaunchImageSize. */
    5.93 +        if (screenw > screenh) {
    5.94 +            int width = screenw;
    5.95 +            screenw = screenh;
    5.96 +            screenh = width;
    5.97 +        }
    5.98 +
    5.99 +        /* Xcode 5 introduced a dictionary of launch images in Info.plist. */
   5.100 +        if (launchimages) {
   5.101 +            for (NSDictionary *dict in launchimages) {
   5.102 +                UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
   5.103 +                NSString *minversion   = dict[@"UILaunchImageMinimumOSVersion"];
   5.104 +                NSString *sizestring   = dict[@"UILaunchImageSize"];
   5.105 +                NSString *orientstring = dict[@"UILaunchImageOrientation"];
   5.106 +
   5.107 +                /* Ignore this image if the current version is too low. */
   5.108 +                if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) {
   5.109 +                    continue;
   5.110 +                }
   5.111 +
   5.112 +                /* Ignore this image if the size doesn't match. */
   5.113 +                if (sizestring) {
   5.114 +                    CGSize size = CGSizeFromString(sizestring);
   5.115 +                    if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) {
   5.116 +                        continue;
   5.117 +                    }
   5.118 +                }
   5.119 +
   5.120 +                if (orientstring) {
   5.121 +                    if ([orientstring isEqualToString:@"PortraitUpsideDown"]) {
   5.122 +                        orientmask = UIInterfaceOrientationMaskPortraitUpsideDown;
   5.123 +                    } else if ([orientstring isEqualToString:@"Landscape"]) {
   5.124 +                        orientmask = UIInterfaceOrientationMaskLandscape;
   5.125 +                    } else if ([orientstring isEqualToString:@"LandscapeLeft"]) {
   5.126 +                        orientmask = UIInterfaceOrientationMaskLandscapeLeft;
   5.127 +                    } else if ([orientstring isEqualToString:@"LandscapeRight"]) {
   5.128 +                        orientmask = UIInterfaceOrientationMaskLandscapeRight;
   5.129 +                    }
   5.130 +                }
   5.131 +
   5.132 +                /* Ignore this image if the orientation doesn't match. */
   5.133 +                if ((orientmask & (1 << curorient)) == 0) {
   5.134 +                    continue;
   5.135 +                }
   5.136 +
   5.137 +                imagename = dict[@"UILaunchImageName"];
   5.138 +            }
   5.139 +
   5.140 +            if (imagename) {
   5.141 +                image = [UIImage imageNamed:imagename];
   5.142 +            }
   5.143 +        } else {
   5.144 +            imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
   5.145 +
   5.146 +            if (imagename) {
   5.147 +                image = SDL_LoadLaunchImageNamed(imagename, screenh);
   5.148 +            }
   5.149 +
   5.150 +            if (!image) {
   5.151 +                image = SDL_LoadLaunchImageNamed(@"Default", screenh);
   5.152 +            }
   5.153 +        }
   5.154 +
   5.155 +        if (image) {
   5.156 +            self.view = [[UIImageView alloc] initWithImage:image];
   5.157 +        }
   5.158 +    }
   5.159 +
   5.160 +    return self;
   5.161 +}
   5.162 +
   5.163 +- (void)loadView
   5.164 +{
   5.165 +    /* Do nothing. */
   5.166 +}
   5.167 +
   5.168 +- (BOOL)shouldAutorotate
   5.169 +{
   5.170 +    return YES;
   5.171 +}
   5.172 +
   5.173 +- (NSUInteger)supportedInterfaceOrientations
   5.174 +{
   5.175 +    return UIInterfaceOrientationMaskAll;
   5.176 +}
   5.177 +
   5.178 +@end
   5.179 +
   5.180 +@implementation SDLUIKitDelegate {
   5.181 +    UIWindow *launchWindow;
   5.182 +}
   5.183  
   5.184  /* convenience method */
   5.185 -+ (id) sharedAppDelegate
   5.186 ++ (id)sharedAppDelegate
   5.187  {
   5.188 -    /* the delegate is set in UIApplicationMain(), which is guaranteed to be called before this method */
   5.189 -    return [[UIApplication sharedApplication] delegate];
   5.190 +    /* the delegate is set in UIApplicationMain(), which is guaranteed to be
   5.191 +     * called before this method */
   5.192 +    return [UIApplication sharedApplication].delegate;
   5.193  }
   5.194  
   5.195  + (NSString *)getAppDelegateClassName
   5.196  {
   5.197 -    /* subclassing notice: when you subclass this appdelegate, make sure to add a category to override
   5.198 -       this method and return the actual name of the delegate */
   5.199 +    /* subclassing notice: when you subclass this appdelegate, make sure to add
   5.200 +     * a category to override this method and return the actual name of the
   5.201 +     * delegate */
   5.202      return @"SDLUIKitDelegate";
   5.203  }
   5.204  
   5.205 -- (id)init
   5.206 +- (void)hideLaunchScreen
   5.207  {
   5.208 -    self = [super init];
   5.209 -    return self;
   5.210 +    UIWindow *window = launchWindow;
   5.211 +
   5.212 +    if (!window || window.hidden) {
   5.213 +        return;
   5.214 +    }
   5.215 +
   5.216 +    launchWindow = nil;
   5.217 +
   5.218 +    /* Do a nice animated fade-out (roughly matches the real launch behavior.) */
   5.219 +    [UIView animateWithDuration:0.2 animations:^{
   5.220 +        window.alpha = 0.0;
   5.221 +    } completion:^(BOOL finished) {
   5.222 +        window.hidden = YES;
   5.223 +    }];
   5.224  }
   5.225  
   5.226  - (void)postFinishLaunch
   5.227  {
   5.228 +    /* Hide the launch screen the next time the run loop is run. SDL apps will
   5.229 +     * have a chance to load resources while the launch screen is still up. */
   5.230 +    [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0];
   5.231 +
   5.232      /* run the user's application, passing argc and argv */
   5.233      SDL_iPhoneSetEventPump(SDL_TRUE);
   5.234      exit_status = SDL_main(forward_argc, forward_argv);
   5.235      SDL_iPhoneSetEventPump(SDL_FALSE);
   5.236  
   5.237 +    if (launchWindow) {
   5.238 +        launchWindow.hidden = YES;
   5.239 +        launchWindow = nil;
   5.240 +    }
   5.241 +
   5.242      /* exit, passing the return status from the user's application */
   5.243 -    /* We don't actually exit to support applications that do setup in
   5.244 -     * their main function and then allow the Cocoa event loop to run.
   5.245 -     */
   5.246 +    /* We don't actually exit to support applications that do setup in their
   5.247 +     * main function and then allow the Cocoa event loop to run. */
   5.248      /* exit(exit_status); */
   5.249  }
   5.250  
   5.251  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
   5.252  {
   5.253 +    NSBundle *bundle = [NSBundle mainBundle];
   5.254 +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
   5.255 +
   5.256 +#if SDL_IPHONE_LAUNCHSCREEN
   5.257 +    /* The normal launch screen is displayed until didFinishLaunching returns,
   5.258 +     * but SDL_main is called after that happens and there may be a noticeable
   5.259 +     * delay between the start of SDL_main and when the first real frame is
   5.260 +     * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is
   5.261 +     * called), so we show the launch screen programmatically until the first
   5.262 +     * time events are pumped. */
   5.263 +    UIViewController *viewcontroller = [[SDLLaunchScreenController alloc] init];
   5.264 +
   5.265 +    if (viewcontroller.view) {
   5.266 +        launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
   5.267 +
   5.268 +        /* We don't want the launch window immediately hidden when a real SDL
   5.269 +         * window is shown - we fade it out ourselves when we're ready. */
   5.270 +        launchWindow.windowLevel = UIWindowLevelNormal + 1.0;
   5.271 +
   5.272 +        /* Show the window but don't make it key. Events should always go to
   5.273 +         * other windows when possible. */
   5.274 +        launchWindow.hidden = NO;
   5.275 +
   5.276 +        launchWindow.rootViewController = viewcontroller;
   5.277 +    }
   5.278 +#endif
   5.279 +
   5.280      /* Set working directory to resource path */
   5.281 -    [[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]];
   5.282 +    [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
   5.283  
   5.284      /* register a callback for the idletimer hint */
   5.285      SDL_AddHintCallback(SDL_HINT_IDLE_TIMER_DISABLED,
   5.286 @@ -121,7 +333,7 @@
   5.287  
   5.288      SDL_SetMainReady();
   5.289      [self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:0.0];
   5.290 -
   5.291 +    
   5.292      return YES;
   5.293  }
   5.294  
   5.295 @@ -147,8 +359,7 @@
   5.296          /* The desktop display mode should be kept in sync with the screen
   5.297           * orientation so that updating a window's fullscreen state to
   5.298           * SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the
   5.299 -         * correct orientation.
   5.300 -         */
   5.301 +         * correct orientation. */
   5.302          if (isLandscape != (desktopmode->w > desktopmode->h)) {
   5.303              int height = desktopmode->w;
   5.304              desktopmode->w = desktopmode->h;
   5.305 @@ -164,7 +375,7 @@
   5.306      }
   5.307  }
   5.308  
   5.309 -- (void) applicationWillResignActive:(UIApplication*)application
   5.310 +- (void)applicationWillResignActive:(UIApplication*)application
   5.311  {
   5.312      SDL_VideoDevice *_this = SDL_GetVideoDevice();
   5.313      if (_this) {
   5.314 @@ -177,17 +388,17 @@
   5.315      SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
   5.316  }
   5.317  
   5.318 -- (void) applicationDidEnterBackground:(UIApplication*)application
   5.319 +- (void)applicationDidEnterBackground:(UIApplication*)application
   5.320  {
   5.321      SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
   5.322  }
   5.323  
   5.324 -- (void) applicationWillEnterForeground:(UIApplication*)application
   5.325 +- (void)applicationWillEnterForeground:(UIApplication*)application
   5.326  {
   5.327      SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
   5.328  }
   5.329  
   5.330 -- (void) applicationDidBecomeActive:(UIApplication*)application
   5.331 +- (void)applicationDidBecomeActive:(UIApplication*)application
   5.332  {
   5.333      SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
   5.334  
   5.335 @@ -203,11 +414,11 @@
   5.336  
   5.337  - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
   5.338  {
   5.339 -    NSURL *fileURL = [url filePathURL];
   5.340 +    NSURL *fileURL = url.filePathURL;
   5.341      if (fileURL != nil) {
   5.342 -        SDL_SendDropFile([[fileURL path] UTF8String]);
   5.343 +        SDL_SendDropFile([fileURL.path UTF8String]);
   5.344      } else {
   5.345 -        SDL_SendDropFile([[url absoluteString] UTF8String]);
   5.346 +        SDL_SendDropFile([url.absoluteString UTF8String]);
   5.347      }
   5.348      return YES;
   5.349  }
     6.1 --- a/src/video/uikit/SDL_uikitmessagebox.m	Tue Dec 02 02:52:45 2014 -0400
     6.2 +++ b/src/video/uikit/SDL_uikitmessagebox.m	Thu Jan 15 01:06:14 2015 -0400
     6.3 @@ -30,35 +30,20 @@
     6.4  
     6.5  static SDL_bool s_showingMessageBox = SDL_FALSE;
     6.6  
     6.7 -@interface UIKit_UIAlertViewDelegate : NSObject <UIAlertViewDelegate>
     6.8 +@interface SDLAlertViewDelegate : NSObject <UIAlertViewDelegate>
     6.9  
    6.10 -- (id)initWithButtonIndex:(int *)buttonIndex;
    6.11 -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
    6.12 +@property (nonatomic, assign) int clickedIndex;
    6.13  
    6.14  @end
    6.15  
    6.16 -@implementation UIKit_UIAlertViewDelegate {
    6.17 -    int *clickedButtonIndex;
    6.18 -}
    6.19 -
    6.20 -- (id)initWithButtonIndex:(int *)buttonIndex
    6.21 -{
    6.22 -    self = [self init];
    6.23 -    if (self == nil) {
    6.24 -        return nil;
    6.25 -    }
    6.26 -
    6.27 -    clickedButtonIndex = buttonIndex;
    6.28 -
    6.29 -    return self;
    6.30 -}
    6.31 +@implementation SDLAlertViewDelegate
    6.32  
    6.33  - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
    6.34  {
    6.35 -    *clickedButtonIndex = (int)buttonIndex;
    6.36 +    _clickedIndex = (int)buttonIndex;
    6.37  }
    6.38  
    6.39 -@end /* UIKit_UIAlertViewDelegate */
    6.40 +@end
    6.41  
    6.42  
    6.43  SDL_bool
    6.44 @@ -70,36 +55,35 @@
    6.45  int
    6.46  UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
    6.47  {
    6.48 -    int clicked;
    6.49      int i;
    6.50      const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
    6.51  
    6.52      @autoreleasepool {
    6.53 -        UIAlertView* alert = [[UIAlertView alloc] init];
    6.54 -        UIKit_UIAlertViewDelegate *delegate = [[UIKit_UIAlertViewDelegate alloc] initWithButtonIndex:&clicked];
    6.55 +        UIAlertView *alert = [[UIAlertView alloc] init];
    6.56 +        SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init];
    6.57  
    6.58 +        alert.delegate = delegate;
    6.59          alert.title = @(messageboxdata->title);
    6.60          alert.message = @(messageboxdata->message);
    6.61 -        alert.delegate = delegate;
    6.62  
    6.63          for (i = 0; i < messageboxdata->numbuttons; ++i) {
    6.64              [alert addButtonWithTitle:@(buttons[i].text)];
    6.65          }
    6.66  
    6.67          /* Set up for showing the alert */
    6.68 -        clicked = messageboxdata->numbuttons;
    6.69 +        delegate.clickedIndex = messageboxdata->numbuttons;
    6.70  
    6.71          [alert show];
    6.72  
    6.73          /* Run the main event loop until the alert has finished */
    6.74          /* Note that this needs to be done on the main thread */
    6.75          s_showingMessageBox = SDL_TRUE;
    6.76 -        while (clicked == messageboxdata->numbuttons) {
    6.77 +        while (delegate.clickedIndex == messageboxdata->numbuttons) {
    6.78              [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    6.79          }
    6.80          s_showingMessageBox = SDL_FALSE;
    6.81  
    6.82 -        *buttonid = messageboxdata->buttons[clicked].buttonid;
    6.83 +        *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid;
    6.84  
    6.85          alert.delegate = nil;
    6.86      }
     7.1 --- a/src/video/uikit/SDL_uikitmodes.m	Tue Dec 02 02:52:45 2014 -0400
     7.2 +++ b/src/video/uikit/SDL_uikitmodes.m	Thu Jan 15 01:06:14 2015 -0400
     7.3 @@ -112,7 +112,7 @@
     7.4  static int
     7.5  UIKit_AddDisplay(UIScreen *uiscreen)
     7.6  {
     7.7 -    CGSize size = [uiscreen bounds].size;
     7.8 +    CGSize size = uiscreen.bounds.size;
     7.9  
    7.10      /* Make sure the width/height are oriented correctly */
    7.11      if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
    7.12 @@ -128,7 +128,7 @@
    7.13      mode.w = (int) size.width;
    7.14      mode.h = (int) size.height;
    7.15  
    7.16 -    UIScreenMode *uiscreenmode = [uiscreen currentMode];
    7.17 +    UIScreenMode *uiscreenmode = uiscreen.currentMode;
    7.18  
    7.19      if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
    7.20          return -1;
    7.21 @@ -157,9 +157,9 @@
    7.22  UIKit_IsDisplayLandscape(UIScreen *uiscreen)
    7.23  {
    7.24      if (uiscreen == [UIScreen mainScreen]) {
    7.25 -        return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
    7.26 +        return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
    7.27      } else {
    7.28 -        CGSize size = [uiscreen bounds].size;
    7.29 +        CGSize size = uiscreen.bounds.size;
    7.30          return (size.width > size.height);
    7.31      }
    7.32  }
    7.33 @@ -196,7 +196,7 @@
    7.34          }
    7.35  #endif
    7.36  
    7.37 -        for (UIScreenMode *uimode in [data.uiscreen availableModes]) {
    7.38 +        for (UIScreenMode *uimode in data.uiscreen.availableModes) {
    7.39              /* The size of a UIScreenMode is in pixels, but we deal exclusively
    7.40               * in points (except in SDL_GL_GetDrawableSize.) */
    7.41              int w = (int)(uimode.size.width / scale);
    7.42 @@ -209,7 +209,6 @@
    7.43                  h = tmp;
    7.44              }
    7.45  
    7.46 -            /* Add the native screen resolution. */
    7.47              UIKit_AddDisplayMode(display, w, h, uimode, addRotation);
    7.48          }
    7.49      }
    7.50 @@ -225,13 +224,16 @@
    7.51          [data.uiscreen setCurrentMode:modedata.uiscreenmode];
    7.52  
    7.53          if (data.uiscreen == [UIScreen mainScreen]) {
    7.54 +            /* [UIApplication setStatusBarOrientation:] no longer works reliably
    7.55 +             * in recent iOS versions, so we can't rotate the screen when setting
    7.56 +             * the display mode. */
    7.57              if (mode->w > mode->h) {
    7.58                  if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
    7.59 -                    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
    7.60 +                    return SDL_SetError("Screen orientation does not match display mode size");
    7.61                  }
    7.62              } else if (mode->w < mode->h) {
    7.63                  if (UIKit_IsDisplayLandscape(data.uiscreen)) {
    7.64 -                    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
    7.65 +                    return SDL_SetError("Screen orientation does not match display mode size");
    7.66                  }
    7.67              }
    7.68          }
     8.1 --- a/src/video/uikit/SDL_uikitopengles.m	Tue Dec 02 02:52:45 2014 -0400
     8.2 +++ b/src/video/uikit/SDL_uikitopengles.m	Thu Jan 15 01:06:14 2015 -0400
     8.3 @@ -23,10 +23,10 @@
     8.4  #if SDL_VIDEO_DRIVER_UIKIT
     8.5  
     8.6  #include "SDL_uikitopengles.h"
     8.7 -#include "SDL_uikitopenglview.h"
     8.8 -#include "SDL_uikitappdelegate.h"
     8.9 +#import "SDL_uikitopenglview.h"
    8.10  #include "SDL_uikitmodes.h"
    8.11  #include "SDL_uikitwindow.h"
    8.12 +#include "SDL_uikitevents.h"
    8.13  #include "../SDL_sysvideo.h"
    8.14  #include "../../events/SDL_keyboard_c.h"
    8.15  #include "../../events/SDL_mouse_c.h"
    8.16 @@ -40,21 +40,29 @@
    8.17  UIKit_GL_GetProcAddress(_THIS, const char *proc)
    8.18  {
    8.19      /* Look through all SO's for the proc symbol.  Here's why:
    8.20 -       -Looking for the path to the OpenGL Library seems not to work in the iPhone Simulator.
    8.21 -       -We don't know that the path won't change in the future.
    8.22 -    */
    8.23 +     * -Looking for the path to the OpenGL Library seems not to work in the iOS Simulator.
    8.24 +     * -We don't know that the path won't change in the future. */
    8.25      return dlsym(RTLD_DEFAULT, proc);
    8.26  }
    8.27  
    8.28  /*
    8.29 -    note that SDL_GL_Delete context makes it current without passing the window
    8.30 +  note that SDL_GL_DeleteContext makes it current without passing the window
    8.31  */
    8.32  int
    8.33  UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
    8.34  {
    8.35      @autoreleasepool {
    8.36 -        [EAGLContext setCurrentContext:(__bridge EAGLContext *)context];
    8.37 +        SDLEAGLContext *eaglcontext = (__bridge SDLEAGLContext *) context;
    8.38 +
    8.39 +        if (![EAGLContext setCurrentContext:eaglcontext]) {
    8.40 +            return SDL_SetError("Could not make EAGL context current");
    8.41 +        }
    8.42 +
    8.43 +        if (eaglcontext) {
    8.44 +            [eaglcontext.sdlView setSDLWindow:window];
    8.45 +        }
    8.46      }
    8.47 +
    8.48      return 0;
    8.49  }
    8.50  
    8.51 @@ -63,27 +71,26 @@
    8.52  {
    8.53      @autoreleasepool {
    8.54          SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
    8.55 -
    8.56 -        if (w) {
    8.57 -            *w = data.view.backingWidth;
    8.58 -        }
    8.59 -        if (h) {
    8.60 -            *h = data.view.backingHeight;
    8.61 +        UIView *view = data.viewcontroller.view;
    8.62 +        if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
    8.63 +            SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
    8.64 +            if (w) {
    8.65 +                *w = glview.backingWidth;
    8.66 +            }
    8.67 +            if (h) {
    8.68 +                *h = glview.backingHeight;
    8.69 +            }
    8.70          }
    8.71      }
    8.72  }
    8.73  
    8.74 -
    8.75  int
    8.76  UIKit_GL_LoadLibrary(_THIS, const char *path)
    8.77  {
    8.78 -    /*
    8.79 -        shouldn't be passing a path into this function
    8.80 -        why?  Because we've already loaded the library
    8.81 -        and because the SDK forbids loading an external SO
    8.82 -    */
    8.83 +    /* We shouldn't pass a path to this function, since we've already loaded the
    8.84 +     * library. */
    8.85      if (path != NULL) {
    8.86 -        return SDL_SetError("iPhone GL Load Library just here for compatibility");
    8.87 +        return SDL_SetError("iOS GL Load Library just here for compatibility");
    8.88      }
    8.89      return 0;
    8.90  }
    8.91 @@ -91,22 +98,18 @@
    8.92  void UIKit_GL_SwapWindow(_THIS, SDL_Window * window)
    8.93  {
    8.94      @autoreleasepool {
    8.95 -        SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
    8.96 +        SDLEAGLContext *context = (__bridge SDLEAGLContext *) SDL_GL_GetCurrentContext();
    8.97  
    8.98  #if SDL_POWER_UIKIT
    8.99          /* Check once a frame to see if we should turn off the battery monitor. */
   8.100          SDL_UIKit_UpdateBatteryMonitoring();
   8.101  #endif
   8.102  
   8.103 -        if (data.view == nil) {
   8.104 -            return;
   8.105 -        }
   8.106 -        [data.view swapBuffers];
   8.107 +        [context.sdlView swapBuffers];
   8.108  
   8.109          /* You need to pump events in order for the OS to make changes visible.
   8.110 -           We don't pump events here because we don't want iOS application events
   8.111 -           (low memory, terminate, etc.) to happen inside low level rendering.
   8.112 -         */
   8.113 +         * We don't pump events here because we don't want iOS application events
   8.114 +         * (low memory, terminate, etc.) to happen inside low level rendering. */
   8.115      }
   8.116  }
   8.117  
   8.118 @@ -116,31 +119,29 @@
   8.119      @autoreleasepool {
   8.120          SDL_uikitopenglview *view;
   8.121          SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
   8.122 -        UIWindow *uiwindow = data.uiwindow;
   8.123 -        CGRect frame = UIKit_ComputeViewFrame(window, uiwindow.screen);
   8.124 -        EAGLSharegroup *share_group = nil;
   8.125 +        CGRect frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
   8.126 +        EAGLSharegroup *sharegroup = nil;
   8.127          CGFloat scale = 1.0;
   8.128  
   8.129 +        if (_this->gl_config.share_with_current_context) {
   8.130 +            EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext();
   8.131 +            sharegroup = context.sharegroup;
   8.132 +        }
   8.133 +
   8.134          if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
   8.135              /* Set the scale to the natural scale factor of the screen - the
   8.136 -               backing dimensions of the OpenGL view will match the pixel
   8.137 -               dimensions of the screen rather than the dimensions in points.
   8.138 -             */
   8.139 +             * backing dimensions of the OpenGL view will match the pixel
   8.140 +             * dimensions of the screen rather than the dimensions in points. */
   8.141  #ifdef __IPHONE_8_0
   8.142 -            if ([uiwindow.screen respondsToSelector:@selector(nativeScale)]) {
   8.143 -                scale = uiwindow.screen.nativeScale;
   8.144 +            if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) {
   8.145 +                scale = data.uiwindow.screen.nativeScale;
   8.146              } else
   8.147  #endif
   8.148              {
   8.149 -                scale = uiwindow.screen.scale;
   8.150 +                scale = data.uiwindow.screen.scale;
   8.151              }
   8.152          }
   8.153  
   8.154 -        if (_this->gl_config.share_with_current_context) {
   8.155 -            EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext();
   8.156 -            share_group = context.sharegroup;
   8.157 -        }
   8.158 -
   8.159          /* construct our view, passing in SDL's OpenGL configuration data */
   8.160          view = [[SDL_uikitopenglview alloc] initWithFrame:frame
   8.161                                                      scale:scale
   8.162 @@ -153,35 +154,19 @@
   8.163                                                stencilBits:_this->gl_config.stencil_size
   8.164                                                       sRGB:_this->gl_config.framebuffer_srgb_capable
   8.165                                               majorVersion:_this->gl_config.major_version
   8.166 -                                               shareGroup:share_group];
   8.167 +                                               shareGroup:sharegroup];
   8.168          if (!view) {
   8.169              return NULL;
   8.170          }
   8.171  
   8.172 -        view.sdlwindow = window;
   8.173 -        data.view = view;
   8.174 -        data.viewcontroller.view = view;
   8.175 -
   8.176 -        /* The view controller needs to be the root in order to control rotation */
   8.177 -        if (uiwindow.rootViewController == nil) {
   8.178 -            uiwindow.rootViewController = data.viewcontroller;
   8.179 -        } else {
   8.180 -            [uiwindow addSubview:view];
   8.181 -        }
   8.182 -
   8.183 -        EAGLContext *context = view.context;
   8.184 +        SDLEAGLContext *context = view.context;
   8.185          if (UIKit_GL_MakeCurrent(_this, window, (__bridge SDL_GLContext) context) < 0) {
   8.186              UIKit_GL_DeleteContext(_this, (SDL_GLContext) CFBridgingRetain(context));
   8.187              return NULL;
   8.188          }
   8.189  
   8.190 -        /* Make this window the current mouse focus for touch input */
   8.191 -        if (uiwindow.screen == [UIScreen mainScreen]) {
   8.192 -            SDL_SetMouseFocus(window);
   8.193 -            SDL_SetKeyboardFocus(window);
   8.194 -        }
   8.195 -
   8.196 -        /* We return a +1'd context. The window's driverdata owns the view. */
   8.197 +        /* We return a +1'd context. The window's driverdata owns the view (via
   8.198 +         * MakeCurrent.) */
   8.199          return (SDL_GLContext) CFBridgingRetain(context);
   8.200      }
   8.201  }
   8.202 @@ -191,29 +176,10 @@
   8.203  {
   8.204      @autoreleasepool {
   8.205          /* Transfer ownership the +1'd context to ARC. */
   8.206 -        EAGLContext *eaglcontext = (EAGLContext *) CFBridgingRelease(context);
   8.207 -        SDL_Window *window;
   8.208 +        SDLEAGLContext *eaglcontext = (SDLEAGLContext *) CFBridgingRelease(context);
   8.209  
   8.210 -        /* Find the view associated with this context */
   8.211 -        for (window = _this->windows; window; window = window->next) {
   8.212 -            SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
   8.213 -            SDL_uikitopenglview *view = data.view;
   8.214 -            if (view.context == eaglcontext) {
   8.215 -                /* the view controller has retained the view */
   8.216 -                if (data.viewcontroller) {
   8.217 -                    UIWindow *uiwindow = (UIWindow *)view.superview;
   8.218 -                    if (uiwindow.rootViewController == data.viewcontroller) {
   8.219 -                        uiwindow.rootViewController = nil;
   8.220 -                    }
   8.221 -                    data.viewcontroller.view = nil;
   8.222 -                }
   8.223 -
   8.224 -                [view removeFromSuperview];
   8.225 -                view.sdlwindow = NULL;
   8.226 -                data.view = nil;
   8.227 -                return;
   8.228 -            }
   8.229 -        }
   8.230 +        /* Detach the context's view from its window. */
   8.231 +        [eaglcontext.sdlView setSDLWindow:NULL];
   8.232      }
   8.233  }
   8.234  
   8.235 @@ -227,12 +193,15 @@
   8.236  
   8.237      @autoreleasepool {
   8.238          SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
   8.239 -        if (data.view != nil) {
   8.240 -            return data.view.drawableRenderbuffer;
   8.241 -        } else {
   8.242 -            return 0;
   8.243 +        UIView *view = data.viewcontroller.view;
   8.244 +        if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
   8.245 +            SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
   8.246 +            return glview.drawableRenderbuffer;
   8.247          }
   8.248      }
   8.249 +
   8.250 +    SDL_SetError("Window does not have an attached OpenGL view");
   8.251 +    return 0;
   8.252  }
   8.253  
   8.254  Uint32
   8.255 @@ -245,12 +214,15 @@
   8.256  
   8.257      @autoreleasepool {
   8.258          SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
   8.259 -        if (data.view != nil) {
   8.260 -            return data.view.drawableFramebuffer;
   8.261 -        } else {
   8.262 -            return 0;
   8.263 +        UIView *view = data.viewcontroller.view;
   8.264 +        if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
   8.265 +            SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
   8.266 +            return glview.drawableFramebuffer;
   8.267          }
   8.268      }
   8.269 +
   8.270 +    SDL_SetError("Window does not have an attached OpenGL view");
   8.271 +    return 0;
   8.272  }
   8.273  
   8.274  #endif /* SDL_VIDEO_DRIVER_UIKIT */
     9.1 --- a/src/video/uikit/SDL_uikitopenglview.h	Tue Dec 02 02:52:45 2014 -0400
     9.2 +++ b/src/video/uikit/SDL_uikitopenglview.h	Thu Jan 15 01:06:14 2015 -0400
     9.3 @@ -21,29 +21,35 @@
     9.4  
     9.5  #import <UIKit/UIKit.h>
     9.6  #import <OpenGLES/EAGL.h>
     9.7 -#import <OpenGLES/gltypes.h>
     9.8 +#import <OpenGLES/ES2/gl.h>
     9.9 +
    9.10  #import "SDL_uikitview.h"
    9.11 -/*
    9.12 -    This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
    9.13 -    The view content is basically an EAGL surface you render your OpenGL scene into.
    9.14 -    Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
    9.15 - */
    9.16 +#include "SDL_uikitvideo.h"
    9.17 +
    9.18 +@class SDL_uikitopenglview;
    9.19 +
    9.20 +@interface SDLEAGLContext : EAGLContext
    9.21 +
    9.22 +@property (nonatomic, weak) SDL_uikitopenglview *sdlView;
    9.23 +
    9.24 +@end
    9.25 +
    9.26  @interface SDL_uikitopenglview : SDL_uikitview
    9.27  
    9.28 -- (id)initWithFrame:(CGRect)frame
    9.29 -              scale:(CGFloat)scale
    9.30 -      retainBacking:(BOOL)retained
    9.31 -              rBits:(int)rBits
    9.32 -              gBits:(int)gBits
    9.33 -              bBits:(int)bBits
    9.34 -              aBits:(int)aBits
    9.35 -          depthBits:(int)depthBits
    9.36 -        stencilBits:(int)stencilBits
    9.37 -               sRGB:(BOOL)sRGB
    9.38 -       majorVersion:(int)majorVersion
    9.39 -         shareGroup:(EAGLSharegroup*)shareGroup;
    9.40 +- (instancetype)initWithFrame:(CGRect)frame
    9.41 +                        scale:(CGFloat)scale
    9.42 +                retainBacking:(BOOL)retained
    9.43 +                        rBits:(int)rBits
    9.44 +                        gBits:(int)gBits
    9.45 +                        bBits:(int)bBits
    9.46 +                        aBits:(int)aBits
    9.47 +                    depthBits:(int)depthBits
    9.48 +                  stencilBits:(int)stencilBits
    9.49 +                         sRGB:(BOOL)sRGB
    9.50 +                 majorVersion:(int)majorVersion
    9.51 +                   shareGroup:(EAGLSharegroup*)shareGroup;
    9.52  
    9.53 -@property (nonatomic, strong, readonly) EAGLContext *context;
    9.54 +@property (nonatomic, readonly, strong) SDLEAGLContext *context;
    9.55  
    9.56  /* The width and height of the drawable in pixels (as opposed to points.) */
    9.57  @property (nonatomic, readonly) int backingWidth;
    9.58 @@ -57,17 +63,6 @@
    9.59  
    9.60  - (void)updateFrame;
    9.61  
    9.62 -- (void)setDebugLabels;
    9.63 -
    9.64 -- (void)setAnimationCallback:(int)interval
    9.65 -                    callback:(void (*)(void*))callback
    9.66 -               callbackParam:(void*)callbackParam;
    9.67 -
    9.68 -- (void)startAnimation;
    9.69 -- (void)stopAnimation;
    9.70 -
    9.71 -- (void)doLoop:(CADisplayLink*)sender;
    9.72 -
    9.73  @end
    9.74  
    9.75  /* vi: set ts=4 sw=4 expandtab: */
    10.1 --- a/src/video/uikit/SDL_uikitopenglview.m	Tue Dec 02 02:52:45 2014 -0400
    10.2 +++ b/src/video/uikit/SDL_uikitopenglview.m	Thu Jan 15 01:06:14 2015 -0400
    10.3 @@ -22,34 +22,27 @@
    10.4  
    10.5  #if SDL_VIDEO_DRIVER_UIKIT
    10.6  
    10.7 -#include <QuartzCore/QuartzCore.h>
    10.8  #include <OpenGLES/EAGLDrawable.h>
    10.9 -#include <OpenGLES/ES2/gl.h>
   10.10  #include <OpenGLES/ES2/glext.h>
   10.11 -#include "SDL_uikitopenglview.h"
   10.12 -#include "SDL_uikitmessagebox.h"
   10.13 -#include "SDL_uikitvideo.h"
   10.14 +#import "SDL_uikitopenglview.h"
   10.15 +#include "SDL_uikitwindow.h"
   10.16  
   10.17 +@implementation SDLEAGLContext
   10.18 +
   10.19 +@end
   10.20  
   10.21  @implementation SDL_uikitopenglview {
   10.22 -
   10.23 -    /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
   10.24 +    /* The renderbuffer and framebuffer used to render to this layer. */
   10.25      GLuint viewRenderbuffer, viewFramebuffer;
   10.26  
   10.27 -    /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
   10.28 +    /* The depth buffer that is attached to viewFramebuffer, if it exists. */
   10.29      GLuint depthRenderbuffer;
   10.30  
   10.31      /* format of depthRenderbuffer */
   10.32      GLenum depthBufferFormat;
   10.33 -
   10.34 -    id displayLink;
   10.35 -    int animationInterval;
   10.36 -    void (*animationCallback)(void*);
   10.37 -    void *animationCallbackParam;
   10.38  }
   10.39  
   10.40  @synthesize context;
   10.41 -
   10.42  @synthesize backingWidth;
   10.43  @synthesize backingHeight;
   10.44  
   10.45 @@ -58,38 +51,36 @@
   10.46      return [CAEAGLLayer class];
   10.47  }
   10.48  
   10.49 -- (id)initWithFrame:(CGRect)frame
   10.50 -              scale:(CGFloat)scale
   10.51 -      retainBacking:(BOOL)retained
   10.52 -              rBits:(int)rBits
   10.53 -              gBits:(int)gBits
   10.54 -              bBits:(int)bBits
   10.55 -              aBits:(int)aBits
   10.56 -          depthBits:(int)depthBits
   10.57 -        stencilBits:(int)stencilBits
   10.58 -               sRGB:(BOOL)sRGB
   10.59 -       majorVersion:(int)majorVersion
   10.60 -         shareGroup:(EAGLSharegroup*)shareGroup
   10.61 +- (instancetype)initWithFrame:(CGRect)frame
   10.62 +                        scale:(CGFloat)scale
   10.63 +                retainBacking:(BOOL)retained
   10.64 +                        rBits:(int)rBits
   10.65 +                        gBits:(int)gBits
   10.66 +                        bBits:(int)bBits
   10.67 +                        aBits:(int)aBits
   10.68 +                    depthBits:(int)depthBits
   10.69 +                  stencilBits:(int)stencilBits
   10.70 +                         sRGB:(BOOL)sRGB
   10.71 +                 majorVersion:(int)majorVersion
   10.72 +                   shareGroup:(EAGLSharegroup*)shareGroup
   10.73  {
   10.74      if ((self = [super initWithFrame:frame])) {
   10.75          const BOOL useStencilBuffer = (stencilBits != 0);
   10.76          const BOOL useDepthBuffer = (depthBits != 0);
   10.77          NSString *colorFormat = nil;
   10.78  
   10.79 -        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
   10.80 -        self.autoresizesSubviews = YES;
   10.81 -
   10.82          /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES
   10.83 -           versions, and this allows us to handle future OpenGL ES versions.
   10.84 -         */
   10.85 +         * versions, and this allows us to handle future OpenGL ES versions. */
   10.86          EAGLRenderingAPI api = majorVersion;
   10.87  
   10.88 -        context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
   10.89 +        context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
   10.90          if (!context || ![EAGLContext setCurrentContext:context]) {
   10.91              SDL_SetError("OpenGL ES %d not supported", majorVersion);
   10.92              return nil;
   10.93          }
   10.94  
   10.95 +        context.sdlView = self;
   10.96 +
   10.97          if (sRGB) {
   10.98              /* sRGB EAGL drawable support was added in iOS 7. */
   10.99              if (UIKit_IsSystemVersionAtLeast(7.0)) {
  10.100 @@ -102,11 +93,10 @@
  10.101              /* if user specifically requests rbg888 or some color format higher than 16bpp */
  10.102              colorFormat = kEAGLColorFormatRGBA8;
  10.103          } else {
  10.104 -            /* default case (faster) */
  10.105 +            /* default case (potentially faster) */
  10.106              colorFormat = kEAGLColorFormatRGB565;
  10.107          }
  10.108  
  10.109 -        /* Get the layer */
  10.110          CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
  10.111  
  10.112          eaglLayer.opaque = YES;
  10.113 @@ -142,7 +132,8 @@
  10.114                  /* Apparently you need to pack stencil and depth into one buffer. */
  10.115                  depthBufferFormat = GL_DEPTH24_STENCIL8_OES;
  10.116              } else if (useDepthBuffer) {
  10.117 -                /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16 */
  10.118 +                /* iOS only uses 32-bit float (exposed as fixed point 24-bit)
  10.119 +                 * depth buffers. */
  10.120                  depthBufferFormat = GL_DEPTH_COMPONENT24_OES;
  10.121              }
  10.122  
  10.123 @@ -186,7 +177,7 @@
  10.124      glGetIntegerv(GL_RENDERBUFFER_BINDING, &prevRenderbuffer);
  10.125  
  10.126      glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
  10.127 -    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
  10.128 +    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
  10.129  
  10.130      glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
  10.131      glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
  10.132 @@ -218,42 +209,6 @@
  10.133      }
  10.134  }
  10.135  
  10.136 -- (void)setAnimationCallback:(int)interval
  10.137 -                    callback:(void (*)(void*))callback
  10.138 -               callbackParam:(void*)callbackParam
  10.139 -{
  10.140 -    [self stopAnimation];
  10.141 -
  10.142 -    animationInterval = interval;
  10.143 -    animationCallback = callback;
  10.144 -    animationCallbackParam = callbackParam;
  10.145 -
  10.146 -    if (animationCallback) {
  10.147 -        [self startAnimation];
  10.148 -    }
  10.149 -}
  10.150 -
  10.151 -- (void)startAnimation
  10.152 -{
  10.153 -    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
  10.154 -    [displayLink setFrameInterval:animationInterval];
  10.155 -    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  10.156 -}
  10.157 -
  10.158 -- (void)stopAnimation
  10.159 -{
  10.160 -    [displayLink invalidate];
  10.161 -    displayLink = nil;
  10.162 -}
  10.163 -
  10.164 -- (void)doLoop:(CADisplayLink*)sender
  10.165 -{
  10.166 -    /* Don't run the game loop while a messagebox is up */
  10.167 -    if (!UIKit_ShowingMessageBox()) {
  10.168 -        animationCallback(animationCallbackParam);
  10.169 -    }
  10.170 -}
  10.171 -
  10.172  - (void)setCurrentContext
  10.173  {
  10.174      [EAGLContext setCurrentContext:context];
  10.175 @@ -262,8 +217,8 @@
  10.176  - (void)swapBuffers
  10.177  {
  10.178      /* viewRenderbuffer should always be bound here. Code that binds something
  10.179 -       else is responsible for rebinding viewRenderbuffer, to reduce duplicate
  10.180 -       state changes. */
  10.181 +     * else is responsible for rebinding viewRenderbuffer, to reduce duplicate
  10.182 +     * state changes. */
  10.183      [context presentRenderbuffer:GL_RENDERBUFFER];
  10.184  }
  10.185  
  10.186 @@ -271,14 +226,21 @@
  10.187  {
  10.188      [super layoutSubviews];
  10.189  
  10.190 -    CGSize layersize = self.layer.bounds.size;
  10.191 -    int width = (int) (layersize.width * self.layer.contentsScale);
  10.192 -    int height = (int) (layersize.height * self.layer.contentsScale);
  10.193 +    int width  = (int) (self.bounds.size.width * self.contentScaleFactor);
  10.194 +    int height = (int) (self.bounds.size.height * self.contentScaleFactor);
  10.195  
  10.196      /* Update the color and depth buffer storage if the layer size has changed. */
  10.197      if (width != backingWidth || height != backingHeight) {
  10.198 -        [EAGLContext setCurrentContext:context];
  10.199 +        EAGLContext *prevContext = [EAGLContext currentContext];
  10.200 +        if (prevContext != context) {
  10.201 +            [EAGLContext setCurrentContext:context];
  10.202 +        }
  10.203 +
  10.204          [self updateFrame];
  10.205 +
  10.206 +        if (prevContext != context) {
  10.207 +            [EAGLContext setCurrentContext:prevContext];
  10.208 +        }
  10.209      }
  10.210  }
  10.211  
  10.212 @@ -300,7 +262,6 @@
  10.213      }
  10.214  }
  10.215  
  10.216 -
  10.217  - (void)dealloc
  10.218  {
  10.219      if ([EAGLContext currentContext] == context) {
    11.1 --- a/src/video/uikit/SDL_uikitview.h	Tue Dec 02 02:52:45 2014 -0400
    11.2 +++ b/src/video/uikit/SDL_uikitview.h	Thu Jan 15 01:06:14 2015 -0400
    11.3 @@ -20,46 +20,22 @@
    11.4  */
    11.5  
    11.6  #import <UIKit/UIKit.h>
    11.7 +
    11.8  #include "../SDL_sysvideo.h"
    11.9  
   11.10  #include "SDL_touch.h"
   11.11  
   11.12 -#if SDL_IPHONE_KEYBOARD
   11.13 -@interface SDL_uikitview : UIView <UITextFieldDelegate>
   11.14 -#else
   11.15  @interface SDL_uikitview : UIView
   11.16 -#endif
   11.17  
   11.18 -@property (nonatomic, assign) SDL_Window *sdlwindow;
   11.19 +- (instancetype)initWithFrame:(CGRect)frame;
   11.20 +
   11.21 +- (void)setSDLWindow:(SDL_Window *)window;
   11.22  
   11.23  - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize;
   11.24  - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
   11.25  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
   11.26  - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
   11.27  
   11.28 -#if SDL_IPHONE_KEYBOARD
   11.29 -- (void)showKeyboard;
   11.30 -- (void)hideKeyboard;
   11.31 -- (void)initKeyboard;
   11.32 -- (void)deinitKeyboard;
   11.33 -
   11.34 -- (void)keyboardWillShow:(NSNotification *)notification;
   11.35 -- (void)keyboardWillHide:(NSNotification *)notification;
   11.36 -
   11.37 -- (void)updateKeyboard;
   11.38 -
   11.39 -@property (nonatomic, assign, getter=isKeyboardVisible) BOOL keyboardVisible;
   11.40 -@property (nonatomic, assign) SDL_Rect textInputRect;
   11.41 -@property (nonatomic, assign) int keyboardHeight;
   11.42 -
   11.43 -SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
   11.44 -void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
   11.45 -void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
   11.46 -SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
   11.47 -void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
   11.48 -
   11.49 -#endif
   11.50 -
   11.51  @end
   11.52  
   11.53  /* vi: set ts=4 sw=4 expandtab: */
    12.1 --- a/src/video/uikit/SDL_uikitview.m	Tue Dec 02 02:52:45 2014 -0400
    12.2 +++ b/src/video/uikit/SDL_uikitview.m	Thu Jan 15 01:06:14 2015 -0400
    12.3 @@ -24,36 +24,26 @@
    12.4  
    12.5  #include "SDL_uikitview.h"
    12.6  
    12.7 -#include "../../events/SDL_keyboard_c.h"
    12.8  #include "../../events/SDL_mouse_c.h"
    12.9  #include "../../events/SDL_touch_c.h"
   12.10 +#include "../../events/SDL_events_c.h"
   12.11  
   12.12 -#if SDL_IPHONE_KEYBOARD
   12.13 -#include "keyinfotable.h"
   12.14 -#endif
   12.15 -#include "SDL_uikitappdelegate.h"
   12.16 -#include "SDL_uikitmodes.h"
   12.17 -#include "SDL_uikitwindow.h"
   12.18 +#import "SDL_uikitappdelegate.h"
   12.19 +#import "SDL_uikitmodes.h"
   12.20 +#import "SDL_uikitwindow.h"
   12.21  
   12.22  @implementation SDL_uikitview {
   12.23 +    SDL_Window *sdlwindow;
   12.24  
   12.25      SDL_TouchID touchId;
   12.26 -    UITouch *leftFingerDown;
   12.27 -
   12.28 -#if SDL_IPHONE_KEYBOARD
   12.29 -    UITextField *textField;
   12.30 -#endif
   12.31 -
   12.32 +    UITouch * __weak firstFingerDown;
   12.33  }
   12.34  
   12.35 -@synthesize sdlwindow;
   12.36 -
   12.37 -- (id)initWithFrame:(CGRect)frame
   12.38 +- (instancetype)initWithFrame:(CGRect)frame
   12.39  {
   12.40 -    if (self = [super initWithFrame:frame]) {
   12.41 -#if SDL_IPHONE_KEYBOARD
   12.42 -        [self initKeyboard];
   12.43 -#endif
   12.44 +    if ((self = [super initWithFrame:frame])) {
   12.45 +        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
   12.46 +        self.autoresizesSubviews = YES;
   12.47  
   12.48          self.multipleTouchEnabled = YES;
   12.49  
   12.50 @@ -62,14 +52,65 @@
   12.51      }
   12.52  
   12.53      return self;
   12.54 -
   12.55  }
   12.56  
   12.57 -- (void)dealloc
   12.58 +- (void)setSDLWindow:(SDL_Window *)window
   12.59  {
   12.60 -#if SDL_IPHONE_KEYBOARD
   12.61 -    [self deinitKeyboard];
   12.62 -#endif
   12.63 +    SDL_WindowData *data = nil;
   12.64 +
   12.65 +    if (window == sdlwindow) {
   12.66 +        return;
   12.67 +    }
   12.68 +
   12.69 +    if (sdlwindow) {
   12.70 +        SDL_uikitview *view = nil;
   12.71 +        data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
   12.72 +
   12.73 +        [data.views removeObject:self];
   12.74 +
   12.75 +        [self removeFromSuperview];
   12.76 +
   12.77 +        /* Restore the next-oldest view in the old window. */
   12.78 +        if (data.views.count > 0) {
   12.79 +            view = data.views[data.views.count - 1];
   12.80 +        }
   12.81 +
   12.82 +        data.viewcontroller.view = view;
   12.83 +
   12.84 +        if (data.uiwindow.rootViewController != data.viewcontroller) {
   12.85 +            data.uiwindow.rootViewController = data.viewcontroller;
   12.86 +        } else if (view) {
   12.87 +            [data.uiwindow addSubview:view];
   12.88 +        }
   12.89 +
   12.90 +        [data.uiwindow layoutIfNeeded];
   12.91 +    }
   12.92 +
   12.93 +    if (window) {
   12.94 +        data = (__bridge SDL_WindowData *) window->driverdata;
   12.95 +
   12.96 +        /* Make sure the SDL window has a strong reference to this view. */
   12.97 +        [data.views addObject:self];
   12.98 +
   12.99 +        /* Replace the view controller's old view with this one. */
  12.100 +        [data.viewcontroller.view removeFromSuperview];
  12.101 +        data.viewcontroller.view = self;
  12.102 +
  12.103 +        if (data.uiwindow.rootViewController != data.viewcontroller) {
  12.104 +            /* The root view controller handles rotation and the status bar.
  12.105 +             * Assigning it also adds the controller's view to the window. */
  12.106 +            data.uiwindow.rootViewController = data.viewcontroller;
  12.107 +        } else {
  12.108 +            [data.uiwindow addSubview:self];
  12.109 +        }
  12.110 +
  12.111 +        /* The view's bounds may not be correct until the next event cycle. That
  12.112 +         * might happen after the current dimensions are queried, so we force a
  12.113 +         * layout now to immediately update the bounds. */
  12.114 +        [data.uiwindow layoutIfNeeded];
  12.115 +    }
  12.116 +
  12.117 +    sdlwindow = window;
  12.118  }
  12.119  
  12.120  - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
  12.121 @@ -88,16 +129,16 @@
  12.122  - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  12.123  {
  12.124      for (UITouch *touch in touches) {
  12.125 -        if (!leftFingerDown) {
  12.126 +        if (!firstFingerDown) {
  12.127              CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
  12.128  
  12.129 -            /* send moved event */
  12.130 +            /* send mouse moved event */
  12.131              SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
  12.132  
  12.133              /* send mouse down event */
  12.134              SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
  12.135  
  12.136 -            leftFingerDown = touch;
  12.137 +            firstFingerDown = touch;
  12.138          }
  12.139  
  12.140          CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
  12.141 @@ -109,10 +150,10 @@
  12.142  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
  12.143  {
  12.144      for (UITouch *touch in touches) {
  12.145 -        if (touch == leftFingerDown) {
  12.146 +        if (touch == firstFingerDown) {
  12.147              /* send mouse up */
  12.148              SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
  12.149 -            leftFingerDown = nil;
  12.150 +            firstFingerDown = nil;
  12.151          }
  12.152  
  12.153          CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
  12.154 @@ -123,18 +164,13 @@
  12.155  
  12.156  - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
  12.157  {
  12.158 -    /*
  12.159 -        this can happen if the user puts more than 5 touches on the screen
  12.160 -        at once, or perhaps in other circumstances.  Usually (it seems)
  12.161 -        all active touches are canceled.
  12.162 -    */
  12.163      [self touchesEnded:touches withEvent:event];
  12.164  }
  12.165  
  12.166  - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
  12.167  {
  12.168      for (UITouch *touch in touches) {
  12.169 -        if (touch == leftFingerDown) {
  12.170 +        if (touch == firstFingerDown) {
  12.171              CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
  12.172  
  12.173              /* send moved event */
  12.174 @@ -147,274 +183,8 @@
  12.175      }
  12.176  }
  12.177  
  12.178 -/*
  12.179 -    ---- Keyboard related functionality below this line ----
  12.180 -*/
  12.181 -#if SDL_IPHONE_KEYBOARD
  12.182 -
  12.183 -@synthesize textInputRect;
  12.184 -@synthesize keyboardHeight;
  12.185 -@synthesize keyboardVisible;
  12.186 -
  12.187 -/* Set ourselves up as a UITextFieldDelegate */
  12.188 -- (void)initKeyboard
  12.189 -{
  12.190 -    textField = [[UITextField alloc] initWithFrame:CGRectZero];
  12.191 -    textField.delegate = self;
  12.192 -    /* placeholder so there is something to delete! */
  12.193 -    textField.text = @" ";
  12.194 -
  12.195 -    /* set UITextInputTrait properties, mostly to defaults */
  12.196 -    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
  12.197 -    textField.autocorrectionType = UITextAutocorrectionTypeNo;
  12.198 -    textField.enablesReturnKeyAutomatically = NO;
  12.199 -    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
  12.200 -    textField.keyboardType = UIKeyboardTypeDefault;
  12.201 -    textField.returnKeyType = UIReturnKeyDefault;
  12.202 -    textField.secureTextEntry = NO;
  12.203 -
  12.204 -    textField.hidden = YES;
  12.205 -    keyboardVisible = NO;
  12.206 -    /* add the UITextField (hidden) to our view */
  12.207 -    [self addSubview:textField];
  12.208 -
  12.209 -    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  12.210 -    [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
  12.211 -    [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
  12.212 -}
  12.213 -
  12.214 -- (void)deinitKeyboard
  12.215 -{
  12.216 -    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  12.217 -    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
  12.218 -    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
  12.219 -}
  12.220 -
  12.221 -/* reveal onscreen virtual keyboard */
  12.222 -- (void)showKeyboard
  12.223 -{
  12.224 -    keyboardVisible = YES;
  12.225 -    [textField becomeFirstResponder];
  12.226 -}
  12.227 -
  12.228 -/* hide onscreen virtual keyboard */
  12.229 -- (void)hideKeyboard
  12.230 -{
  12.231 -    keyboardVisible = NO;
  12.232 -    [textField resignFirstResponder];
  12.233 -}
  12.234 -
  12.235 -- (void)keyboardWillShow:(NSNotification *)notification
  12.236 -{
  12.237 -    CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
  12.238 -    int height;
  12.239 -
  12.240 -    /* The keyboard rect is in the coordinate space of the screen, but we want
  12.241 -     * its height in the view's coordinate space.
  12.242 -     */
  12.243 -#ifdef __IPHONE_8_0
  12.244 -    if ([self respondsToSelector:@selector(convertRect:fromCoordinateSpace:)]) {
  12.245 -        UIScreen *screen = self.window.screen;
  12.246 -        kbrect = [self convertRect:kbrect fromCoordinateSpace:screen.coordinateSpace];
  12.247 -        height = kbrect.size.height;
  12.248 -    } else
  12.249 -#endif
  12.250 -    {
  12.251 -        /* In iOS 7 and below, the screen's coordinate space is never rotated. */
  12.252 -        if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
  12.253 -            height = kbrect.size.width;
  12.254 -        } else {
  12.255 -            height = kbrect.size.height;
  12.256 -        }
  12.257 -    }
  12.258 -
  12.259 -    [self setKeyboardHeight:height];
  12.260 -}
  12.261 -
  12.262 - - (void)keyboardWillHide:(NSNotification *)notification
  12.263 -{
  12.264 -    [self setKeyboardHeight:0];
  12.265 -}
  12.266 -
  12.267 -- (void)updateKeyboard
  12.268 -{
  12.269 -    SDL_Rect textrect = self.textInputRect;
  12.270 -    CGAffineTransform t = self.transform;
  12.271 -    CGPoint offset = CGPointMake(0.0, 0.0);
  12.272 -
  12.273 -    if (self.keyboardHeight) {
  12.274 -        int rectbottom = textrect.y + textrect.h;
  12.275 -        int kbottom = self.bounds.size.height - self.keyboardHeight;
  12.276 -        if (kbottom < rectbottom) {
  12.277 -            offset.y = kbottom - rectbottom;
  12.278 -        }
  12.279 -    }
  12.280 -
  12.281 -    /* Put the offset into the this view transform's coordinate space. */
  12.282 -    t.tx = 0.0;
  12.283 -    t.ty = 0.0;
  12.284 -    offset = CGPointApplyAffineTransform(offset, t);
  12.285 -
  12.286 -    t.tx = offset.x;
  12.287 -    t.ty = offset.y;
  12.288 -
  12.289 -    /* Move the view by applying the updated transform. */
  12.290 -    self.transform = t;
  12.291 -}
  12.292 -
  12.293 -- (void)setKeyboardHeight:(int)height
  12.294 -{
  12.295 -    keyboardVisible = height > 0;
  12.296 -    keyboardHeight = height;
  12.297 -    [self updateKeyboard];
  12.298 -}
  12.299 -
  12.300 -/* UITextFieldDelegate method.  Invoked when user types something. */
  12.301 -- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
  12.302 -{
  12.303 -    NSUInteger len = string.length;
  12.304 -
  12.305 -    if (len == 0) {
  12.306 -        /* it wants to replace text with nothing, ie a delete */
  12.307 -        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
  12.308 -        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
  12.309 -    } else {
  12.310 -        /* go through all the characters in the string we've been sent
  12.311 -           and convert them to key presses */
  12.312 -        for (int i = 0; i < len; i++) {
  12.313 -            unichar c = [string characterAtIndex:i];
  12.314 -            Uint16 mod = 0;
  12.315 -            SDL_Scancode code;
  12.316 -
  12.317 -            if (c < 127) {
  12.318 -                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
  12.319 -                code = unicharToUIKeyInfoTable[c].code;
  12.320 -                mod  = unicharToUIKeyInfoTable[c].mod;
  12.321 -            }
  12.322 -            else {
  12.323 -                /* we only deal with ASCII right now */
  12.324 -                code = SDL_SCANCODE_UNKNOWN;
  12.325 -                mod = 0;
  12.326 -            }
  12.327 -
  12.328 -            if (mod & KMOD_SHIFT) {
  12.329 -                /* If character uses shift, press shift down */
  12.330 -                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
  12.331 -            }
  12.332 -
  12.333 -            /* send a keydown and keyup even for the character */
  12.334 -            SDL_SendKeyboardKey(SDL_PRESSED, code);
  12.335 -            SDL_SendKeyboardKey(SDL_RELEASED, code);
  12.336 -
  12.337 -            if (mod & KMOD_SHIFT) {
  12.338 -                /* If character uses shift, press shift back up */
  12.339 -                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
  12.340 -            }
  12.341 -        }
  12.342 -
  12.343 -        SDL_SendKeyboardText([string UTF8String]);
  12.344 -    }
  12.345 -
  12.346 -    return NO; /* don't allow the edit! (keep placeholder text there) */
  12.347 -}
  12.348 -
  12.349 -/* Terminates the editing session */
  12.350 -- (BOOL)textFieldShouldReturn:(UITextField*)_textField
  12.351 -{
  12.352 -    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
  12.353 -    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
  12.354 -    SDL_StopTextInput();
  12.355 -    return YES;
  12.356 -}
  12.357 -
  12.358 -#endif
  12.359 -
  12.360  @end
  12.361  
  12.362 -/* iPhone keyboard addition functions */
  12.363 -#if SDL_IPHONE_KEYBOARD
  12.364 -
  12.365 -static SDL_uikitview *
  12.366 -GetWindowView(SDL_Window * window)
  12.367 -{
  12.368 -    if (window == NULL) {
  12.369 -        SDL_SetError("Window does not exist");
  12.370 -        return nil;
  12.371 -    }
  12.372 -
  12.373 -    SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
  12.374 -    SDL_uikitview *view = data != nil ? data.view : nil;
  12.375 -
  12.376 -    if (view == nil) {
  12.377 -        SDL_SetError("Window has no view");
  12.378 -    }
  12.379 -
  12.380 -    return view;
  12.381 -}
  12.382 -
  12.383 -SDL_bool
  12.384 -UIKit_HasScreenKeyboardSupport(_THIS)
  12.385 -{
  12.386 -    return SDL_TRUE;
  12.387 -}
  12.388 -
  12.389 -void
  12.390 -UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
  12.391 -{
  12.392 -    @autoreleasepool {
  12.393 -        SDL_uikitview *view = GetWindowView(window);
  12.394 -        if (view != nil) {
  12.395 -            [view showKeyboard];
  12.396 -        }
  12.397 -    }
  12.398 -}
  12.399 -
  12.400 -void
  12.401 -UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
  12.402 -{
  12.403 -    @autoreleasepool {
  12.404 -        SDL_uikitview *view = GetWindowView(window);
  12.405 -        if (view != nil) {
  12.406 -            [view hideKeyboard];
  12.407 -        }
  12.408 -    }
  12.409 -}
  12.410 -
  12.411 -SDL_bool
  12.412 -UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
  12.413 -{
  12.414 -    @autoreleasepool {
  12.415 -        SDL_uikitview *view = GetWindowView(window);
  12.416 -        if (view != nil) {
  12.417 -            return view.isKeyboardVisible;
  12.418 -        }
  12.419 -        return 0;
  12.420 -    }
  12.421 -}
  12.422 -
  12.423 -void
  12.424 -UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
  12.425 -{
  12.426 -    if (!rect) {
  12.427 -        SDL_InvalidParamError("rect");
  12.428 -        return;
  12.429 -    }
  12.430 -
  12.431 -    @autoreleasepool {
  12.432 -        SDL_uikitview *view = GetWindowView(SDL_GetFocusWindow());
  12.433 -        if (view != nil) {
  12.434 -            view.textInputRect = *rect;
  12.435 -
  12.436 -            if (view.keyboardVisible) {
  12.437 -                [view updateKeyboard];
  12.438 -            }
  12.439 -        }
  12.440 -    }
  12.441 -}
  12.442 -
  12.443 -
  12.444 -#endif /* SDL_IPHONE_KEYBOARD */
  12.445 -
  12.446  #endif /* SDL_VIDEO_DRIVER_UIKIT */
  12.447  
  12.448  /* vi: set ts=4 sw=4 expandtab: */
    13.1 --- a/src/video/uikit/SDL_uikitviewcontroller.h	Tue Dec 02 02:52:45 2014 -0400
    13.2 +++ b/src/video/uikit/SDL_uikitviewcontroller.h	Thu Jan 15 01:06:14 2015 -0400
    13.3 @@ -23,11 +23,27 @@
    13.4  
    13.5  #include "../SDL_sysvideo.h"
    13.6  
    13.7 +#include "SDL_touch.h"
    13.8 +
    13.9 +#if SDL_IPHONE_KEYBOARD
   13.10 +@interface SDL_uikitviewcontroller : UIViewController <UITextFieldDelegate>
   13.11 +#else
   13.12  @interface SDL_uikitviewcontroller : UIViewController
   13.13 +#endif
   13.14  
   13.15  @property (nonatomic, assign) SDL_Window *window;
   13.16  
   13.17 -- (id)initWithSDLWindow:(SDL_Window *)_window;
   13.18 +- (instancetype)initWithSDLWindow:(SDL_Window *)_window;
   13.19 +
   13.20 +- (void)setAnimationCallback:(int)interval
   13.21 +                    callback:(void (*)(void*))callback
   13.22 +               callbackParam:(void*)callbackParam;
   13.23 +
   13.24 +- (void)startAnimation;
   13.25 +- (void)stopAnimation;
   13.26 +
   13.27 +- (void)doLoop:(CADisplayLink*)sender;
   13.28 +
   13.29  - (void)loadView;
   13.30  - (void)viewDidLayoutSubviews;
   13.31  - (NSUInteger)supportedInterfaceOrientations;
   13.32 @@ -35,4 +51,28 @@
   13.33  - (BOOL)prefersStatusBarHidden;
   13.34  - (UIStatusBarStyle)preferredStatusBarStyle;
   13.35  
   13.36 +#if SDL_IPHONE_KEYBOARD
   13.37 +- (void)showKeyboard;
   13.38 +- (void)hideKeyboard;
   13.39 +- (void)initKeyboard;
   13.40 +- (void)deinitKeyboard;
   13.41 +
   13.42 +- (void)keyboardWillShow:(NSNotification *)notification;
   13.43 +- (void)keyboardWillHide:(NSNotification *)notification;
   13.44 +
   13.45 +- (void)updateKeyboard;
   13.46 +
   13.47 +@property (nonatomic, assign, getter=isKeyboardVisible) BOOL keyboardVisible;
   13.48 +@property (nonatomic, assign) SDL_Rect textInputRect;
   13.49 +@property (nonatomic, assign) int keyboardHeight;
   13.50 +#endif
   13.51 +
   13.52  @end
   13.53 +
   13.54 +#if SDL_IPHONE_KEYBOARD
   13.55 +SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
   13.56 +void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
   13.57 +void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
   13.58 +SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
   13.59 +void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
   13.60 +#endif
    14.1 --- a/src/video/uikit/SDL_uikitviewcontroller.m	Tue Dec 02 02:52:45 2014 -0400
    14.2 +++ b/src/video/uikit/SDL_uikitviewcontroller.m	Thu Jan 15 01:06:14 2015 -0400
    14.3 @@ -28,27 +28,87 @@
    14.4  #include "../SDL_sysvideo.h"
    14.5  #include "../../events/SDL_events_c.h"
    14.6  
    14.7 -#include "SDL_uikitviewcontroller.h"
    14.8 +#import "SDL_uikitviewcontroller.h"
    14.9 +#import "SDL_uikitmessagebox.h"
   14.10  #include "SDL_uikitvideo.h"
   14.11  #include "SDL_uikitmodes.h"
   14.12  #include "SDL_uikitwindow.h"
   14.13  
   14.14 +#if SDL_IPHONE_KEYBOARD
   14.15 +#include "keyinfotable.h"
   14.16 +#endif
   14.17  
   14.18 -@implementation SDL_uikitviewcontroller
   14.19 +@implementation SDL_uikitviewcontroller {
   14.20 +    CADisplayLink *displayLink;
   14.21 +    int animationInterval;
   14.22 +    void (*animationCallback)(void*);
   14.23 +    void *animationCallbackParam;
   14.24 +
   14.25 +#if SDL_IPHONE_KEYBOARD
   14.26 +    UITextField *textField;
   14.27 +#endif
   14.28 +}
   14.29  
   14.30  @synthesize window;
   14.31  
   14.32 -- (id)initWithSDLWindow:(SDL_Window *)_window
   14.33 +- (instancetype)initWithSDLWindow:(SDL_Window *)_window
   14.34  {
   14.35      if (self = [super initWithNibName:nil bundle:nil]) {
   14.36          self.window = _window;
   14.37 +
   14.38 +#if SDL_IPHONE_KEYBOARD
   14.39 +        [self initKeyboard];
   14.40 +#endif
   14.41      }
   14.42      return self;
   14.43  }
   14.44  
   14.45 +- (void)dealloc
   14.46 +{
   14.47 +#if SDL_IPHONE_KEYBOARD
   14.48 +    [self deinitKeyboard];
   14.49 +#endif
   14.50 +}
   14.51 +
   14.52 +- (void)setAnimationCallback:(int)interval
   14.53 +                    callback:(void (*)(void*))callback
   14.54 +               callbackParam:(void*)callbackParam
   14.55 +{
   14.56 +    [self stopAnimation];
   14.57 +
   14.58 +    animationInterval = interval;
   14.59 +    animationCallback = callback;
   14.60 +    animationCallbackParam = callbackParam;
   14.61 +
   14.62 +    if (animationCallback) {
   14.63 +        [self startAnimation];
   14.64 +    }
   14.65 +}
   14.66 +
   14.67 +- (void)startAnimation
   14.68 +{
   14.69 +    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
   14.70 +    [displayLink setFrameInterval:animationInterval];
   14.71 +    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
   14.72 +}
   14.73 +
   14.74 +- (void)stopAnimation
   14.75 +{
   14.76 +    [displayLink invalidate];
   14.77 +    displayLink = nil;
   14.78 +}
   14.79 +
   14.80 +- (void)doLoop:(CADisplayLink*)sender
   14.81 +{
   14.82 +    /* Don't run the game loop while a messagebox is up */
   14.83 +    if (!UIKit_ShowingMessageBox()) {
   14.84 +        animationCallback(animationCallbackParam);
   14.85 +    }
   14.86 +}
   14.87 +
   14.88  - (void)loadView
   14.89  {
   14.90 -    /* do nothing. */
   14.91 +    /* Do nothing. */
   14.92  }
   14.93  
   14.94  - (void)viewDidLayoutSubviews
   14.95 @@ -67,8 +127,7 @@
   14.96  
   14.97  - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
   14.98  {
   14.99 -    NSUInteger orientationMask = [self supportedInterfaceOrientations];
  14.100 -    return (orientationMask & (1 << orient));
  14.101 +    return ([self supportedInterfaceOrientations] & (1 << orient)) != 0;
  14.102  }
  14.103  
  14.104  - (BOOL)prefersStatusBarHidden
  14.105 @@ -82,8 +141,276 @@
  14.106      return UIStatusBarStyleLightContent;
  14.107  }
  14.108  
  14.109 +/*
  14.110 + ---- Keyboard related functionality below this line ----
  14.111 + */
  14.112 +#if SDL_IPHONE_KEYBOARD
  14.113 +
  14.114 +@synthesize textInputRect;
  14.115 +@synthesize keyboardHeight;
  14.116 +@synthesize keyboardVisible;
  14.117 +
  14.118 +/* Set ourselves up as a UITextFieldDelegate */
  14.119 +- (void)initKeyboard
  14.120 +{
  14.121 +    textField = [[UITextField alloc] initWithFrame:CGRectZero];
  14.122 +    textField.delegate = self;
  14.123 +    /* placeholder so there is something to delete! */
  14.124 +    textField.text = @" ";
  14.125 +
  14.126 +    /* set UITextInputTrait properties, mostly to defaults */
  14.127 +    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
  14.128 +    textField.autocorrectionType = UITextAutocorrectionTypeNo;
  14.129 +    textField.enablesReturnKeyAutomatically = NO;
  14.130 +    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
  14.131 +    textField.keyboardType = UIKeyboardTypeDefault;
  14.132 +    textField.returnKeyType = UIReturnKeyDefault;
  14.133 +    textField.secureTextEntry = NO;
  14.134 +
  14.135 +    textField.hidden = YES;
  14.136 +    keyboardVisible = NO;
  14.137 +
  14.138 +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  14.139 +    [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
  14.140 +    [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
  14.141 +}
  14.142 +
  14.143 +- (void)setView:(UIView *)view
  14.144 +{
  14.145 +    [super setView:view];
  14.146 +
  14.147 +    [view addSubview:textField];
  14.148 +
  14.149 +    if (keyboardVisible) {
  14.150 +        [self showKeyboard];
  14.151 +    }
  14.152 +}
  14.153 +
  14.154 +- (void)deinitKeyboard
  14.155 +{
  14.156 +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  14.157 +    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
  14.158 +    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
  14.159 +}
  14.160 +
  14.161 +/* reveal onscreen virtual keyboard */
  14.162 +- (void)showKeyboard
  14.163 +{
  14.164 +    keyboardVisible = YES;
  14.165 +    if (textField.window) {
  14.166 +        [textField becomeFirstResponder];
  14.167 +    }
  14.168 +}
  14.169 +
  14.170 +/* hide onscreen virtual keyboard */
  14.171 +- (void)hideKeyboard
  14.172 +{
  14.173 +    keyboardVisible = NO;
  14.174 +    [textField resignFirstResponder];
  14.175 +}
  14.176 +
  14.177 +- (void)keyboardWillShow:(NSNotification *)notification
  14.178 +{
  14.179 +    CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
  14.180 +    UIView *view = self.view;
  14.181 +    int height = 0;
  14.182 +
  14.183 +    /* The keyboard rect is in the coordinate space of the screen, but we want
  14.184 +     * its height in the view's coordinate space. */
  14.185 +#ifdef __IPHONE_8_0
  14.186 +    if ([view respondsToSelector:@selector(convertRect:fromCoordinateSpace:)]) {
  14.187 +        UIScreen *screen = view.window.screen;
  14.188 +        kbrect = [view convertRect:kbrect fromCoordinateSpace:screen.coordinateSpace];
  14.189 +        height = kbrect.size.height;
  14.190 +    } else
  14.191 +#endif
  14.192 +    {
  14.193 +        /* In iOS 7 and below, the screen's coordinate space is never rotated. */
  14.194 +        if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
  14.195 +            height = kbrect.size.width;
  14.196 +        } else {
  14.197 +            height = kbrect.size.height;
  14.198 +        }
  14.199 +    }
  14.200 +
  14.201 +    [self setKeyboardHeight:height];
  14.202 +}
  14.203 +
  14.204 +- (void)keyboardWillHide:(NSNotification *)notification
  14.205 +{
  14.206 +    [self setKeyboardHeight:0];
  14.207 +}
  14.208 +
  14.209 +- (void)updateKeyboard
  14.210 +{
  14.211 +    SDL_Rect textrect = self.textInputRect;
  14.212 +    CGAffineTransform t = self.view.transform;
  14.213 +    CGPoint offset = CGPointMake(0.0, 0.0);
  14.214 +
  14.215 +    if (self.keyboardHeight) {
  14.216 +        int rectbottom = textrect.y + textrect.h;
  14.217 +        int kbottom = self.view.bounds.size.height - self.keyboardHeight;
  14.218 +        if (kbottom < rectbottom) {
  14.219 +            offset.y = kbottom - rectbottom;
  14.220 +        }
  14.221 +    }
  14.222 +
  14.223 +    /* Put the offset into the this view transform's coordinate space. */
  14.224 +    t.tx = 0.0;
  14.225 +    t.ty = 0.0;
  14.226 +    offset = CGPointApplyAffineTransform(offset, t);
  14.227 +
  14.228 +    t.tx = offset.x;
  14.229 +    t.ty = offset.y;
  14.230 +
  14.231 +    /* Move the view by applying the updated transform. */
  14.232 +    self.view.transform = t;
  14.233 +}
  14.234 +
  14.235 +- (void)setKeyboardHeight:(int)height
  14.236 +{
  14.237 +    keyboardVisible = height > 0;
  14.238 +    keyboardHeight = height;
  14.239 +    [self updateKeyboard];
  14.240 +}
  14.241 +
  14.242 +/* UITextFieldDelegate method.  Invoked when user types something. */
  14.243 +- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
  14.244 +{
  14.245 +    NSUInteger len = string.length;
  14.246 +
  14.247 +    if (len == 0) {
  14.248 +        /* it wants to replace text with nothing, ie a delete */
  14.249 +        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
  14.250 +        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
  14.251 +    } else {
  14.252 +        /* go through all the characters in the string we've been sent and
  14.253 +         * convert them to key presses */
  14.254 +        int i;
  14.255 +        for (i = 0; i < len; i++) {
  14.256 +            unichar c = [string characterAtIndex:i];
  14.257 +            Uint16 mod = 0;
  14.258 +            SDL_Scancode code;
  14.259 +
  14.260 +            if (c < 127) {
  14.261 +                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
  14.262 +                code = unicharToUIKeyInfoTable[c].code;
  14.263 +                mod  = unicharToUIKeyInfoTable[c].mod;
  14.264 +            } else {
  14.265 +                /* we only deal with ASCII right now */
  14.266 +                code = SDL_SCANCODE_UNKNOWN;
  14.267 +                mod = 0;
  14.268 +            }
  14.269 +
  14.270 +            if (mod & KMOD_SHIFT) {
  14.271 +                /* If character uses shift, press shift down */
  14.272 +                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
  14.273 +            }
  14.274 +
  14.275 +            /* send a keydown and keyup even for the character */
  14.276 +            SDL_SendKeyboardKey(SDL_PRESSED, code);
  14.277 +            SDL_SendKeyboardKey(SDL_RELEASED, code);
  14.278 +
  14.279 +            if (mod & KMOD_SHIFT) {
  14.280 +                /* If character uses shift, press shift back up */
  14.281 +                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
  14.282 +            }
  14.283 +        }
  14.284 +
  14.285 +        SDL_SendKeyboardText([string UTF8String]);
  14.286 +    }
  14.287 +
  14.288 +    return NO; /* don't allow the edit! (keep placeholder text there) */
  14.289 +}
  14.290 +
  14.291 +/* Terminates the editing session */
  14.292 +- (BOOL)textFieldShouldReturn:(UITextField*)_textField
  14.293 +{
  14.294 +    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
  14.295 +    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
  14.296 +    SDL_StopTextInput();
  14.297 +    return YES;
  14.298 +}
  14.299 +
  14.300 +#endif
  14.301 +
  14.302  @end
  14.303  
  14.304 +/* iPhone keyboard addition functions */
  14.305 +#if SDL_IPHONE_KEYBOARD
  14.306 +
  14.307 +static SDL_uikitviewcontroller *
  14.308 +GetWindowViewController(SDL_Window * window)
  14.309 +{
  14.310 +    if (!window || !window->driverdata) {
  14.311 +        SDL_SetError("Invalid window");
  14.312 +        return nil;
  14.313 +    }
  14.314 +
  14.315 +    SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
  14.316 +
  14.317 +    return data.viewcontroller;
  14.318 +}
  14.319 +
  14.320 +SDL_bool
  14.321 +UIKit_HasScreenKeyboardSupport(_THIS)
  14.322 +{
  14.323 +    return SDL_TRUE;
  14.324 +}
  14.325 +
  14.326 +void
  14.327 +UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
  14.328 +{
  14.329 +    @autoreleasepool {
  14.330 +        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
  14.331 +        [vc showKeyboard];
  14.332 +    }
  14.333 +}
  14.334 +
  14.335 +void
  14.336 +UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
  14.337 +{
  14.338 +    @autoreleasepool {
  14.339 +        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
  14.340 +        [vc hideKeyboard];
  14.341 +    }
  14.342 +}
  14.343 +
  14.344 +SDL_bool
  14.345 +UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
  14.346 +{
  14.347 +    @autoreleasepool {
  14.348 +        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
  14.349 +        if (vc != nil) {
  14.350 +            return vc.isKeyboardVisible;
  14.351 +        }
  14.352 +        return SDL_FALSE;
  14.353 +    }
  14.354 +}
  14.355 +
  14.356 +void
  14.357 +UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
  14.358 +{
  14.359 +    if (!rect) {
  14.360 +        SDL_InvalidParamError("rect");
  14.361 +        return;
  14.362 +    }
  14.363 +
  14.364 +    @autoreleasepool {
  14.365 +        SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow());
  14.366 +        if (vc != nil) {
  14.367 +            vc.textInputRect = *rect;
  14.368 +
  14.369 +            if (vc.keyboardVisible) {
  14.370 +                [vc updateKeyboard];
  14.371 +            }
  14.372 +        }
  14.373 +    }
  14.374 +}
  14.375 +
  14.376 +
  14.377 +#endif /* SDL_IPHONE_KEYBOARD */
  14.378 +
  14.379  #endif /* SDL_VIDEO_DRIVER_UIKIT */
  14.380  
  14.381  /* vi: set ts=4 sw=4 expandtab: */
    15.1 --- a/src/video/uikit/SDL_uikitwindow.h	Tue Dec 02 02:52:45 2014 -0400
    15.2 +++ b/src/video/uikit/SDL_uikitwindow.h	Thu Jan 15 01:06:14 2015 -0400
    15.3 @@ -23,7 +23,7 @@
    15.4  
    15.5  #include "../SDL_sysvideo.h"
    15.6  #import "SDL_uikitvideo.h"
    15.7 -#import "SDL_uikitopenglview.h"
    15.8 +#import "SDL_uikitview.h"
    15.9  #import "SDL_uikitviewcontroller.h"
   15.10  
   15.11  extern int UIKit_CreateWindow(_THIS, SDL_Window * window);
   15.12 @@ -44,9 +44,11 @@
   15.13  @interface SDL_WindowData : NSObject
   15.14  
   15.15  @property (nonatomic, strong) UIWindow *uiwindow;
   15.16 -@property (nonatomic, strong) SDL_uikitopenglview *view;
   15.17  @property (nonatomic, strong) SDL_uikitviewcontroller *viewcontroller;
   15.18  
   15.19 +/* Array of SDL_uikitviews owned by this window. */
   15.20 +@property (nonatomic, copy) NSMutableArray *views;
   15.21 +
   15.22  @end
   15.23  
   15.24  #endif /* _SDL_uikitwindow_h */
    16.1 --- a/src/video/uikit/SDL_uikitwindow.m	Tue Dec 02 02:52:45 2014 -0400
    16.2 +++ b/src/video/uikit/SDL_uikitwindow.m	Thu Jan 15 01:06:14 2015 -0400
    16.3 @@ -37,15 +37,41 @@
    16.4  #include "SDL_uikitwindow.h"
    16.5  #import "SDL_uikitappdelegate.h"
    16.6  
    16.7 -#import "SDL_uikitopenglview.h"
    16.8 +#import "SDL_uikitview.h"
    16.9  
   16.10  #include <Foundation/Foundation.h>
   16.11  
   16.12  @implementation SDL_WindowData
   16.13  
   16.14  @synthesize uiwindow;
   16.15 -@synthesize view;
   16.16  @synthesize viewcontroller;
   16.17 +@synthesize views;
   16.18 +
   16.19 +- (instancetype)init
   16.20 +{
   16.21 +    if ((self = [super init])) {
   16.22 +        views = [NSMutableArray new];
   16.23 +    }
   16.24 +
   16.25 +    return self;
   16.26 +}
   16.27 +
   16.28 +@end
   16.29 +
   16.30 +@interface SDL_uikitwindow : UIWindow
   16.31 +
   16.32 +- (void)layoutSubviews;
   16.33 +
   16.34 +@end
   16.35 +
   16.36 +@implementation SDL_uikitwindow
   16.37 +
   16.38 +- (void)layoutSubviews
   16.39 +{
   16.40 +    /* Workaround to fix window orientation issues in iOS 8+. */
   16.41 +    self.frame = self.screen.bounds;
   16.42 +    [super layoutSubviews];
   16.43 +}
   16.44  
   16.45  @end
   16.46  
   16.47 @@ -54,66 +80,68 @@
   16.48  {
   16.49      SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   16.50      SDL_DisplayData *displaydata = (__bridge SDL_DisplayData *) display->driverdata;
   16.51 +    SDL_uikitview *view;
   16.52 +
   16.53 +    CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen);
   16.54 +    int width  = (int) frame.size.width;
   16.55 +    int height = (int) frame.size.height;
   16.56  
   16.57      SDL_WindowData *data = [[SDL_WindowData alloc] init];
   16.58      if (!data) {
   16.59          return SDL_OutOfMemory();
   16.60      }
   16.61  
   16.62 +    window->driverdata = (void *) CFBridgingRetain(data);
   16.63 +
   16.64      data.uiwindow = uiwindow;
   16.65  
   16.66 -    /* Fill in the SDL window with the window data */
   16.67 -    {
   16.68 -        CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen);
   16.69 +    /* only one window on iOS, always shown */
   16.70 +    window->flags &= ~SDL_WINDOW_HIDDEN;
   16.71  
   16.72 -        int width = (int) frame.size.width;
   16.73 -        int height = (int) frame.size.height;
   16.74 +    if (displaydata.uiscreen == [UIScreen mainScreen]) {
   16.75 +        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
   16.76 +    } else {
   16.77 +        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizable */
   16.78 +        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
   16.79 +        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
   16.80 +    }
   16.81 +
   16.82 +    if (displaydata.uiscreen == [UIScreen mainScreen]) {
   16.83 +        NSUInteger orients = UIKit_GetSupportedOrientations(window);
   16.84 +        BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0;
   16.85 +        BOOL supportsPortrait = (orients & (UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown)) != 0;
   16.86  
   16.87          /* Make sure the width/height are oriented correctly */
   16.88 -        if (UIKit_IsDisplayLandscape(displaydata.uiscreen) != (width > height)) {
   16.89 +        if ((width > height && !supportsLandscape) || (height > width && !supportsPortrait)) {
   16.90              int temp = width;
   16.91              width = height;
   16.92              height = temp;
   16.93          }
   16.94 -
   16.95 -        window->x = 0;
   16.96 -        window->y = 0;
   16.97 -        window->w = width;
   16.98 -        window->h = height;
   16.99      }
  16.100  
  16.101 -    window->driverdata = (void *) CFBridgingRetain(data);
  16.102 +    window->x = 0;
  16.103 +    window->y = 0;
  16.104 +    window->w = width;
  16.105 +    window->h = height;
  16.106  
  16.107 -    /* only one window on iOS, always shown */
  16.108 -    window->flags &= ~SDL_WINDOW_HIDDEN;
  16.109 +    /* The View Controller will handle rotating the view when the device
  16.110 +     * orientation changes. This will trigger resize events, if appropriate. */
  16.111 +    data.viewcontroller = [[SDL_uikitviewcontroller alloc] initWithSDLWindow:window];
  16.112  
  16.113 -    /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
  16.114 -     * This is only set if the window is on the main screen. Other screens
  16.115 -     *  just force the window to have the borderless flag.
  16.116 -     */
  16.117 +    /* The window will initially contain a generic view so resizes, touch events,
  16.118 +     * etc. can be handled without an active OpenGL view/context. */
  16.119 +    view = [[SDL_uikitview alloc] initWithFrame:frame];
  16.120 +
  16.121 +    /* Sets this view as the controller's view, and adds the view to the window
  16.122 +     * heirarchy. */
  16.123 +    [view setSDLWindow:window];
  16.124 +
  16.125 +    /* Make this window the current mouse focus for touch input */
  16.126      if (displaydata.uiscreen == [UIScreen mainScreen]) {
  16.127 -        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
  16.128 -
  16.129 -        /* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application
  16.130 -        if ([UIApplication sharedApplication].statusBarHidden) {
  16.131 -            window->flags |= SDL_WINDOW_BORDERLESS;
  16.132 -        } else {
  16.133 -            window->flags &= ~SDL_WINDOW_BORDERLESS;
  16.134 -        }
  16.135 -        */
  16.136 -    } else {
  16.137 -        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizeable */
  16.138 -        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
  16.139 -        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
  16.140 +        SDL_SetMouseFocus(window);
  16.141 +        SDL_SetKeyboardFocus(window);
  16.142      }
  16.143  
  16.144 -    /* The View Controller will handle rotating the view when the
  16.145 -     * device orientation changes. This will trigger resize events, if
  16.146 -     * appropriate.
  16.147 -     */
  16.148 -    data.viewcontroller = [[SDL_uikitviewcontroller alloc] initWithSDLWindow:window];
  16.149 -    data.viewcontroller.title = @"";
  16.150 -
  16.151      return 0;
  16.152  }
  16.153  
  16.154 @@ -123,8 +151,7 @@
  16.155      @autoreleasepool {
  16.156          SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  16.157          SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
  16.158 -        const BOOL external = ([UIScreen mainScreen] != data.uiscreen);
  16.159 -        const CGSize origsize = [[data.uiscreen currentMode] size];
  16.160 +        const CGSize origsize = data.uiscreen.currentMode.size;
  16.161  
  16.162          /* SDL currently puts this window at the start of display's linked list. We rely on this. */
  16.163          SDL_assert(_this->windows == window);
  16.164 @@ -136,8 +163,7 @@
  16.165  
  16.166          /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
  16.167           * user, so it's in standby), try to force the display to a resolution
  16.168 -         * that most closely matches the desired window size.
  16.169 -         */
  16.170 +         * that most closely matches the desired window size. */
  16.171          if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
  16.172              if (display->num_display_modes == 0) {
  16.173                  _this->GetDisplayModes(_this, display);
  16.174 @@ -147,8 +173,9 @@
  16.175              const SDL_DisplayMode *bestmode = NULL;
  16.176              for (i = display->num_display_modes; i >= 0; i--) {
  16.177                  const SDL_DisplayMode *mode = &display->display_modes[i];
  16.178 -                if ((mode->w >= window->w) && (mode->h >= window->h))
  16.179 +                if ((mode->w >= window->w) && (mode->h >= window->h)) {
  16.180                      bestmode = mode;
  16.181 +                }
  16.182              }
  16.183  
  16.184              if (bestmode) {
  16.185 @@ -157,8 +184,7 @@
  16.186  
  16.187                  /* desktop_mode doesn't change here (the higher level will
  16.188                   * use it to set all the screens back to their defaults
  16.189 -                 * upon window destruction, SDL_Quit(), etc.
  16.190 -                 */
  16.191 +                 * upon window destruction, SDL_Quit(), etc. */
  16.192                  display->current_mode = *bestmode;
  16.193              }
  16.194          }
  16.195 @@ -172,36 +198,14 @@
  16.196              } else {
  16.197                  app.statusBarHidden = NO;
  16.198              }
  16.199 -
  16.200 -            /* Make sure the screen is using a supported orientation. We do it
  16.201 -             * now so that SetupWindowData assigns the properly oriented width
  16.202 -             * and height to the window's w and h variables.
  16.203 -             */
  16.204 -            if (UIKit_IsDisplayLandscape(data.uiscreen)) {
  16.205 -                if (!(orientations & UIInterfaceOrientationMaskLandscape)) {
  16.206 -                    [app setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
  16.207 -                }
  16.208 -            } else {
  16.209 -                if (!(orientations & (UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown))) {
  16.210 -                    UIInterfaceOrientation orient = UIInterfaceOrientationLandscapeLeft;
  16.211 -                    if (orientations & UIInterfaceOrientationMaskLandscapeRight) {
  16.212 -                        orient = UIInterfaceOrientationLandscapeRight;
  16.213 -                    }
  16.214 -                    [app setStatusBarOrientation:orient animated:NO];
  16.215 -                }
  16.216 -            }
  16.217          }
  16.218  
  16.219          /* ignore the size user requested, and make a fullscreen window */
  16.220          /* !!! FIXME: can we have a smaller view? */
  16.221 -        UIWindow *uiwindow = [[UIWindow alloc] initWithFrame:data.uiscreen.bounds];
  16.222 +        UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
  16.223  
  16.224 -        /* put the window on an external display if appropriate. This implicitly
  16.225 -         * does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
  16.226 -         * main display, where we land by default, as that would eat the
  16.227 -         * status bar real estate.
  16.228 -         */
  16.229 -        if (external) {
  16.230 +        /* put the window on an external display if appropriate. */
  16.231 +        if (data.uiscreen != [UIScreen mainScreen]) {
  16.232              [uiwindow setScreen:data.uiscreen];
  16.233          }
  16.234  
  16.235 @@ -217,11 +221,11 @@
  16.236  UIKit_SetWindowTitle(_THIS, SDL_Window * window)
  16.237  {
  16.238      @autoreleasepool {
  16.239 -        SDL_uikitviewcontroller *vc = ((__bridge SDL_WindowData *) window->driverdata).viewcontroller;
  16.240 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  16.241          if (window->title) {
  16.242 -            vc.title = @(window->title);
  16.243 +            data.viewcontroller.title = @(window->title);
  16.244          } else {
  16.245 -            vc.title = @"";
  16.246 +            data.viewcontroller.title = nil;
  16.247          }
  16.248      }
  16.249  }
  16.250 @@ -230,8 +234,8 @@
  16.251  UIKit_ShowWindow(_THIS, SDL_Window * window)
  16.252  {
  16.253      @autoreleasepool {
  16.254 -        UIWindow *uiwindow = ((__bridge SDL_WindowData *) window->driverdata).uiwindow;
  16.255 -        [uiwindow makeKeyAndVisible];
  16.256 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  16.257 +        [data.uiwindow makeKeyAndVisible];
  16.258      }
  16.259  }
  16.260  
  16.261 @@ -239,8 +243,8 @@
  16.262  UIKit_HideWindow(_THIS, SDL_Window * window)
  16.263  {
  16.264      @autoreleasepool {
  16.265 -        UIWindow *uiwindow = ((__bridge SDL_WindowData *) window->driverdata).uiwindow;
  16.266 -        uiwindow.hidden = YES;
  16.267 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  16.268 +        data.uiwindow.hidden = YES;
  16.269      }
  16.270  }
  16.271  
  16.272 @@ -248,21 +252,19 @@
  16.273  UIKit_RaiseWindow(_THIS, SDL_Window * window)
  16.274  {
  16.275      /* We don't currently offer a concept of "raising" the SDL window, since
  16.276 -     *  we only allow one per display, in the iOS fashion.
  16.277 +     * we only allow one per display, in the iOS fashion.
  16.278       * However, we use this entry point to rebind the context to the view
  16.279 -     *  during OnWindowRestored processing.
  16.280 -     */
  16.281 +     * during OnWindowRestored processing. */
  16.282      _this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
  16.283  }
  16.284  
  16.285  static void
  16.286  UIKit_UpdateWindowBorder(_THIS, SDL_Window * window)
  16.287  {
  16.288 -    SDL_WindowData *windowdata = (__bridge SDL_WindowData *) window->driverdata;
  16.289 -    SDL_uikitviewcontroller *viewcontroller = windowdata.viewcontroller;
  16.290 -    CGRect frame;
  16.291 +    SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  16.292 +    SDL_uikitviewcontroller *viewcontroller = data.viewcontroller;
  16.293  
  16.294 -    if (windowdata.uiwindow.screen == [UIScreen mainScreen]) {
  16.295 +    if (data.uiwindow.screen == [UIScreen mainScreen]) {
  16.296          if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) {
  16.297              [UIApplication sharedApplication].statusBarHidden = YES;
  16.298          } else {
  16.299 @@ -276,24 +278,9 @@
  16.300      }
  16.301  
  16.302      /* Update the view's frame to account for the status bar change. */
  16.303 -    frame = UIKit_ComputeViewFrame(window, windowdata.uiwindow.screen);
  16.304 -
  16.305 -    windowdata.view.frame = frame;
  16.306 -    [windowdata.view setNeedsLayout];
  16.307 -    [windowdata.view layoutIfNeeded];
  16.308 -
  16.309 -    /* Get frame dimensions */
  16.310 -    int w = (int) frame.size.width;
  16.311 -    int h = (int) frame.size.height;
  16.312 -
  16.313 -    /* We can pick either width or height here and we'll rotate the
  16.314 -     screen to match, so we pick the closest to what we wanted.
  16.315 -     */
  16.316 -    if (window->w >= window->h) {
  16.317 -        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, SDL_max(w, h), SDL_min(w, h));
  16.318 -    } else {
  16.319 -        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, SDL_min(w, h), SDL_max(w, h));
  16.320 -    }
  16.321 +    viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
  16.322 +    [viewcontroller.view setNeedsLayout];
  16.323 +    [viewcontroller.view layoutIfNeeded];
  16.324  }
  16.325  
  16.326  void
  16.327 @@ -317,7 +304,8 @@
  16.328  {
  16.329      @autoreleasepool {
  16.330          if (window->driverdata != NULL) {
  16.331 -            CFRelease(window->driverdata);
  16.332 +            SDL_WindowData *data = (SDL_WindowData *) CFBridgingRelease(window->driverdata);
  16.333 +            [data.viewcontroller stopAnimation];
  16.334          }
  16.335      }
  16.336      window->driverdata = NULL;
  16.337 @@ -327,11 +315,11 @@
  16.338  UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  16.339  {
  16.340      @autoreleasepool {
  16.341 -        UIWindow *uiwindow = ((__bridge SDL_WindowData *) window->driverdata).uiwindow;
  16.342 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  16.343  
  16.344          if (info->version.major <= SDL_MAJOR_VERSION) {
  16.345              info->subsystem = SDL_SYSWM_UIKIT;
  16.346 -            info->info.uikit.window = uiwindow;
  16.347 +            info->info.uikit.window = data.uiwindow;
  16.348              return SDL_TRUE;
  16.349          } else {
  16.350              SDL_SetError("Application not compiled with SDL %d.%d\n",
  16.351 @@ -380,7 +368,7 @@
  16.352          }
  16.353  
  16.354          /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
  16.355 -        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
  16.356 +        if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
  16.357              orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
  16.358          }
  16.359      }
  16.360 @@ -391,14 +379,15 @@
  16.361  int
  16.362  SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
  16.363  {
  16.364 +    if (!window || !window->driverdata) {
  16.365 +        return SDL_SetError("Invalid window");
  16.366 +    }
  16.367 +
  16.368      @autoreleasepool {
  16.369 -        SDL_WindowData *data = window ? (__bridge SDL_WindowData *)window->driverdata : nil;
  16.370 -
  16.371 -        if (!data || !data.view) {
  16.372 -            return SDL_SetError("Invalid window or view not set");
  16.373 -        }
  16.374 -
  16.375 -        [data.view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
  16.376 +        SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
  16.377 +        [data.viewcontroller setAnimationCallback:interval
  16.378 +                                         callback:callback
  16.379 +                                    callbackParam:callbackParam];
  16.380      }
  16.381  
  16.382      return 0;