Merged Alex Szpakowski's iOS-improvement branch to default.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 09 Apr 2015 22:28:37 -0400
changeset 9541 cf8fab52e33b
parent 9486 296b5f754af7 (current diff)
parent 9540 32ddc92d78cf (diff)
child 9543 07cdf7b8f9bc
Merged Alex Szpakowski's iOS-improvement branch to default. Fixes Bugzilla #2798. Fixes Bugzilla #2212. Fixes Bugzilla #2826. Fixes Bugzilla #2661. Fixes Bugzilla #1885. Fixes Bugzilla #1578. Fixes Bugzilla #2751. (whew!) Notable changes, from Alex's notes: - The SDL_WINDOW_ALLOW_HIGHDPI flag is now needed (along with SDL_GL_GetDrawableSize or SDL_GetRendererOutputSize) to use Retina / high DPI resolutions, bringing SDL’s Retina-related behavior on iOS in line with Mac OS X. Window dimensions and display modes are now in the “points” (non-high DPI) coordinate system rather than pixels, whereas SDL_GL_GetDrawableSize is in pixels. - Reworked the custom extended launch screen code: - It now hides after the first SDL_PumpEvents call rather than SDL_CreateWindow, and it fades out in a similar manner to the system launch screen behavior. - It now mirrors the system launch screen behavior when deciding which image to display: it falls back to using the Launch Images dictionary in Info.plist if the iOS 8+ launch screen nib isn’t available, and if the Launch Images dictionary doesn’t exist it uses the old standard launch image names. - The extended launch screen can now be disabled via the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h. - Added support for SDL_HINT_ACCELEROMETER_AS_JOYSTICK. - Added access to a window view's renderbuffer and framebuffer to syswm. - Added OpenGL ES debug labels for the Renderbuffer and Framebuffer Objects created with SDL_GL_CreateContext. - Added support for sRGB OpenGL ES contexts on iOS 7+. - Updated OpenGL ES contexts to support native-resolution rendering (when SDL_WINDOW_ALLOW_HIGHDPI is enabled) on the iPhone 6 Plus, i.e. 1080x1920 rather than 1242x2208. - Updated SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext to be more robust. - Updated SDL windows to display a UIView at all times, even when an OpenGL context is not active. This allows rotation, touch events, and other windowing-related events to work properly without an active OpenGL context. It also makes it easier to use SDL_GetWindowWMInfo after creating a SDL window. - Updated the iOS-specific Objective-C code to use cleaner and more modern language features and APIs, including ARC instead of manual reference counting. - Updated SDL_HINT_ORIENTATIONS to allow disabling custom orientations if the hint is set with no valid orientation names. - Fixed several rotation and orientation bugs with windows and display modes, especially in iOS 8+. - Fixed SDL_SetWindowFullscreen failing to update the status bar visibility on iOS 7+. - Fixed the orientation of the offset applied to the window’s view when the onscreen keyboard is shown in iOS 8+. - Fixed SDL_IsScreenKeyboardShown (patch by Phil Hassey.) - Fixed several major memory leaks caused by missing autorelease pool blocks in the iOS-specific Objective-C code. - Removed several dead code paths. - The iOS 7 SDK (Xcode 5) or newer is now required to build SDL for iOS.
--- a/.hgignore	Thu Apr 09 22:14:05 2015 +0200
+++ b/.hgignore	Thu Apr 09 22:28:37 2015 -0400
@@ -8,6 +8,9 @@
 sdl-config
 SDL2.spec
 build
+Build
+*xcuserdata*
+*xcworkspacedata*
 
 # for Xcode
 *.orig
--- a/Xcode-iOS/Demos/src/fireworks.c	Thu Apr 09 22:14:05 2015 +0200
+++ b/Xcode-iOS/Demos/src/fireworks.c	Thu Apr 09 22:28:37 2015 -0400
@@ -387,6 +387,9 @@
     SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
     SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
 
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+
     /* create main window and renderer */
     window = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
                                 SDL_WINDOW_OPENGL |
--- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj	Thu Apr 09 22:14:05 2015 +0200
+++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj	Thu Apr 09 22:28:37 2015 -0400
@@ -1274,8 +1274,14 @@
 		FD6526640DE8FCCB002AD96B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
 				COPY_PHASE_STRIP = NO;
 				IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
+				GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES;
+				GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				PRODUCT_NAME = SDL2;
 				SKIP_INSTALL = YES;
 			};
@@ -1284,8 +1290,14 @@
 		FD6526650DE8FCCB002AD96B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
 				COPY_PHASE_STRIP = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
+				GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES;
+				GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				PRODUCT_NAME = SDL2;
 				SKIP_INSTALL = YES;
 			};
--- a/include/SDL_config_iphoneos.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/include/SDL_config_iphoneos.h	Thu Apr 09 22:28:37 2015 -0400
@@ -145,6 +145,9 @@
 /* enable iPhone keyboard support */
 #define SDL_IPHONE_KEYBOARD 1
 
+/* enable iOS extended launch screen */
+#define SDL_IPHONE_LAUNCHSCREEN 1
+
 /* enable joystick subsystem */
 #define SDL_JOYSTICK_DISABLED 0
 
--- a/include/SDL_hints.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/include/SDL_hints.h	Thu Apr 09 22:28:37 2015 -0400
@@ -261,8 +261,9 @@
 #define SDL_HINT_ORIENTATIONS "SDL_IOS_ORIENTATIONS"
     
 /**
- *  \brief  A variable controlling whether an Android built-in accelerometer should be
- *  listed as a joystick device, rather than listing actual joysticks only.
+ *  \brief  A variable controlling whether the Android / iOS built-in
+ *  accelerometer should be listed as a joystick device, rather than listing
+ *  actual joysticks only.
  *
  *  This variable can be set to the following values:
  *    "0"       - List only real joysticks and accept input from them
@@ -345,7 +346,7 @@
 
 
 /**
- *  \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac)
+ *  \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac and iOS)
  */
 #define SDL_HINT_VIDEO_HIGHDPI_DISABLED "SDL_VIDEO_HIGHDPI_DISABLED"
 
--- a/include/SDL_system.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/include/SDL_system.h	Thu Apr 09 22:28:37 2015 -0400
@@ -73,7 +73,10 @@
 /* Platform specific functions for iOS */
 #if defined(__IPHONEOS__) && __IPHONEOS__
 
+#define SDL_iOSSetAnimationCallback(window, interval, callback, callbackParam) SDL_iPhoneSetAnimationCallback(window, interval, callback, callbackParam)
 extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam);
+
+#define SDL_iOSSetEventPump(enabled) SDL_iPhoneSetEventPump(enabled)
 extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled);
 
 #endif /* __IPHONEOS__ */
--- a/include/SDL_syswm.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/include/SDL_syswm.h	Thu Apr 09 22:28:37 2015 -0400
@@ -98,6 +98,7 @@
 typedef struct _UIWindow UIWindow;
 typedef struct _UIViewController UIViewController;
 #endif
+typedef Uint32 GLuint;
 #endif
 
 #if defined(SDL_VIDEO_DRIVER_ANDROID)
@@ -228,6 +229,8 @@
 #else
             UIWindow *window;                     /* The UIKit window */
 #endif
+            GLuint framebuffer; /* The GL view's Framebuffer Object. It must be bound when rendering to the screen using GL. */
+            GLuint colorbuffer; /* The GL view's color Renderbuffer Object. It must be bound when SDL_GL_SwapWindow is called. */
         } uikit;
 #endif
 #if defined(SDL_VIDEO_DRIVER_WAYLAND)
--- a/premake/Xcode-iOS/SDL_config_premake.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/premake/Xcode-iOS/SDL_config_premake.h	Thu Apr 09 22:28:37 2015 -0400
@@ -126,6 +126,9 @@
 #ifndef SDL_IPHONE_KEYBOARD
 #define SDL_IPHONE_KEYBOARD 1
 #endif
+#ifndef SDL_IPHONE_LAUNCHSCREEN
+#define SDL_IPHONE_LAUNCHSCREEN 1
+#endif
 #ifndef SDL_POWER_UIKIT
 #define SDL_POWER_UIKIT 1
 #endif
--- a/src/file/cocoa/SDL_rwopsbundlesupport.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/file/cocoa/SDL_rwopsbundlesupport.m	Thu Apr 09 22:28:37 2015 -0400
@@ -50,14 +50,13 @@
     NSString* full_path_with_file_to_try = [resource_path stringByAppendingPathComponent:ns_string_file_component];
     if([file_manager fileExistsAtPath:full_path_with_file_to_try]) {
         fp = fopen([full_path_with_file_to_try fileSystemRepresentation], mode);
-    }
-    else {
+    } else {
         fp = fopen(file, mode);
     }
 
     return fp;
 }}
 
-#endif /* __MACOSX__ */
+#endif /* __APPLE__ */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/filesystem/cocoa/SDL_sysfilesystem.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/filesystem/cocoa/SDL_sysfilesystem.m	Thu Apr 09 22:28:37 2015 -0400
@@ -41,6 +41,7 @@
     const char* baseType = [[[bundle infoDictionary] objectForKey:@"SDL_FILESYSTEM_BASE_DIR_TYPE"] UTF8String];
     const char *base = NULL;
     char *retval = NULL;
+
     if (baseType == NULL) {
         baseType = "resource";
     }
@@ -52,6 +53,7 @@
         /* this returns the exedir for non-bundled  and the resourceDir for bundled apps */
         base = [[bundle resourcePath] fileSystemRepresentation];
     }
+
     if (base) {
         const size_t len = SDL_strlen(base) + 2;
         retval = (char *) SDL_malloc(len);
@@ -69,8 +71,9 @@
 SDL_GetPrefPath(const char *org, const char *app)
 { @autoreleasepool
 {
+    char *retval = NULL;
+
     NSArray *array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
-    char *retval = NULL;
 
     if ([array count] > 0) {  /* we only want the first item in the list. */
         NSString *str = [array objectAtIndex:0];
--- a/src/joystick/iphoneos/SDL_sysjoystick.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/joystick/iphoneos/SDL_sysjoystick.m	Thu Apr 09 22:28:37 2015 -0400
@@ -23,6 +23,7 @@
 /* This is the iOS implementation of the SDL joystick API */
 
 #include "SDL_joystick.h"
+#include "SDL_hints.h"
 #include "SDL_stdinc.h"
 #include "../SDL_sysjoystick.h"
 #include "../SDL_joystick_c.h"
@@ -32,9 +33,10 @@
 /* needed for SDL_IPHONE_MAX_GFORCE macro */
 #import "SDL_config_iphoneos.h"
 
-const char *accelerometerName = "iOS accelerometer";
+const char *accelerometerName = "iOS Accelerometer";
 
 static CMMotionManager *motionManager = nil;
+static int numjoysticks = 0;
 
 /* Function to scan the system for joysticks.
  * Joystick 0 should be the system default joystick.
@@ -43,12 +45,18 @@
 int
 SDL_SYS_JoystickInit(void)
 {
-    return (1);
+    const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
+    if (!hint || SDL_atoi(hint)) {
+        /* Default behavior, accelerometer as joystick */
+        numjoysticks = 1;
+    }
+
+    return numjoysticks;
 }
 
 int SDL_SYS_NumJoysticks()
 {
-    return 1;
+    return numjoysticks;
 }
 
 void SDL_SYS_JoystickDetect()
@@ -81,13 +89,15 @@
     joystick->nballs = 0;
     joystick->nbuttons = 0;
 
-    if (motionManager == nil) {
-        motionManager = [[CMMotionManager alloc] init];
-    }
+    @autoreleasepool {
+        if (motionManager == nil) {
+            motionManager = [[CMMotionManager alloc] init];
+        }
 
-    /* Shorter times between updates can significantly increase CPU usage. */
-    motionManager.accelerometerUpdateInterval = 0.1;
-    [motionManager startAccelerometerUpdates];
+        /* Shorter times between updates can significantly increase CPU usage. */
+        motionManager.accelerometerUpdateInterval = 0.1;
+        [motionManager startAccelerometerUpdates];
+    }
 
     return 0;
 }
@@ -104,12 +114,14 @@
     const SInt16 maxsint16 = 0x7FFF;
     CMAcceleration accel;
 
-    if (!motionManager.accelerometerActive) {
-        return;
+    @autoreleasepool {
+        if (!motionManager.accelerometerActive) {
+            return;
+        }
+
+        accel = motionManager.accelerometerData.acceleration;
     }
 
-    accel = [[motionManager accelerometerData] acceleration];
-
     /*
      Convert accelerometer data from floating point to Sint16, which is what
      the joystick system expects.
@@ -152,17 +164,20 @@
 void
 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
 {
-    [motionManager stopAccelerometerUpdates];
+    @autoreleasepool {
+        [motionManager stopAccelerometerUpdates];
+    }
 }
 
 /* Function to perform any system-specific joystick related cleanup */
 void
 SDL_SYS_JoystickQuit(void)
 {
-    if (motionManager != nil) {
-        [motionManager release];
+    @autoreleasepool {
         motionManager = nil;
     }
+
+    numjoysticks = 0;
 }
 
 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
--- a/src/power/uikit/SDL_syspower.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/power/uikit/SDL_syspower.m	Thu Apr 09 22:28:37 2015 -0400
@@ -50,24 +50,24 @@
 SDL_bool
 SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent)
 {
-    UIDevice *uidev = [UIDevice currentDevice];
+    @autoreleasepool {
+        UIDevice *uidev = [UIDevice currentDevice];
 
-    if (!SDL_UIKitLastPowerInfoQuery) {
-        SDL_assert([uidev isBatteryMonitoringEnabled] == NO);
-        [uidev setBatteryMonitoringEnabled:YES];
-    }
+        if (!SDL_UIKitLastPowerInfoQuery) {
+            SDL_assert(uidev.isBatteryMonitoringEnabled == NO);
+            uidev.batteryMonitoringEnabled = YES;
+        }
 
-    /* UIKit_GL_SwapWindow() (etc) will check this and disable the battery
-     *  monitoring if the app hasn't queried it in the last X seconds.
-     *  Apparently monitoring the battery burns battery life.  :)
-     *  Apple's docs say not to monitor the battery unless you need it.
-     */
-    SDL_UIKitLastPowerInfoQuery = SDL_GetTicks();
+        /* UIKit_GL_SwapWindow() (etc) will check this and disable the battery
+         *  monitoring if the app hasn't queried it in the last X seconds.
+         *  Apparently monitoring the battery burns battery life.  :)
+         *  Apple's docs say not to monitor the battery unless you need it.
+         */
+        SDL_UIKitLastPowerInfoQuery = SDL_GetTicks();
 
-    *seconds = -1;   /* no API to estimate this in UIKit. */
+        *seconds = -1;   /* no API to estimate this in UIKit. */
 
-    switch ([uidev batteryState])
-    {
+        switch (uidev.batteryState) {
         case UIDeviceBatteryStateCharging:
             *state = SDL_POWERSTATE_CHARGING;
             break;
@@ -84,11 +84,12 @@
         default:
             *state = SDL_POWERSTATE_UNKNOWN;
             break;
-    }
+        }
 
-    const float level = [uidev batteryLevel];
-    *percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) );
-    return SDL_TRUE;            /* always the definitive answer on iOS. */
+        const float level = uidev.batteryLevel;
+        *percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) );
+        return SDL_TRUE; /* always the definitive answer on iOS. */
+    }
 }
 
 #endif /* SDL_POWER_UIKIT */
--- a/src/render/opengles/SDL_render_gles.c	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/render/opengles/SDL_render_gles.c	Thu Apr 09 22:28:37 2015 -0400
@@ -55,6 +55,7 @@
 static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
 static void GLES_WindowEvent(SDL_Renderer * renderer,
                              const SDL_WindowEvent *event);
+static int GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
 static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                               const SDL_Rect * rect, const void *pixels,
@@ -321,6 +322,7 @@
     }
 
     renderer->WindowEvent = GLES_WindowEvent;
+    renderer->GetOutputSize = GLES_GetOutputSize;
     renderer->CreateTexture = GLES_CreateTexture;
     renderer->UpdateTexture = GLES_UpdateTexture;
     renderer->LockTexture = GLES_LockTexture;
@@ -438,6 +440,13 @@
     }
 }
 
+static int
+GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
+{
+    SDL_GL_GetDrawableSize(renderer->window, w, h);
+    return 0;
+}
+
 static SDL_INLINE int
 power_of_2(int input)
 {
--- a/src/render/opengles2/SDL_render_gles2.c	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/render/opengles2/SDL_render_gles2.c	Thu Apr 09 22:28:37 2015 -0400
@@ -370,6 +370,13 @@
 }
 
 static int
+GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
+{
+    SDL_GL_GetDrawableSize(renderer->window, w, h);
+    return 0;
+}
+
+static int
 GLES2_UpdateViewport(SDL_Renderer * renderer)
 {
     GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
@@ -2059,6 +2066,7 @@
 
     /* Populate the function pointers for the module */
     renderer->WindowEvent         = &GLES2_WindowEvent;
+    renderer->GetOutputSize       = &GLES2_GetOutputSize;
     renderer->CreateTexture       = &GLES2_CreateTexture;
     renderer->UpdateTexture       = &GLES2_UpdateTexture;
     renderer->UpdateTextureYUV    = &GLES2_UpdateTextureYUV;
--- a/src/video/SDL_video.c	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/SDL_video.c	Thu Apr 09 22:28:37 2015 -0400
@@ -1107,22 +1107,22 @@
     }
 }
 
-static void
+static int
 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
 {
     SDL_VideoDisplay *display;
     SDL_Window *other;
 
-    CHECK_WINDOW_MAGIC(window,);
+    CHECK_WINDOW_MAGIC(window,-1);
 
     /* if we are in the process of hiding don't go back to fullscreen */
     if ( window->is_hiding && fullscreen )
-        return;
+        return 0;
     
 #ifdef __MACOSX__
     if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
         window->last_fullscreen_flags = window->flags;
-        return;
+        return 0;
     }
 #endif
 
@@ -1139,7 +1139,7 @@
     /* See if anything needs to be done now */
     if ((display->fullscreen_window == window) == fullscreen) {
         if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
-            return;
+            return 0;
         }
     }
 
@@ -1168,9 +1168,13 @@
 
                 /* only do the mode change if we want exclusive fullscreen */
                 if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
-                    SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
+                    if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
+                        return -1;
+                    }
                 } else {
-                    SDL_SetDisplayModeForDisplay(display, NULL);
+                    if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
+                        return -1;
+                    }
                 }
 
                 if (_this->SetWindowFullscreen) {
@@ -1189,7 +1193,7 @@
                 SDL_RestoreMousePosition(other);
 
                 window->last_fullscreen_flags = window->flags;
-                return;
+                return 0;
             }
         }
     }
@@ -1209,6 +1213,7 @@
     SDL_RestoreMousePosition(window);
 
     window->last_fullscreen_flags = window->flags;
+    return 0;
 }
 
 #define CREATE_FLAGS \
@@ -1938,9 +1943,7 @@
     window->flags &= ~FULLSCREEN_MASK;
     window->flags |= flags;
 
-    SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
-
-    return 0;
+    return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
 }
 
 static SDL_Surface *
--- a/src/video/uikit/SDL_uikitappdelegate.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitappdelegate.h	Thu Apr 09 22:28:37 2015 -0400
@@ -21,12 +21,21 @@
 
 #import <UIKit/UIKit.h>
 
-@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate> {
-}
+@interface SDLLaunchScreenController : UIViewController
+
+- (instancetype)init;
+- (void)loadView;
+- (NSUInteger)supportedInterfaceOrientations;
 
-+ (id) sharedAppDelegate;
+@end
+
+@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate>
+
++ (id)sharedAppDelegate;
 + (NSString *)getAppDelegateClassName;
 
+- (void)hideLaunchScreen;
+
 @end
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitappdelegate.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitappdelegate.m	Thu Apr 09 22:28:37 2015 -0400
@@ -28,8 +28,10 @@
 #include "SDL_system.h"
 #include "SDL_main.h"
 
-#include "SDL_uikitappdelegate.h"
-#include "SDL_uikitmodes.h"
+#import "SDL_uikitappdelegate.h"
+#import "SDL_uikitmodes.h"
+#import "SDL_uikitwindow.h"
+
 #include "../../events/SDL_events_c.h"
 
 #ifdef main
@@ -39,12 +41,10 @@
 static int forward_argc;
 static char **forward_argv;
 static int exit_status;
-static UIWindow *launch_window;
 
 int main(int argc, char **argv)
 {
     int i;
-    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
     /* store arguments */
     forward_argc = argc;
@@ -56,7 +56,9 @@
     forward_argv[i] = NULL;
 
     /* Give over control to run loop, SDLUIKitDelegate will handle most things from here */
-    UIApplicationMain(argc, argv, NULL, [SDLUIKitDelegate getAppDelegateClassName]);
+    @autoreleasepool {
+        UIApplicationMain(argc, argv, nil, [SDLUIKitDelegate getAppDelegateClassName]);
+    }
 
     /* free the memory we used to hold copies of argc and argv */
     for (i = 0; i < forward_argc; i++) {
@@ -64,7 +66,6 @@
     }
     free(forward_argv);
 
-    [pool release];
     return exit_status;
 }
 
@@ -75,224 +76,262 @@
     [UIApplication sharedApplication].idleTimerDisabled = disable;
 }
 
+/* Load a launch image using the old UILaunchImageFile-era naming rules. */
+static UIImage *
+SDL_LoadLaunchImageNamed(NSString *name, int screenh)
+{
+    UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
+    UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom;
+    UIImage *image = nil;
 
-@interface SDL_launchscreenviewcontroller : UIViewController {
-	
+    if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) {
+        /* The image name for the iPhone 5 uses its height as a suffix. */
+        image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]];
+    } else if (idiom == UIUserInterfaceIdiomPad) {
+        /* iPad apps can launch in any orientation. */
+        if (UIInterfaceOrientationIsLandscape(curorient)) {
+            if (curorient == UIInterfaceOrientationLandscapeLeft) {
+                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]];
+            } else {
+                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]];
+            }
+            if (!image) {
+                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]];
+            }
+        } else {
+            if (curorient == UIInterfaceOrientationPortraitUpsideDown) {
+                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]];
+            }
+            if (!image) {
+                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]];
+            }
+        }
+    }
+
+    if (!image) {
+        image = [UIImage imageNamed:name];
+    }
+
+    return image;
 }
 
-@end
-
-@implementation SDL_launchscreenviewcontroller
+@implementation SDLLaunchScreenController {
+    UIInterfaceOrientationMask supportedOrientations;
+}
 
-- (id)init
+- (instancetype)init
 {
-    self = [super init];
-    if (self == nil) {
+    if (!(self = [super initWithNibName:nil bundle:nil])) {
         return nil;
     }
 
-    NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
+    NSBundle *bundle = [NSBundle mainBundle];
+    NSString *screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
+
+    /* Normally we don't want to rotate from the initial orientation. */
+    supportedOrientations = (1 << [UIApplication sharedApplication].statusBarOrientation);
 
-    if(launch_screen_name) {
-        // TODO: If the NIB is not in the bundle, this will throw an exception. We might consider a pre-emptive check, but returning a useless viewcontroller isn't helpful and the check should be outside.
-        UIView* launch_screen = [[[NSBundle mainBundle] loadNibNamed:launch_screen_name owner:self options:nil] objectAtIndex:0];
-        CGSize size = [UIScreen mainScreen].bounds.size;
-        
-        CGRect bounds = CGRectMake(0, 0, size.width, size.height);
-        
-        [launch_screen setFrame:bounds];
-        [self setView:launch_screen];
-        [launch_screen release];
+    /* Launch screens were added in iOS 8. Otherwise we use launch images. */
+    if (screenname && UIKit_IsSystemVersionAtLeast(8.0)) {
+        @try {
+            self.view = [bundle loadNibNamed:screenname owner:self options:nil][0];
+        }
+        @catch (NSException *exception) {
+            /* iOS displays a blank screen rather than falling back to an image,
+             * if a launch screen name is specified but it fails to load. */
+            return nil;
+        }
     }
 
-    
+    if (!self.view) {
+        NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
+        UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
+        NSString *imagename = nil;
+        UIImage *image = nil;
+
+        int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
+        int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
+
+        /* We always want portrait-oriented size, to match UILaunchImageSize. */
+        if (screenw > screenh) {
+            int width = screenw;
+            screenw = screenh;
+            screenh = width;
+        }
+
+        /* Xcode 5 introduced a dictionary of launch images in Info.plist. */
+        if (launchimages) {
+            for (NSDictionary *dict in launchimages) {
+                UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
+                NSString *minversion   = dict[@"UILaunchImageMinimumOSVersion"];
+                NSString *sizestring   = dict[@"UILaunchImageSize"];
+                NSString *orientstring = dict[@"UILaunchImageOrientation"];
+
+                /* Ignore this image if the current version is too low. */
+                if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) {
+                    continue;
+                }
+
+                /* Ignore this image if the size doesn't match. */
+                if (sizestring) {
+                    CGSize size = CGSizeFromString(sizestring);
+                    if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) {
+                        continue;
+                    }
+                }
 
+                if (orientstring) {
+                    if ([orientstring isEqualToString:@"PortraitUpsideDown"]) {
+                        orientmask = UIInterfaceOrientationMaskPortraitUpsideDown;
+                    } else if ([orientstring isEqualToString:@"Landscape"]) {
+                        orientmask = UIInterfaceOrientationMaskLandscape;
+                    } else if ([orientstring isEqualToString:@"LandscapeLeft"]) {
+                        orientmask = UIInterfaceOrientationMaskLandscapeLeft;
+                    } else if ([orientstring isEqualToString:@"LandscapeRight"]) {
+                        orientmask = UIInterfaceOrientationMaskLandscapeRight;
+                    }
+                }
+
+                /* Ignore this image if the orientation doesn't match. */
+                if ((orientmask & (1 << curorient)) == 0) {
+                    continue;
+                }
+
+                imagename = dict[@"UILaunchImageName"];
+            }
+
+            if (imagename) {
+                image = [UIImage imageNamed:imagename];
+            }
+        } else {
+            imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
+
+            if (imagename) {
+                image = SDL_LoadLaunchImageNamed(imagename, screenh);
+            }
+
+            if (!image) {
+                image = SDL_LoadLaunchImageNamed(@"Default", screenh);
+            }
+        }
+
+        if (image) {
+            if (image.size.width > image.size.height) {
+                supportedOrientations = UIInterfaceOrientationMaskLandscape;
+            } else {
+                supportedOrientations = UIInterfaceOrientationMaskPortrait;
+            }
+
+            self.view = [[UIImageView alloc] initWithImage:image];
+        }
+    }
 
     return self;
 }
 
+- (void)loadView
+{
+    /* Do nothing. */
+}
+
 - (NSUInteger)supportedInterfaceOrientations
 {
-    NSUInteger orientationMask = UIInterfaceOrientationMaskAll;
-    
-    /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
-    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
-        orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
-    }
-    return orientationMask;
-}
-
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
-{
-    NSUInteger orientationMask = [self supportedInterfaceOrientations];
-    return (orientationMask & (1 << orient));
+    return supportedOrientations;
 }
 
 @end
 
-
-@interface SDL_splashviewcontroller : UIViewController {
-    UIImageView *splash;
-    UIImage *splashPortrait;
-    UIImage *splashLandscape;
+@implementation SDLUIKitDelegate {
+    UIWindow *launchWindow;
 }
 
-- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation;
-@end
-
-@implementation SDL_splashviewcontroller
-
-- (id)init
+/* convenience method */
++ (id)sharedAppDelegate
 {
-    self = [super init];
-    if (self == nil) {
-        return nil;
-    }
-
-    self->splash = [[UIImageView alloc] init];
-    [self setView:self->splash];
-
-    CGSize size = [UIScreen mainScreen].bounds.size;
-    float height = SDL_max(size.width, size.height);
-    /* FIXME: Some where around iOS 7, UILaunchImages in the Info.plist was introduced which explicitly maps image names to devices and orientations.
-     This gets rid of the hardcoded magic file names and allows more control for OS version, orientation, retina, and device.
-     But this existing code needs to be modified to look in the Info.plist for each key and act appropriately for the correct iOS version.
-     But iOS 8 superscedes this process and introduces the LaunchScreen NIB which uses autolayout to handle all orientations and devices.
-     Since we now have a LaunchScreen solution, this may never get fixed, 
-     but this note is here for anybody trying to debug their program on iOS 7 and doesn't understand why their Info.plist isn't working.
-     */
-    self->splashPortrait = [UIImage imageNamed:[NSString stringWithFormat:@"Default-%dh.png", (int)height]];
-    if (!self->splashPortrait) {
-        self->splashPortrait = [UIImage imageNamed:@"Default.png"];
-    }
-    self->splashLandscape = [UIImage imageNamed:@"Default-Landscape.png"];
-    if (!self->splashLandscape && self->splashPortrait) {
-        self->splashLandscape = [[UIImage alloc] initWithCGImage: self->splashPortrait.CGImage
-                                                           scale: 1.0
-                                                     orientation: UIImageOrientationRight];
-    }
-    if (self->splashPortrait) {
-        [self->splashPortrait retain];
-    }
-    if (self->splashLandscape) {
-        [self->splashLandscape retain];
-    }
-
-    [self updateSplashImage:[[UIApplication sharedApplication] statusBarOrientation]];
-
-    return self;
-}
-
-- (NSUInteger)supportedInterfaceOrientations
-{
-    NSUInteger orientationMask = UIInterfaceOrientationMaskAll;
-
-    /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
-    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
-        orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
-    }
-    return orientationMask;
-}
-
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
-{
-    NSUInteger orientationMask = [self supportedInterfaceOrientations];
-    return (orientationMask & (1 << orient));
-}
-
-- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
-{
-    [self updateSplashImage:interfaceOrientation];
-}
-
-- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation
-{
-    UIImage *image;
-
-    if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
-        image = self->splashLandscape;
-    } else {
-        image = self->splashPortrait;
-    }
-    if (image)
-    {
-        splash.image = image;
-    }
-}
-
-@end
-
-
-@implementation SDLUIKitDelegate
-
-/* convenience method */
-+ (id) sharedAppDelegate
-{
-    /* the delegate is set in UIApplicationMain(), which is garaunteed to be called before this method */
-    return [[UIApplication sharedApplication] delegate];
+    /* the delegate is set in UIApplicationMain(), which is guaranteed to be
+     * called before this method */
+    return [UIApplication sharedApplication].delegate;
 }
 
 + (NSString *)getAppDelegateClassName
 {
-    /* subclassing notice: when you subclass this appdelegate, make sure to add a category to override
-       this method and return the actual name of the delegate */
+    /* subclassing notice: when you subclass this appdelegate, make sure to add
+     * a category to override this method and return the actual name of the
+     * delegate */
     return @"SDLUIKitDelegate";
 }
 
-- (id)init
+- (void)hideLaunchScreen
 {
-    self = [super init];
-    return self;
+    UIWindow *window = launchWindow;
+
+    if (!window || window.hidden) {
+        return;
+    }
+
+    launchWindow = nil;
+
+    /* Do a nice animated fade-out (roughly matches the real launch behavior.) */
+    [UIView animateWithDuration:0.2 animations:^{
+        window.alpha = 0.0;
+    } completion:^(BOOL finished) {
+        window.hidden = YES;
+    }];
 }
 
 - (void)postFinishLaunch
 {
+    /* Hide the launch screen the next time the run loop is run. SDL apps will
+     * have a chance to load resources while the launch screen is still up. */
+    [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0];
+
     /* run the user's application, passing argc and argv */
     SDL_iPhoneSetEventPump(SDL_TRUE);
     exit_status = SDL_main(forward_argc, forward_argv);
     SDL_iPhoneSetEventPump(SDL_FALSE);
 
-    /* If we showed a splash image, clean it up */
-    if (launch_window) {
-        [launch_window release];
-        launch_window = NULL;
+    if (launchWindow) {
+        launchWindow.hidden = YES;
+        launchWindow = nil;
     }
 
     /* exit, passing the return status from the user's application */
-    /* We don't actually exit to support applications that do setup in
-     * their main function and then allow the Cocoa event loop to run.
-     */
+    /* We don't actually exit to support applications that do setup in their
+     * main function and then allow the Cocoa event loop to run. */
     /* exit(exit_status); */
 }
 
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
-    /* Keep the launch image up until we set a video mode */
-    launch_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+    NSBundle *bundle = [NSBundle mainBundle];
+    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+
+#if SDL_IPHONE_LAUNCHSCREEN
+    /* The normal launch screen is displayed until didFinishLaunching returns,
+     * but SDL_main is called after that happens and there may be a noticeable
+     * delay between the start of SDL_main and when the first real frame is
+     * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is
+     * called), so we show the launch screen programmatically until the first
+     * time events are pumped. */
+    UIViewController *viewcontroller = [[SDLLaunchScreenController alloc] init];
 
-    /* iOS 8 introduces LaunchScreen NIBs which use autolayout to handle all devices and orientations with a single NIB instead of multiple launch images.
-     This is also the only way to get the App Store badge "Optimized for iPhone 6 and iPhone 6 Plus".
-     So if the application is running on iOS 8 or greater AND has specified a LaunchScreen in their Info.plist, we should use the LaunchScreen NIB.
-     Otherwise, we should fallback to the legacy behavior of launch screen images.
-     */
-    NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
-    if( ([[UIDevice currentDevice].systemVersion intValue] >= 8) && (nil != launch_screen_name) ) {
-        // iOS 8.0 and above uses LaunchScreen.xib
-        SDL_launchscreenviewcontroller* launch_screen_view_controller = [[SDL_launchscreenviewcontroller alloc] init];
-        launch_window.rootViewController = launch_screen_view_controller;
-        [launch_window addSubview:launch_screen_view_controller.view];
-        [launch_window makeKeyAndVisible];
-    } else {
-        // Anything less than iOS 8.0
+    if (viewcontroller.view) {
+        launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+
+        /* We don't want the launch window immediately hidden when a real SDL
+         * window is shown - we fade it out ourselves when we're ready. */
+        launchWindow.windowLevel = UIWindowLevelNormal + 1.0;
 
-        UIViewController *splashViewController = [[SDL_splashviewcontroller alloc] init];
-        launch_window.rootViewController = splashViewController;
-        [launch_window addSubview:splashViewController.view];
-        [launch_window makeKeyAndVisible];
+        /* Show the window but don't make it key. Events should always go to
+         * other windows when possible. */
+        launchWindow.hidden = NO;
+
+        launchWindow.rootViewController = viewcontroller;
     }
+#endif
 
     /* Set working directory to resource path */
-    [[NSFileManager defaultManager] changeCurrentDirectoryPath: [[NSBundle mainBundle] resourcePath]];
+    [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
 
     /* register a callback for the idletimer hint */
     SDL_AddHintCallback(SDL_HINT_IDLE_TIMER_DISABLED,
@@ -314,7 +353,35 @@
     SDL_SendAppEvent(SDL_APP_LOWMEMORY);
 }
 
-- (void) applicationWillResignActive:(UIApplication*)application
+- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
+{
+    BOOL isLandscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation);
+    SDL_VideoDevice *_this = SDL_GetVideoDevice();
+
+    if (_this && _this->num_displays > 0) {
+        SDL_DisplayMode *desktopmode = &_this->displays[0].desktop_mode;
+        SDL_DisplayMode *currentmode = &_this->displays[0].current_mode;
+
+        /* The desktop display mode should be kept in sync with the screen
+         * orientation so that updating a window's fullscreen state to
+         * SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the
+         * correct orientation. */
+        if (isLandscape != (desktopmode->w > desktopmode->h)) {
+            int height = desktopmode->w;
+            desktopmode->w = desktopmode->h;
+            desktopmode->h = height;
+        }
+
+        /* Same deal with the current mode + SDL_GetCurrentDisplayMode. */
+        if (isLandscape != (currentmode->w > currentmode->h)) {
+            int height = currentmode->w;
+            currentmode->w = currentmode->h;
+            currentmode->h = height;
+        }
+    }
+}
+
+- (void)applicationWillResignActive:(UIApplication*)application
 {
     SDL_VideoDevice *_this = SDL_GetVideoDevice();
     if (_this) {
@@ -327,17 +394,17 @@
     SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
 }
 
-- (void) applicationDidEnterBackground:(UIApplication*)application
+- (void)applicationDidEnterBackground:(UIApplication*)application
 {
     SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
 }
 
-- (void) applicationWillEnterForeground:(UIApplication*)application
+- (void)applicationWillEnterForeground:(UIApplication*)application
 {
     SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
 }
 
-- (void) applicationDidBecomeActive:(UIApplication*)application
+- (void)applicationDidBecomeActive:(UIApplication*)application
 {
     SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
 
@@ -353,11 +420,11 @@
 
 - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
 {
-    NSURL *fileURL = [url filePathURL];
+    NSURL *fileURL = url.filePathURL;
     if (fileURL != nil) {
-        SDL_SendDropFile([[fileURL path] UTF8String]);
+        SDL_SendDropFile([fileURL.path UTF8String]);
     } else {
-        SDL_SendDropFile([[url absoluteString] UTF8String]);
+        SDL_SendDropFile([url.absoluteString UTF8String]);
     }
     return YES;
 }
--- a/src/video/uikit/SDL_uikitevents.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitevents.m	Thu Apr 09 22:28:37 2015 -0400
@@ -40,8 +40,9 @@
 void
 UIKit_PumpEvents(_THIS)
 {
-    if (!UIKit_EventPumpEnabled)
+    if (!UIKit_EventPumpEnabled) {
         return;
+    }
 
     /* Let the run loop run for a short amount of time: long enough for
        touch events to get processed (which is important to get certain
--- a/src/video/uikit/SDL_uikitmessagebox.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitmessagebox.m	Thu Apr 09 22:28:37 2015 -0400
@@ -30,35 +30,20 @@
 
 static SDL_bool s_showingMessageBox = SDL_FALSE;
 
-@interface UIKit_UIAlertViewDelegate : NSObject <UIAlertViewDelegate> {
-@private
-    int *clickedButtonIndex;
-}
+@interface SDLAlertViewDelegate : NSObject <UIAlertViewDelegate>
 
-- (id)initWithButtonIndex:(int *)_buttonIndex;
-- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
+@property (nonatomic, assign) int clickedIndex;
 
 @end
 
-@implementation UIKit_UIAlertViewDelegate
+@implementation SDLAlertViewDelegate
 
-- (id)initWithButtonIndex:(int *)buttonIndex
+- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
 {
-    self = [self init];
-    if (self == nil) {
-        return nil;
-    }
-    self->clickedButtonIndex = buttonIndex;
-
-    return self;
+    _clickedIndex = (int)buttonIndex;
 }
 
-- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
-{
-    *clickedButtonIndex = (int)buttonIndex;
-}
-
-@end /* UIKit_UIAlertViewDelegate */
+@end
 
 
 SDL_bool
@@ -70,41 +55,38 @@
 int
 UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
 {
-    int clicked;
+    int i;
+    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
 
-    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
-    UIAlertView* alert = [[UIAlertView alloc] init];
+    @autoreleasepool {
+        UIAlertView *alert = [[UIAlertView alloc] init];
+        SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init];
 
-    alert.title = [NSString stringWithUTF8String:messageboxdata->title];
-    alert.message = [NSString stringWithUTF8String:messageboxdata->message];
-    alert.delegate = [[UIKit_UIAlertViewDelegate alloc] initWithButtonIndex:&clicked];
+        alert.delegate = delegate;
+        alert.title = @(messageboxdata->title);
+        alert.message = @(messageboxdata->message);
 
-    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
-    int i;
-    for (i = 0; i < messageboxdata->numbuttons; ++i) {
-        [alert addButtonWithTitle:[[NSString alloc] initWithUTF8String:buttons[i].text]];
-    }
+        for (i = 0; i < messageboxdata->numbuttons; ++i) {
+            [alert addButtonWithTitle:@(buttons[i].text)];
+        }
 
-    /* Set up for showing the alert */
-    clicked = messageboxdata->numbuttons;
+        /* Set up for showing the alert */
+        delegate.clickedIndex = messageboxdata->numbuttons;
 
-    [alert show];
+        [alert show];
 
-    /* Run the main event loop until the alert has finished */
-    /* Note that this needs to be done on the main thread */
-    s_showingMessageBox = SDL_TRUE;
-    while (clicked == messageboxdata->numbuttons) {
-        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+        /* Run the main event loop until the alert has finished */
+        /* Note that this needs to be done on the main thread */
+        s_showingMessageBox = SDL_TRUE;
+        while (delegate.clickedIndex == messageboxdata->numbuttons) {
+            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+        }
+        s_showingMessageBox = SDL_FALSE;
+
+        *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid;
+
+        alert.delegate = nil;
     }
-    s_showingMessageBox = SDL_FALSE;
-
-    *buttonid = messageboxdata->buttons[clicked].buttonid;
-
-    [alert.delegate release];
-    [alert release];
-
-    [pool release];
 
     return 0;
 }
--- a/src/video/uikit/SDL_uikitmodes.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitmodes.h	Thu Apr 09 22:28:37 2015 -0400
@@ -25,17 +25,17 @@
 
 #include "SDL_uikitvideo.h"
 
-typedef struct
-{
-    UIScreen *uiscreen;
-    CGFloat scale;
-} SDL_DisplayData;
+@interface SDL_DisplayData : NSObject
+
+@property (nonatomic, strong) UIScreen *uiscreen;
+
+@end
 
-typedef struct
-{
-    UIScreenMode *uiscreenmode;
-    CGFloat scale;
-} SDL_DisplayModeData;
+@interface SDL_DisplayModeData : NSObject
+
+@property (nonatomic, strong) UIScreenMode *uiscreenmode;
+
+@end
 
 extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen);
 
--- a/src/video/uikit/SDL_uikitmodes.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitmodes.m	Thu Apr 09 22:28:37 2015 -0400
@@ -25,27 +25,36 @@
 #include "SDL_assert.h"
 #include "SDL_uikitmodes.h"
 
+@implementation SDL_DisplayData
+
+@synthesize uiscreen;
+
+@end
+
+@implementation SDL_DisplayModeData
+
+@synthesize uiscreenmode;
+
+@end
+
 
 static int
 UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode,
-    UIScreenMode * uiscreenmode, CGFloat scale)
+    UIScreenMode * uiscreenmode)
 {
-    SDL_DisplayModeData *data = NULL;
+    SDL_DisplayModeData *data = nil;
 
     if (uiscreenmode != nil) {
         /* Allocate the display mode data */
-        data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
+        data = [[SDL_DisplayModeData alloc] init];
         if (!data) {
             return SDL_OutOfMemory();
         }
 
-        data->uiscreenmode = uiscreenmode;
-        [data->uiscreenmode retain];
-
-        data->scale = scale;
+        data.uiscreenmode = uiscreenmode;
     }
 
-    mode->driverdata = data;
+    mode->driverdata = (void *) CFBridgingRetain(data);
 
     return 0;
 }
@@ -54,23 +63,21 @@
 UIKit_FreeDisplayModeData(SDL_DisplayMode * mode)
 {
     if (mode->driverdata != NULL) {
-        SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
-        [data->uiscreenmode release];
-        SDL_free(data);
+        CFRelease(mode->driverdata);
         mode->driverdata = NULL;
     }
 }
 
 static int
 UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
-    UIScreenMode * uiscreenmode, CGFloat scale)
+    UIScreenMode * uiscreenmode)
 {
     SDL_DisplayMode mode;
     SDL_zero(mode);
 
     mode.format = SDL_PIXELFORMAT_ABGR8888;
     mode.refresh_rate = 0;
-    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
+    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
         return -1;
     }
 
@@ -85,16 +92,16 @@
 }
 
 static int
-UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale,
+UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h,
                      UIScreenMode * uiscreenmode, SDL_bool addRotation)
 {
-    if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode, scale) < 0) {
+    if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode) < 0) {
         return -1;
     }
 
     if (addRotation) {
         /* Add the rotated version */
-        if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode, scale) < 0) {
+        if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode) < 0) {
             return -1;
         }
     }
@@ -105,7 +112,7 @@
 static int
 UIKit_AddDisplay(UIScreen *uiscreen)
 {
-    CGSize size = [uiscreen bounds].size;
+    CGSize size = uiscreen.bounds.size;
 
     /* Make sure the width/height are oriented correctly */
     if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
@@ -114,24 +121,16 @@
         size.height = height;
     }
 
-    /* When dealing with UIKit all coordinates are specified in terms of
-     * what Apple refers to as points. [UIScreen scale] indicates the
-     * relationship between points and pixels. Since SDL has no notion
-     * of points, we must compensate in all cases where dealing with such
-     * units.
-     */
-    CGFloat scale = [uiscreen scale];
-
     SDL_VideoDisplay display;
     SDL_DisplayMode mode;
     SDL_zero(mode);
     mode.format = SDL_PIXELFORMAT_ABGR8888;
-    mode.w = (int)(size.width * scale);
-    mode.h = (int)(size.height * scale);
+    mode.w = (int) size.width;
+    mode.h = (int) size.height;
 
-    UIScreenMode * uiscreenmode = [uiscreen currentMode];
+    UIScreenMode *uiscreenmode = uiscreen.currentMode;
 
-    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
+    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
         return -1;
     }
 
@@ -140,17 +139,15 @@
     display.current_mode = mode;
 
     /* Allocate the display data */
-    SDL_DisplayData *data = (SDL_DisplayData *) SDL_malloc(sizeof(*data));
+    SDL_DisplayData *data = [[SDL_DisplayData alloc] init];
     if (!data) {
         UIKit_FreeDisplayModeData(&display.desktop_mode);
         return SDL_OutOfMemory();
     }
 
-    [uiscreen retain];
-    data->uiscreen = uiscreen;
-    data->scale = scale;
+    data.uiscreen = uiscreen;
 
-    display.driverdata = data;
+    display.driverdata = (void *) CFBridgingRetain(data);
     SDL_AddVideoDisplay(&display);
 
     return 0;
@@ -160,9 +157,9 @@
 UIKit_IsDisplayLandscape(UIScreen *uiscreen)
 {
     if (uiscreen == [UIScreen mainScreen]) {
-        return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
+        return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
     } else {
-        CGSize size = [uiscreen bounds].size;
+        CGSize size = uiscreen.bounds.size;
         return (size.width > size.height);
     }
 }
@@ -170,9 +167,11 @@
 int
 UIKit_InitModes(_THIS)
 {
-    for (UIScreen *uiscreen in [UIScreen screens]) {
-        if (UIKit_AddDisplay(uiscreen) < 0) {
-            return -1;
+    @autoreleasepool {
+        for (UIScreen *uiscreen in [UIScreen screens]) {
+            if (UIKit_AddDisplay(uiscreen) < 0) {
+                return -1;
+            }
         }
     }
 
@@ -182,34 +181,35 @@
 void
 UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
 {
-    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+    @autoreleasepool {
+        SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
 
-    SDL_bool isLandscape = UIKit_IsDisplayLandscape(data->uiscreen);
-    SDL_bool addRotation = (data->uiscreen == [UIScreen mainScreen]);
+        SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
+        SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
+        CGFloat scale = data.uiscreen.scale;
 
-    for (UIScreenMode *uimode in [data->uiscreen availableModes]) {
-        CGSize size = [uimode size];
-        int w = (int)size.width;
-        int h = (int)size.height;
+#ifdef __IPHONE_8_0
+        /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than
+         * 1242x2208 (414x736@3x), so we should use the native scale. */
+        if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) {
+            scale = data.uiscreen.nativeScale;
+        }
+#endif
 
-        /* Make sure the width/height are oriented correctly */
-        if (isLandscape != (w > h)) {
-            int tmp = w;
-            w = h;
-            h = tmp;
-        }
+        for (UIScreenMode *uimode in data.uiscreen.availableModes) {
+            /* The size of a UIScreenMode is in pixels, but we deal exclusively
+             * in points (except in SDL_GL_GetDrawableSize.) */
+            int w = (int)(uimode.size.width / scale);
+            int h = (int)(uimode.size.height / scale);
 
-        /* Add the native screen resolution. */
-        UIKit_AddDisplayMode(display, w, h, data->scale, uimode, addRotation);
+            /* Make sure the width/height are oriented correctly */
+            if (isLandscape != (w > h)) {
+                int tmp = w;
+                w = h;
+                h = tmp;
+            }
 
-        if (data->scale != 1.0f) {
-            /* Add the native screen resolution divided by its scale.
-             * This is so devices capable of e.g. 640x960 also advertise 320x480.
-             */
-            UIKit_AddDisplayMode(display,
-                (int)(size.width / data->scale),
-                (int)(size.height / data->scale),
-                1.0f, uimode, addRotation);
+            UIKit_AddDisplayMode(display, w, h, uimode, addRotation);
         }
     }
 }
@@ -217,19 +217,24 @@
 int
 UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
 {
-    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
-    SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
+    @autoreleasepool {
+        SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
+        SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
 
-    [data->uiscreen setCurrentMode:modedata->uiscreenmode];
+        [data.uiscreen setCurrentMode:modedata.uiscreenmode];
 
-    if (data->uiscreen == [UIScreen mainScreen]) {
-        if (mode->w > mode->h) {
-            if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
-                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
-            }
-        } else if (mode->w < mode->h) {
-            if (UIKit_IsDisplayLandscape(data->uiscreen)) {
-                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
+        if (data.uiscreen == [UIScreen mainScreen]) {
+            /* [UIApplication setStatusBarOrientation:] no longer works reliably
+             * in recent iOS versions, so we can't rotate the screen when setting
+             * the display mode. */
+            if (mode->w > mode->h) {
+                if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
+                    return SDL_SetError("Screen orientation does not match display mode size");
+                }
+            } else if (mode->w < mode->h) {
+                if (UIKit_IsDisplayLandscape(data.uiscreen)) {
+                    return SDL_SetError("Screen orientation does not match display mode size");
+                }
             }
         }
     }
@@ -242,19 +247,21 @@
 {
     /* Release Objective-C objects, so higher level doesn't free() them. */
     int i, j;
-    for (i = 0; i < _this->num_displays; i++) {
-        SDL_VideoDisplay *display = &_this->displays[i];
+    @autoreleasepool {
+        for (i = 0; i < _this->num_displays; i++) {
+            SDL_VideoDisplay *display = &_this->displays[i];
 
-        UIKit_FreeDisplayModeData(&display->desktop_mode);
-        for (j = 0; j < display->num_display_modes; j++) {
-            SDL_DisplayMode *mode = &display->display_modes[j];
-            UIKit_FreeDisplayModeData(mode);
+            UIKit_FreeDisplayModeData(&display->desktop_mode);
+            for (j = 0; j < display->num_display_modes; j++) {
+                SDL_DisplayMode *mode = &display->display_modes[j];
+                UIKit_FreeDisplayModeData(mode);
+            }
+
+            if (display->driverdata != NULL) {
+                CFRelease(display->driverdata);
+                display->driverdata = NULL;
+            }
         }
-
-        SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
-        [data->uiscreen release];
-        SDL_free(data);
-        display->driverdata = NULL;
     }
 }
 
--- a/src/video/uikit/SDL_uikitopengles.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitopengles.h	Thu Apr 09 22:28:37 2015 -0400
@@ -25,6 +25,8 @@
 
 extern int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window,
                                 SDL_GLContext context);
+extern void UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window,
+                                     int * w, int * h);
 extern void UIKit_GL_SwapWindow(_THIS, SDL_Window * window);
 extern SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window);
 extern void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context);
--- a/src/video/uikit/SDL_uikitopengles.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitopengles.m	Thu Apr 09 22:28:37 2015 -0400
@@ -23,10 +23,10 @@
 #if SDL_VIDEO_DRIVER_UIKIT
 
 #include "SDL_uikitopengles.h"
-#include "SDL_uikitopenglview.h"
-#include "SDL_uikitappdelegate.h"
+#import "SDL_uikitopenglview.h"
 #include "SDL_uikitmodes.h"
 #include "SDL_uikitwindow.h"
+#include "SDL_uikitevents.h"
 #include "../SDL_sysvideo.h"
 #include "../../events/SDL_keyboard_c.h"
 #include "../../events/SDL_mouse_c.h"
@@ -40,148 +40,147 @@
 UIKit_GL_GetProcAddress(_THIS, const char *proc)
 {
     /* Look through all SO's for the proc symbol.  Here's why:
-       -Looking for the path to the OpenGL Library seems not to work in the iPhone Simulator.
-       -We don't know that the path won't change in the future.
-    */
+     * -Looking for the path to the OpenGL Library seems not to work in the iOS Simulator.
+     * -We don't know that the path won't change in the future. */
     return dlsym(RTLD_DEFAULT, proc);
 }
 
 /*
-    note that SDL_GL_Delete context makes it current without passing the window
+  note that SDL_GL_DeleteContext makes it current without passing the window
 */
-int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+int
+UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
 {
-    [EAGLContext setCurrentContext: context];
+    @autoreleasepool {
+        SDLEAGLContext *eaglcontext = (__bridge SDLEAGLContext *) context;
+
+        if (![EAGLContext setCurrentContext:eaglcontext]) {
+            return SDL_SetError("Could not make EAGL context current");
+        }
+
+        if (eaglcontext) {
+            [eaglcontext.sdlView setSDLWindow:window];
+        }
+    }
+
     return 0;
 }
 
+void
+UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
+{
+    @autoreleasepool {
+        SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
+        UIView *view = data.viewcontroller.view;
+        if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
+            SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
+            if (w) {
+                *w = glview.backingWidth;
+            }
+            if (h) {
+                *h = glview.backingHeight;
+            }
+        }
+    }
+}
+
 int
 UIKit_GL_LoadLibrary(_THIS, const char *path)
 {
-    /*
-        shouldn't be passing a path into this function
-        why?  Because we've already loaded the library
-        and because the SDK forbids loading an external SO
-    */
+    /* We shouldn't pass a path to this function, since we've already loaded the
+     * library. */
     if (path != NULL) {
-        return SDL_SetError("iPhone GL Load Library just here for compatibility");
+        return SDL_SetError("iOS GL Load Library just here for compatibility");
     }
     return 0;
 }
 
 void UIKit_GL_SwapWindow(_THIS, SDL_Window * window)
 {
+    @autoreleasepool {
+        SDLEAGLContext *context = (__bridge SDLEAGLContext *) SDL_GL_GetCurrentContext();
+
 #if SDL_POWER_UIKIT
-    /* Check once a frame to see if we should turn off the battery monitor. */
-    SDL_UIKit_UpdateBatteryMonitoring();
+        /* Check once a frame to see if we should turn off the battery monitor. */
+        SDL_UIKit_UpdateBatteryMonitoring();
 #endif
 
-    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+        [context.sdlView swapBuffers];
 
-    if (nil == data->view) {
-        return;
+        /* You need to pump events in order for the OS to make changes visible.
+         * We don't pump events here because we don't want iOS application events
+         * (low memory, terminate, etc.) to happen inside low level rendering. */
     }
-    [data->view swapBuffers];
-
-    /* You need to pump events in order for the OS to make changes visible.
-       We don't pump events here because we don't want iOS application events
-       (low memory, terminate, etc.) to happen inside low level rendering.
-     */
 }
 
-SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)
+SDL_GLContext
+UIKit_GL_CreateContext(_THIS, SDL_Window * window)
 {
-    SDL_uikitopenglview *view;
-    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
-    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
-    SDL_DisplayData *displaydata = display->driverdata;
-    SDL_DisplayModeData *displaymodedata = display->current_mode.driverdata;
-    UIWindow *uiwindow = data->uiwindow;
-    EAGLSharegroup *share_group = nil;
+    @autoreleasepool {
+        SDL_uikitopenglview *view;
+        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
+        CGRect frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
+        EAGLSharegroup *sharegroup = nil;
+        CGFloat scale = 1.0;
+
+        if (_this->gl_config.share_with_current_context) {
+            EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext();
+            sharegroup = context.sharegroup;
+        }
 
-    if (_this->gl_config.share_with_current_context) {
-        SDL_uikitopenglview *view = (SDL_uikitopenglview *) SDL_GL_GetCurrentContext();
-        share_group = [view.context sharegroup];
-    }
+        if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
+            /* Set the scale to the natural scale factor of the screen - the
+             * backing dimensions of the OpenGL view will match the pixel
+             * dimensions of the screen rather than the dimensions in points. */
+#ifdef __IPHONE_8_0
+            if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) {
+                scale = data.uiwindow.screen.nativeScale;
+            } else
+#endif
+            {
+                scale = data.uiwindow.screen.scale;
+            }
+        }
 
-    /* construct our view, passing in SDL's OpenGL configuration data */
-    CGRect frame;
-    if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
-        frame = [displaydata->uiscreen bounds];
-    } else {
-        frame = [displaydata->uiscreen applicationFrame];
+        /* construct our view, passing in SDL's OpenGL configuration data */
+        view = [[SDL_uikitopenglview alloc] initWithFrame:frame
+                                                    scale:scale
+                                            retainBacking:_this->gl_config.retained_backing
+                                                    rBits:_this->gl_config.red_size
+                                                    gBits:_this->gl_config.green_size
+                                                    bBits:_this->gl_config.blue_size
+                                                    aBits:_this->gl_config.alpha_size
+                                                depthBits:_this->gl_config.depth_size
+                                              stencilBits:_this->gl_config.stencil_size
+                                                     sRGB:_this->gl_config.framebuffer_srgb_capable
+                                             majorVersion:_this->gl_config.major_version
+                                               shareGroup:sharegroup];
+        if (!view) {
+            return NULL;
+        }
+
+        SDLEAGLContext *context = view.context;
+        if (UIKit_GL_MakeCurrent(_this, window, (__bridge SDL_GLContext) context) < 0) {
+            UIKit_GL_DeleteContext(_this, (SDL_GLContext) CFBridgingRetain(context));
+            return NULL;
+        }
+
+        /* We return a +1'd context. The window's driverdata owns the view (via
+         * MakeCurrent.) */
+        return (SDL_GLContext) CFBridgingRetain(context);
     }
-    view = [[SDL_uikitopenglview alloc] initWithFrame: frame
-                                    scale: displaymodedata->scale
-                                    retainBacking: _this->gl_config.retained_backing
-                                    rBits: _this->gl_config.red_size
-                                    gBits: _this->gl_config.green_size
-                                    bBits: _this->gl_config.blue_size
-                                    aBits: _this->gl_config.alpha_size
-                                    depthBits: _this->gl_config.depth_size
-                                    stencilBits: _this->gl_config.stencil_size
-                                    majorVersion: _this->gl_config.major_version
-                                    shareGroup: share_group];
-    if (!view) {
-        return NULL;
-    }
-
-    data->view = view;
-    view->viewcontroller = data->viewcontroller;
-    if (view->viewcontroller != nil) {
-        [view->viewcontroller setView:view];
-        [view->viewcontroller retain];
-    }
-    [uiwindow addSubview: view];
-
-    /* The view controller needs to be the root in order to control rotation on iOS 6.0 */
-    if (uiwindow.rootViewController == nil) {
-        uiwindow.rootViewController = view->viewcontroller;
-    }
-
-    EAGLContext *context = view.context;
-    if (UIKit_GL_MakeCurrent(_this, window, context) < 0) {
-        UIKit_GL_DeleteContext(_this, context);
-        return NULL;
-    }
-
-    /* Make this window the current mouse focus for touch input */
-    if (displaydata->uiscreen == [UIScreen mainScreen]) {
-        SDL_SetMouseFocus(window);
-        SDL_SetKeyboardFocus(window);
-    }
-
-    return context;
 }
 
-void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context)
+void
+UIKit_GL_DeleteContext(_THIS, SDL_GLContext context)
 {
-    SDL_Window *window;
+    @autoreleasepool {
+        /* Transfer ownership the +1'd context to ARC. */
+        SDLEAGLContext *eaglcontext = (SDLEAGLContext *) CFBridgingRelease(context);
 
-    /* Find the view associated with this context */
-    for (window = _this->windows; window; window = window->next) {
-        SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
-        SDL_uikitopenglview *view = data->view;
-        if (view.context == context) {
-            /* the delegate has retained the view, this will release him */
-            if (view->viewcontroller) {
-                UIWindow *uiwindow = (UIWindow *)view.superview;
-                if (uiwindow.rootViewController == view->viewcontroller) {
-                    uiwindow.rootViewController = nil;
-                }
-                [view->viewcontroller setView:nil];
-                [view->viewcontroller release];
-            }
-            [view removeFromSuperview];
-
-            /* FIXME: This doesn't actually call view dealloc - what is holding a reference to it? */
-            [view release];
-            return;
-        }
+        /* Detach the context's view from its window. */
+        [eaglcontext.sdlView setSDLWindow:NULL];
     }
-
-    /* View not found... delete the context anyway? */
-    [(EAGLContext *)context release];
 }
 
 #endif /* SDL_VIDEO_DRIVER_UIKIT */
--- a/src/video/uikit/SDL_uikitopenglview.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitopenglview.h	Thu Apr 09 22:28:37 2015 -0400
@@ -21,66 +21,48 @@
 
 #import <UIKit/UIKit.h>
 #import <OpenGLES/EAGL.h>
-#import <OpenGLES/ES1/gl.h>
-#import <OpenGLES/ES1/glext.h>
+#import <OpenGLES/ES2/gl.h>
+
 #import "SDL_uikitview.h"
-/*
-    This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
-    The view content is basically an EAGL surface you render your OpenGL scene into.
-    Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
- */
-@interface SDL_uikitopenglview : SDL_uikitview {
+#include "SDL_uikitvideo.h"
+
+@class SDL_uikitopenglview;
+
+@interface SDLEAGLContext : EAGLContext
 
-@private
-    /* The pixel dimensions of the backbuffer */
-    GLint backingWidth;
-    GLint backingHeight;
+@property (nonatomic, weak) SDL_uikitopenglview *sdlView;
 
-    EAGLContext *context;
+@end
+
+@interface SDL_uikitopenglview : SDL_uikitview
 
-    /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
-    GLuint viewRenderbuffer, viewFramebuffer;
-
-    /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
-    GLuint depthRenderbuffer;
+- (instancetype)initWithFrame:(CGRect)frame
+                        scale:(CGFloat)scale
+                retainBacking:(BOOL)retained
+                        rBits:(int)rBits
+                        gBits:(int)gBits
+                        bBits:(int)bBits
+                        aBits:(int)aBits
+                    depthBits:(int)depthBits
+                  stencilBits:(int)stencilBits
+                         sRGB:(BOOL)sRGB
+                 majorVersion:(int)majorVersion
+                   shareGroup:(EAGLSharegroup*)shareGroup;
 
-    /* format of depthRenderbuffer */
-    GLenum depthBufferFormat;
+@property (nonatomic, readonly, strong) SDLEAGLContext *context;
 
-    id displayLink;
-    int animationInterval;
-    void (*animationCallback)(void*);
-    void *animationCallbackParam;
-}
+/* The width and height of the drawable in pixels (as opposed to points.) */
+@property (nonatomic, readonly) int backingWidth;
+@property (nonatomic, readonly) int backingHeight;
 
-@property (nonatomic, retain, readonly) EAGLContext *context;
+@property (nonatomic, readonly) GLuint drawableRenderbuffer;
+@property (nonatomic, readonly) GLuint drawableFramebuffer;
 
 - (void)swapBuffers;
 - (void)setCurrentContext;
 
-- (id)initWithFrame:(CGRect)frame
-    scale:(CGFloat)scale
-    retainBacking:(BOOL)retained
-    rBits:(int)rBits
-    gBits:(int)gBits
-    bBits:(int)bBits
-    aBits:(int)aBits
-    depthBits:(int)depthBits
-    stencilBits:(int)stencilBits
-    majorVersion:(int)majorVersion
-    shareGroup:(EAGLSharegroup*)shareGroup;
-
 - (void)updateFrame;
 
-- (void)setAnimationCallback:(int)interval
-    callback:(void (*)(void*))callback
-    callbackParam:(void*)callbackParam;
-
-- (void)startAnimation;
-- (void)stopAnimation;
-
-- (void)doLoop:(CADisplayLink*)sender;
-
 @end
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitopenglview.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitopenglview.m	Thu Apr 09 22:28:37 2015 -0400
@@ -22,170 +22,190 @@
 
 #if SDL_VIDEO_DRIVER_UIKIT
 
-#include <QuartzCore/QuartzCore.h>
 #include <OpenGLES/EAGLDrawable.h>
-#include "SDL_uikitopenglview.h"
-#include "SDL_uikitmessagebox.h"
+#include <OpenGLES/ES2/glext.h>
+#import "SDL_uikitopenglview.h"
+#include "SDL_uikitwindow.h"
+
+@implementation SDLEAGLContext
+
+@end
 
+@implementation SDL_uikitopenglview {
+    /* The renderbuffer and framebuffer used to render to this layer. */
+    GLuint viewRenderbuffer, viewFramebuffer;
 
-@implementation SDL_uikitopenglview
+    /* The depth buffer that is attached to viewFramebuffer, if it exists. */
+    GLuint depthRenderbuffer;
+
+    /* format of depthRenderbuffer */
+    GLenum depthBufferFormat;
+}
 
 @synthesize context;
+@synthesize backingWidth;
+@synthesize backingHeight;
 
 + (Class)layerClass
 {
     return [CAEAGLLayer class];
 }
 
-- (id)initWithFrame:(CGRect)frame
-      scale:(CGFloat)scale
-      retainBacking:(BOOL)retained
-      rBits:(int)rBits
-      gBits:(int)gBits
-      bBits:(int)bBits
-      aBits:(int)aBits
-      depthBits:(int)depthBits
-      stencilBits:(int)stencilBits
-      majorVersion:(int)majorVersion
-      shareGroup:(EAGLSharegroup*)shareGroup
+- (instancetype)initWithFrame:(CGRect)frame
+                        scale:(CGFloat)scale
+                retainBacking:(BOOL)retained
+                        rBits:(int)rBits
+                        gBits:(int)gBits
+                        bBits:(int)bBits
+                        aBits:(int)aBits
+                    depthBits:(int)depthBits
+                  stencilBits:(int)stencilBits
+                         sRGB:(BOOL)sRGB
+                 majorVersion:(int)majorVersion
+                   shareGroup:(EAGLSharegroup*)shareGroup
 {
-    depthBufferFormat = 0;
-
     if ((self = [super initWithFrame:frame])) {
         const BOOL useStencilBuffer = (stencilBits != 0);
         const BOOL useDepthBuffer = (depthBits != 0);
         NSString *colorFormat = nil;
 
         /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES
-           versions, and this allows us to handle future OpenGL ES versions.
-         */
+         * versions, and this allows us to handle future OpenGL ES versions. */
         EAGLRenderingAPI api = majorVersion;
 
-        if (rBits == 8 && gBits == 8 && bBits == 8) {
-            /* if user specifically requests rbg888 or some color format higher than 16bpp */
-            colorFormat = kEAGLColorFormatRGBA8;
-        } else {
-            /* default case (faster) */
-            colorFormat = kEAGLColorFormatRGB565;
-        }
-
-        /* Get the layer */
-        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
-
-        eaglLayer.opaque = YES;
-        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
-                                        [NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil];
-
-        context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
+        context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
         if (!context || ![EAGLContext setCurrentContext:context]) {
-            [self release];
             SDL_SetError("OpenGL ES %d not supported", majorVersion);
             return nil;
         }
 
+        context.sdlView = self;
+
+        if (sRGB) {
+            /* sRGB EAGL drawable support was added in iOS 7. */
+            if (UIKit_IsSystemVersionAtLeast(7.0)) {
+                colorFormat = kEAGLColorFormatSRGBA8;
+            } else {
+                SDL_SetError("sRGB drawables are not supported.");
+                return nil;
+            }
+        } else if (rBits >= 8 || gBits >= 8 || bBits >= 8) {
+            /* if user specifically requests rbg888 or some color format higher than 16bpp */
+            colorFormat = kEAGLColorFormatRGBA8;
+        } else {
+            /* default case (potentially faster) */
+            colorFormat = kEAGLColorFormatRGB565;
+        }
+
+        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
+
+        eaglLayer.opaque = YES;
+        eaglLayer.drawableProperties = @{
+            kEAGLDrawablePropertyRetainedBacking:@(retained),
+            kEAGLDrawablePropertyColorFormat:colorFormat
+        };
+
         /* Set the appropriate scale (for retina display support) */
         self.contentScaleFactor = scale;
 
-        /* create the buffers */
-        glGenFramebuffersOES(1, &viewFramebuffer);
-        glGenRenderbuffersOES(1, &viewRenderbuffer);
+        /* Create the color Renderbuffer Object */
+        glGenRenderbuffers(1, &viewRenderbuffer);
+        glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
+
+        if (![context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer]) {
+            SDL_SetError("Failed to create OpenGL ES drawable");
+            return nil;
+        }
 
-        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
-        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
-        [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
-        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
+        /* Create the Framebuffer Object */
+        glGenFramebuffers(1, &viewFramebuffer);
+        glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
 
-        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
-        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+        /* attach the color renderbuffer to the FBO */
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewRenderbuffer);
+
+        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
+        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
 
         if ((useDepthBuffer) || (useStencilBuffer)) {
             if (useStencilBuffer) {
                 /* Apparently you need to pack stencil and depth into one buffer. */
                 depthBufferFormat = GL_DEPTH24_STENCIL8_OES;
             } else if (useDepthBuffer) {
-                /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */
+                /* iOS only uses 32-bit float (exposed as fixed point 24-bit)
+                 * depth buffers. */
                 depthBufferFormat = GL_DEPTH_COMPONENT24_OES;
             }
 
-            glGenRenderbuffersOES(1, &depthRenderbuffer);
-            glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
-            glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
+            glGenRenderbuffers(1, &depthRenderbuffer);
+            glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
+            glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight);
             if (useDepthBuffer) {
-                glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
+                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
             }
             if (useStencilBuffer) {
-                glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
+                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
             }
         }
 
-        if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
-            return NO;
+        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+            SDL_SetError("Failed creating OpenGL ES framebuffer");
+            return nil;
         }
 
-        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
-        /* end create buffers */
+        glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
+
+        [self setDebugLabels];
+    }
+
+    return self;
+}
 
-        self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
-        self.autoresizesSubviews = YES;
-    }
-    return self;
+- (GLuint)drawableRenderbuffer
+{
+    return viewRenderbuffer;
+}
+
+- (GLuint)drawableFramebuffer
+{
+    return viewFramebuffer;
 }
 
 - (void)updateFrame
 {
-    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
-    glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
-    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0);
-    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
+    GLint prevRenderbuffer = 0;
+    glGetIntegerv(GL_RENDERBUFFER_BINDING, &prevRenderbuffer);
 
-    glGenRenderbuffersOES(1, &viewRenderbuffer);
-    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
-    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
-    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
+    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
 
-    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
-    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
 
     if (depthRenderbuffer != 0) {
-        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
-        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
+        glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
+        glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight);
     }
 
-    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, prevRenderbuffer);
 }
 
-- (void)setAnimationCallback:(int)interval
-    callback:(void (*)(void*))callback
-    callbackParam:(void*)callbackParam
-{
-    [self stopAnimation];
-
-    animationInterval = interval;
-    animationCallback = callback;
-    animationCallbackParam = callbackParam;
-
-    if (animationCallback)
-        [self startAnimation];
-}
-
-- (void)startAnimation
+- (void)setDebugLabels
 {
-    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
-    [displayLink setFrameInterval:animationInterval];
-    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-}
+    if (viewFramebuffer != 0) {
+        glLabelObjectEXT(GL_FRAMEBUFFER, viewFramebuffer, 0, "context FBO");
+    }
 
-- (void)stopAnimation
-{
-    [displayLink invalidate];
-    displayLink = nil;
-}
+    if (viewRenderbuffer != 0) {
+        glLabelObjectEXT(GL_RENDERBUFFER, viewRenderbuffer, 0, "context color buffer");
+    }
 
-- (void)doLoop:(CADisplayLink*)sender
-{
-    /* Don't run the game loop while a messagebox is up */
-    if (!UIKit_ShowingMessageBox()) {
-        animationCallback(animationCallbackParam);
+    if (depthRenderbuffer != 0) {
+        if (depthBufferFormat == GL_DEPTH24_STENCIL8_OES) {
+            glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth-stencil buffer");
+        } else {
+            glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth buffer");
+        }
     }
 }
 
@@ -194,44 +214,60 @@
     [EAGLContext setCurrentContext:context];
 }
 
-
 - (void)swapBuffers
 {
     /* viewRenderbuffer should always be bound here. Code that binds something
-        else is responsible for rebinding viewRenderbuffer, to reduce
-        duplicate state changes. */
-    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
+     * else is responsible for rebinding viewRenderbuffer, to reduce duplicate
+     * state changes. */
+    [context presentRenderbuffer:GL_RENDERBUFFER];
 }
 
-
 - (void)layoutSubviews
 {
-    [EAGLContext setCurrentContext:context];
-    [self updateFrame];
+    [super layoutSubviews];
+
+    int width  = (int) (self.bounds.size.width * self.contentScaleFactor);
+    int height = (int) (self.bounds.size.height * self.contentScaleFactor);
+
+    /* Update the color and depth buffer storage if the layer size has changed. */
+    if (width != backingWidth || height != backingHeight) {
+        EAGLContext *prevContext = [EAGLContext currentContext];
+        if (prevContext != context) {
+            [EAGLContext setCurrentContext:context];
+        }
+
+        [self updateFrame];
+
+        if (prevContext != context) {
+            [EAGLContext setCurrentContext:prevContext];
+        }
+    }
 }
 
 - (void)destroyFramebuffer
 {
-    glDeleteFramebuffersOES(1, &viewFramebuffer);
-    viewFramebuffer = 0;
-    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
-    viewRenderbuffer = 0;
+    if (viewFramebuffer != 0) {
+        glDeleteFramebuffers(1, &viewFramebuffer);
+        viewFramebuffer = 0;
+    }
 
-    if (depthRenderbuffer) {
-        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
+    if (viewRenderbuffer != 0) {
+        glDeleteRenderbuffers(1, &viewRenderbuffer);
+        viewRenderbuffer = 0;
+    }
+
+    if (depthRenderbuffer != 0) {
+        glDeleteRenderbuffers(1, &depthRenderbuffer);
         depthRenderbuffer = 0;
     }
 }
 
-
 - (void)dealloc
 {
-    [self destroyFramebuffer];
     if ([EAGLContext currentContext] == context) {
+        [self destroyFramebuffer];
         [EAGLContext setCurrentContext:nil];
     }
-    [context release];
-    [super dealloc];
 }
 
 @end
--- a/src/video/uikit/SDL_uikitvideo.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitvideo.h	Thu Apr 09 22:28:37 2015 -0400
@@ -25,20 +25,8 @@
 
 #include "../SDL_sysvideo.h"
 
-#ifndef __IPHONE_6_0
-/* This enum isn't available in older SDKs, but we use it for our own purposes on iOS 5.1 and for the system on iOS 6.0 */
-enum UIInterfaceOrientationMask
-{
-    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
-    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
-    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
-    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
-    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
-    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
-    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
-};
-#endif /* !__IPHONE_6_0 */
-
+BOOL UIKit_IsSystemVersionAtLeast(double version);
+CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen);
 
 #endif /* _SDL_uikitvideo_h */
 
--- a/src/video/uikit/SDL_uikitvideo.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitvideo.m	Thu Apr 09 22:28:37 2015 -0400
@@ -75,15 +75,15 @@
     device->SetDisplayMode = UIKit_SetDisplayMode;
     device->PumpEvents = UIKit_PumpEvents;
     device->CreateWindow = UIKit_CreateWindow;
+    device->SetWindowTitle = UIKit_SetWindowTitle;
     device->ShowWindow = UIKit_ShowWindow;
     device->HideWindow = UIKit_HideWindow;
     device->RaiseWindow = UIKit_RaiseWindow;
+    device->SetWindowBordered = UIKit_SetWindowBordered;
     device->SetWindowFullscreen = UIKit_SetWindowFullscreen;
     device->DestroyWindow = UIKit_DestroyWindow;
     device->GetWindowWMInfo = UIKit_GetWindowWMInfo;
 
-    /* !!! FIXME: implement SetWindowBordered */
-
 #if SDL_IPHONE_KEYBOARD
     device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport;
     device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard;
@@ -93,12 +93,13 @@
 #endif
 
     /* OpenGL (ES) functions */
-    device->GL_MakeCurrent        = UIKit_GL_MakeCurrent;
-    device->GL_SwapWindow        = UIKit_GL_SwapWindow;
+    device->GL_MakeCurrent      = UIKit_GL_MakeCurrent;
+    device->GL_GetDrawableSize  = UIKit_GL_GetDrawableSize;
+    device->GL_SwapWindow       = UIKit_GL_SwapWindow;
     device->GL_CreateContext    = UIKit_GL_CreateContext;
     device->GL_DeleteContext    = UIKit_GL_DeleteContext;
     device->GL_GetProcAddress   = UIKit_GL_GetProcAddress;
-    device->GL_LoadLibrary        = UIKit_GL_LoadLibrary;
+    device->GL_LoadLibrary      = UIKit_GL_LoadLibrary;
     device->free = UIKit_DeleteDevice;
 
     device->gl_config.accelerated = 1;
@@ -129,6 +130,25 @@
     UIKit_QuitModes(_this);
 }
 
+BOOL
+UIKit_IsSystemVersionAtLeast(double version)
+{
+    return [[UIDevice currentDevice].systemVersion doubleValue] >= version;
+}
+
+CGRect
+UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
+{
+    BOOL hasiOS7 = UIKit_IsSystemVersionAtLeast(7.0);
+
+    if (hasiOS7 || (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN))) {
+        /* The view should always show behind the status bar in iOS 7+. */
+        return screen.bounds;
+    } else {
+        return screen.applicationFrame;
+    }
+}
+
 /*
  * iOS log support.
  *
--- a/src/video/uikit/SDL_uikitview.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitview.h	Thu Apr 09 22:28:37 2015 -0400
@@ -20,59 +20,22 @@
 */
 
 #import <UIKit/UIKit.h>
-#import "SDL_uikitviewcontroller.h"
+
+#include "../SDL_sysvideo.h"
 
 #include "SDL_touch.h"
 
-#define IPHONE_TOUCH_EFFICIENT_DANGEROUS
-
-#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
-#define MAX_SIMULTANEOUS_TOUCHES 5
-#endif
-
-#if SDL_IPHONE_KEYBOARD
-@interface SDL_uikitview : UIView<UITextFieldDelegate> {
-#else
-@interface SDL_uikitview : UIView {
-#endif
+@interface SDL_uikitview : UIView
 
-    SDL_TouchID touchId;
-    UITouch *leftFingerDown;
-#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
-    UITouch *finger[MAX_SIMULTANEOUS_TOUCHES];
-#endif
+- (instancetype)initWithFrame:(CGRect)frame;
 
-#if SDL_IPHONE_KEYBOARD
-    UITextField *textField;
-    BOOL keyboardVisible;
-    SDL_Rect textInputRect;
-    int keyboardHeight;
-#endif
+- (void)setSDLWindow:(SDL_Window *)window;
 
-@public
-    SDL_uikitviewcontroller *viewcontroller;
-}
 - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize;
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
 
-#if SDL_IPHONE_KEYBOARD
-- (void)showKeyboard;
-- (void)hideKeyboard;
-- (void)initializeKeyboard;
-@property (readonly) BOOL keyboardVisible;
-@property (nonatomic,assign) SDL_Rect textInputRect;
-@property (nonatomic,assign) int keyboardHeight;
-
-SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
-void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
-void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
-SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
-void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
-
-#endif
-
 @end
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitview.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitview.m	Thu Apr 09 22:28:37 2015 -0400
@@ -24,438 +24,167 @@
 
 #include "SDL_uikitview.h"
 
-#include "../../events/SDL_keyboard_c.h"
 #include "../../events/SDL_mouse_c.h"
 #include "../../events/SDL_touch_c.h"
+#include "../../events/SDL_events_c.h"
 
-#if SDL_IPHONE_KEYBOARD
-#include "keyinfotable.h"
-#endif
-#include "SDL_uikitappdelegate.h"
-#include "SDL_uikitmodes.h"
-#include "SDL_uikitwindow.h"
+#import "SDL_uikitappdelegate.h"
+#import "SDL_uikitmodes.h"
+#import "SDL_uikitwindow.h"
+
+@implementation SDL_uikitview {
+    SDL_Window *sdlwindow;
+
+    SDL_TouchID touchId;
+    UITouch * __weak firstFingerDown;
+}
 
-void _uikit_keyboard_init() ;
-
-@implementation SDL_uikitview
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    if ((self = [super initWithFrame:frame])) {
+        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+        self.autoresizesSubviews = YES;
 
-- (void)dealloc
-{
-    [super dealloc];
+        self.multipleTouchEnabled = YES;
+
+        touchId = 1;
+        SDL_AddTouch(touchId, "");
+    }
+
+    return self;
 }
 
-- (id)initWithFrame:(CGRect)frame
+- (void)setSDLWindow:(SDL_Window *)window
 {
-    self = [super initWithFrame: frame];
+    SDL_WindowData *data = nil;
+
+    if (window == sdlwindow) {
+        return;
+    }
+
+    if (sdlwindow) {
+        SDL_uikitview *view = nil;
+        data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
+
+        [data.views removeObject:self];
 
-#if SDL_IPHONE_KEYBOARD
-    [self initializeKeyboard];
-#endif
+        [self removeFromSuperview];
+
+        /* Restore the next-oldest view in the old window. */
+        if (data.views.count > 0) {
+            view = data.views[data.views.count - 1];
+        }
+
+        data.viewcontroller.view = view;
+
+        if (data.uiwindow.rootViewController != data.viewcontroller) {
+            data.uiwindow.rootViewController = data.viewcontroller;
+        } else if (view) {
+            [data.uiwindow addSubview:view];
+        }
 
-    self.multipleTouchEnabled = YES;
+        [data.uiwindow layoutIfNeeded];
+    }
+
+    if (window) {
+        data = (__bridge SDL_WindowData *) window->driverdata;
+
+        /* Make sure the SDL window has a strong reference to this view. */
+        [data.views addObject:self];
+
+        /* Replace the view controller's old view with this one. */
+        [data.viewcontroller.view removeFromSuperview];
+        data.viewcontroller.view = self;
 
-    touchId = 1;
-    SDL_AddTouch(touchId, "");
+        if (data.uiwindow.rootViewController != data.viewcontroller) {
+            /* The root view controller handles rotation and the status bar.
+             * Assigning it also adds the controller's view to the window. */
+            data.uiwindow.rootViewController = data.viewcontroller;
+        } else {
+            [data.uiwindow addSubview:self];
+        }
 
-    return self;
+        /* The view's bounds may not be correct until the next event cycle. That
+         * might happen after the current dimensions are queried, so we force a
+         * layout now to immediately update the bounds. */
+        [data.uiwindow layoutIfNeeded];
+    }
 
+    sdlwindow = window;
 }
 
 - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
 {
-    CGPoint point = [touch locationInView: self];
-
-    /* Get the display scale and apply that to the input coordinates */
-    SDL_Window *window = self->viewcontroller.window;
-    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
-    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
+    CGPoint point = [touch locationInView:self];
 
     if (normalize) {
-        CGRect bounds = [self bounds];
+        CGRect bounds = self.bounds;
         point.x /= bounds.size.width;
         point.y /= bounds.size.height;
-    } else {
-        point.x *= displaymodedata->scale;
-        point.y *= displaymodedata->scale;
     }
+
     return point;
 }
 
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    NSEnumerator *enumerator = [touches objectEnumerator];
-    UITouch *touch = (UITouch*)[enumerator nextObject];
-
-    while (touch) {
-        if (!leftFingerDown) {
+    for (UITouch *touch in touches) {
+        if (!firstFingerDown) {
             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
 
-            /* send moved event */
-            SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
+            /* send mouse moved event */
+            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
 
             /* send mouse down event */
-            SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
+            SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
 
-            leftFingerDown = touch;
+            firstFingerDown = touch;
         }
 
         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
-#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
-        /* FIXME: TODO: Using touch as the fingerId is potentially dangerous
-         * It is also much more efficient than storing the UITouch pointer
-         * and comparing it to the incoming event.
-         */
         SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
                       SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
-#else
-        int i;
-        for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
-            if (finger[i] == NULL) {
-                finger[i] = touch;
-                SDL_SendTouch(touchId, i,
-                              SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
-                break;
-            }
-        }
-#endif
-        touch = (UITouch*)[enumerator nextObject];
     }
 }
 
 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    NSEnumerator *enumerator = [touches objectEnumerator];
-    UITouch *touch = (UITouch*)[enumerator nextObject];
-
-    while(touch) {
-        if (touch == leftFingerDown) {
+    for (UITouch *touch in touches) {
+        if (touch == firstFingerDown) {
             /* send mouse up */
-            SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
-            leftFingerDown = nil;
+            SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
+            firstFingerDown = nil;
         }
 
         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
-#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
-        SDL_SendTouch(touchId, (long)touch,
+        SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
                       SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
-#else
-        int i;
-        for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
-            if (finger[i] == touch) {
-                SDL_SendTouch(touchId, i,
-                              SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
-                finger[i] = NULL;
-                break;
-            }
-        }
-#endif
-        touch = (UITouch*)[enumerator nextObject];
     }
 }
 
 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    /*
-        this can happen if the user puts more than 5 touches on the screen
-        at once, or perhaps in other circumstances.  Usually (it seems)
-        all active touches are canceled.
-    */
-    [self touchesEnded: touches withEvent: event];
+    [self touchesEnded:touches withEvent:event];
 }
 
 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    NSEnumerator *enumerator = [touches objectEnumerator];
-    UITouch *touch = (UITouch*)[enumerator nextObject];
-
-    while (touch) {
-        if (touch == leftFingerDown) {
+    for (UITouch *touch in touches) {
+        if (touch == firstFingerDown) {
             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
 
             /* send moved event */
-            SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
+            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
         }
 
         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
-#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
-        SDL_SendTouchMotion(touchId, (long)touch,
+        SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
                             locationInView.x, locationInView.y, 1.0f);
-#else
-        int i;
-        for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
-            if (finger[i] == touch) {
-                SDL_SendTouchMotion(touchId, i,
-                                    locationInView.x, locationInView.y, 1.0f);
-                break;
-            }
-        }
-#endif
-        touch = (UITouch*)[enumerator nextObject];
     }
 }
 
-/*
-    ---- Keyboard related functionality below this line ----
-*/
-#if SDL_IPHONE_KEYBOARD
-
-@synthesize textInputRect = textInputRect;
-@synthesize keyboardHeight = keyboardHeight;
-
-/* Is the iPhone virtual keyboard visible onscreen? */
-- (BOOL)keyboardVisible
-{
-    return keyboardVisible;
-}
-
-/* Set ourselves up as a UITextFieldDelegate */
-- (void)initializeKeyboard
-{
-    textField = [[UITextField alloc] initWithFrame: CGRectZero];
-    textField.delegate = self;
-    /* placeholder so there is something to delete! */
-    textField.text = @" ";
-
-    /* set UITextInputTrait properties, mostly to defaults */
-    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
-    textField.autocorrectionType = UITextAutocorrectionTypeNo;
-    textField.enablesReturnKeyAutomatically = NO;
-    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
-    textField.keyboardType = UIKeyboardTypeDefault;
-    textField.returnKeyType = UIReturnKeyDefault;
-    textField.secureTextEntry = NO;
-
-    textField.hidden = YES;
-    keyboardVisible = NO;
-    /* add the UITextField (hidden) to our view */
-    [self addSubview: textField];
-    [textField release];
-    
-    _uikit_keyboard_init();
-}
-
-/* reveal onscreen virtual keyboard */
-- (void)showKeyboard
-{
-    keyboardVisible = YES;
-    [textField becomeFirstResponder];
-}
-
-/* hide onscreen virtual keyboard */
-- (void)hideKeyboard
-{
-    keyboardVisible = NO;
-    [textField resignFirstResponder];
-}
-
-/* UITextFieldDelegate method.  Invoked when user types something. */
-- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
-{
-    if ([string length] == 0) {
-        /* it wants to replace text with nothing, ie a delete */
-        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
-        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
-    }
-    else {
-        /* go through all the characters in the string we've been sent
-           and convert them to key presses */
-        int i;
-        for (i = 0; i < [string length]; i++) {
-
-            unichar c = [string characterAtIndex: i];
-
-            Uint16 mod = 0;
-            SDL_Scancode code;
-
-            if (c < 127) {
-                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
-                code = unicharToUIKeyInfoTable[c].code;
-                mod  = unicharToUIKeyInfoTable[c].mod;
-            }
-            else {
-                /* we only deal with ASCII right now */
-                code = SDL_SCANCODE_UNKNOWN;
-                mod = 0;
-            }
-
-            if (mod & KMOD_SHIFT) {
-                /* If character uses shift, press shift down */
-                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
-            }
-            /* send a keydown and keyup even for the character */
-            SDL_SendKeyboardKey(SDL_PRESSED, code);
-            SDL_SendKeyboardKey(SDL_RELEASED, code);
-            if (mod & KMOD_SHIFT) {
-                /* If character uses shift, press shift back up */
-                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
-            }
-        }
-        SDL_SendKeyboardText([string UTF8String]);
-    }
-    return NO; /* don't allow the edit! (keep placeholder text there) */
-}
-
-/* Terminates the editing session */
-- (BOOL)textFieldShouldReturn:(UITextField*)_textField
-{
-    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
-    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
-    SDL_StopTextInput();
-    return YES;
-}
-
-#endif
-
 @end
 
-/* iPhone keyboard addition functions */
-#if SDL_IPHONE_KEYBOARD
-
-static SDL_uikitview * getWindowView(SDL_Window * window)
-{
-    if (window == NULL) {
-        SDL_SetError("Window does not exist");
-        return nil;
-    }
-
-    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
-    SDL_uikitview *view = data != NULL ? data->view : nil;
-
-    if (view == nil) {
-        SDL_SetError("Window has no view");
-    }
-
-    return view;
-}
-
-SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
-{
-    return SDL_TRUE;
-}
-
-void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
-{
-    SDL_uikitview *view = getWindowView(window);
-    if (view != nil) {
-        [view showKeyboard];
-    }
-}
-
-void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
-{
-    SDL_uikitview *view = getWindowView(window);
-    if (view != nil) {
-        [view hideKeyboard];
-    }
-}
-
-SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
-{
-    SDL_uikitview *view = getWindowView(window);
-    if (view == nil) {
-        return 0;
-    }
-
-    return view.keyboardVisible;
-}
-
-
-void _uikit_keyboard_update() {
-    SDL_Window *window = SDL_GetFocusWindow();
-    if (!window) { return; }
-    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
-    if (!data) { return; }
-    SDL_uikitview *view = data->view;
-    if (!view) { return; }
-    
-    SDL_Rect r = view.textInputRect;
-    int height = view.keyboardHeight;
-    int offsetx = 0;
-    int offsety = 0;
-    float scale = [UIScreen mainScreen].scale;
-    if (height) {
-        int sw,sh;
-        SDL_GetWindowSize(window,&sw,&sh);
-        int bottom = (r.y + r.h);
-        int kbottom = sh - height;
-        if (kbottom < bottom) {
-            offsety = kbottom-bottom;
-        }
-    }
-    UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
-    if (ui_orient == UIInterfaceOrientationLandscapeLeft) {
-        int tmp = offsetx; offsetx = offsety; offsety = tmp;
-    }
-    if (ui_orient == UIInterfaceOrientationLandscapeRight) {
-        offsety = -offsety;
-        int tmp = offsetx; offsetx = offsety; offsety = tmp;
-    }
-    if (ui_orient == UIInterfaceOrientationPortraitUpsideDown) {
-        offsety = -offsety;
-    }
-
-    offsetx /= scale;
-    offsety /= scale;
-
-    view.frame = CGRectMake(offsetx,offsety,view.frame.size.width,view.frame.size.height);
-}
-
-void _uikit_keyboard_set_height(int height) {
-    SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
-    if (view == nil) {
-        return ;
-    }
-    
-    view.keyboardHeight = height;
-    _uikit_keyboard_update();
-}
-
-void _uikit_keyboard_init() {
-    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-    NSOperationQueue *queue = [NSOperationQueue mainQueue];
-    [center addObserverForName:UIKeyboardWillShowNotification
-                        object:nil
-                         queue:queue
-                    usingBlock:^(NSNotification *notification) {
-                        int height = 0;
-                        CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
-                        height = keyboardSize.height;
-                        UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
-                        if (ui_orient == UIInterfaceOrientationLandscapeRight || ui_orient == UIInterfaceOrientationLandscapeLeft) {
-                            height = keyboardSize.width;
-                        }
-                        height *= [UIScreen mainScreen].scale;
-                        _uikit_keyboard_set_height(height);
-                    }
-     ];
-    [center addObserverForName:UIKeyboardDidHideNotification
-                        object:nil
-                         queue:queue
-                    usingBlock:^(NSNotification *notification) {
-                        _uikit_keyboard_set_height(0);
-                    }
-     ];
-}
-
-void
-UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
-{
-    if (!rect) {
-        SDL_InvalidParamError("rect");
-        return;
-    }
-    
-    SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
-    if (view == nil) {
-        return ;
-    }
-
-    view.textInputRect = *rect;
-}
-
-
-#endif /* SDL_IPHONE_KEYBOARD */
-
 #endif /* SDL_VIDEO_DRIVER_UIKIT */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitviewcontroller.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitviewcontroller.h	Thu Apr 09 22:28:37 2015 -0400
@@ -23,18 +23,56 @@
 
 #include "../SDL_sysvideo.h"
 
-@interface SDL_uikitviewcontroller : UIViewController {
-@private
-    SDL_Window *window;
-}
+#include "SDL_touch.h"
+
+#if SDL_IPHONE_KEYBOARD
+@interface SDL_uikitviewcontroller : UIViewController <UITextFieldDelegate>
+#else
+@interface SDL_uikitviewcontroller : UIViewController
+#endif
+
+@property (nonatomic, assign) SDL_Window *window;
 
-@property (readwrite) SDL_Window *window;
+- (instancetype)initWithSDLWindow:(SDL_Window *)_window;
+
+- (void)setAnimationCallback:(int)interval
+                    callback:(void (*)(void*))callback
+               callbackParam:(void*)callbackParam;
 
-- (id)initWithSDLWindow:(SDL_Window *)_window;
+- (void)startAnimation;
+- (void)stopAnimation;
+
+- (void)doLoop:(CADisplayLink*)sender;
+
 - (void)loadView;
 - (void)viewDidLayoutSubviews;
 - (NSUInteger)supportedInterfaceOrientations;
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient;
 - (BOOL)prefersStatusBarHidden;
+- (UIStatusBarStyle)preferredStatusBarStyle;
+
+#if SDL_IPHONE_KEYBOARD
+- (void)showKeyboard;
+- (void)hideKeyboard;
+- (void)initKeyboard;
+- (void)deinitKeyboard;
+
+- (void)keyboardWillShow:(NSNotification *)notification;
+- (void)keyboardWillHide:(NSNotification *)notification;
+
+- (void)updateKeyboard;
+
+@property (nonatomic, assign, getter=isKeyboardVisible) BOOL keyboardVisible;
+@property (nonatomic, assign) SDL_Rect textInputRect;
+@property (nonatomic, assign) int keyboardHeight;
+#endif
 
 @end
+
+#if SDL_IPHONE_KEYBOARD
+SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
+void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
+void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
+SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
+void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
+#endif
--- a/src/video/uikit/SDL_uikitviewcontroller.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitviewcontroller.m	Thu Apr 09 22:28:37 2015 -0400
@@ -28,108 +28,389 @@
 #include "../SDL_sysvideo.h"
 #include "../../events/SDL_events_c.h"
 
-#include "SDL_uikitviewcontroller.h"
+#import "SDL_uikitviewcontroller.h"
+#import "SDL_uikitmessagebox.h"
 #include "SDL_uikitvideo.h"
 #include "SDL_uikitmodes.h"
 #include "SDL_uikitwindow.h"
 
+#if SDL_IPHONE_KEYBOARD
+#include "keyinfotable.h"
+#endif
 
-@implementation SDL_uikitviewcontroller
+@implementation SDL_uikitviewcontroller {
+    CADisplayLink *displayLink;
+    int animationInterval;
+    void (*animationCallback)(void*);
+    void *animationCallbackParam;
+
+#if SDL_IPHONE_KEYBOARD
+    UITextField *textField;
+#endif
+}
 
 @synthesize window;
 
-- (id)initWithSDLWindow:(SDL_Window *)_window
+- (instancetype)initWithSDLWindow:(SDL_Window *)_window
+{
+    if (self = [super initWithNibName:nil bundle:nil]) {
+        self.window = _window;
+
+#if SDL_IPHONE_KEYBOARD
+        [self initKeyboard];
+#endif
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+#if SDL_IPHONE_KEYBOARD
+    [self deinitKeyboard];
+#endif
+}
+
+- (void)setAnimationCallback:(int)interval
+                    callback:(void (*)(void*))callback
+               callbackParam:(void*)callbackParam
 {
-    self = [self init];
-    if (self == nil) {
-        return nil;
+    [self stopAnimation];
+
+    animationInterval = interval;
+    animationCallback = callback;
+    animationCallbackParam = callbackParam;
+
+    if (animationCallback) {
+        [self startAnimation];
     }
-    self.window = _window;
+}
+
+- (void)startAnimation
+{
+    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
+    [displayLink setFrameInterval:animationInterval];
+    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+}
 
-    return self;
+- (void)stopAnimation
+{
+    [displayLink invalidate];
+    displayLink = nil;
+}
+
+- (void)doLoop:(CADisplayLink*)sender
+{
+    /* Don't run the game loop while a messagebox is up */
+    if (!UIKit_ShowingMessageBox()) {
+        animationCallback(animationCallbackParam);
+    }
 }
 
 - (void)loadView
 {
-    /* do nothing. */
+    /* Do nothing. */
 }
 
 - (void)viewDidLayoutSubviews
 {
-    if (self->window->flags & SDL_WINDOW_RESIZABLE) {
-        SDL_WindowData *data = self->window->driverdata;
-        SDL_VideoDisplay *display = SDL_GetDisplayForWindow(self->window);
-        SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
-        const CGSize size = data->view.bounds.size;
-        int w, h;
+    const CGSize size = self.view.bounds.size;
+    int w = (int) size.width;
+    int h = (int) size.height;
 
-        w = (int)(size.width * displaymodedata->scale);
-        h = (int)(size.height * displaymodedata->scale);
-
-        SDL_SendWindowEvent(self->window, SDL_WINDOWEVENT_RESIZED, w, h);
-    }
+    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
 }
 
 - (NSUInteger)supportedInterfaceOrientations
 {
-    NSUInteger orientationMask = 0;
-
-    const char *orientationsCString;
-    if ((orientationsCString = SDL_GetHint(SDL_HINT_ORIENTATIONS)) != NULL) {
-        BOOL rotate = NO;
-        NSString *orientationsNSString = [NSString stringWithCString:orientationsCString
-                                                            encoding:NSUTF8StringEncoding];
-        NSArray *orientations = [orientationsNSString componentsSeparatedByCharactersInSet:
-                                 [NSCharacterSet characterSetWithCharactersInString:@" "]];
-
-        if ([orientations containsObject:@"LandscapeLeft"]) {
-            orientationMask |= UIInterfaceOrientationMaskLandscapeLeft;
-        }
-        if ([orientations containsObject:@"LandscapeRight"]) {
-            orientationMask |= UIInterfaceOrientationMaskLandscapeRight;
-        }
-        if ([orientations containsObject:@"Portrait"]) {
-            orientationMask |= UIInterfaceOrientationMaskPortrait;
-        }
-        if ([orientations containsObject:@"PortraitUpsideDown"]) {
-            orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown;
-        }
-
-    } else if (self->window->flags & SDL_WINDOW_RESIZABLE) {
-        orientationMask = UIInterfaceOrientationMaskAll;  /* any orientation is okay. */
-    } else {
-        if (self->window->w >= self->window->h) {
-            orientationMask |= UIInterfaceOrientationMaskLandscape;
-        }
-        if (self->window->h >= self->window->w) {
-            orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
-        }
-    }
-
-    /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
-    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
-        orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
-    }
-    return orientationMask;
+    return UIKit_GetSupportedOrientations(window);
 }
 
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
 {
-    NSUInteger orientationMask = [self supportedInterfaceOrientations];
-    return (orientationMask & (1 << orient));
+    return ([self supportedInterfaceOrientations] & (1 << orient)) != 0;
 }
 
 - (BOOL)prefersStatusBarHidden
 {
-    if (self->window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
-        return YES;
-    } else {
-        return NO;
+    return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0;
+}
+
+- (UIStatusBarStyle)preferredStatusBarStyle
+{
+    /* We assume most SDL apps don't have a bright white background. */
+    return UIStatusBarStyleLightContent;
+}
+
+/*
+ ---- Keyboard related functionality below this line ----
+ */
+#if SDL_IPHONE_KEYBOARD
+
+@synthesize textInputRect;
+@synthesize keyboardHeight;
+@synthesize keyboardVisible;
+
+/* Set ourselves up as a UITextFieldDelegate */
+- (void)initKeyboard
+{
+    textField = [[UITextField alloc] initWithFrame:CGRectZero];
+    textField.delegate = self;
+    /* placeholder so there is something to delete! */
+    textField.text = @" ";
+
+    /* set UITextInputTrait properties, mostly to defaults */
+    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
+    textField.autocorrectionType = UITextAutocorrectionTypeNo;
+    textField.enablesReturnKeyAutomatically = NO;
+    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
+    textField.keyboardType = UIKeyboardTypeDefault;
+    textField.returnKeyType = UIReturnKeyDefault;
+    textField.secureTextEntry = NO;
+
+    textField.hidden = YES;
+    keyboardVisible = NO;
+
+    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+    [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
+    [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
+}
+
+- (void)setView:(UIView *)view
+{
+    [super setView:view];
+
+    [view addSubview:textField];
+
+    if (keyboardVisible) {
+        [self showKeyboard];
+    }
+}
+
+- (void)deinitKeyboard
+{
+    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
+    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
+}
+
+/* reveal onscreen virtual keyboard */
+- (void)showKeyboard
+{
+    keyboardVisible = YES;
+    if (textField.window) {
+        [textField becomeFirstResponder];
     }
 }
 
+/* hide onscreen virtual keyboard */
+- (void)hideKeyboard
+{
+    keyboardVisible = NO;
+    [textField resignFirstResponder];
+}
+
+- (void)keyboardWillShow:(NSNotification *)notification
+{
+    CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
+    UIView *view = self.view;
+    int height = 0;
+
+    /* The keyboard rect is in the coordinate space of the screen, but we want
+     * its height in the view's coordinate space. */
+#ifdef __IPHONE_8_0
+    if ([view respondsToSelector:@selector(convertRect:fromCoordinateSpace:)]) {
+        UIScreen *screen = view.window.screen;
+        kbrect = [view convertRect:kbrect fromCoordinateSpace:screen.coordinateSpace];
+        height = kbrect.size.height;
+    } else
+#endif
+    {
+        /* In iOS 7 and below, the screen's coordinate space is never rotated. */
+        if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
+            height = kbrect.size.width;
+        } else {
+            height = kbrect.size.height;
+        }
+    }
+
+    [self setKeyboardHeight:height];
+}
+
+- (void)keyboardWillHide:(NSNotification *)notification
+{
+    [self setKeyboardHeight:0];
+}
+
+- (void)updateKeyboard
+{
+    SDL_Rect textrect = self.textInputRect;
+    CGAffineTransform t = self.view.transform;
+    CGPoint offset = CGPointMake(0.0, 0.0);
+
+    if (self.keyboardHeight) {
+        int rectbottom = textrect.y + textrect.h;
+        int kbottom = self.view.bounds.size.height - self.keyboardHeight;
+        if (kbottom < rectbottom) {
+            offset.y = kbottom - rectbottom;
+        }
+    }
+
+    /* Put the offset into the this view transform's coordinate space. */
+    t.tx = 0.0;
+    t.ty = 0.0;
+    offset = CGPointApplyAffineTransform(offset, t);
+
+    t.tx = offset.x;
+    t.ty = offset.y;
+
+    /* Move the view by applying the updated transform. */
+    self.view.transform = t;
+}
+
+- (void)setKeyboardHeight:(int)height
+{
+    keyboardVisible = height > 0;
+    keyboardHeight = height;
+    [self updateKeyboard];
+}
+
+/* UITextFieldDelegate method.  Invoked when user types something. */
+- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
+{
+    NSUInteger len = string.length;
+
+    if (len == 0) {
+        /* it wants to replace text with nothing, ie a delete */
+        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
+        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
+    } else {
+        /* go through all the characters in the string we've been sent and
+         * convert them to key presses */
+        int i;
+        for (i = 0; i < len; i++) {
+            unichar c = [string characterAtIndex:i];
+            Uint16 mod = 0;
+            SDL_Scancode code;
+
+            if (c < 127) {
+                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
+                code = unicharToUIKeyInfoTable[c].code;
+                mod  = unicharToUIKeyInfoTable[c].mod;
+            } else {
+                /* we only deal with ASCII right now */
+                code = SDL_SCANCODE_UNKNOWN;
+                mod = 0;
+            }
+
+            if (mod & KMOD_SHIFT) {
+                /* If character uses shift, press shift down */
+                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
+            }
+
+            /* send a keydown and keyup even for the character */
+            SDL_SendKeyboardKey(SDL_PRESSED, code);
+            SDL_SendKeyboardKey(SDL_RELEASED, code);
+
+            if (mod & KMOD_SHIFT) {
+                /* If character uses shift, press shift back up */
+                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
+            }
+        }
+
+        SDL_SendKeyboardText([string UTF8String]);
+    }
+
+    return NO; /* don't allow the edit! (keep placeholder text there) */
+}
+
+/* Terminates the editing session */
+- (BOOL)textFieldShouldReturn:(UITextField*)_textField
+{
+    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
+    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
+    SDL_StopTextInput();
+    return YES;
+}
+
+#endif
+
 @end
 
+/* iPhone keyboard addition functions */
+#if SDL_IPHONE_KEYBOARD
+
+static SDL_uikitviewcontroller *
+GetWindowViewController(SDL_Window * window)
+{
+    if (!window || !window->driverdata) {
+        SDL_SetError("Invalid window");
+        return nil;
+    }
+
+    SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
+
+    return data.viewcontroller;
+}
+
+SDL_bool
+UIKit_HasScreenKeyboardSupport(_THIS)
+{
+    return SDL_TRUE;
+}
+
+void
+UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
+{
+    @autoreleasepool {
+        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
+        [vc showKeyboard];
+    }
+}
+
+void
+UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
+{
+    @autoreleasepool {
+        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
+        [vc hideKeyboard];
+    }
+}
+
+SDL_bool
+UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
+{
+    @autoreleasepool {
+        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
+        if (vc != nil) {
+            return vc.isKeyboardVisible;
+        }
+        return SDL_FALSE;
+    }
+}
+
+void
+UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
+{
+    if (!rect) {
+        SDL_InvalidParamError("rect");
+        return;
+    }
+
+    @autoreleasepool {
+        SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow());
+        if (vc != nil) {
+            vc.textInputRect = *rect;
+
+            if (vc.keyboardVisible) {
+                [vc updateKeyboard];
+            }
+        }
+    }
+}
+
+
+#endif /* SDL_IPHONE_KEYBOARD */
+
 #endif /* SDL_VIDEO_DRIVER_UIKIT */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitwindow.h	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitwindow.h	Thu Apr 09 22:28:37 2015 -0400
@@ -23,28 +23,33 @@
 
 #include "../SDL_sysvideo.h"
 #import "SDL_uikitvideo.h"
-#import "SDL_uikitopenglview.h"
+#import "SDL_uikitview.h"
 #import "SDL_uikitviewcontroller.h"
 
-typedef struct SDL_WindowData SDL_WindowData;
-
 extern int UIKit_CreateWindow(_THIS, SDL_Window * window);
+extern void UIKit_SetWindowTitle(_THIS, SDL_Window * window);
 extern void UIKit_ShowWindow(_THIS, SDL_Window * window);
 extern void UIKit_HideWindow(_THIS, SDL_Window * window);
 extern void UIKit_RaiseWindow(_THIS, SDL_Window * window);
+extern void UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered);
 extern void UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
 extern void UIKit_DestroyWindow(_THIS, SDL_Window * window);
 extern SDL_bool UIKit_GetWindowWMInfo(_THIS, SDL_Window * window,
                                       struct SDL_SysWMinfo * info);
 
+extern NSUInteger UIKit_GetSupportedOrientations(SDL_Window * window);
+
 @class UIWindow;
 
-struct SDL_WindowData
-{
-    UIWindow *uiwindow;
-    SDL_uikitopenglview *view;
-    SDL_uikitviewcontroller *viewcontroller;
-};
+@interface SDL_WindowData : NSObject
+
+@property (nonatomic, strong) UIWindow *uiwindow;
+@property (nonatomic, strong) SDL_uikitviewcontroller *viewcontroller;
+
+/* Array of SDL_uikitviews owned by this window. */
+@property (nonatomic, copy) NSMutableArray *views;
+
+@end
 
 #endif /* _SDL_uikitwindow_h */
 
--- a/src/video/uikit/SDL_uikitwindow.m	Thu Apr 09 22:14:05 2015 +0200
+++ b/src/video/uikit/SDL_uikitwindow.m	Thu Apr 09 22:28:37 2015 -0400
@@ -37,263 +37,273 @@
 #include "SDL_uikitwindow.h"
 #import "SDL_uikitappdelegate.h"
 
+#import "SDL_uikitview.h"
 #import "SDL_uikitopenglview.h"
 
 #include <Foundation/Foundation.h>
 
+@implementation SDL_WindowData
 
+@synthesize uiwindow;
+@synthesize viewcontroller;
+@synthesize views;
+
+- (instancetype)init
+{
+    if ((self = [super init])) {
+        views = [NSMutableArray new];
+    }
+
+    return self;
+}
+
+@end
+
+@interface SDL_uikitwindow : UIWindow
+
+- (void)layoutSubviews;
+
+@end
+
+@implementation SDL_uikitwindow
+
+- (void)layoutSubviews
+{
+    /* Workaround to fix window orientation issues in iOS 8+. */
+    self.frame = self.screen.bounds;
+    [super layoutSubviews];
+}
+
+@end
 
 
 static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
 {
     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
-    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
-    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
-    SDL_WindowData *data;
+    SDL_DisplayData *displaydata = (__bridge SDL_DisplayData *) display->driverdata;
+    SDL_uikitview *view;
 
-    /* Allocate the window data */
-    data = (SDL_WindowData *)SDL_malloc(sizeof(*data));
+    CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen);
+    int width  = (int) frame.size.width;
+    int height = (int) frame.size.height;
+
+    SDL_WindowData *data = [[SDL_WindowData alloc] init];
     if (!data) {
         return SDL_OutOfMemory();
     }
-    data->uiwindow = uiwindow;
-    data->viewcontroller = nil;
-    data->view = nil;
+
+    window->driverdata = (void *) CFBridgingRetain(data);
 
-    /* Fill in the SDL window with the window data */
-    {
-        window->x = 0;
-        window->y = 0;
+    data.uiwindow = uiwindow;
+
+    /* only one window on iOS, always shown */
+    window->flags &= ~SDL_WINDOW_HIDDEN;
 
-        CGRect bounds;
-        if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
-            bounds = [displaydata->uiscreen bounds];
-        } else {
-            bounds = [displaydata->uiscreen applicationFrame];
-        }
+    if (displaydata.uiscreen == [UIScreen mainScreen]) {
+        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
+    } else {
+        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizable */
+        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
+        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
+    }
 
-        /* Get frame dimensions in pixels */
-        int width = (int)(bounds.size.width * displaymodedata->scale);
-        int height = (int)(bounds.size.height * displaymodedata->scale);
+    if (displaydata.uiscreen == [UIScreen mainScreen]) {
+        NSUInteger orients = UIKit_GetSupportedOrientations(window);
+        BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0;
+        BOOL supportsPortrait = (orients & (UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown)) != 0;
 
         /* Make sure the width/height are oriented correctly */
-        if (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) {
+        if ((width > height && !supportsLandscape) || (height > width && !supportsPortrait)) {
             int temp = width;
             width = height;
             height = temp;
         }
-
-        window->w = width;
-        window->h = height;
     }
 
-    window->driverdata = data;
-
-    /* only one window on iOS, always shown */
-    window->flags &= ~SDL_WINDOW_HIDDEN;
+    window->x = 0;
+    window->y = 0;
+    window->w = width;
+    window->h = height;
 
-    /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
-     * This is only set if the window is on the main screen. Other screens
-     *  just force the window to have the borderless flag.
-     */
-    if (displaydata->uiscreen == [UIScreen mainScreen]) {
-        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
+    /* The View Controller will handle rotating the view when the device
+     * orientation changes. This will trigger resize events, if appropriate. */
+    data.viewcontroller = [[SDL_uikitviewcontroller alloc] initWithSDLWindow:window];
 
-        /* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application
-        if ([UIApplication sharedApplication].statusBarHidden) {
-            window->flags |= SDL_WINDOW_BORDERLESS;
-        } else {
-            window->flags &= ~SDL_WINDOW_BORDERLESS;
-        }
-        */
-    } else {
-        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizeable */
-        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
-        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
+    /* The window will initially contain a generic view so resizes, touch events,
+     * etc. can be handled without an active OpenGL view/context. */
+    view = [[SDL_uikitview alloc] initWithFrame:frame];
+
+    /* Sets this view as the controller's view, and adds the view to the window
+     * heirarchy. */
+    [view setSDLWindow:window];
+
+    /* Make this window the current mouse focus for touch input */
+    if (displaydata.uiscreen == [UIScreen mainScreen]) {
+        SDL_SetMouseFocus(window);
+        SDL_SetKeyboardFocus(window);
     }
 
-    /* The View Controller will handle rotating the view when the
-     * device orientation changes. This will trigger resize events, if
-     * appropriate.
-     */
-    SDL_uikitviewcontroller *controller;
-    controller = [SDL_uikitviewcontroller alloc];
-    data->viewcontroller = [controller initWithSDLWindow:window];
-    [data->viewcontroller setTitle:@"SDL App"];  /* !!! FIXME: hook up SDL_SetWindowTitle() */
-
     return 0;
 }
 
 int
 UIKit_CreateWindow(_THIS, SDL_Window *window)
 {
-    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
-    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
-    const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
-    const CGSize origsize = [[data->uiscreen currentMode] size];
-
-    /* SDL currently puts this window at the start of display's linked list. We rely on this. */
-    SDL_assert(_this->windows == window);
+    @autoreleasepool {
+        SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+        SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
+        const CGSize origsize = data.uiscreen.currentMode.size;
 
-    /* We currently only handle a single window per display on iOS */
-    if (window->next != NULL) {
-        return SDL_SetError("Only one window allowed per display.");
-    }
+        /* SDL currently puts this window at the start of display's linked list. We rely on this. */
+        SDL_assert(_this->windows == window);
 
-    /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
-     * user, so it's in standby), try to force the display to a resolution
-     * that most closely matches the desired window size.
-     */
-    if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
-        if (display->num_display_modes == 0) {
-            _this->GetDisplayModes(_this, display);
+        /* We currently only handle a single window per display on iOS */
+        if (window->next != NULL) {
+            return SDL_SetError("Only one window allowed per display.");
         }
 
-        int i;
-        const SDL_DisplayMode *bestmode = NULL;
-        for (i = display->num_display_modes; i >= 0; i--) {
-            const SDL_DisplayMode *mode = &display->display_modes[i];
-            if ((mode->w >= window->w) && (mode->h >= window->h))
-                bestmode = mode;
+        /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
+         * user, so it's in standby), try to force the display to a resolution
+         * that most closely matches the desired window size. */
+        if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
+            if (display->num_display_modes == 0) {
+                _this->GetDisplayModes(_this, display);
+            }
+
+            int i;
+            const SDL_DisplayMode *bestmode = NULL;
+            for (i = display->num_display_modes; i >= 0; i--) {
+                const SDL_DisplayMode *mode = &display->display_modes[i];
+                if ((mode->w >= window->w) && (mode->h >= window->h)) {
+                    bestmode = mode;
+                }
+            }
+
+            if (bestmode) {
+                SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)bestmode->driverdata;
+                [data.uiscreen setCurrentMode:modedata.uiscreenmode];
+
+                /* desktop_mode doesn't change here (the higher level will
+                 * use it to set all the screens back to their defaults
+                 * upon window destruction, SDL_Quit(), etc. */
+                display->current_mode = *bestmode;
+            }
         }
 
-        if (bestmode) {
-            SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
-            [data->uiscreen setCurrentMode:modedata->uiscreenmode];
+        if (data.uiscreen == [UIScreen mainScreen]) {
+            NSUInteger orientations = UIKit_GetSupportedOrientations(window);
+            UIApplication *app = [UIApplication sharedApplication];
+
+            if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
+                app.statusBarHidden = YES;
+            } else {
+                app.statusBarHidden = NO;
+            }
+        }
 
-            /* desktop_mode doesn't change here (the higher level will
-             * use it to set all the screens back to their defaults
-             * upon window destruction, SDL_Quit(), etc.
-             */
-            display->current_mode = *bestmode;
+        /* ignore the size user requested, and make a fullscreen window */
+        /* !!! FIXME: can we have a smaller view? */
+        UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
+
+        /* put the window on an external display if appropriate. */
+        if (data.uiscreen != [UIScreen mainScreen]) {
+            [uiwindow setScreen:data.uiscreen];
+        }
+
+        if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
+            return -1;
         }
     }
 
-    if (data->uiscreen == [UIScreen mainScreen]) {
-        if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
-            [UIApplication sharedApplication].statusBarHidden = YES;
-        } else {
-            [UIApplication sharedApplication].statusBarHidden = NO;
-        }
-    }
-
-    if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
-        if (window->w > window->h) {
-            if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
-                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
-            }
-        } else if (window->w < window->h) {
-            if (UIKit_IsDisplayLandscape(data->uiscreen)) {
-                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
-            }
-        }
-    }
+    return 1;
+}
 
-    /* ignore the size user requested, and make a fullscreen window */
-    /* !!! FIXME: can we have a smaller view? */
-    UIWindow *uiwindow = [UIWindow alloc];
-    uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]];
-
-    /* put the window on an external display if appropriate. This implicitly
-     * does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
-     * main display, where we land by default, as that would eat the
-     * status bar real estate.
-     */
-    if (external) {
-        [uiwindow setScreen:data->uiscreen];
+void
+UIKit_SetWindowTitle(_THIS, SDL_Window * window)
+{
+    @autoreleasepool {
+        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
+        data.viewcontroller.title = @(window->title);
     }
-
-    if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
-        [uiwindow release];
-        return -1;
-    }
-
-    return 1;
-
 }
 
 void
 UIKit_ShowWindow(_THIS, SDL_Window * window)
 {
-    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
-
-    [uiwindow makeKeyAndVisible];
+    @autoreleasepool {
+        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
+        [data.uiwindow makeKeyAndVisible];
+    }
 }
 
 void
 UIKit_HideWindow(_THIS, SDL_Window * window)
 {
-    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
-
-    uiwindow.hidden = YES;
+    @autoreleasepool {
+        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
+        data.uiwindow.hidden = YES;
+    }
 }
 
 void
 UIKit_RaiseWindow(_THIS, SDL_Window * window)
 {
     /* We don't currently offer a concept of "raising" the SDL window, since
-     *  we only allow one per display, in the iOS fashion.
+     * we only allow one per display, in the iOS fashion.
      * However, we use this entry point to rebind the context to the view
-     *  during OnWindowRestored processing.
-     */
+     * during OnWindowRestored processing. */
     _this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
 }
 
+static void
+UIKit_UpdateWindowBorder(_THIS, SDL_Window * window)
+{
+    SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
+    SDL_uikitviewcontroller *viewcontroller = data.viewcontroller;
+
+    if (data.uiwindow.screen == [UIScreen mainScreen]) {
+        if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) {
+            [UIApplication sharedApplication].statusBarHidden = YES;
+        } else {
+            [UIApplication sharedApplication].statusBarHidden = NO;
+        }
+
+        /* iOS 7+ won't update the status bar until we tell it to. */
+        if ([viewcontroller respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
+            [viewcontroller setNeedsStatusBarAppearanceUpdate];
+        }
+    }
+
+    /* Update the view's frame to account for the status bar change. */
+    viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
+    [viewcontroller.view setNeedsLayout];
+    [viewcontroller.view layoutIfNeeded];
+}
+
+void
+UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
+{
+    @autoreleasepool {
+        UIKit_UpdateWindowBorder(_this, window);
+    }
+}
+
 void
 UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
 {
-    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
-    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
-    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
-
-    if (fullscreen) {
-        [UIApplication sharedApplication].statusBarHidden = YES;
-    } else {
-        [UIApplication sharedApplication].statusBarHidden = NO;
-    }
-
-    CGRect bounds;
-    if (fullscreen) {
-        bounds = [displaydata->uiscreen bounds];
-    } else {
-        bounds = [displaydata->uiscreen applicationFrame];
-    }
-
-    /* Get frame dimensions in pixels */
-    int width = (int)(bounds.size.width * displaymodedata->scale);
-    int height = (int)(bounds.size.height * displaymodedata->scale);
-
-    /* We can pick either width or height here and we'll rotate the
-       screen to match, so we pick the closest to what we wanted.
-     */
-    if (window->w >= window->h) {
-        if (width > height) {
-            window->w = width;
-            window->h = height;
-        } else {
-            window->w = height;
-            window->h = width;
-        }
-    } else {
-        if (width > height) {
-            window->w = height;
-            window->h = width;
-        } else {
-            window->w = width;
-            window->h = height;
-        }
+    @autoreleasepool {
+        UIKit_UpdateWindowBorder(_this, window);
     }
 }
 
 void
 UIKit_DestroyWindow(_THIS, SDL_Window * window)
 {
-    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
-
-    if (data) {
-        [data->viewcontroller release];
-        [data->uiwindow release];
-        SDL_free(data);
+    @autoreleasepool {
+        if (window->driverdata != NULL) {
+            SDL_WindowData *data = (SDL_WindowData *) CFBridgingRelease(window->driverdata);
+            [data.viewcontroller stopAnimation];
+        }
     }
     window->driverdata = NULL;
 }
@@ -301,29 +311,97 @@
 SDL_bool
 UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
 {
-    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
+    @autoreleasepool {
+        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
+
+        if (info->version.major <= SDL_MAJOR_VERSION) {
+            int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch);
+
+            info->subsystem = SDL_SYSWM_UIKIT;
+            info->info.uikit.window = data.uiwindow;
+
+            /* These struct members were added in SDL 2.0.4. */
+            if (versionnum >= SDL_VERSIONNUM(2,0,4)) {
+                if ([data.viewcontroller.view isKindOfClass:[SDL_uikitopenglview class]]) {
+                    SDL_uikitopenglview *glview = (SDL_uikitopenglview *)data.viewcontroller.view;
+                    info->info.uikit.framebuffer = glview.drawableFramebuffer;
+                    info->info.uikit.colorbuffer = glview.drawableRenderbuffer;
+                } else {
+                    info->info.uikit.framebuffer = 0;
+                    info->info.uikit.colorbuffer = 0;
+                }
+            }
+
+            return SDL_TRUE;
+        } else {
+            SDL_SetError("Application not compiled with SDL %d.%d\n",
+                         SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
+            return SDL_FALSE;
+        }
+    }
+}
+
+NSUInteger
+UIKit_GetSupportedOrientations(SDL_Window * window)
+{
+    const char *hint = SDL_GetHint(SDL_HINT_ORIENTATIONS);
+    NSUInteger orientationMask = 0;
 
-    if (info->version.major <= SDL_MAJOR_VERSION) {
-        info->subsystem = SDL_SYSWM_UIKIT;
-        info->info.uikit.window = uiwindow;
-        return SDL_TRUE;
-    } else {
-        SDL_SetError("Application not compiled with SDL %d.%d\n",
-                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
-        return SDL_FALSE;
+    @autoreleasepool {
+        if (hint != NULL) {
+            NSArray *orientations = [@(hint) componentsSeparatedByString:@" "];
+
+            if ([orientations containsObject:@"LandscapeLeft"]) {
+                orientationMask |= UIInterfaceOrientationMaskLandscapeLeft;
+            }
+            if ([orientations containsObject:@"LandscapeRight"]) {
+                orientationMask |= UIInterfaceOrientationMaskLandscapeRight;
+            }
+            if ([orientations containsObject:@"Portrait"]) {
+                orientationMask |= UIInterfaceOrientationMaskPortrait;
+            }
+            if ([orientations containsObject:@"PortraitUpsideDown"]) {
+                orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown;
+            }
+        }
+
+        if (orientationMask == 0 && (window->flags & SDL_WINDOW_RESIZABLE)) {
+            /* any orientation is okay. */
+            orientationMask = UIInterfaceOrientationMaskAll;
+        }
+
+        if (orientationMask == 0) {
+            if (window->w >= window->h) {
+                orientationMask |= UIInterfaceOrientationMaskLandscape;
+            }
+            if (window->h >= window->w) {
+                orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
+            }
+        }
+
+        /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
+        if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
+            orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
+        }
     }
+
+    return orientationMask;
 }
 
 int
 SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
 {
-    SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL;
-
-    if (!data || !data->view) {
-        return SDL_SetError("Invalid window or view not set");
+    if (!window || !window->driverdata) {
+        return SDL_SetError("Invalid window");
     }
 
-    [data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
+    @autoreleasepool {
+        SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
+        [data.viewcontroller setAnimationCallback:interval
+                                         callback:callback
+                                    callbackParam:callbackParam];
+    }
+
     return 0;
 }