Merged Alex Szpakowski's iOS-improvement branch to default.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 09 Apr 2015 22:28:37 -0400
changeset 9541cf8fab52e33b
parent 9486 296b5f754af7
parent 9540 32ddc92d78cf
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.
     1.1 --- a/.hgignore	Thu Apr 09 22:14:05 2015 +0200
     1.2 +++ b/.hgignore	Thu Apr 09 22:28:37 2015 -0400
     1.3 @@ -8,6 +8,9 @@
     1.4  sdl-config
     1.5  SDL2.spec
     1.6  build
     1.7 +Build
     1.8 +*xcuserdata*
     1.9 +*xcworkspacedata*
    1.10  
    1.11  # for Xcode
    1.12  *.orig
     2.1 --- a/Xcode-iOS/Demos/src/fireworks.c	Thu Apr 09 22:14:05 2015 +0200
     2.2 +++ b/Xcode-iOS/Demos/src/fireworks.c	Thu Apr 09 22:28:37 2015 -0400
     2.3 @@ -387,6 +387,9 @@
     2.4      SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
     2.5      SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
     2.6  
     2.7 +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
     2.8 +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
     2.9 +
    2.10      /* create main window and renderer */
    2.11      window = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
    2.12                                  SDL_WINDOW_OPENGL |
     3.1 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj	Thu Apr 09 22:14:05 2015 +0200
     3.2 +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj	Thu Apr 09 22:28:37 2015 -0400
     3.3 @@ -1274,8 +1274,14 @@
     3.4  		FD6526640DE8FCCB002AD96B /* Debug */ = {
     3.5  			isa = XCBuildConfiguration;
     3.6  			buildSettings = {
     3.7 +				CLANG_ENABLE_OBJC_ARC = YES;
     3.8 +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
     3.9 +				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
    3.10  				COPY_PHASE_STRIP = NO;
    3.11  				IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
    3.12 +				GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES;
    3.13 +				GCC_WARN_STRICT_SELECTOR_MATCH = YES;
    3.14 +				GCC_WARN_UNDECLARED_SELECTOR = YES;
    3.15  				PRODUCT_NAME = SDL2;
    3.16  				SKIP_INSTALL = YES;
    3.17  			};
    3.18 @@ -1284,8 +1290,14 @@
    3.19  		FD6526650DE8FCCB002AD96B /* Release */ = {
    3.20  			isa = XCBuildConfiguration;
    3.21  			buildSettings = {
    3.22 +				CLANG_ENABLE_OBJC_ARC = YES;
    3.23 +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
    3.24 +				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
    3.25  				COPY_PHASE_STRIP = YES;
    3.26  				IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
    3.27 +				GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES;
    3.28 +				GCC_WARN_STRICT_SELECTOR_MATCH = YES;
    3.29 +				GCC_WARN_UNDECLARED_SELECTOR = YES;
    3.30  				PRODUCT_NAME = SDL2;
    3.31  				SKIP_INSTALL = YES;
    3.32  			};
     4.1 --- a/include/SDL_config_iphoneos.h	Thu Apr 09 22:14:05 2015 +0200
     4.2 +++ b/include/SDL_config_iphoneos.h	Thu Apr 09 22:28:37 2015 -0400
     4.3 @@ -145,6 +145,9 @@
     4.4  /* enable iPhone keyboard support */
     4.5  #define SDL_IPHONE_KEYBOARD 1
     4.6  
     4.7 +/* enable iOS extended launch screen */
     4.8 +#define SDL_IPHONE_LAUNCHSCREEN 1
     4.9 +
    4.10  /* enable joystick subsystem */
    4.11  #define SDL_JOYSTICK_DISABLED 0
    4.12  
     5.1 --- a/include/SDL_hints.h	Thu Apr 09 22:14:05 2015 +0200
     5.2 +++ b/include/SDL_hints.h	Thu Apr 09 22:28:37 2015 -0400
     5.3 @@ -261,8 +261,9 @@
     5.4  #define SDL_HINT_ORIENTATIONS "SDL_IOS_ORIENTATIONS"
     5.5      
     5.6  /**
     5.7 - *  \brief  A variable controlling whether an Android built-in accelerometer should be
     5.8 - *  listed as a joystick device, rather than listing actual joysticks only.
     5.9 + *  \brief  A variable controlling whether the Android / iOS built-in
    5.10 + *  accelerometer should be listed as a joystick device, rather than listing
    5.11 + *  actual joysticks only.
    5.12   *
    5.13   *  This variable can be set to the following values:
    5.14   *    "0"       - List only real joysticks and accept input from them
    5.15 @@ -345,7 +346,7 @@
    5.16  
    5.17  
    5.18  /**
    5.19 - *  \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac)
    5.20 + *  \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac and iOS)
    5.21   */
    5.22  #define SDL_HINT_VIDEO_HIGHDPI_DISABLED "SDL_VIDEO_HIGHDPI_DISABLED"
    5.23  
     6.1 --- a/include/SDL_system.h	Thu Apr 09 22:14:05 2015 +0200
     6.2 +++ b/include/SDL_system.h	Thu Apr 09 22:28:37 2015 -0400
     6.3 @@ -73,7 +73,10 @@
     6.4  /* Platform specific functions for iOS */
     6.5  #if defined(__IPHONEOS__) && __IPHONEOS__
     6.6  
     6.7 +#define SDL_iOSSetAnimationCallback(window, interval, callback, callbackParam) SDL_iPhoneSetAnimationCallback(window, interval, callback, callbackParam)
     6.8  extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam);
     6.9 +
    6.10 +#define SDL_iOSSetEventPump(enabled) SDL_iPhoneSetEventPump(enabled)
    6.11  extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled);
    6.12  
    6.13  #endif /* __IPHONEOS__ */
     7.1 --- a/include/SDL_syswm.h	Thu Apr 09 22:14:05 2015 +0200
     7.2 +++ b/include/SDL_syswm.h	Thu Apr 09 22:28:37 2015 -0400
     7.3 @@ -98,6 +98,7 @@
     7.4  typedef struct _UIWindow UIWindow;
     7.5  typedef struct _UIViewController UIViewController;
     7.6  #endif
     7.7 +typedef Uint32 GLuint;
     7.8  #endif
     7.9  
    7.10  #if defined(SDL_VIDEO_DRIVER_ANDROID)
    7.11 @@ -228,6 +229,8 @@
    7.12  #else
    7.13              UIWindow *window;                     /* The UIKit window */
    7.14  #endif
    7.15 +            GLuint framebuffer; /* The GL view's Framebuffer Object. It must be bound when rendering to the screen using GL. */
    7.16 +            GLuint colorbuffer; /* The GL view's color Renderbuffer Object. It must be bound when SDL_GL_SwapWindow is called. */
    7.17          } uikit;
    7.18  #endif
    7.19  #if defined(SDL_VIDEO_DRIVER_WAYLAND)
     8.1 --- a/premake/Xcode-iOS/SDL_config_premake.h	Thu Apr 09 22:14:05 2015 +0200
     8.2 +++ b/premake/Xcode-iOS/SDL_config_premake.h	Thu Apr 09 22:28:37 2015 -0400
     8.3 @@ -126,6 +126,9 @@
     8.4  #ifndef SDL_IPHONE_KEYBOARD
     8.5  #define SDL_IPHONE_KEYBOARD 1
     8.6  #endif
     8.7 +#ifndef SDL_IPHONE_LAUNCHSCREEN
     8.8 +#define SDL_IPHONE_LAUNCHSCREEN 1
     8.9 +#endif
    8.10  #ifndef SDL_POWER_UIKIT
    8.11  #define SDL_POWER_UIKIT 1
    8.12  #endif
     9.1 --- a/src/file/cocoa/SDL_rwopsbundlesupport.m	Thu Apr 09 22:14:05 2015 +0200
     9.2 +++ b/src/file/cocoa/SDL_rwopsbundlesupport.m	Thu Apr 09 22:28:37 2015 -0400
     9.3 @@ -50,14 +50,13 @@
     9.4      NSString* full_path_with_file_to_try = [resource_path stringByAppendingPathComponent:ns_string_file_component];
     9.5      if([file_manager fileExistsAtPath:full_path_with_file_to_try]) {
     9.6          fp = fopen([full_path_with_file_to_try fileSystemRepresentation], mode);
     9.7 -    }
     9.8 -    else {
     9.9 +    } else {
    9.10          fp = fopen(file, mode);
    9.11      }
    9.12  
    9.13      return fp;
    9.14  }}
    9.15  
    9.16 -#endif /* __MACOSX__ */
    9.17 +#endif /* __APPLE__ */
    9.18  
    9.19  /* vi: set ts=4 sw=4 expandtab: */
    10.1 --- a/src/filesystem/cocoa/SDL_sysfilesystem.m	Thu Apr 09 22:14:05 2015 +0200
    10.2 +++ b/src/filesystem/cocoa/SDL_sysfilesystem.m	Thu Apr 09 22:28:37 2015 -0400
    10.3 @@ -41,6 +41,7 @@
    10.4      const char* baseType = [[[bundle infoDictionary] objectForKey:@"SDL_FILESYSTEM_BASE_DIR_TYPE"] UTF8String];
    10.5      const char *base = NULL;
    10.6      char *retval = NULL;
    10.7 +
    10.8      if (baseType == NULL) {
    10.9          baseType = "resource";
   10.10      }
   10.11 @@ -52,6 +53,7 @@
   10.12          /* this returns the exedir for non-bundled  and the resourceDir for bundled apps */
   10.13          base = [[bundle resourcePath] fileSystemRepresentation];
   10.14      }
   10.15 +
   10.16      if (base) {
   10.17          const size_t len = SDL_strlen(base) + 2;
   10.18          retval = (char *) SDL_malloc(len);
   10.19 @@ -69,8 +71,9 @@
   10.20  SDL_GetPrefPath(const char *org, const char *app)
   10.21  { @autoreleasepool
   10.22  {
   10.23 +    char *retval = NULL;
   10.24 +
   10.25      NSArray *array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
   10.26 -    char *retval = NULL;
   10.27  
   10.28      if ([array count] > 0) {  /* we only want the first item in the list. */
   10.29          NSString *str = [array objectAtIndex:0];
    11.1 --- a/src/joystick/iphoneos/SDL_sysjoystick.m	Thu Apr 09 22:14:05 2015 +0200
    11.2 +++ b/src/joystick/iphoneos/SDL_sysjoystick.m	Thu Apr 09 22:28:37 2015 -0400
    11.3 @@ -23,6 +23,7 @@
    11.4  /* This is the iOS implementation of the SDL joystick API */
    11.5  
    11.6  #include "SDL_joystick.h"
    11.7 +#include "SDL_hints.h"
    11.8  #include "SDL_stdinc.h"
    11.9  #include "../SDL_sysjoystick.h"
   11.10  #include "../SDL_joystick_c.h"
   11.11 @@ -32,9 +33,10 @@
   11.12  /* needed for SDL_IPHONE_MAX_GFORCE macro */
   11.13  #import "SDL_config_iphoneos.h"
   11.14  
   11.15 -const char *accelerometerName = "iOS accelerometer";
   11.16 +const char *accelerometerName = "iOS Accelerometer";
   11.17  
   11.18  static CMMotionManager *motionManager = nil;
   11.19 +static int numjoysticks = 0;
   11.20  
   11.21  /* Function to scan the system for joysticks.
   11.22   * Joystick 0 should be the system default joystick.
   11.23 @@ -43,12 +45,18 @@
   11.24  int
   11.25  SDL_SYS_JoystickInit(void)
   11.26  {
   11.27 -    return (1);
   11.28 +    const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
   11.29 +    if (!hint || SDL_atoi(hint)) {
   11.30 +        /* Default behavior, accelerometer as joystick */
   11.31 +        numjoysticks = 1;
   11.32 +    }
   11.33 +
   11.34 +    return numjoysticks;
   11.35  }
   11.36  
   11.37  int SDL_SYS_NumJoysticks()
   11.38  {
   11.39 -    return 1;
   11.40 +    return numjoysticks;
   11.41  }
   11.42  
   11.43  void SDL_SYS_JoystickDetect()
   11.44 @@ -81,14 +89,16 @@
   11.45      joystick->nballs = 0;
   11.46      joystick->nbuttons = 0;
   11.47  
   11.48 -    if (motionManager == nil) {
   11.49 -        motionManager = [[CMMotionManager alloc] init];
   11.50 +    @autoreleasepool {
   11.51 +        if (motionManager == nil) {
   11.52 +            motionManager = [[CMMotionManager alloc] init];
   11.53 +        }
   11.54 +
   11.55 +        /* Shorter times between updates can significantly increase CPU usage. */
   11.56 +        motionManager.accelerometerUpdateInterval = 0.1;
   11.57 +        [motionManager startAccelerometerUpdates];
   11.58      }
   11.59  
   11.60 -    /* Shorter times between updates can significantly increase CPU usage. */
   11.61 -    motionManager.accelerometerUpdateInterval = 0.1;
   11.62 -    [motionManager startAccelerometerUpdates];
   11.63 -
   11.64      return 0;
   11.65  }
   11.66  
   11.67 @@ -104,12 +114,14 @@
   11.68      const SInt16 maxsint16 = 0x7FFF;
   11.69      CMAcceleration accel;
   11.70  
   11.71 -    if (!motionManager.accelerometerActive) {
   11.72 -        return;
   11.73 +    @autoreleasepool {
   11.74 +        if (!motionManager.accelerometerActive) {
   11.75 +            return;
   11.76 +        }
   11.77 +
   11.78 +        accel = motionManager.accelerometerData.acceleration;
   11.79      }
   11.80  
   11.81 -    accel = [[motionManager accelerometerData] acceleration];
   11.82 -
   11.83      /*
   11.84       Convert accelerometer data from floating point to Sint16, which is what
   11.85       the joystick system expects.
   11.86 @@ -152,17 +164,20 @@
   11.87  void
   11.88  SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   11.89  {
   11.90 -    [motionManager stopAccelerometerUpdates];
   11.91 +    @autoreleasepool {
   11.92 +        [motionManager stopAccelerometerUpdates];
   11.93 +    }
   11.94  }
   11.95  
   11.96  /* Function to perform any system-specific joystick related cleanup */
   11.97  void
   11.98  SDL_SYS_JoystickQuit(void)
   11.99  {
  11.100 -    if (motionManager != nil) {
  11.101 -        [motionManager release];
  11.102 +    @autoreleasepool {
  11.103          motionManager = nil;
  11.104      }
  11.105 +
  11.106 +    numjoysticks = 0;
  11.107  }
  11.108  
  11.109  SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
    12.1 --- a/src/power/uikit/SDL_syspower.m	Thu Apr 09 22:14:05 2015 +0200
    12.2 +++ b/src/power/uikit/SDL_syspower.m	Thu Apr 09 22:28:37 2015 -0400
    12.3 @@ -50,24 +50,24 @@
    12.4  SDL_bool
    12.5  SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent)
    12.6  {
    12.7 -    UIDevice *uidev = [UIDevice currentDevice];
    12.8 +    @autoreleasepool {
    12.9 +        UIDevice *uidev = [UIDevice currentDevice];
   12.10  
   12.11 -    if (!SDL_UIKitLastPowerInfoQuery) {
   12.12 -        SDL_assert([uidev isBatteryMonitoringEnabled] == NO);
   12.13 -        [uidev setBatteryMonitoringEnabled:YES];
   12.14 -    }
   12.15 +        if (!SDL_UIKitLastPowerInfoQuery) {
   12.16 +            SDL_assert(uidev.isBatteryMonitoringEnabled == NO);
   12.17 +            uidev.batteryMonitoringEnabled = YES;
   12.18 +        }
   12.19  
   12.20 -    /* UIKit_GL_SwapWindow() (etc) will check this and disable the battery
   12.21 -     *  monitoring if the app hasn't queried it in the last X seconds.
   12.22 -     *  Apparently monitoring the battery burns battery life.  :)
   12.23 -     *  Apple's docs say not to monitor the battery unless you need it.
   12.24 -     */
   12.25 -    SDL_UIKitLastPowerInfoQuery = SDL_GetTicks();
   12.26 +        /* UIKit_GL_SwapWindow() (etc) will check this and disable the battery
   12.27 +         *  monitoring if the app hasn't queried it in the last X seconds.
   12.28 +         *  Apparently monitoring the battery burns battery life.  :)
   12.29 +         *  Apple's docs say not to monitor the battery unless you need it.
   12.30 +         */
   12.31 +        SDL_UIKitLastPowerInfoQuery = SDL_GetTicks();
   12.32  
   12.33 -    *seconds = -1;   /* no API to estimate this in UIKit. */
   12.34 +        *seconds = -1;   /* no API to estimate this in UIKit. */
   12.35  
   12.36 -    switch ([uidev batteryState])
   12.37 -    {
   12.38 +        switch (uidev.batteryState) {
   12.39          case UIDeviceBatteryStateCharging:
   12.40              *state = SDL_POWERSTATE_CHARGING;
   12.41              break;
   12.42 @@ -84,11 +84,12 @@
   12.43          default:
   12.44              *state = SDL_POWERSTATE_UNKNOWN;
   12.45              break;
   12.46 +        }
   12.47 +
   12.48 +        const float level = uidev.batteryLevel;
   12.49 +        *percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) );
   12.50 +        return SDL_TRUE; /* always the definitive answer on iOS. */
   12.51      }
   12.52 -
   12.53 -    const float level = [uidev batteryLevel];
   12.54 -    *percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) );
   12.55 -    return SDL_TRUE;            /* always the definitive answer on iOS. */
   12.56  }
   12.57  
   12.58  #endif /* SDL_POWER_UIKIT */
    13.1 --- a/src/render/opengles/SDL_render_gles.c	Thu Apr 09 22:14:05 2015 +0200
    13.2 +++ b/src/render/opengles/SDL_render_gles.c	Thu Apr 09 22:28:37 2015 -0400
    13.3 @@ -55,6 +55,7 @@
    13.4  static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
    13.5  static void GLES_WindowEvent(SDL_Renderer * renderer,
    13.6                               const SDL_WindowEvent *event);
    13.7 +static int GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
    13.8  static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    13.9  static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   13.10                                const SDL_Rect * rect, const void *pixels,
   13.11 @@ -321,6 +322,7 @@
   13.12      }
   13.13  
   13.14      renderer->WindowEvent = GLES_WindowEvent;
   13.15 +    renderer->GetOutputSize = GLES_GetOutputSize;
   13.16      renderer->CreateTexture = GLES_CreateTexture;
   13.17      renderer->UpdateTexture = GLES_UpdateTexture;
   13.18      renderer->LockTexture = GLES_LockTexture;
   13.19 @@ -438,6 +440,13 @@
   13.20      }
   13.21  }
   13.22  
   13.23 +static int
   13.24 +GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
   13.25 +{
   13.26 +    SDL_GL_GetDrawableSize(renderer->window, w, h);
   13.27 +    return 0;
   13.28 +}
   13.29 +
   13.30  static SDL_INLINE int
   13.31  power_of_2(int input)
   13.32  {
    14.1 --- a/src/render/opengles2/SDL_render_gles2.c	Thu Apr 09 22:14:05 2015 +0200
    14.2 +++ b/src/render/opengles2/SDL_render_gles2.c	Thu Apr 09 22:28:37 2015 -0400
    14.3 @@ -370,6 +370,13 @@
    14.4  }
    14.5  
    14.6  static int
    14.7 +GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
    14.8 +{
    14.9 +    SDL_GL_GetDrawableSize(renderer->window, w, h);
   14.10 +    return 0;
   14.11 +}
   14.12 +
   14.13 +static int
   14.14  GLES2_UpdateViewport(SDL_Renderer * renderer)
   14.15  {
   14.16      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   14.17 @@ -2059,6 +2066,7 @@
   14.18  
   14.19      /* Populate the function pointers for the module */
   14.20      renderer->WindowEvent         = &GLES2_WindowEvent;
   14.21 +    renderer->GetOutputSize       = &GLES2_GetOutputSize;
   14.22      renderer->CreateTexture       = &GLES2_CreateTexture;
   14.23      renderer->UpdateTexture       = &GLES2_UpdateTexture;
   14.24      renderer->UpdateTextureYUV    = &GLES2_UpdateTextureYUV;
    15.1 --- a/src/video/SDL_video.c	Thu Apr 09 22:14:05 2015 +0200
    15.2 +++ b/src/video/SDL_video.c	Thu Apr 09 22:28:37 2015 -0400
    15.3 @@ -1107,22 +1107,22 @@
    15.4      }
    15.5  }
    15.6  
    15.7 -static void
    15.8 +static int
    15.9  SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
   15.10  {
   15.11      SDL_VideoDisplay *display;
   15.12      SDL_Window *other;
   15.13  
   15.14 -    CHECK_WINDOW_MAGIC(window,);
   15.15 +    CHECK_WINDOW_MAGIC(window,-1);
   15.16  
   15.17      /* if we are in the process of hiding don't go back to fullscreen */
   15.18      if ( window->is_hiding && fullscreen )
   15.19 -        return;
   15.20 +        return 0;
   15.21      
   15.22  #ifdef __MACOSX__
   15.23      if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
   15.24          window->last_fullscreen_flags = window->flags;
   15.25 -        return;
   15.26 +        return 0;
   15.27      }
   15.28  #endif
   15.29  
   15.30 @@ -1139,7 +1139,7 @@
   15.31      /* See if anything needs to be done now */
   15.32      if ((display->fullscreen_window == window) == fullscreen) {
   15.33          if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
   15.34 -            return;
   15.35 +            return 0;
   15.36          }
   15.37      }
   15.38  
   15.39 @@ -1168,9 +1168,13 @@
   15.40  
   15.41                  /* only do the mode change if we want exclusive fullscreen */
   15.42                  if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   15.43 -                    SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
   15.44 +                    if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
   15.45 +                        return -1;
   15.46 +                    }
   15.47                  } else {
   15.48 -                    SDL_SetDisplayModeForDisplay(display, NULL);
   15.49 +                    if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
   15.50 +                        return -1;
   15.51 +                    }
   15.52                  }
   15.53  
   15.54                  if (_this->SetWindowFullscreen) {
   15.55 @@ -1189,7 +1193,7 @@
   15.56                  SDL_RestoreMousePosition(other);
   15.57  
   15.58                  window->last_fullscreen_flags = window->flags;
   15.59 -                return;
   15.60 +                return 0;
   15.61              }
   15.62          }
   15.63      }
   15.64 @@ -1209,6 +1213,7 @@
   15.65      SDL_RestoreMousePosition(window);
   15.66  
   15.67      window->last_fullscreen_flags = window->flags;
   15.68 +    return 0;
   15.69  }
   15.70  
   15.71  #define CREATE_FLAGS \
   15.72 @@ -1938,9 +1943,7 @@
   15.73      window->flags &= ~FULLSCREEN_MASK;
   15.74      window->flags |= flags;
   15.75  
   15.76 -    SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
   15.77 -
   15.78 -    return 0;
   15.79 +    return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
   15.80  }
   15.81  
   15.82  static SDL_Surface *
    16.1 --- a/src/video/uikit/SDL_uikitappdelegate.h	Thu Apr 09 22:14:05 2015 +0200
    16.2 +++ b/src/video/uikit/SDL_uikitappdelegate.h	Thu Apr 09 22:28:37 2015 -0400
    16.3 @@ -21,12 +21,21 @@
    16.4  
    16.5  #import <UIKit/UIKit.h>
    16.6  
    16.7 -@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate> {
    16.8 -}
    16.9 +@interface SDLLaunchScreenController : UIViewController
   16.10  
   16.11 -+ (id) sharedAppDelegate;
   16.12 +- (instancetype)init;
   16.13 +- (void)loadView;
   16.14 +- (NSUInteger)supportedInterfaceOrientations;
   16.15 +
   16.16 +@end
   16.17 +
   16.18 +@interface SDLUIKitDelegate : NSObject<UIApplicationDelegate>
   16.19 +
   16.20 ++ (id)sharedAppDelegate;
   16.21  + (NSString *)getAppDelegateClassName;
   16.22  
   16.23 +- (void)hideLaunchScreen;
   16.24 +
   16.25  @end
   16.26  
   16.27  /* vi: set ts=4 sw=4 expandtab: */
    17.1 --- a/src/video/uikit/SDL_uikitappdelegate.m	Thu Apr 09 22:14:05 2015 +0200
    17.2 +++ b/src/video/uikit/SDL_uikitappdelegate.m	Thu Apr 09 22:28:37 2015 -0400
    17.3 @@ -28,8 +28,10 @@
    17.4  #include "SDL_system.h"
    17.5  #include "SDL_main.h"
    17.6  
    17.7 -#include "SDL_uikitappdelegate.h"
    17.8 -#include "SDL_uikitmodes.h"
    17.9 +#import "SDL_uikitappdelegate.h"
   17.10 +#import "SDL_uikitmodes.h"
   17.11 +#import "SDL_uikitwindow.h"
   17.12 +
   17.13  #include "../../events/SDL_events_c.h"
   17.14  
   17.15  #ifdef main
   17.16 @@ -39,12 +41,10 @@
   17.17  static int forward_argc;
   17.18  static char **forward_argv;
   17.19  static int exit_status;
   17.20 -static UIWindow *launch_window;
   17.21  
   17.22  int main(int argc, char **argv)
   17.23  {
   17.24      int i;
   17.25 -    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   17.26  
   17.27      /* store arguments */
   17.28      forward_argc = argc;
   17.29 @@ -56,7 +56,9 @@
   17.30      forward_argv[i] = NULL;
   17.31  
   17.32      /* Give over control to run loop, SDLUIKitDelegate will handle most things from here */
   17.33 -    UIApplicationMain(argc, argv, NULL, [SDLUIKitDelegate getAppDelegateClassName]);
   17.34 +    @autoreleasepool {
   17.35 +        UIApplicationMain(argc, argv, nil, [SDLUIKitDelegate getAppDelegateClassName]);
   17.36 +    }
   17.37  
   17.38      /* free the memory we used to hold copies of argc and argv */
   17.39      for (i = 0; i < forward_argc; i++) {
   17.40 @@ -64,7 +66,6 @@
   17.41      }
   17.42      free(forward_argv);
   17.43  
   17.44 -    [pool release];
   17.45      return exit_status;
   17.46  }
   17.47  
   17.48 @@ -75,224 +76,262 @@
   17.49      [UIApplication sharedApplication].idleTimerDisabled = disable;
   17.50  }
   17.51  
   17.52 +/* Load a launch image using the old UILaunchImageFile-era naming rules. */
   17.53 +static UIImage *
   17.54 +SDL_LoadLaunchImageNamed(NSString *name, int screenh)
   17.55 +{
   17.56 +    UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
   17.57 +    UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom;
   17.58 +    UIImage *image = nil;
   17.59  
   17.60 -@interface SDL_launchscreenviewcontroller : UIViewController {
   17.61 -	
   17.62 +    if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) {
   17.63 +        /* The image name for the iPhone 5 uses its height as a suffix. */
   17.64 +        image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]];
   17.65 +    } else if (idiom == UIUserInterfaceIdiomPad) {
   17.66 +        /* iPad apps can launch in any orientation. */
   17.67 +        if (UIInterfaceOrientationIsLandscape(curorient)) {
   17.68 +            if (curorient == UIInterfaceOrientationLandscapeLeft) {
   17.69 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]];
   17.70 +            } else {
   17.71 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]];
   17.72 +            }
   17.73 +            if (!image) {
   17.74 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]];
   17.75 +            }
   17.76 +        } else {
   17.77 +            if (curorient == UIInterfaceOrientationPortraitUpsideDown) {
   17.78 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]];
   17.79 +            }
   17.80 +            if (!image) {
   17.81 +                image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]];
   17.82 +            }
   17.83 +        }
   17.84 +    }
   17.85 +
   17.86 +    if (!image) {
   17.87 +        image = [UIImage imageNamed:name];
   17.88 +    }
   17.89 +
   17.90 +    return image;
   17.91 +}
   17.92 +
   17.93 +@implementation SDLLaunchScreenController {
   17.94 +    UIInterfaceOrientationMask supportedOrientations;
   17.95 +}
   17.96 +
   17.97 +- (instancetype)init
   17.98 +{
   17.99 +    if (!(self = [super initWithNibName:nil bundle:nil])) {
  17.100 +        return nil;
  17.101 +    }
  17.102 +
  17.103 +    NSBundle *bundle = [NSBundle mainBundle];
  17.104 +    NSString *screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
  17.105 +
  17.106 +    /* Normally we don't want to rotate from the initial orientation. */
  17.107 +    supportedOrientations = (1 << [UIApplication sharedApplication].statusBarOrientation);
  17.108 +
  17.109 +    /* Launch screens were added in iOS 8. Otherwise we use launch images. */
  17.110 +    if (screenname && UIKit_IsSystemVersionAtLeast(8.0)) {
  17.111 +        @try {
  17.112 +            self.view = [bundle loadNibNamed:screenname owner:self options:nil][0];
  17.113 +        }
  17.114 +        @catch (NSException *exception) {
  17.115 +            /* iOS displays a blank screen rather than falling back to an image,
  17.116 +             * if a launch screen name is specified but it fails to load. */
  17.117 +            return nil;
  17.118 +        }
  17.119 +    }
  17.120 +
  17.121 +    if (!self.view) {
  17.122 +        NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
  17.123 +        UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
  17.124 +        NSString *imagename = nil;
  17.125 +        UIImage *image = nil;
  17.126 +
  17.127 +        int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
  17.128 +        int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
  17.129 +
  17.130 +        /* We always want portrait-oriented size, to match UILaunchImageSize. */
  17.131 +        if (screenw > screenh) {
  17.132 +            int width = screenw;
  17.133 +            screenw = screenh;
  17.134 +            screenh = width;
  17.135 +        }
  17.136 +
  17.137 +        /* Xcode 5 introduced a dictionary of launch images in Info.plist. */
  17.138 +        if (launchimages) {
  17.139 +            for (NSDictionary *dict in launchimages) {
  17.140 +                UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
  17.141 +                NSString *minversion   = dict[@"UILaunchImageMinimumOSVersion"];
  17.142 +                NSString *sizestring   = dict[@"UILaunchImageSize"];
  17.143 +                NSString *orientstring = dict[@"UILaunchImageOrientation"];
  17.144 +
  17.145 +                /* Ignore this image if the current version is too low. */
  17.146 +                if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) {
  17.147 +                    continue;
  17.148 +                }
  17.149 +
  17.150 +                /* Ignore this image if the size doesn't match. */
  17.151 +                if (sizestring) {
  17.152 +                    CGSize size = CGSizeFromString(sizestring);
  17.153 +                    if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) {
  17.154 +                        continue;
  17.155 +                    }
  17.156 +                }
  17.157 +
  17.158 +                if (orientstring) {
  17.159 +                    if ([orientstring isEqualToString:@"PortraitUpsideDown"]) {
  17.160 +                        orientmask = UIInterfaceOrientationMaskPortraitUpsideDown;
  17.161 +                    } else if ([orientstring isEqualToString:@"Landscape"]) {
  17.162 +                        orientmask = UIInterfaceOrientationMaskLandscape;
  17.163 +                    } else if ([orientstring isEqualToString:@"LandscapeLeft"]) {
  17.164 +                        orientmask = UIInterfaceOrientationMaskLandscapeLeft;
  17.165 +                    } else if ([orientstring isEqualToString:@"LandscapeRight"]) {
  17.166 +                        orientmask = UIInterfaceOrientationMaskLandscapeRight;
  17.167 +                    }
  17.168 +                }
  17.169 +
  17.170 +                /* Ignore this image if the orientation doesn't match. */
  17.171 +                if ((orientmask & (1 << curorient)) == 0) {
  17.172 +                    continue;
  17.173 +                }
  17.174 +
  17.175 +                imagename = dict[@"UILaunchImageName"];
  17.176 +            }
  17.177 +
  17.178 +            if (imagename) {
  17.179 +                image = [UIImage imageNamed:imagename];
  17.180 +            }
  17.181 +        } else {
  17.182 +            imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
  17.183 +
  17.184 +            if (imagename) {
  17.185 +                image = SDL_LoadLaunchImageNamed(imagename, screenh);
  17.186 +            }
  17.187 +
  17.188 +            if (!image) {
  17.189 +                image = SDL_LoadLaunchImageNamed(@"Default", screenh);
  17.190 +            }
  17.191 +        }
  17.192 +
  17.193 +        if (image) {
  17.194 +            if (image.size.width > image.size.height) {
  17.195 +                supportedOrientations = UIInterfaceOrientationMaskLandscape;
  17.196 +            } else {
  17.197 +                supportedOrientations = UIInterfaceOrientationMaskPortrait;
  17.198 +            }
  17.199 +
  17.200 +            self.view = [[UIImageView alloc] initWithImage:image];
  17.201 +        }
  17.202 +    }
  17.203 +
  17.204 +    return self;
  17.205 +}
  17.206 +
  17.207 +- (void)loadView
  17.208 +{
  17.209 +    /* Do nothing. */
  17.210 +}
  17.211 +
  17.212 +- (NSUInteger)supportedInterfaceOrientations
  17.213 +{
  17.214 +    return supportedOrientations;
  17.215  }
  17.216  
  17.217  @end
  17.218  
  17.219 -@implementation SDL_launchscreenviewcontroller
  17.220 -
  17.221 -- (id)init
  17.222 -{
  17.223 -    self = [super init];
  17.224 -    if (self == nil) {
  17.225 -        return nil;
  17.226 -    }
  17.227 -
  17.228 -    NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
  17.229 -
  17.230 -    if(launch_screen_name) {
  17.231 -        // 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.
  17.232 -        UIView* launch_screen = [[[NSBundle mainBundle] loadNibNamed:launch_screen_name owner:self options:nil] objectAtIndex:0];
  17.233 -        CGSize size = [UIScreen mainScreen].bounds.size;
  17.234 -        
  17.235 -        CGRect bounds = CGRectMake(0, 0, size.width, size.height);
  17.236 -        
  17.237 -        [launch_screen setFrame:bounds];
  17.238 -        [self setView:launch_screen];
  17.239 -        [launch_screen release];
  17.240 -    }
  17.241 -
  17.242 -    
  17.243 -
  17.244 -
  17.245 -    return self;
  17.246 +@implementation SDLUIKitDelegate {
  17.247 +    UIWindow *launchWindow;
  17.248  }
  17.249  
  17.250 -- (NSUInteger)supportedInterfaceOrientations
  17.251 +/* convenience method */
  17.252 ++ (id)sharedAppDelegate
  17.253  {
  17.254 -    NSUInteger orientationMask = UIInterfaceOrientationMaskAll;
  17.255 -    
  17.256 -    /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
  17.257 -    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
  17.258 -        orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
  17.259 -    }
  17.260 -    return orientationMask;
  17.261 -}
  17.262 -
  17.263 -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
  17.264 -{
  17.265 -    NSUInteger orientationMask = [self supportedInterfaceOrientations];
  17.266 -    return (orientationMask & (1 << orient));
  17.267 -}
  17.268 -
  17.269 -@end
  17.270 -
  17.271 -
  17.272 -@interface SDL_splashviewcontroller : UIViewController {
  17.273 -    UIImageView *splash;
  17.274 -    UIImage *splashPortrait;
  17.275 -    UIImage *splashLandscape;
  17.276 -}
  17.277 -
  17.278 -- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation;
  17.279 -@end
  17.280 -
  17.281 -@implementation SDL_splashviewcontroller
  17.282 -
  17.283 -- (id)init
  17.284 -{
  17.285 -    self = [super init];
  17.286 -    if (self == nil) {
  17.287 -        return nil;
  17.288 -    }
  17.289 -
  17.290 -    self->splash = [[UIImageView alloc] init];
  17.291 -    [self setView:self->splash];
  17.292 -
  17.293 -    CGSize size = [UIScreen mainScreen].bounds.size;
  17.294 -    float height = SDL_max(size.width, size.height);
  17.295 -    /* FIXME: Some where around iOS 7, UILaunchImages in the Info.plist was introduced which explicitly maps image names to devices and orientations.
  17.296 -     This gets rid of the hardcoded magic file names and allows more control for OS version, orientation, retina, and device.
  17.297 -     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.
  17.298 -     But iOS 8 superscedes this process and introduces the LaunchScreen NIB which uses autolayout to handle all orientations and devices.
  17.299 -     Since we now have a LaunchScreen solution, this may never get fixed, 
  17.300 -     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.
  17.301 -     */
  17.302 -    self->splashPortrait = [UIImage imageNamed:[NSString stringWithFormat:@"Default-%dh.png", (int)height]];
  17.303 -    if (!self->splashPortrait) {
  17.304 -        self->splashPortrait = [UIImage imageNamed:@"Default.png"];
  17.305 -    }
  17.306 -    self->splashLandscape = [UIImage imageNamed:@"Default-Landscape.png"];
  17.307 -    if (!self->splashLandscape && self->splashPortrait) {
  17.308 -        self->splashLandscape = [[UIImage alloc] initWithCGImage: self->splashPortrait.CGImage
  17.309 -                                                           scale: 1.0
  17.310 -                                                     orientation: UIImageOrientationRight];
  17.311 -    }
  17.312 -    if (self->splashPortrait) {
  17.313 -        [self->splashPortrait retain];
  17.314 -    }
  17.315 -    if (self->splashLandscape) {
  17.316 -        [self->splashLandscape retain];
  17.317 -    }
  17.318 -
  17.319 -    [self updateSplashImage:[[UIApplication sharedApplication] statusBarOrientation]];
  17.320 -
  17.321 -    return self;
  17.322 -}
  17.323 -
  17.324 -- (NSUInteger)supportedInterfaceOrientations
  17.325 -{
  17.326 -    NSUInteger orientationMask = UIInterfaceOrientationMaskAll;
  17.327 -
  17.328 -    /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
  17.329 -    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
  17.330 -        orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
  17.331 -    }
  17.332 -    return orientationMask;
  17.333 -}
  17.334 -
  17.335 -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
  17.336 -{
  17.337 -    NSUInteger orientationMask = [self supportedInterfaceOrientations];
  17.338 -    return (orientationMask & (1 << orient));
  17.339 -}
  17.340 -
  17.341 -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
  17.342 -{
  17.343 -    [self updateSplashImage:interfaceOrientation];
  17.344 -}
  17.345 -
  17.346 -- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation
  17.347 -{
  17.348 -    UIImage *image;
  17.349 -
  17.350 -    if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
  17.351 -        image = self->splashLandscape;
  17.352 -    } else {
  17.353 -        image = self->splashPortrait;
  17.354 -    }
  17.355 -    if (image)
  17.356 -    {
  17.357 -        splash.image = image;
  17.358 -    }
  17.359 -}
  17.360 -
  17.361 -@end
  17.362 -
  17.363 -
  17.364 -@implementation SDLUIKitDelegate
  17.365 -
  17.366 -/* convenience method */
  17.367 -+ (id) sharedAppDelegate
  17.368 -{
  17.369 -    /* the delegate is set in UIApplicationMain(), which is garaunteed to be called before this method */
  17.370 -    return [[UIApplication sharedApplication] delegate];
  17.371 +    /* the delegate is set in UIApplicationMain(), which is guaranteed to be
  17.372 +     * called before this method */
  17.373 +    return [UIApplication sharedApplication].delegate;
  17.374  }
  17.375  
  17.376  + (NSString *)getAppDelegateClassName
  17.377  {
  17.378 -    /* subclassing notice: when you subclass this appdelegate, make sure to add a category to override
  17.379 -       this method and return the actual name of the delegate */
  17.380 +    /* subclassing notice: when you subclass this appdelegate, make sure to add
  17.381 +     * a category to override this method and return the actual name of the
  17.382 +     * delegate */
  17.383      return @"SDLUIKitDelegate";
  17.384  }
  17.385  
  17.386 -- (id)init
  17.387 +- (void)hideLaunchScreen
  17.388  {
  17.389 -    self = [super init];
  17.390 -    return self;
  17.391 +    UIWindow *window = launchWindow;
  17.392 +
  17.393 +    if (!window || window.hidden) {
  17.394 +        return;
  17.395 +    }
  17.396 +
  17.397 +    launchWindow = nil;
  17.398 +
  17.399 +    /* Do a nice animated fade-out (roughly matches the real launch behavior.) */
  17.400 +    [UIView animateWithDuration:0.2 animations:^{
  17.401 +        window.alpha = 0.0;
  17.402 +    } completion:^(BOOL finished) {
  17.403 +        window.hidden = YES;
  17.404 +    }];
  17.405  }
  17.406  
  17.407  - (void)postFinishLaunch
  17.408  {
  17.409 +    /* Hide the launch screen the next time the run loop is run. SDL apps will
  17.410 +     * have a chance to load resources while the launch screen is still up. */
  17.411 +    [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0];
  17.412 +
  17.413      /* run the user's application, passing argc and argv */
  17.414      SDL_iPhoneSetEventPump(SDL_TRUE);
  17.415      exit_status = SDL_main(forward_argc, forward_argv);
  17.416      SDL_iPhoneSetEventPump(SDL_FALSE);
  17.417  
  17.418 -    /* If we showed a splash image, clean it up */
  17.419 -    if (launch_window) {
  17.420 -        [launch_window release];
  17.421 -        launch_window = NULL;
  17.422 +    if (launchWindow) {
  17.423 +        launchWindow.hidden = YES;
  17.424 +        launchWindow = nil;
  17.425      }
  17.426  
  17.427      /* exit, passing the return status from the user's application */
  17.428 -    /* We don't actually exit to support applications that do setup in
  17.429 -     * their main function and then allow the Cocoa event loop to run.
  17.430 -     */
  17.431 +    /* We don't actually exit to support applications that do setup in their
  17.432 +     * main function and then allow the Cocoa event loop to run. */
  17.433      /* exit(exit_status); */
  17.434  }
  17.435  
  17.436  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  17.437  {
  17.438 -    /* Keep the launch image up until we set a video mode */
  17.439 -    launch_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  17.440 +    NSBundle *bundle = [NSBundle mainBundle];
  17.441 +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  17.442  
  17.443 -    /* iOS 8 introduces LaunchScreen NIBs which use autolayout to handle all devices and orientations with a single NIB instead of multiple launch images.
  17.444 -     This is also the only way to get the App Store badge "Optimized for iPhone 6 and iPhone 6 Plus".
  17.445 -     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.
  17.446 -     Otherwise, we should fallback to the legacy behavior of launch screen images.
  17.447 -     */
  17.448 -    NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
  17.449 -    if( ([[UIDevice currentDevice].systemVersion intValue] >= 8) && (nil != launch_screen_name) ) {
  17.450 -        // iOS 8.0 and above uses LaunchScreen.xib
  17.451 -        SDL_launchscreenviewcontroller* launch_screen_view_controller = [[SDL_launchscreenviewcontroller alloc] init];
  17.452 -        launch_window.rootViewController = launch_screen_view_controller;
  17.453 -        [launch_window addSubview:launch_screen_view_controller.view];
  17.454 -        [launch_window makeKeyAndVisible];
  17.455 -    } else {
  17.456 -        // Anything less than iOS 8.0
  17.457 +#if SDL_IPHONE_LAUNCHSCREEN
  17.458 +    /* The normal launch screen is displayed until didFinishLaunching returns,
  17.459 +     * but SDL_main is called after that happens and there may be a noticeable
  17.460 +     * delay between the start of SDL_main and when the first real frame is
  17.461 +     * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is
  17.462 +     * called), so we show the launch screen programmatically until the first
  17.463 +     * time events are pumped. */
  17.464 +    UIViewController *viewcontroller = [[SDLLaunchScreenController alloc] init];
  17.465  
  17.466 -        UIViewController *splashViewController = [[SDL_splashviewcontroller alloc] init];
  17.467 -        launch_window.rootViewController = splashViewController;
  17.468 -        [launch_window addSubview:splashViewController.view];
  17.469 -        [launch_window makeKeyAndVisible];
  17.470 +    if (viewcontroller.view) {
  17.471 +        launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  17.472 +
  17.473 +        /* We don't want the launch window immediately hidden when a real SDL
  17.474 +         * window is shown - we fade it out ourselves when we're ready. */
  17.475 +        launchWindow.windowLevel = UIWindowLevelNormal + 1.0;
  17.476 +
  17.477 +        /* Show the window but don't make it key. Events should always go to
  17.478 +         * other windows when possible. */
  17.479 +        launchWindow.hidden = NO;
  17.480 +
  17.481 +        launchWindow.rootViewController = viewcontroller;
  17.482      }
  17.483 +#endif
  17.484  
  17.485      /* Set working directory to resource path */
  17.486 -    [[NSFileManager defaultManager] changeCurrentDirectoryPath: [[NSBundle mainBundle] resourcePath]];
  17.487 +    [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]];
  17.488  
  17.489      /* register a callback for the idletimer hint */
  17.490      SDL_AddHintCallback(SDL_HINT_IDLE_TIMER_DISABLED,
  17.491 @@ -314,7 +353,35 @@
  17.492      SDL_SendAppEvent(SDL_APP_LOWMEMORY);
  17.493  }
  17.494  
  17.495 -- (void) applicationWillResignActive:(UIApplication*)application
  17.496 +- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
  17.497 +{
  17.498 +    BOOL isLandscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation);
  17.499 +    SDL_VideoDevice *_this = SDL_GetVideoDevice();
  17.500 +
  17.501 +    if (_this && _this->num_displays > 0) {
  17.502 +        SDL_DisplayMode *desktopmode = &_this->displays[0].desktop_mode;
  17.503 +        SDL_DisplayMode *currentmode = &_this->displays[0].current_mode;
  17.504 +
  17.505 +        /* The desktop display mode should be kept in sync with the screen
  17.506 +         * orientation so that updating a window's fullscreen state to
  17.507 +         * SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the
  17.508 +         * correct orientation. */
  17.509 +        if (isLandscape != (desktopmode->w > desktopmode->h)) {
  17.510 +            int height = desktopmode->w;
  17.511 +            desktopmode->w = desktopmode->h;
  17.512 +            desktopmode->h = height;
  17.513 +        }
  17.514 +
  17.515 +        /* Same deal with the current mode + SDL_GetCurrentDisplayMode. */
  17.516 +        if (isLandscape != (currentmode->w > currentmode->h)) {
  17.517 +            int height = currentmode->w;
  17.518 +            currentmode->w = currentmode->h;
  17.519 +            currentmode->h = height;
  17.520 +        }
  17.521 +    }
  17.522 +}
  17.523 +
  17.524 +- (void)applicationWillResignActive:(UIApplication*)application
  17.525  {
  17.526      SDL_VideoDevice *_this = SDL_GetVideoDevice();
  17.527      if (_this) {
  17.528 @@ -327,17 +394,17 @@
  17.529      SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
  17.530  }
  17.531  
  17.532 -- (void) applicationDidEnterBackground:(UIApplication*)application
  17.533 +- (void)applicationDidEnterBackground:(UIApplication*)application
  17.534  {
  17.535      SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
  17.536  }
  17.537  
  17.538 -- (void) applicationWillEnterForeground:(UIApplication*)application
  17.539 +- (void)applicationWillEnterForeground:(UIApplication*)application
  17.540  {
  17.541      SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
  17.542  }
  17.543  
  17.544 -- (void) applicationDidBecomeActive:(UIApplication*)application
  17.545 +- (void)applicationDidBecomeActive:(UIApplication*)application
  17.546  {
  17.547      SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
  17.548  
  17.549 @@ -353,11 +420,11 @@
  17.550  
  17.551  - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
  17.552  {
  17.553 -    NSURL *fileURL = [url filePathURL];
  17.554 +    NSURL *fileURL = url.filePathURL;
  17.555      if (fileURL != nil) {
  17.556 -        SDL_SendDropFile([[fileURL path] UTF8String]);
  17.557 +        SDL_SendDropFile([fileURL.path UTF8String]);
  17.558      } else {
  17.559 -        SDL_SendDropFile([[url absoluteString] UTF8String]);
  17.560 +        SDL_SendDropFile([url.absoluteString UTF8String]);
  17.561      }
  17.562      return YES;
  17.563  }
    18.1 --- a/src/video/uikit/SDL_uikitevents.m	Thu Apr 09 22:14:05 2015 +0200
    18.2 +++ b/src/video/uikit/SDL_uikitevents.m	Thu Apr 09 22:28:37 2015 -0400
    18.3 @@ -40,8 +40,9 @@
    18.4  void
    18.5  UIKit_PumpEvents(_THIS)
    18.6  {
    18.7 -    if (!UIKit_EventPumpEnabled)
    18.8 +    if (!UIKit_EventPumpEnabled) {
    18.9          return;
   18.10 +    }
   18.11  
   18.12      /* Let the run loop run for a short amount of time: long enough for
   18.13         touch events to get processed (which is important to get certain
    19.1 --- a/src/video/uikit/SDL_uikitmessagebox.m	Thu Apr 09 22:14:05 2015 +0200
    19.2 +++ b/src/video/uikit/SDL_uikitmessagebox.m	Thu Apr 09 22:28:37 2015 -0400
    19.3 @@ -30,35 +30,20 @@
    19.4  
    19.5  static SDL_bool s_showingMessageBox = SDL_FALSE;
    19.6  
    19.7 -@interface UIKit_UIAlertViewDelegate : NSObject <UIAlertViewDelegate> {
    19.8 -@private
    19.9 -    int *clickedButtonIndex;
   19.10 -}
   19.11 +@interface SDLAlertViewDelegate : NSObject <UIAlertViewDelegate>
   19.12  
   19.13 -- (id)initWithButtonIndex:(int *)_buttonIndex;
   19.14 -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
   19.15 +@property (nonatomic, assign) int clickedIndex;
   19.16  
   19.17  @end
   19.18  
   19.19 -@implementation UIKit_UIAlertViewDelegate
   19.20 +@implementation SDLAlertViewDelegate
   19.21  
   19.22 -- (id)initWithButtonIndex:(int *)buttonIndex
   19.23 +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
   19.24  {
   19.25 -    self = [self init];
   19.26 -    if (self == nil) {
   19.27 -        return nil;
   19.28 -    }
   19.29 -    self->clickedButtonIndex = buttonIndex;
   19.30 -
   19.31 -    return self;
   19.32 +    _clickedIndex = (int)buttonIndex;
   19.33  }
   19.34  
   19.35 -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
   19.36 -{
   19.37 -    *clickedButtonIndex = (int)buttonIndex;
   19.38 -}
   19.39 -
   19.40 -@end /* UIKit_UIAlertViewDelegate */
   19.41 +@end
   19.42  
   19.43  
   19.44  SDL_bool
   19.45 @@ -70,42 +55,39 @@
   19.46  int
   19.47  UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
   19.48  {
   19.49 -    int clicked;
   19.50 +    int i;
   19.51 +    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
   19.52  
   19.53 -    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   19.54 +    @autoreleasepool {
   19.55 +        UIAlertView *alert = [[UIAlertView alloc] init];
   19.56 +        SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init];
   19.57  
   19.58 -    UIAlertView* alert = [[UIAlertView alloc] init];
   19.59 +        alert.delegate = delegate;
   19.60 +        alert.title = @(messageboxdata->title);
   19.61 +        alert.message = @(messageboxdata->message);
   19.62  
   19.63 -    alert.title = [NSString stringWithUTF8String:messageboxdata->title];
   19.64 -    alert.message = [NSString stringWithUTF8String:messageboxdata->message];
   19.65 -    alert.delegate = [[UIKit_UIAlertViewDelegate alloc] initWithButtonIndex:&clicked];
   19.66 +        for (i = 0; i < messageboxdata->numbuttons; ++i) {
   19.67 +            [alert addButtonWithTitle:@(buttons[i].text)];
   19.68 +        }
   19.69  
   19.70 -    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
   19.71 -    int i;
   19.72 -    for (i = 0; i < messageboxdata->numbuttons; ++i) {
   19.73 -        [alert addButtonWithTitle:[[NSString alloc] initWithUTF8String:buttons[i].text]];
   19.74 +        /* Set up for showing the alert */
   19.75 +        delegate.clickedIndex = messageboxdata->numbuttons;
   19.76 +
   19.77 +        [alert show];
   19.78 +
   19.79 +        /* Run the main event loop until the alert has finished */
   19.80 +        /* Note that this needs to be done on the main thread */
   19.81 +        s_showingMessageBox = SDL_TRUE;
   19.82 +        while (delegate.clickedIndex == messageboxdata->numbuttons) {
   19.83 +            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
   19.84 +        }
   19.85 +        s_showingMessageBox = SDL_FALSE;
   19.86 +
   19.87 +        *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid;
   19.88 +
   19.89 +        alert.delegate = nil;
   19.90      }
   19.91  
   19.92 -    /* Set up for showing the alert */
   19.93 -    clicked = messageboxdata->numbuttons;
   19.94 -
   19.95 -    [alert show];
   19.96 -
   19.97 -    /* Run the main event loop until the alert has finished */
   19.98 -    /* Note that this needs to be done on the main thread */
   19.99 -    s_showingMessageBox = SDL_TRUE;
  19.100 -    while (clicked == messageboxdata->numbuttons) {
  19.101 -        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
  19.102 -    }
  19.103 -    s_showingMessageBox = SDL_FALSE;
  19.104 -
  19.105 -    *buttonid = messageboxdata->buttons[clicked].buttonid;
  19.106 -
  19.107 -    [alert.delegate release];
  19.108 -    [alert release];
  19.109 -
  19.110 -    [pool release];
  19.111 -
  19.112      return 0;
  19.113  }
  19.114  
    20.1 --- a/src/video/uikit/SDL_uikitmodes.h	Thu Apr 09 22:14:05 2015 +0200
    20.2 +++ b/src/video/uikit/SDL_uikitmodes.h	Thu Apr 09 22:28:37 2015 -0400
    20.3 @@ -25,17 +25,17 @@
    20.4  
    20.5  #include "SDL_uikitvideo.h"
    20.6  
    20.7 -typedef struct
    20.8 -{
    20.9 -    UIScreen *uiscreen;
   20.10 -    CGFloat scale;
   20.11 -} SDL_DisplayData;
   20.12 +@interface SDL_DisplayData : NSObject
   20.13  
   20.14 -typedef struct
   20.15 -{
   20.16 -    UIScreenMode *uiscreenmode;
   20.17 -    CGFloat scale;
   20.18 -} SDL_DisplayModeData;
   20.19 +@property (nonatomic, strong) UIScreen *uiscreen;
   20.20 +
   20.21 +@end
   20.22 +
   20.23 +@interface SDL_DisplayModeData : NSObject
   20.24 +
   20.25 +@property (nonatomic, strong) UIScreenMode *uiscreenmode;
   20.26 +
   20.27 +@end
   20.28  
   20.29  extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen);
   20.30  
    21.1 --- a/src/video/uikit/SDL_uikitmodes.m	Thu Apr 09 22:14:05 2015 +0200
    21.2 +++ b/src/video/uikit/SDL_uikitmodes.m	Thu Apr 09 22:28:37 2015 -0400
    21.3 @@ -25,27 +25,36 @@
    21.4  #include "SDL_assert.h"
    21.5  #include "SDL_uikitmodes.h"
    21.6  
    21.7 +@implementation SDL_DisplayData
    21.8 +
    21.9 +@synthesize uiscreen;
   21.10 +
   21.11 +@end
   21.12 +
   21.13 +@implementation SDL_DisplayModeData
   21.14 +
   21.15 +@synthesize uiscreenmode;
   21.16 +
   21.17 +@end
   21.18 +
   21.19  
   21.20  static int
   21.21  UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode,
   21.22 -    UIScreenMode * uiscreenmode, CGFloat scale)
   21.23 +    UIScreenMode * uiscreenmode)
   21.24  {
   21.25 -    SDL_DisplayModeData *data = NULL;
   21.26 +    SDL_DisplayModeData *data = nil;
   21.27  
   21.28      if (uiscreenmode != nil) {
   21.29          /* Allocate the display mode data */
   21.30 -        data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
   21.31 +        data = [[SDL_DisplayModeData alloc] init];
   21.32          if (!data) {
   21.33              return SDL_OutOfMemory();
   21.34          }
   21.35  
   21.36 -        data->uiscreenmode = uiscreenmode;
   21.37 -        [data->uiscreenmode retain];
   21.38 -
   21.39 -        data->scale = scale;
   21.40 +        data.uiscreenmode = uiscreenmode;
   21.41      }
   21.42  
   21.43 -    mode->driverdata = data;
   21.44 +    mode->driverdata = (void *) CFBridgingRetain(data);
   21.45  
   21.46      return 0;
   21.47  }
   21.48 @@ -54,23 +63,21 @@
   21.49  UIKit_FreeDisplayModeData(SDL_DisplayMode * mode)
   21.50  {
   21.51      if (mode->driverdata != NULL) {
   21.52 -        SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
   21.53 -        [data->uiscreenmode release];
   21.54 -        SDL_free(data);
   21.55 +        CFRelease(mode->driverdata);
   21.56          mode->driverdata = NULL;
   21.57      }
   21.58  }
   21.59  
   21.60  static int
   21.61  UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
   21.62 -    UIScreenMode * uiscreenmode, CGFloat scale)
   21.63 +    UIScreenMode * uiscreenmode)
   21.64  {
   21.65      SDL_DisplayMode mode;
   21.66      SDL_zero(mode);
   21.67  
   21.68      mode.format = SDL_PIXELFORMAT_ABGR8888;
   21.69      mode.refresh_rate = 0;
   21.70 -    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
   21.71 +    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
   21.72          return -1;
   21.73      }
   21.74  
   21.75 @@ -85,16 +92,16 @@
   21.76  }
   21.77  
   21.78  static int
   21.79 -UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale,
   21.80 +UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h,
   21.81                       UIScreenMode * uiscreenmode, SDL_bool addRotation)
   21.82  {
   21.83 -    if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode, scale) < 0) {
   21.84 +    if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode) < 0) {
   21.85          return -1;
   21.86      }
   21.87  
   21.88      if (addRotation) {
   21.89          /* Add the rotated version */
   21.90 -        if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode, scale) < 0) {
   21.91 +        if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode) < 0) {
   21.92              return -1;
   21.93          }
   21.94      }
   21.95 @@ -105,7 +112,7 @@
   21.96  static int
   21.97  UIKit_AddDisplay(UIScreen *uiscreen)
   21.98  {
   21.99 -    CGSize size = [uiscreen bounds].size;
  21.100 +    CGSize size = uiscreen.bounds.size;
  21.101  
  21.102      /* Make sure the width/height are oriented correctly */
  21.103      if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
  21.104 @@ -114,24 +121,16 @@
  21.105          size.height = height;
  21.106      }
  21.107  
  21.108 -    /* When dealing with UIKit all coordinates are specified in terms of
  21.109 -     * what Apple refers to as points. [UIScreen scale] indicates the
  21.110 -     * relationship between points and pixels. Since SDL has no notion
  21.111 -     * of points, we must compensate in all cases where dealing with such
  21.112 -     * units.
  21.113 -     */
  21.114 -    CGFloat scale = [uiscreen scale];
  21.115 -
  21.116      SDL_VideoDisplay display;
  21.117      SDL_DisplayMode mode;
  21.118      SDL_zero(mode);
  21.119      mode.format = SDL_PIXELFORMAT_ABGR8888;
  21.120 -    mode.w = (int)(size.width * scale);
  21.121 -    mode.h = (int)(size.height * scale);
  21.122 +    mode.w = (int) size.width;
  21.123 +    mode.h = (int) size.height;
  21.124  
  21.125 -    UIScreenMode * uiscreenmode = [uiscreen currentMode];
  21.126 +    UIScreenMode *uiscreenmode = uiscreen.currentMode;
  21.127  
  21.128 -    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
  21.129 +    if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
  21.130          return -1;
  21.131      }
  21.132  
  21.133 @@ -140,17 +139,15 @@
  21.134      display.current_mode = mode;
  21.135  
  21.136      /* Allocate the display data */
  21.137 -    SDL_DisplayData *data = (SDL_DisplayData *) SDL_malloc(sizeof(*data));
  21.138 +    SDL_DisplayData *data = [[SDL_DisplayData alloc] init];
  21.139      if (!data) {
  21.140          UIKit_FreeDisplayModeData(&display.desktop_mode);
  21.141          return SDL_OutOfMemory();
  21.142      }
  21.143  
  21.144 -    [uiscreen retain];
  21.145 -    data->uiscreen = uiscreen;
  21.146 -    data->scale = scale;
  21.147 +    data.uiscreen = uiscreen;
  21.148  
  21.149 -    display.driverdata = data;
  21.150 +    display.driverdata = (void *) CFBridgingRetain(data);
  21.151      SDL_AddVideoDisplay(&display);
  21.152  
  21.153      return 0;
  21.154 @@ -160,9 +157,9 @@
  21.155  UIKit_IsDisplayLandscape(UIScreen *uiscreen)
  21.156  {
  21.157      if (uiscreen == [UIScreen mainScreen]) {
  21.158 -        return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
  21.159 +        return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
  21.160      } else {
  21.161 -        CGSize size = [uiscreen bounds].size;
  21.162 +        CGSize size = uiscreen.bounds.size;
  21.163          return (size.width > size.height);
  21.164      }
  21.165  }
  21.166 @@ -170,9 +167,11 @@
  21.167  int
  21.168  UIKit_InitModes(_THIS)
  21.169  {
  21.170 -    for (UIScreen *uiscreen in [UIScreen screens]) {
  21.171 -        if (UIKit_AddDisplay(uiscreen) < 0) {
  21.172 -            return -1;
  21.173 +    @autoreleasepool {
  21.174 +        for (UIScreen *uiscreen in [UIScreen screens]) {
  21.175 +            if (UIKit_AddDisplay(uiscreen) < 0) {
  21.176 +                return -1;
  21.177 +            }
  21.178          }
  21.179      }
  21.180  
  21.181 @@ -182,34 +181,35 @@
  21.182  void
  21.183  UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
  21.184  {
  21.185 -    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
  21.186 +    @autoreleasepool {
  21.187 +        SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
  21.188  
  21.189 -    SDL_bool isLandscape = UIKit_IsDisplayLandscape(data->uiscreen);
  21.190 -    SDL_bool addRotation = (data->uiscreen == [UIScreen mainScreen]);
  21.191 +        SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
  21.192 +        SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
  21.193 +        CGFloat scale = data.uiscreen.scale;
  21.194  
  21.195 -    for (UIScreenMode *uimode in [data->uiscreen availableModes]) {
  21.196 -        CGSize size = [uimode size];
  21.197 -        int w = (int)size.width;
  21.198 -        int h = (int)size.height;
  21.199 +#ifdef __IPHONE_8_0
  21.200 +        /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than
  21.201 +         * 1242x2208 (414x736@3x), so we should use the native scale. */
  21.202 +        if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) {
  21.203 +            scale = data.uiscreen.nativeScale;
  21.204 +        }
  21.205 +#endif
  21.206  
  21.207 -        /* Make sure the width/height are oriented correctly */
  21.208 -        if (isLandscape != (w > h)) {
  21.209 -            int tmp = w;
  21.210 -            w = h;
  21.211 -            h = tmp;
  21.212 -        }
  21.213 +        for (UIScreenMode *uimode in data.uiscreen.availableModes) {
  21.214 +            /* The size of a UIScreenMode is in pixels, but we deal exclusively
  21.215 +             * in points (except in SDL_GL_GetDrawableSize.) */
  21.216 +            int w = (int)(uimode.size.width / scale);
  21.217 +            int h = (int)(uimode.size.height / scale);
  21.218  
  21.219 -        /* Add the native screen resolution. */
  21.220 -        UIKit_AddDisplayMode(display, w, h, data->scale, uimode, addRotation);
  21.221 +            /* Make sure the width/height are oriented correctly */
  21.222 +            if (isLandscape != (w > h)) {
  21.223 +                int tmp = w;
  21.224 +                w = h;
  21.225 +                h = tmp;
  21.226 +            }
  21.227  
  21.228 -        if (data->scale != 1.0f) {
  21.229 -            /* Add the native screen resolution divided by its scale.
  21.230 -             * This is so devices capable of e.g. 640x960 also advertise 320x480.
  21.231 -             */
  21.232 -            UIKit_AddDisplayMode(display,
  21.233 -                (int)(size.width / data->scale),
  21.234 -                (int)(size.height / data->scale),
  21.235 -                1.0f, uimode, addRotation);
  21.236 +            UIKit_AddDisplayMode(display, w, h, uimode, addRotation);
  21.237          }
  21.238      }
  21.239  }
  21.240 @@ -217,19 +217,24 @@
  21.241  int
  21.242  UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
  21.243  {
  21.244 -    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
  21.245 -    SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
  21.246 +    @autoreleasepool {
  21.247 +        SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
  21.248 +        SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
  21.249  
  21.250 -    [data->uiscreen setCurrentMode:modedata->uiscreenmode];
  21.251 +        [data.uiscreen setCurrentMode:modedata.uiscreenmode];
  21.252  
  21.253 -    if (data->uiscreen == [UIScreen mainScreen]) {
  21.254 -        if (mode->w > mode->h) {
  21.255 -            if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
  21.256 -                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
  21.257 -            }
  21.258 -        } else if (mode->w < mode->h) {
  21.259 -            if (UIKit_IsDisplayLandscape(data->uiscreen)) {
  21.260 -                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
  21.261 +        if (data.uiscreen == [UIScreen mainScreen]) {
  21.262 +            /* [UIApplication setStatusBarOrientation:] no longer works reliably
  21.263 +             * in recent iOS versions, so we can't rotate the screen when setting
  21.264 +             * the display mode. */
  21.265 +            if (mode->w > mode->h) {
  21.266 +                if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
  21.267 +                    return SDL_SetError("Screen orientation does not match display mode size");
  21.268 +                }
  21.269 +            } else if (mode->w < mode->h) {
  21.270 +                if (UIKit_IsDisplayLandscape(data.uiscreen)) {
  21.271 +                    return SDL_SetError("Screen orientation does not match display mode size");
  21.272 +                }
  21.273              }
  21.274          }
  21.275      }
  21.276 @@ -242,19 +247,21 @@
  21.277  {
  21.278      /* Release Objective-C objects, so higher level doesn't free() them. */
  21.279      int i, j;
  21.280 -    for (i = 0; i < _this->num_displays; i++) {
  21.281 -        SDL_VideoDisplay *display = &_this->displays[i];
  21.282 +    @autoreleasepool {
  21.283 +        for (i = 0; i < _this->num_displays; i++) {
  21.284 +            SDL_VideoDisplay *display = &_this->displays[i];
  21.285  
  21.286 -        UIKit_FreeDisplayModeData(&display->desktop_mode);
  21.287 -        for (j = 0; j < display->num_display_modes; j++) {
  21.288 -            SDL_DisplayMode *mode = &display->display_modes[j];
  21.289 -            UIKit_FreeDisplayModeData(mode);
  21.290 +            UIKit_FreeDisplayModeData(&display->desktop_mode);
  21.291 +            for (j = 0; j < display->num_display_modes; j++) {
  21.292 +                SDL_DisplayMode *mode = &display->display_modes[j];
  21.293 +                UIKit_FreeDisplayModeData(mode);
  21.294 +            }
  21.295 +
  21.296 +            if (display->driverdata != NULL) {
  21.297 +                CFRelease(display->driverdata);
  21.298 +                display->driverdata = NULL;
  21.299 +            }
  21.300          }
  21.301 -
  21.302 -        SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
  21.303 -        [data->uiscreen release];
  21.304 -        SDL_free(data);
  21.305 -        display->driverdata = NULL;
  21.306      }
  21.307  }
  21.308  
    22.1 --- a/src/video/uikit/SDL_uikitopengles.h	Thu Apr 09 22:14:05 2015 +0200
    22.2 +++ b/src/video/uikit/SDL_uikitopengles.h	Thu Apr 09 22:28:37 2015 -0400
    22.3 @@ -25,6 +25,8 @@
    22.4  
    22.5  extern int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window,
    22.6                                  SDL_GLContext context);
    22.7 +extern void UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window,
    22.8 +                                     int * w, int * h);
    22.9  extern void UIKit_GL_SwapWindow(_THIS, SDL_Window * window);
   22.10  extern SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window);
   22.11  extern void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context);
    23.1 --- a/src/video/uikit/SDL_uikitopengles.m	Thu Apr 09 22:14:05 2015 +0200
    23.2 +++ b/src/video/uikit/SDL_uikitopengles.m	Thu Apr 09 22:28:37 2015 -0400
    23.3 @@ -23,10 +23,10 @@
    23.4  #if SDL_VIDEO_DRIVER_UIKIT
    23.5  
    23.6  #include "SDL_uikitopengles.h"
    23.7 -#include "SDL_uikitopenglview.h"
    23.8 -#include "SDL_uikitappdelegate.h"
    23.9 +#import "SDL_uikitopenglview.h"
   23.10  #include "SDL_uikitmodes.h"
   23.11  #include "SDL_uikitwindow.h"
   23.12 +#include "SDL_uikitevents.h"
   23.13  #include "../SDL_sysvideo.h"
   23.14  #include "../../events/SDL_keyboard_c.h"
   23.15  #include "../../events/SDL_mouse_c.h"
   23.16 @@ -40,148 +40,147 @@
   23.17  UIKit_GL_GetProcAddress(_THIS, const char *proc)
   23.18  {
   23.19      /* Look through all SO's for the proc symbol.  Here's why:
   23.20 -       -Looking for the path to the OpenGL Library seems not to work in the iPhone Simulator.
   23.21 -       -We don't know that the path won't change in the future.
   23.22 -    */
   23.23 +     * -Looking for the path to the OpenGL Library seems not to work in the iOS Simulator.
   23.24 +     * -We don't know that the path won't change in the future. */
   23.25      return dlsym(RTLD_DEFAULT, proc);
   23.26  }
   23.27  
   23.28  /*
   23.29 -    note that SDL_GL_Delete context makes it current without passing the window
   23.30 +  note that SDL_GL_DeleteContext makes it current without passing the window
   23.31  */
   23.32 -int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   23.33 +int
   23.34 +UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   23.35  {
   23.36 -    [EAGLContext setCurrentContext: context];
   23.37 +    @autoreleasepool {
   23.38 +        SDLEAGLContext *eaglcontext = (__bridge SDLEAGLContext *) context;
   23.39 +
   23.40 +        if (![EAGLContext setCurrentContext:eaglcontext]) {
   23.41 +            return SDL_SetError("Could not make EAGL context current");
   23.42 +        }
   23.43 +
   23.44 +        if (eaglcontext) {
   23.45 +            [eaglcontext.sdlView setSDLWindow:window];
   23.46 +        }
   23.47 +    }
   23.48 +
   23.49      return 0;
   23.50  }
   23.51  
   23.52 +void
   23.53 +UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
   23.54 +{
   23.55 +    @autoreleasepool {
   23.56 +        SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
   23.57 +        UIView *view = data.viewcontroller.view;
   23.58 +        if ([view isKindOfClass:[SDL_uikitopenglview class]]) {
   23.59 +            SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view;
   23.60 +            if (w) {
   23.61 +                *w = glview.backingWidth;
   23.62 +            }
   23.63 +            if (h) {
   23.64 +                *h = glview.backingHeight;
   23.65 +            }
   23.66 +        }
   23.67 +    }
   23.68 +}
   23.69 +
   23.70  int
   23.71  UIKit_GL_LoadLibrary(_THIS, const char *path)
   23.72  {
   23.73 -    /*
   23.74 -        shouldn't be passing a path into this function
   23.75 -        why?  Because we've already loaded the library
   23.76 -        and because the SDK forbids loading an external SO
   23.77 -    */
   23.78 +    /* We shouldn't pass a path to this function, since we've already loaded the
   23.79 +     * library. */
   23.80      if (path != NULL) {
   23.81 -        return SDL_SetError("iPhone GL Load Library just here for compatibility");
   23.82 +        return SDL_SetError("iOS GL Load Library just here for compatibility");
   23.83      }
   23.84      return 0;
   23.85  }
   23.86  
   23.87  void UIKit_GL_SwapWindow(_THIS, SDL_Window * window)
   23.88  {
   23.89 +    @autoreleasepool {
   23.90 +        SDLEAGLContext *context = (__bridge SDLEAGLContext *) SDL_GL_GetCurrentContext();
   23.91 +
   23.92  #if SDL_POWER_UIKIT
   23.93 -    /* Check once a frame to see if we should turn off the battery monitor. */
   23.94 -    SDL_UIKit_UpdateBatteryMonitoring();
   23.95 +        /* Check once a frame to see if we should turn off the battery monitor. */
   23.96 +        SDL_UIKit_UpdateBatteryMonitoring();
   23.97  #endif
   23.98  
   23.99 -    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
  23.100 +        [context.sdlView swapBuffers];
  23.101  
  23.102 -    if (nil == data->view) {
  23.103 -        return;
  23.104 +        /* You need to pump events in order for the OS to make changes visible.
  23.105 +         * We don't pump events here because we don't want iOS application events
  23.106 +         * (low memory, terminate, etc.) to happen inside low level rendering. */
  23.107      }
  23.108 -    [data->view swapBuffers];
  23.109 -
  23.110 -    /* You need to pump events in order for the OS to make changes visible.
  23.111 -       We don't pump events here because we don't want iOS application events
  23.112 -       (low memory, terminate, etc.) to happen inside low level rendering.
  23.113 -     */
  23.114  }
  23.115  
  23.116 -SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)
  23.117 +SDL_GLContext
  23.118 +UIKit_GL_CreateContext(_THIS, SDL_Window * window)
  23.119  {
  23.120 -    SDL_uikitopenglview *view;
  23.121 -    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  23.122 -    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  23.123 -    SDL_DisplayData *displaydata = display->driverdata;
  23.124 -    SDL_DisplayModeData *displaymodedata = display->current_mode.driverdata;
  23.125 -    UIWindow *uiwindow = data->uiwindow;
  23.126 -    EAGLSharegroup *share_group = nil;
  23.127 +    @autoreleasepool {
  23.128 +        SDL_uikitopenglview *view;
  23.129 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  23.130 +        CGRect frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
  23.131 +        EAGLSharegroup *sharegroup = nil;
  23.132 +        CGFloat scale = 1.0;
  23.133  
  23.134 -    if (_this->gl_config.share_with_current_context) {
  23.135 -        SDL_uikitopenglview *view = (SDL_uikitopenglview *) SDL_GL_GetCurrentContext();
  23.136 -        share_group = [view.context sharegroup];
  23.137 +        if (_this->gl_config.share_with_current_context) {
  23.138 +            EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext();
  23.139 +            sharegroup = context.sharegroup;
  23.140 +        }
  23.141 +
  23.142 +        if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  23.143 +            /* Set the scale to the natural scale factor of the screen - the
  23.144 +             * backing dimensions of the OpenGL view will match the pixel
  23.145 +             * dimensions of the screen rather than the dimensions in points. */
  23.146 +#ifdef __IPHONE_8_0
  23.147 +            if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) {
  23.148 +                scale = data.uiwindow.screen.nativeScale;
  23.149 +            } else
  23.150 +#endif
  23.151 +            {
  23.152 +                scale = data.uiwindow.screen.scale;
  23.153 +            }
  23.154 +        }
  23.155 +
  23.156 +        /* construct our view, passing in SDL's OpenGL configuration data */
  23.157 +        view = [[SDL_uikitopenglview alloc] initWithFrame:frame
  23.158 +                                                    scale:scale
  23.159 +                                            retainBacking:_this->gl_config.retained_backing
  23.160 +                                                    rBits:_this->gl_config.red_size
  23.161 +                                                    gBits:_this->gl_config.green_size
  23.162 +                                                    bBits:_this->gl_config.blue_size
  23.163 +                                                    aBits:_this->gl_config.alpha_size
  23.164 +                                                depthBits:_this->gl_config.depth_size
  23.165 +                                              stencilBits:_this->gl_config.stencil_size
  23.166 +                                                     sRGB:_this->gl_config.framebuffer_srgb_capable
  23.167 +                                             majorVersion:_this->gl_config.major_version
  23.168 +                                               shareGroup:sharegroup];
  23.169 +        if (!view) {
  23.170 +            return NULL;
  23.171 +        }
  23.172 +
  23.173 +        SDLEAGLContext *context = view.context;
  23.174 +        if (UIKit_GL_MakeCurrent(_this, window, (__bridge SDL_GLContext) context) < 0) {
  23.175 +            UIKit_GL_DeleteContext(_this, (SDL_GLContext) CFBridgingRetain(context));
  23.176 +            return NULL;
  23.177 +        }
  23.178 +
  23.179 +        /* We return a +1'd context. The window's driverdata owns the view (via
  23.180 +         * MakeCurrent.) */
  23.181 +        return (SDL_GLContext) CFBridgingRetain(context);
  23.182      }
  23.183 -
  23.184 -    /* construct our view, passing in SDL's OpenGL configuration data */
  23.185 -    CGRect frame;
  23.186 -    if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
  23.187 -        frame = [displaydata->uiscreen bounds];
  23.188 -    } else {
  23.189 -        frame = [displaydata->uiscreen applicationFrame];
  23.190 -    }
  23.191 -    view = [[SDL_uikitopenglview alloc] initWithFrame: frame
  23.192 -                                    scale: displaymodedata->scale
  23.193 -                                    retainBacking: _this->gl_config.retained_backing
  23.194 -                                    rBits: _this->gl_config.red_size
  23.195 -                                    gBits: _this->gl_config.green_size
  23.196 -                                    bBits: _this->gl_config.blue_size
  23.197 -                                    aBits: _this->gl_config.alpha_size
  23.198 -                                    depthBits: _this->gl_config.depth_size
  23.199 -                                    stencilBits: _this->gl_config.stencil_size
  23.200 -                                    majorVersion: _this->gl_config.major_version
  23.201 -                                    shareGroup: share_group];
  23.202 -    if (!view) {
  23.203 -        return NULL;
  23.204 -    }
  23.205 -
  23.206 -    data->view = view;
  23.207 -    view->viewcontroller = data->viewcontroller;
  23.208 -    if (view->viewcontroller != nil) {
  23.209 -        [view->viewcontroller setView:view];
  23.210 -        [view->viewcontroller retain];
  23.211 -    }
  23.212 -    [uiwindow addSubview: view];
  23.213 -
  23.214 -    /* The view controller needs to be the root in order to control rotation on iOS 6.0 */
  23.215 -    if (uiwindow.rootViewController == nil) {
  23.216 -        uiwindow.rootViewController = view->viewcontroller;
  23.217 -    }
  23.218 -
  23.219 -    EAGLContext *context = view.context;
  23.220 -    if (UIKit_GL_MakeCurrent(_this, window, context) < 0) {
  23.221 -        UIKit_GL_DeleteContext(_this, context);
  23.222 -        return NULL;
  23.223 -    }
  23.224 -
  23.225 -    /* Make this window the current mouse focus for touch input */
  23.226 -    if (displaydata->uiscreen == [UIScreen mainScreen]) {
  23.227 -        SDL_SetMouseFocus(window);
  23.228 -        SDL_SetKeyboardFocus(window);
  23.229 -    }
  23.230 -
  23.231 -    return context;
  23.232  }
  23.233  
  23.234 -void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context)
  23.235 +void
  23.236 +UIKit_GL_DeleteContext(_THIS, SDL_GLContext context)
  23.237  {
  23.238 -    SDL_Window *window;
  23.239 +    @autoreleasepool {
  23.240 +        /* Transfer ownership the +1'd context to ARC. */
  23.241 +        SDLEAGLContext *eaglcontext = (SDLEAGLContext *) CFBridgingRelease(context);
  23.242  
  23.243 -    /* Find the view associated with this context */
  23.244 -    for (window = _this->windows; window; window = window->next) {
  23.245 -        SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  23.246 -        SDL_uikitopenglview *view = data->view;
  23.247 -        if (view.context == context) {
  23.248 -            /* the delegate has retained the view, this will release him */
  23.249 -            if (view->viewcontroller) {
  23.250 -                UIWindow *uiwindow = (UIWindow *)view.superview;
  23.251 -                if (uiwindow.rootViewController == view->viewcontroller) {
  23.252 -                    uiwindow.rootViewController = nil;
  23.253 -                }
  23.254 -                [view->viewcontroller setView:nil];
  23.255 -                [view->viewcontroller release];
  23.256 -            }
  23.257 -            [view removeFromSuperview];
  23.258 -
  23.259 -            /* FIXME: This doesn't actually call view dealloc - what is holding a reference to it? */
  23.260 -            [view release];
  23.261 -            return;
  23.262 -        }
  23.263 +        /* Detach the context's view from its window. */
  23.264 +        [eaglcontext.sdlView setSDLWindow:NULL];
  23.265      }
  23.266 -
  23.267 -    /* View not found... delete the context anyway? */
  23.268 -    [(EAGLContext *)context release];
  23.269  }
  23.270  
  23.271  #endif /* SDL_VIDEO_DRIVER_UIKIT */
    24.1 --- a/src/video/uikit/SDL_uikitopenglview.h	Thu Apr 09 22:14:05 2015 +0200
    24.2 +++ b/src/video/uikit/SDL_uikitopenglview.h	Thu Apr 09 22:28:37 2015 -0400
    24.3 @@ -21,66 +21,48 @@
    24.4  
    24.5  #import <UIKit/UIKit.h>
    24.6  #import <OpenGLES/EAGL.h>
    24.7 -#import <OpenGLES/ES1/gl.h>
    24.8 -#import <OpenGLES/ES1/glext.h>
    24.9 +#import <OpenGLES/ES2/gl.h>
   24.10 +
   24.11  #import "SDL_uikitview.h"
   24.12 -/*
   24.13 -    This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
   24.14 -    The view content is basically an EAGL surface you render your OpenGL scene into.
   24.15 -    Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
   24.16 - */
   24.17 -@interface SDL_uikitopenglview : SDL_uikitview {
   24.18 +#include "SDL_uikitvideo.h"
   24.19  
   24.20 -@private
   24.21 -    /* The pixel dimensions of the backbuffer */
   24.22 -    GLint backingWidth;
   24.23 -    GLint backingHeight;
   24.24 +@class SDL_uikitopenglview;
   24.25  
   24.26 -    EAGLContext *context;
   24.27 +@interface SDLEAGLContext : EAGLContext
   24.28  
   24.29 -    /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
   24.30 -    GLuint viewRenderbuffer, viewFramebuffer;
   24.31 +@property (nonatomic, weak) SDL_uikitopenglview *sdlView;
   24.32  
   24.33 -    /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
   24.34 -    GLuint depthRenderbuffer;
   24.35 +@end
   24.36  
   24.37 -    /* format of depthRenderbuffer */
   24.38 -    GLenum depthBufferFormat;
   24.39 +@interface SDL_uikitopenglview : SDL_uikitview
   24.40  
   24.41 -    id displayLink;
   24.42 -    int animationInterval;
   24.43 -    void (*animationCallback)(void*);
   24.44 -    void *animationCallbackParam;
   24.45 -}
   24.46 +- (instancetype)initWithFrame:(CGRect)frame
   24.47 +                        scale:(CGFloat)scale
   24.48 +                retainBacking:(BOOL)retained
   24.49 +                        rBits:(int)rBits
   24.50 +                        gBits:(int)gBits
   24.51 +                        bBits:(int)bBits
   24.52 +                        aBits:(int)aBits
   24.53 +                    depthBits:(int)depthBits
   24.54 +                  stencilBits:(int)stencilBits
   24.55 +                         sRGB:(BOOL)sRGB
   24.56 +                 majorVersion:(int)majorVersion
   24.57 +                   shareGroup:(EAGLSharegroup*)shareGroup;
   24.58  
   24.59 -@property (nonatomic, retain, readonly) EAGLContext *context;
   24.60 +@property (nonatomic, readonly, strong) SDLEAGLContext *context;
   24.61 +
   24.62 +/* The width and height of the drawable in pixels (as opposed to points.) */
   24.63 +@property (nonatomic, readonly) int backingWidth;
   24.64 +@property (nonatomic, readonly) int backingHeight;
   24.65 +
   24.66 +@property (nonatomic, readonly) GLuint drawableRenderbuffer;
   24.67 +@property (nonatomic, readonly) GLuint drawableFramebuffer;
   24.68  
   24.69  - (void)swapBuffers;
   24.70  - (void)setCurrentContext;
   24.71  
   24.72 -- (id)initWithFrame:(CGRect)frame
   24.73 -    scale:(CGFloat)scale
   24.74 -    retainBacking:(BOOL)retained
   24.75 -    rBits:(int)rBits
   24.76 -    gBits:(int)gBits
   24.77 -    bBits:(int)bBits
   24.78 -    aBits:(int)aBits
   24.79 -    depthBits:(int)depthBits
   24.80 -    stencilBits:(int)stencilBits
   24.81 -    majorVersion:(int)majorVersion
   24.82 -    shareGroup:(EAGLSharegroup*)shareGroup;
   24.83 -
   24.84  - (void)updateFrame;
   24.85  
   24.86 -- (void)setAnimationCallback:(int)interval
   24.87 -    callback:(void (*)(void*))callback
   24.88 -    callbackParam:(void*)callbackParam;
   24.89 -
   24.90 -- (void)startAnimation;
   24.91 -- (void)stopAnimation;
   24.92 -
   24.93 -- (void)doLoop:(CADisplayLink*)sender;
   24.94 -
   24.95  @end
   24.96  
   24.97  /* vi: set ts=4 sw=4 expandtab: */
    25.1 --- a/src/video/uikit/SDL_uikitopenglview.m	Thu Apr 09 22:14:05 2015 +0200
    25.2 +++ b/src/video/uikit/SDL_uikitopenglview.m	Thu Apr 09 22:28:37 2015 -0400
    25.3 @@ -22,170 +22,190 @@
    25.4  
    25.5  #if SDL_VIDEO_DRIVER_UIKIT
    25.6  
    25.7 -#include <QuartzCore/QuartzCore.h>
    25.8  #include <OpenGLES/EAGLDrawable.h>
    25.9 -#include "SDL_uikitopenglview.h"
   25.10 -#include "SDL_uikitmessagebox.h"
   25.11 +#include <OpenGLES/ES2/glext.h>
   25.12 +#import "SDL_uikitopenglview.h"
   25.13 +#include "SDL_uikitwindow.h"
   25.14  
   25.15 +@implementation SDLEAGLContext
   25.16  
   25.17 -@implementation SDL_uikitopenglview
   25.18 +@end
   25.19 +
   25.20 +@implementation SDL_uikitopenglview {
   25.21 +    /* The renderbuffer and framebuffer used to render to this layer. */
   25.22 +    GLuint viewRenderbuffer, viewFramebuffer;
   25.23 +
   25.24 +    /* The depth buffer that is attached to viewFramebuffer, if it exists. */
   25.25 +    GLuint depthRenderbuffer;
   25.26 +
   25.27 +    /* format of depthRenderbuffer */
   25.28 +    GLenum depthBufferFormat;
   25.29 +}
   25.30  
   25.31  @synthesize context;
   25.32 +@synthesize backingWidth;
   25.33 +@synthesize backingHeight;
   25.34  
   25.35  + (Class)layerClass
   25.36  {
   25.37      return [CAEAGLLayer class];
   25.38  }
   25.39  
   25.40 -- (id)initWithFrame:(CGRect)frame
   25.41 -      scale:(CGFloat)scale
   25.42 -      retainBacking:(BOOL)retained
   25.43 -      rBits:(int)rBits
   25.44 -      gBits:(int)gBits
   25.45 -      bBits:(int)bBits
   25.46 -      aBits:(int)aBits
   25.47 -      depthBits:(int)depthBits
   25.48 -      stencilBits:(int)stencilBits
   25.49 -      majorVersion:(int)majorVersion
   25.50 -      shareGroup:(EAGLSharegroup*)shareGroup
   25.51 +- (instancetype)initWithFrame:(CGRect)frame
   25.52 +                        scale:(CGFloat)scale
   25.53 +                retainBacking:(BOOL)retained
   25.54 +                        rBits:(int)rBits
   25.55 +                        gBits:(int)gBits
   25.56 +                        bBits:(int)bBits
   25.57 +                        aBits:(int)aBits
   25.58 +                    depthBits:(int)depthBits
   25.59 +                  stencilBits:(int)stencilBits
   25.60 +                         sRGB:(BOOL)sRGB
   25.61 +                 majorVersion:(int)majorVersion
   25.62 +                   shareGroup:(EAGLSharegroup*)shareGroup
   25.63  {
   25.64 -    depthBufferFormat = 0;
   25.65 -
   25.66      if ((self = [super initWithFrame:frame])) {
   25.67          const BOOL useStencilBuffer = (stencilBits != 0);
   25.68          const BOOL useDepthBuffer = (depthBits != 0);
   25.69          NSString *colorFormat = nil;
   25.70  
   25.71          /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES
   25.72 -           versions, and this allows us to handle future OpenGL ES versions.
   25.73 -         */
   25.74 +         * versions, and this allows us to handle future OpenGL ES versions. */
   25.75          EAGLRenderingAPI api = majorVersion;
   25.76  
   25.77 -        if (rBits == 8 && gBits == 8 && bBits == 8) {
   25.78 -            /* if user specifically requests rbg888 or some color format higher than 16bpp */
   25.79 -            colorFormat = kEAGLColorFormatRGBA8;
   25.80 -        } else {
   25.81 -            /* default case (faster) */
   25.82 -            colorFormat = kEAGLColorFormatRGB565;
   25.83 -        }
   25.84 -
   25.85 -        /* Get the layer */
   25.86 -        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
   25.87 -
   25.88 -        eaglLayer.opaque = YES;
   25.89 -        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
   25.90 -                                        [NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil];
   25.91 -
   25.92 -        context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
   25.93 +        context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
   25.94          if (!context || ![EAGLContext setCurrentContext:context]) {
   25.95 -            [self release];
   25.96              SDL_SetError("OpenGL ES %d not supported", majorVersion);
   25.97              return nil;
   25.98          }
   25.99  
  25.100 +        context.sdlView = self;
  25.101 +
  25.102 +        if (sRGB) {
  25.103 +            /* sRGB EAGL drawable support was added in iOS 7. */
  25.104 +            if (UIKit_IsSystemVersionAtLeast(7.0)) {
  25.105 +                colorFormat = kEAGLColorFormatSRGBA8;
  25.106 +            } else {
  25.107 +                SDL_SetError("sRGB drawables are not supported.");
  25.108 +                return nil;
  25.109 +            }
  25.110 +        } else if (rBits >= 8 || gBits >= 8 || bBits >= 8) {
  25.111 +            /* if user specifically requests rbg888 or some color format higher than 16bpp */
  25.112 +            colorFormat = kEAGLColorFormatRGBA8;
  25.113 +        } else {
  25.114 +            /* default case (potentially faster) */
  25.115 +            colorFormat = kEAGLColorFormatRGB565;
  25.116 +        }
  25.117 +
  25.118 +        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
  25.119 +
  25.120 +        eaglLayer.opaque = YES;
  25.121 +        eaglLayer.drawableProperties = @{
  25.122 +            kEAGLDrawablePropertyRetainedBacking:@(retained),
  25.123 +            kEAGLDrawablePropertyColorFormat:colorFormat
  25.124 +        };
  25.125 +
  25.126          /* Set the appropriate scale (for retina display support) */
  25.127          self.contentScaleFactor = scale;
  25.128  
  25.129 -        /* create the buffers */
  25.130 -        glGenFramebuffersOES(1, &viewFramebuffer);
  25.131 -        glGenRenderbuffersOES(1, &viewRenderbuffer);
  25.132 +        /* Create the color Renderbuffer Object */
  25.133 +        glGenRenderbuffers(1, &viewRenderbuffer);
  25.134 +        glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
  25.135  
  25.136 -        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  25.137 -        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  25.138 -        [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
  25.139 -        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
  25.140 +        if (![context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer]) {
  25.141 +            SDL_SetError("Failed to create OpenGL ES drawable");
  25.142 +            return nil;
  25.143 +        }
  25.144  
  25.145 -        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
  25.146 -        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
  25.147 +        /* Create the Framebuffer Object */
  25.148 +        glGenFramebuffers(1, &viewFramebuffer);
  25.149 +        glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
  25.150 +
  25.151 +        /* attach the color renderbuffer to the FBO */
  25.152 +        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewRenderbuffer);
  25.153 +
  25.154 +        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
  25.155 +        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
  25.156  
  25.157          if ((useDepthBuffer) || (useStencilBuffer)) {
  25.158              if (useStencilBuffer) {
  25.159                  /* Apparently you need to pack stencil and depth into one buffer. */
  25.160                  depthBufferFormat = GL_DEPTH24_STENCIL8_OES;
  25.161              } else if (useDepthBuffer) {
  25.162 -                /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */
  25.163 +                /* iOS only uses 32-bit float (exposed as fixed point 24-bit)
  25.164 +                 * depth buffers. */
  25.165                  depthBufferFormat = GL_DEPTH_COMPONENT24_OES;
  25.166              }
  25.167  
  25.168 -            glGenRenderbuffersOES(1, &depthRenderbuffer);
  25.169 -            glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
  25.170 -            glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
  25.171 +            glGenRenderbuffers(1, &depthRenderbuffer);
  25.172 +            glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
  25.173 +            glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight);
  25.174              if (useDepthBuffer) {
  25.175 -                glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
  25.176 +                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
  25.177              }
  25.178              if (useStencilBuffer) {
  25.179 -                glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
  25.180 +                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
  25.181              }
  25.182          }
  25.183  
  25.184 -        if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
  25.185 -            return NO;
  25.186 +        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  25.187 +            SDL_SetError("Failed creating OpenGL ES framebuffer");
  25.188 +            return nil;
  25.189          }
  25.190  
  25.191 -        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  25.192 -        /* end create buffers */
  25.193 +        glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
  25.194  
  25.195 -        self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
  25.196 -        self.autoresizesSubviews = YES;
  25.197 +        [self setDebugLabels];
  25.198      }
  25.199 +
  25.200      return self;
  25.201  }
  25.202  
  25.203 +- (GLuint)drawableRenderbuffer
  25.204 +{
  25.205 +    return viewRenderbuffer;
  25.206 +}
  25.207 +
  25.208 +- (GLuint)drawableFramebuffer
  25.209 +{
  25.210 +    return viewFramebuffer;
  25.211 +}
  25.212 +
  25.213  - (void)updateFrame
  25.214  {
  25.215 -    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  25.216 -    glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
  25.217 -    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0);
  25.218 -    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
  25.219 +    GLint prevRenderbuffer = 0;
  25.220 +    glGetIntegerv(GL_RENDERBUFFER_BINDING, &prevRenderbuffer);
  25.221  
  25.222 -    glGenRenderbuffersOES(1, &viewRenderbuffer);
  25.223 -    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  25.224 -    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
  25.225 -    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
  25.226 +    glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
  25.227 +    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
  25.228  
  25.229 -    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
  25.230 -    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
  25.231 +    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
  25.232 +    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
  25.233  
  25.234      if (depthRenderbuffer != 0) {
  25.235 -        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
  25.236 -        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
  25.237 +        glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
  25.238 +        glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight);
  25.239      }
  25.240  
  25.241 -    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  25.242 +    glBindRenderbuffer(GL_RENDERBUFFER, prevRenderbuffer);
  25.243  }
  25.244  
  25.245 -- (void)setAnimationCallback:(int)interval
  25.246 -    callback:(void (*)(void*))callback
  25.247 -    callbackParam:(void*)callbackParam
  25.248 +- (void)setDebugLabels
  25.249  {
  25.250 -    [self stopAnimation];
  25.251 +    if (viewFramebuffer != 0) {
  25.252 +        glLabelObjectEXT(GL_FRAMEBUFFER, viewFramebuffer, 0, "context FBO");
  25.253 +    }
  25.254  
  25.255 -    animationInterval = interval;
  25.256 -    animationCallback = callback;
  25.257 -    animationCallbackParam = callbackParam;
  25.258 +    if (viewRenderbuffer != 0) {
  25.259 +        glLabelObjectEXT(GL_RENDERBUFFER, viewRenderbuffer, 0, "context color buffer");
  25.260 +    }
  25.261  
  25.262 -    if (animationCallback)
  25.263 -        [self startAnimation];
  25.264 -}
  25.265 -
  25.266 -- (void)startAnimation
  25.267 -{
  25.268 -    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
  25.269 -    [displayLink setFrameInterval:animationInterval];
  25.270 -    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  25.271 -}
  25.272 -
  25.273 -- (void)stopAnimation
  25.274 -{
  25.275 -    [displayLink invalidate];
  25.276 -    displayLink = nil;
  25.277 -}
  25.278 -
  25.279 -- (void)doLoop:(CADisplayLink*)sender
  25.280 -{
  25.281 -    /* Don't run the game loop while a messagebox is up */
  25.282 -    if (!UIKit_ShowingMessageBox()) {
  25.283 -        animationCallback(animationCallbackParam);
  25.284 +    if (depthRenderbuffer != 0) {
  25.285 +        if (depthBufferFormat == GL_DEPTH24_STENCIL8_OES) {
  25.286 +            glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth-stencil buffer");
  25.287 +        } else {
  25.288 +            glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth buffer");
  25.289 +        }
  25.290      }
  25.291  }
  25.292  
  25.293 @@ -194,44 +214,60 @@
  25.294      [EAGLContext setCurrentContext:context];
  25.295  }
  25.296  
  25.297 -
  25.298  - (void)swapBuffers
  25.299  {
  25.300      /* viewRenderbuffer should always be bound here. Code that binds something
  25.301 -        else is responsible for rebinding viewRenderbuffer, to reduce
  25.302 -        duplicate state changes. */
  25.303 -    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  25.304 +     * else is responsible for rebinding viewRenderbuffer, to reduce duplicate
  25.305 +     * state changes. */
  25.306 +    [context presentRenderbuffer:GL_RENDERBUFFER];
  25.307  }
  25.308  
  25.309 -
  25.310  - (void)layoutSubviews
  25.311  {
  25.312 -    [EAGLContext setCurrentContext:context];
  25.313 -    [self updateFrame];
  25.314 +    [super layoutSubviews];
  25.315 +
  25.316 +    int width  = (int) (self.bounds.size.width * self.contentScaleFactor);
  25.317 +    int height = (int) (self.bounds.size.height * self.contentScaleFactor);
  25.318 +
  25.319 +    /* Update the color and depth buffer storage if the layer size has changed. */
  25.320 +    if (width != backingWidth || height != backingHeight) {
  25.321 +        EAGLContext *prevContext = [EAGLContext currentContext];
  25.322 +        if (prevContext != context) {
  25.323 +            [EAGLContext setCurrentContext:context];
  25.324 +        }
  25.325 +
  25.326 +        [self updateFrame];
  25.327 +
  25.328 +        if (prevContext != context) {
  25.329 +            [EAGLContext setCurrentContext:prevContext];
  25.330 +        }
  25.331 +    }
  25.332  }
  25.333  
  25.334  - (void)destroyFramebuffer
  25.335  {
  25.336 -    glDeleteFramebuffersOES(1, &viewFramebuffer);
  25.337 -    viewFramebuffer = 0;
  25.338 -    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
  25.339 -    viewRenderbuffer = 0;
  25.340 +    if (viewFramebuffer != 0) {
  25.341 +        glDeleteFramebuffers(1, &viewFramebuffer);
  25.342 +        viewFramebuffer = 0;
  25.343 +    }
  25.344  
  25.345 -    if (depthRenderbuffer) {
  25.346 -        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
  25.347 +    if (viewRenderbuffer != 0) {
  25.348 +        glDeleteRenderbuffers(1, &viewRenderbuffer);
  25.349 +        viewRenderbuffer = 0;
  25.350 +    }
  25.351 +
  25.352 +    if (depthRenderbuffer != 0) {
  25.353 +        glDeleteRenderbuffers(1, &depthRenderbuffer);
  25.354          depthRenderbuffer = 0;
  25.355      }
  25.356  }
  25.357  
  25.358 -
  25.359  - (void)dealloc
  25.360  {
  25.361 -    [self destroyFramebuffer];
  25.362      if ([EAGLContext currentContext] == context) {
  25.363 +        [self destroyFramebuffer];
  25.364          [EAGLContext setCurrentContext:nil];
  25.365      }
  25.366 -    [context release];
  25.367 -    [super dealloc];
  25.368  }
  25.369  
  25.370  @end
    26.1 --- a/src/video/uikit/SDL_uikitvideo.h	Thu Apr 09 22:14:05 2015 +0200
    26.2 +++ b/src/video/uikit/SDL_uikitvideo.h	Thu Apr 09 22:28:37 2015 -0400
    26.3 @@ -25,20 +25,8 @@
    26.4  
    26.5  #include "../SDL_sysvideo.h"
    26.6  
    26.7 -#ifndef __IPHONE_6_0
    26.8 -/* 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 */
    26.9 -enum UIInterfaceOrientationMask
   26.10 -{
   26.11 -    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
   26.12 -    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
   26.13 -    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
   26.14 -    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
   26.15 -    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
   26.16 -    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
   26.17 -    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
   26.18 -};
   26.19 -#endif /* !__IPHONE_6_0 */
   26.20 -
   26.21 +BOOL UIKit_IsSystemVersionAtLeast(double version);
   26.22 +CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen);
   26.23  
   26.24  #endif /* _SDL_uikitvideo_h */
   26.25  
    27.1 --- a/src/video/uikit/SDL_uikitvideo.m	Thu Apr 09 22:14:05 2015 +0200
    27.2 +++ b/src/video/uikit/SDL_uikitvideo.m	Thu Apr 09 22:28:37 2015 -0400
    27.3 @@ -75,15 +75,15 @@
    27.4      device->SetDisplayMode = UIKit_SetDisplayMode;
    27.5      device->PumpEvents = UIKit_PumpEvents;
    27.6      device->CreateWindow = UIKit_CreateWindow;
    27.7 +    device->SetWindowTitle = UIKit_SetWindowTitle;
    27.8      device->ShowWindow = UIKit_ShowWindow;
    27.9      device->HideWindow = UIKit_HideWindow;
   27.10      device->RaiseWindow = UIKit_RaiseWindow;
   27.11 +    device->SetWindowBordered = UIKit_SetWindowBordered;
   27.12      device->SetWindowFullscreen = UIKit_SetWindowFullscreen;
   27.13      device->DestroyWindow = UIKit_DestroyWindow;
   27.14      device->GetWindowWMInfo = UIKit_GetWindowWMInfo;
   27.15  
   27.16 -    /* !!! FIXME: implement SetWindowBordered */
   27.17 -
   27.18  #if SDL_IPHONE_KEYBOARD
   27.19      device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport;
   27.20      device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard;
   27.21 @@ -93,12 +93,13 @@
   27.22  #endif
   27.23  
   27.24      /* OpenGL (ES) functions */
   27.25 -    device->GL_MakeCurrent        = UIKit_GL_MakeCurrent;
   27.26 -    device->GL_SwapWindow        = UIKit_GL_SwapWindow;
   27.27 +    device->GL_MakeCurrent      = UIKit_GL_MakeCurrent;
   27.28 +    device->GL_GetDrawableSize  = UIKit_GL_GetDrawableSize;
   27.29 +    device->GL_SwapWindow       = UIKit_GL_SwapWindow;
   27.30      device->GL_CreateContext    = UIKit_GL_CreateContext;
   27.31      device->GL_DeleteContext    = UIKit_GL_DeleteContext;
   27.32      device->GL_GetProcAddress   = UIKit_GL_GetProcAddress;
   27.33 -    device->GL_LoadLibrary        = UIKit_GL_LoadLibrary;
   27.34 +    device->GL_LoadLibrary      = UIKit_GL_LoadLibrary;
   27.35      device->free = UIKit_DeleteDevice;
   27.36  
   27.37      device->gl_config.accelerated = 1;
   27.38 @@ -129,6 +130,25 @@
   27.39      UIKit_QuitModes(_this);
   27.40  }
   27.41  
   27.42 +BOOL
   27.43 +UIKit_IsSystemVersionAtLeast(double version)
   27.44 +{
   27.45 +    return [[UIDevice currentDevice].systemVersion doubleValue] >= version;
   27.46 +}
   27.47 +
   27.48 +CGRect
   27.49 +UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
   27.50 +{
   27.51 +    BOOL hasiOS7 = UIKit_IsSystemVersionAtLeast(7.0);
   27.52 +
   27.53 +    if (hasiOS7 || (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN))) {
   27.54 +        /* The view should always show behind the status bar in iOS 7+. */
   27.55 +        return screen.bounds;
   27.56 +    } else {
   27.57 +        return screen.applicationFrame;
   27.58 +    }
   27.59 +}
   27.60 +
   27.61  /*
   27.62   * iOS log support.
   27.63   *
    28.1 --- a/src/video/uikit/SDL_uikitview.h	Thu Apr 09 22:14:05 2015 +0200
    28.2 +++ b/src/video/uikit/SDL_uikitview.h	Thu Apr 09 22:28:37 2015 -0400
    28.3 @@ -20,59 +20,22 @@
    28.4  */
    28.5  
    28.6  #import <UIKit/UIKit.h>
    28.7 -#import "SDL_uikitviewcontroller.h"
    28.8 +
    28.9 +#include "../SDL_sysvideo.h"
   28.10  
   28.11  #include "SDL_touch.h"
   28.12  
   28.13 -#define IPHONE_TOUCH_EFFICIENT_DANGEROUS
   28.14 +@interface SDL_uikitview : UIView
   28.15  
   28.16 -#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   28.17 -#define MAX_SIMULTANEOUS_TOUCHES 5
   28.18 -#endif
   28.19 +- (instancetype)initWithFrame:(CGRect)frame;
   28.20  
   28.21 -#if SDL_IPHONE_KEYBOARD
   28.22 -@interface SDL_uikitview : UIView<UITextFieldDelegate> {
   28.23 -#else
   28.24 -@interface SDL_uikitview : UIView {
   28.25 -#endif
   28.26 +- (void)setSDLWindow:(SDL_Window *)window;
   28.27  
   28.28 -    SDL_TouchID touchId;
   28.29 -    UITouch *leftFingerDown;
   28.30 -#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   28.31 -    UITouch *finger[MAX_SIMULTANEOUS_TOUCHES];
   28.32 -#endif
   28.33 -
   28.34 -#if SDL_IPHONE_KEYBOARD
   28.35 -    UITextField *textField;
   28.36 -    BOOL keyboardVisible;
   28.37 -    SDL_Rect textInputRect;
   28.38 -    int keyboardHeight;
   28.39 -#endif
   28.40 -
   28.41 -@public
   28.42 -    SDL_uikitviewcontroller *viewcontroller;
   28.43 -}
   28.44  - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize;
   28.45  - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
   28.46  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
   28.47  - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
   28.48  
   28.49 -#if SDL_IPHONE_KEYBOARD
   28.50 -- (void)showKeyboard;
   28.51 -- (void)hideKeyboard;
   28.52 -- (void)initializeKeyboard;
   28.53 -@property (readonly) BOOL keyboardVisible;
   28.54 -@property (nonatomic,assign) SDL_Rect textInputRect;
   28.55 -@property (nonatomic,assign) int keyboardHeight;
   28.56 -
   28.57 -SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
   28.58 -void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
   28.59 -void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
   28.60 -SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
   28.61 -void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
   28.62 -
   28.63 -#endif
   28.64 -
   28.65  @end
   28.66  
   28.67  /* vi: set ts=4 sw=4 expandtab: */
    29.1 --- a/src/video/uikit/SDL_uikitview.m	Thu Apr 09 22:14:05 2015 +0200
    29.2 +++ b/src/video/uikit/SDL_uikitview.m	Thu Apr 09 22:28:37 2015 -0400
    29.3 @@ -24,438 +24,167 @@
    29.4  
    29.5  #include "SDL_uikitview.h"
    29.6  
    29.7 -#include "../../events/SDL_keyboard_c.h"
    29.8  #include "../../events/SDL_mouse_c.h"
    29.9  #include "../../events/SDL_touch_c.h"
   29.10 +#include "../../events/SDL_events_c.h"
   29.11  
   29.12 -#if SDL_IPHONE_KEYBOARD
   29.13 -#include "keyinfotable.h"
   29.14 -#endif
   29.15 -#include "SDL_uikitappdelegate.h"
   29.16 -#include "SDL_uikitmodes.h"
   29.17 -#include "SDL_uikitwindow.h"
   29.18 +#import "SDL_uikitappdelegate.h"
   29.19 +#import "SDL_uikitmodes.h"
   29.20 +#import "SDL_uikitwindow.h"
   29.21  
   29.22 -void _uikit_keyboard_init() ;
   29.23 +@implementation SDL_uikitview {
   29.24 +    SDL_Window *sdlwindow;
   29.25  
   29.26 -@implementation SDL_uikitview
   29.27 -
   29.28 -- (void)dealloc
   29.29 -{
   29.30 -    [super dealloc];
   29.31 +    SDL_TouchID touchId;
   29.32 +    UITouch * __weak firstFingerDown;
   29.33  }
   29.34  
   29.35 -- (id)initWithFrame:(CGRect)frame
   29.36 +- (instancetype)initWithFrame:(CGRect)frame
   29.37  {
   29.38 -    self = [super initWithFrame: frame];
   29.39 +    if ((self = [super initWithFrame:frame])) {
   29.40 +        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
   29.41 +        self.autoresizesSubviews = YES;
   29.42  
   29.43 -#if SDL_IPHONE_KEYBOARD
   29.44 -    [self initializeKeyboard];
   29.45 -#endif
   29.46 +        self.multipleTouchEnabled = YES;
   29.47  
   29.48 -    self.multipleTouchEnabled = YES;
   29.49 -
   29.50 -    touchId = 1;
   29.51 -    SDL_AddTouch(touchId, "");
   29.52 +        touchId = 1;
   29.53 +        SDL_AddTouch(touchId, "");
   29.54 +    }
   29.55  
   29.56      return self;
   29.57 +}
   29.58  
   29.59 +- (void)setSDLWindow:(SDL_Window *)window
   29.60 +{
   29.61 +    SDL_WindowData *data = nil;
   29.62 +
   29.63 +    if (window == sdlwindow) {
   29.64 +        return;
   29.65 +    }
   29.66 +
   29.67 +    if (sdlwindow) {
   29.68 +        SDL_uikitview *view = nil;
   29.69 +        data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
   29.70 +
   29.71 +        [data.views removeObject:self];
   29.72 +
   29.73 +        [self removeFromSuperview];
   29.74 +
   29.75 +        /* Restore the next-oldest view in the old window. */
   29.76 +        if (data.views.count > 0) {
   29.77 +            view = data.views[data.views.count - 1];
   29.78 +        }
   29.79 +
   29.80 +        data.viewcontroller.view = view;
   29.81 +
   29.82 +        if (data.uiwindow.rootViewController != data.viewcontroller) {
   29.83 +            data.uiwindow.rootViewController = data.viewcontroller;
   29.84 +        } else if (view) {
   29.85 +            [data.uiwindow addSubview:view];
   29.86 +        }
   29.87 +
   29.88 +        [data.uiwindow layoutIfNeeded];
   29.89 +    }
   29.90 +
   29.91 +    if (window) {
   29.92 +        data = (__bridge SDL_WindowData *) window->driverdata;
   29.93 +
   29.94 +        /* Make sure the SDL window has a strong reference to this view. */
   29.95 +        [data.views addObject:self];
   29.96 +
   29.97 +        /* Replace the view controller's old view with this one. */
   29.98 +        [data.viewcontroller.view removeFromSuperview];
   29.99 +        data.viewcontroller.view = self;
  29.100 +
  29.101 +        if (data.uiwindow.rootViewController != data.viewcontroller) {
  29.102 +            /* The root view controller handles rotation and the status bar.
  29.103 +             * Assigning it also adds the controller's view to the window. */
  29.104 +            data.uiwindow.rootViewController = data.viewcontroller;
  29.105 +        } else {
  29.106 +            [data.uiwindow addSubview:self];
  29.107 +        }
  29.108 +
  29.109 +        /* The view's bounds may not be correct until the next event cycle. That
  29.110 +         * might happen after the current dimensions are queried, so we force a
  29.111 +         * layout now to immediately update the bounds. */
  29.112 +        [data.uiwindow layoutIfNeeded];
  29.113 +    }
  29.114 +
  29.115 +    sdlwindow = window;
  29.116  }
  29.117  
  29.118  - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
  29.119  {
  29.120 -    CGPoint point = [touch locationInView: self];
  29.121 -
  29.122 -    /* Get the display scale and apply that to the input coordinates */
  29.123 -    SDL_Window *window = self->viewcontroller.window;
  29.124 -    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  29.125 -    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
  29.126 +    CGPoint point = [touch locationInView:self];
  29.127  
  29.128      if (normalize) {
  29.129 -        CGRect bounds = [self bounds];
  29.130 +        CGRect bounds = self.bounds;
  29.131          point.x /= bounds.size.width;
  29.132          point.y /= bounds.size.height;
  29.133 -    } else {
  29.134 -        point.x *= displaymodedata->scale;
  29.135 -        point.y *= displaymodedata->scale;
  29.136      }
  29.137 +
  29.138      return point;
  29.139  }
  29.140  
  29.141  - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  29.142  {
  29.143 -    NSEnumerator *enumerator = [touches objectEnumerator];
  29.144 -    UITouch *touch = (UITouch*)[enumerator nextObject];
  29.145 -
  29.146 -    while (touch) {
  29.147 -        if (!leftFingerDown) {
  29.148 +    for (UITouch *touch in touches) {
  29.149 +        if (!firstFingerDown) {
  29.150              CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
  29.151  
  29.152 -            /* send moved event */
  29.153 -            SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
  29.154 +            /* send mouse moved event */
  29.155 +            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
  29.156  
  29.157              /* send mouse down event */
  29.158 -            SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
  29.159 +            SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
  29.160  
  29.161 -            leftFingerDown = touch;
  29.162 +            firstFingerDown = touch;
  29.163          }
  29.164  
  29.165          CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
  29.166 -#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
  29.167 -        /* FIXME: TODO: Using touch as the fingerId is potentially dangerous
  29.168 -         * It is also much more efficient than storing the UITouch pointer
  29.169 -         * and comparing it to the incoming event.
  29.170 -         */
  29.171          SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
  29.172                        SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
  29.173 -#else
  29.174 -        int i;
  29.175 -        for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
  29.176 -            if (finger[i] == NULL) {
  29.177 -                finger[i] = touch;
  29.178 -                SDL_SendTouch(touchId, i,
  29.179 -                              SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
  29.180 -                break;
  29.181 -            }
  29.182 -        }
  29.183 -#endif
  29.184 -        touch = (UITouch*)[enumerator nextObject];
  29.185      }
  29.186  }
  29.187  
  29.188  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
  29.189  {
  29.190 -    NSEnumerator *enumerator = [touches objectEnumerator];
  29.191 -    UITouch *touch = (UITouch*)[enumerator nextObject];
  29.192 -
  29.193 -    while(touch) {
  29.194 -        if (touch == leftFingerDown) {
  29.195 +    for (UITouch *touch in touches) {
  29.196 +        if (touch == firstFingerDown) {
  29.197              /* send mouse up */
  29.198 -            SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
  29.199 -            leftFingerDown = nil;
  29.200 +            SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
  29.201 +            firstFingerDown = nil;
  29.202          }
  29.203  
  29.204          CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
  29.205 -#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
  29.206 -        SDL_SendTouch(touchId, (long)touch,
  29.207 +        SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
  29.208                        SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
  29.209 -#else
  29.210 -        int i;
  29.211 -        for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
  29.212 -            if (finger[i] == touch) {
  29.213 -                SDL_SendTouch(touchId, i,
  29.214 -                              SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
  29.215 -                finger[i] = NULL;
  29.216 -                break;
  29.217 -            }
  29.218 -        }
  29.219 -#endif
  29.220 -        touch = (UITouch*)[enumerator nextObject];
  29.221      }
  29.222  }
  29.223  
  29.224  - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
  29.225  {
  29.226 -    /*
  29.227 -        this can happen if the user puts more than 5 touches on the screen
  29.228 -        at once, or perhaps in other circumstances.  Usually (it seems)
  29.229 -        all active touches are canceled.
  29.230 -    */
  29.231 -    [self touchesEnded: touches withEvent: event];
  29.232 +    [self touchesEnded:touches withEvent:event];
  29.233  }
  29.234  
  29.235  - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
  29.236  {
  29.237 -    NSEnumerator *enumerator = [touches objectEnumerator];
  29.238 -    UITouch *touch = (UITouch*)[enumerator nextObject];
  29.239 -
  29.240 -    while (touch) {
  29.241 -        if (touch == leftFingerDown) {
  29.242 +    for (UITouch *touch in touches) {
  29.243 +        if (touch == firstFingerDown) {
  29.244              CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
  29.245  
  29.246              /* send moved event */
  29.247 -            SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
  29.248 +            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
  29.249          }
  29.250  
  29.251          CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
  29.252 -#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
  29.253 -        SDL_SendTouchMotion(touchId, (long)touch,
  29.254 +        SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
  29.255                              locationInView.x, locationInView.y, 1.0f);
  29.256 -#else
  29.257 -        int i;
  29.258 -        for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
  29.259 -            if (finger[i] == touch) {
  29.260 -                SDL_SendTouchMotion(touchId, i,
  29.261 -                                    locationInView.x, locationInView.y, 1.0f);
  29.262 -                break;
  29.263 -            }
  29.264 -        }
  29.265 -#endif
  29.266 -        touch = (UITouch*)[enumerator nextObject];
  29.267      }
  29.268  }
  29.269  
  29.270 -/*
  29.271 -    ---- Keyboard related functionality below this line ----
  29.272 -*/
  29.273 -#if SDL_IPHONE_KEYBOARD
  29.274 -
  29.275 -@synthesize textInputRect = textInputRect;
  29.276 -@synthesize keyboardHeight = keyboardHeight;
  29.277 -
  29.278 -/* Is the iPhone virtual keyboard visible onscreen? */
  29.279 -- (BOOL)keyboardVisible
  29.280 -{
  29.281 -    return keyboardVisible;
  29.282 -}
  29.283 -
  29.284 -/* Set ourselves up as a UITextFieldDelegate */
  29.285 -- (void)initializeKeyboard
  29.286 -{
  29.287 -    textField = [[UITextField alloc] initWithFrame: CGRectZero];
  29.288 -    textField.delegate = self;
  29.289 -    /* placeholder so there is something to delete! */
  29.290 -    textField.text = @" ";
  29.291 -
  29.292 -    /* set UITextInputTrait properties, mostly to defaults */
  29.293 -    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
  29.294 -    textField.autocorrectionType = UITextAutocorrectionTypeNo;
  29.295 -    textField.enablesReturnKeyAutomatically = NO;
  29.296 -    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
  29.297 -    textField.keyboardType = UIKeyboardTypeDefault;
  29.298 -    textField.returnKeyType = UIReturnKeyDefault;
  29.299 -    textField.secureTextEntry = NO;
  29.300 -
  29.301 -    textField.hidden = YES;
  29.302 -    keyboardVisible = NO;
  29.303 -    /* add the UITextField (hidden) to our view */
  29.304 -    [self addSubview: textField];
  29.305 -    [textField release];
  29.306 -    
  29.307 -    _uikit_keyboard_init();
  29.308 -}
  29.309 -
  29.310 -/* reveal onscreen virtual keyboard */
  29.311 -- (void)showKeyboard
  29.312 -{
  29.313 -    keyboardVisible = YES;
  29.314 -    [textField becomeFirstResponder];
  29.315 -}
  29.316 -
  29.317 -/* hide onscreen virtual keyboard */
  29.318 -- (void)hideKeyboard
  29.319 -{
  29.320 -    keyboardVisible = NO;
  29.321 -    [textField resignFirstResponder];
  29.322 -}
  29.323 -
  29.324 -/* UITextFieldDelegate method.  Invoked when user types something. */
  29.325 -- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
  29.326 -{
  29.327 -    if ([string length] == 0) {
  29.328 -        /* it wants to replace text with nothing, ie a delete */
  29.329 -        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
  29.330 -        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
  29.331 -    }
  29.332 -    else {
  29.333 -        /* go through all the characters in the string we've been sent
  29.334 -           and convert them to key presses */
  29.335 -        int i;
  29.336 -        for (i = 0; i < [string length]; i++) {
  29.337 -
  29.338 -            unichar c = [string characterAtIndex: i];
  29.339 -
  29.340 -            Uint16 mod = 0;
  29.341 -            SDL_Scancode code;
  29.342 -
  29.343 -            if (c < 127) {
  29.344 -                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
  29.345 -                code = unicharToUIKeyInfoTable[c].code;
  29.346 -                mod  = unicharToUIKeyInfoTable[c].mod;
  29.347 -            }
  29.348 -            else {
  29.349 -                /* we only deal with ASCII right now */
  29.350 -                code = SDL_SCANCODE_UNKNOWN;
  29.351 -                mod = 0;
  29.352 -            }
  29.353 -
  29.354 -            if (mod & KMOD_SHIFT) {
  29.355 -                /* If character uses shift, press shift down */
  29.356 -                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
  29.357 -            }
  29.358 -            /* send a keydown and keyup even for the character */
  29.359 -            SDL_SendKeyboardKey(SDL_PRESSED, code);
  29.360 -            SDL_SendKeyboardKey(SDL_RELEASED, code);
  29.361 -            if (mod & KMOD_SHIFT) {
  29.362 -                /* If character uses shift, press shift back up */
  29.363 -                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
  29.364 -            }
  29.365 -        }
  29.366 -        SDL_SendKeyboardText([string UTF8String]);
  29.367 -    }
  29.368 -    return NO; /* don't allow the edit! (keep placeholder text there) */
  29.369 -}
  29.370 -
  29.371 -/* Terminates the editing session */
  29.372 -- (BOOL)textFieldShouldReturn:(UITextField*)_textField
  29.373 -{
  29.374 -    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
  29.375 -    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
  29.376 -    SDL_StopTextInput();
  29.377 -    return YES;
  29.378 -}
  29.379 -
  29.380 -#endif
  29.381 -
  29.382  @end
  29.383  
  29.384 -/* iPhone keyboard addition functions */
  29.385 -#if SDL_IPHONE_KEYBOARD
  29.386 -
  29.387 -static SDL_uikitview * getWindowView(SDL_Window * window)
  29.388 -{
  29.389 -    if (window == NULL) {
  29.390 -        SDL_SetError("Window does not exist");
  29.391 -        return nil;
  29.392 -    }
  29.393 -
  29.394 -    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
  29.395 -    SDL_uikitview *view = data != NULL ? data->view : nil;
  29.396 -
  29.397 -    if (view == nil) {
  29.398 -        SDL_SetError("Window has no view");
  29.399 -    }
  29.400 -
  29.401 -    return view;
  29.402 -}
  29.403 -
  29.404 -SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
  29.405 -{
  29.406 -    return SDL_TRUE;
  29.407 -}
  29.408 -
  29.409 -void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
  29.410 -{
  29.411 -    SDL_uikitview *view = getWindowView(window);
  29.412 -    if (view != nil) {
  29.413 -        [view showKeyboard];
  29.414 -    }
  29.415 -}
  29.416 -
  29.417 -void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
  29.418 -{
  29.419 -    SDL_uikitview *view = getWindowView(window);
  29.420 -    if (view != nil) {
  29.421 -        [view hideKeyboard];
  29.422 -    }
  29.423 -}
  29.424 -
  29.425 -SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
  29.426 -{
  29.427 -    SDL_uikitview *view = getWindowView(window);
  29.428 -    if (view == nil) {
  29.429 -        return 0;
  29.430 -    }
  29.431 -
  29.432 -    return view.keyboardVisible;
  29.433 -}
  29.434 -
  29.435 -
  29.436 -void _uikit_keyboard_update() {
  29.437 -    SDL_Window *window = SDL_GetFocusWindow();
  29.438 -    if (!window) { return; }
  29.439 -    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
  29.440 -    if (!data) { return; }
  29.441 -    SDL_uikitview *view = data->view;
  29.442 -    if (!view) { return; }
  29.443 -    
  29.444 -    SDL_Rect r = view.textInputRect;
  29.445 -    int height = view.keyboardHeight;
  29.446 -    int offsetx = 0;
  29.447 -    int offsety = 0;
  29.448 -    float scale = [UIScreen mainScreen].scale;
  29.449 -    if (height) {
  29.450 -        int sw,sh;
  29.451 -        SDL_GetWindowSize(window,&sw,&sh);
  29.452 -        int bottom = (r.y + r.h);
  29.453 -        int kbottom = sh - height;
  29.454 -        if (kbottom < bottom) {
  29.455 -            offsety = kbottom-bottom;
  29.456 -        }
  29.457 -    }
  29.458 -    UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
  29.459 -    if (ui_orient == UIInterfaceOrientationLandscapeLeft) {
  29.460 -        int tmp = offsetx; offsetx = offsety; offsety = tmp;
  29.461 -    }
  29.462 -    if (ui_orient == UIInterfaceOrientationLandscapeRight) {
  29.463 -        offsety = -offsety;
  29.464 -        int tmp = offsetx; offsetx = offsety; offsety = tmp;
  29.465 -    }
  29.466 -    if (ui_orient == UIInterfaceOrientationPortraitUpsideDown) {
  29.467 -        offsety = -offsety;
  29.468 -    }
  29.469 -
  29.470 -    offsetx /= scale;
  29.471 -    offsety /= scale;
  29.472 -
  29.473 -    view.frame = CGRectMake(offsetx,offsety,view.frame.size.width,view.frame.size.height);
  29.474 -}
  29.475 -
  29.476 -void _uikit_keyboard_set_height(int height) {
  29.477 -    SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
  29.478 -    if (view == nil) {
  29.479 -        return ;
  29.480 -    }
  29.481 -    
  29.482 -    view.keyboardHeight = height;
  29.483 -    _uikit_keyboard_update();
  29.484 -}
  29.485 -
  29.486 -void _uikit_keyboard_init() {
  29.487 -    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  29.488 -    NSOperationQueue *queue = [NSOperationQueue mainQueue];
  29.489 -    [center addObserverForName:UIKeyboardWillShowNotification
  29.490 -                        object:nil
  29.491 -                         queue:queue
  29.492 -                    usingBlock:^(NSNotification *notification) {
  29.493 -                        int height = 0;
  29.494 -                        CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
  29.495 -                        height = keyboardSize.height;
  29.496 -                        UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
  29.497 -                        if (ui_orient == UIInterfaceOrientationLandscapeRight || ui_orient == UIInterfaceOrientationLandscapeLeft) {
  29.498 -                            height = keyboardSize.width;
  29.499 -                        }
  29.500 -                        height *= [UIScreen mainScreen].scale;
  29.501 -                        _uikit_keyboard_set_height(height);
  29.502 -                    }
  29.503 -     ];
  29.504 -    [center addObserverForName:UIKeyboardDidHideNotification
  29.505 -                        object:nil
  29.506 -                         queue:queue
  29.507 -                    usingBlock:^(NSNotification *notification) {
  29.508 -                        _uikit_keyboard_set_height(0);
  29.509 -                    }
  29.510 -     ];
  29.511 -}
  29.512 -
  29.513 -void
  29.514 -UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
  29.515 -{
  29.516 -    if (!rect) {
  29.517 -        SDL_InvalidParamError("rect");
  29.518 -        return;
  29.519 -    }
  29.520 -    
  29.521 -    SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
  29.522 -    if (view == nil) {
  29.523 -        return ;
  29.524 -    }
  29.525 -
  29.526 -    view.textInputRect = *rect;
  29.527 -}
  29.528 -
  29.529 -
  29.530 -#endif /* SDL_IPHONE_KEYBOARD */
  29.531 -
  29.532  #endif /* SDL_VIDEO_DRIVER_UIKIT */
  29.533  
  29.534  /* vi: set ts=4 sw=4 expandtab: */
    30.1 --- a/src/video/uikit/SDL_uikitviewcontroller.h	Thu Apr 09 22:14:05 2015 +0200
    30.2 +++ b/src/video/uikit/SDL_uikitviewcontroller.h	Thu Apr 09 22:28:37 2015 -0400
    30.3 @@ -23,18 +23,56 @@
    30.4  
    30.5  #include "../SDL_sysvideo.h"
    30.6  
    30.7 -@interface SDL_uikitviewcontroller : UIViewController {
    30.8 -@private
    30.9 -    SDL_Window *window;
   30.10 -}
   30.11 +#include "SDL_touch.h"
   30.12  
   30.13 -@property (readwrite) SDL_Window *window;
   30.14 +#if SDL_IPHONE_KEYBOARD
   30.15 +@interface SDL_uikitviewcontroller : UIViewController <UITextFieldDelegate>
   30.16 +#else
   30.17 +@interface SDL_uikitviewcontroller : UIViewController
   30.18 +#endif
   30.19  
   30.20 -- (id)initWithSDLWindow:(SDL_Window *)_window;
   30.21 +@property (nonatomic, assign) SDL_Window *window;
   30.22 +
   30.23 +- (instancetype)initWithSDLWindow:(SDL_Window *)_window;
   30.24 +
   30.25 +- (void)setAnimationCallback:(int)interval
   30.26 +                    callback:(void (*)(void*))callback
   30.27 +               callbackParam:(void*)callbackParam;
   30.28 +
   30.29 +- (void)startAnimation;
   30.30 +- (void)stopAnimation;
   30.31 +
   30.32 +- (void)doLoop:(CADisplayLink*)sender;
   30.33 +
   30.34  - (void)loadView;
   30.35  - (void)viewDidLayoutSubviews;
   30.36  - (NSUInteger)supportedInterfaceOrientations;
   30.37  - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient;
   30.38  - (BOOL)prefersStatusBarHidden;
   30.39 +- (UIStatusBarStyle)preferredStatusBarStyle;
   30.40 +
   30.41 +#if SDL_IPHONE_KEYBOARD
   30.42 +- (void)showKeyboard;
   30.43 +- (void)hideKeyboard;
   30.44 +- (void)initKeyboard;
   30.45 +- (void)deinitKeyboard;
   30.46 +
   30.47 +- (void)keyboardWillShow:(NSNotification *)notification;
   30.48 +- (void)keyboardWillHide:(NSNotification *)notification;
   30.49 +
   30.50 +- (void)updateKeyboard;
   30.51 +
   30.52 +@property (nonatomic, assign, getter=isKeyboardVisible) BOOL keyboardVisible;
   30.53 +@property (nonatomic, assign) SDL_Rect textInputRect;
   30.54 +@property (nonatomic, assign) int keyboardHeight;
   30.55 +#endif
   30.56  
   30.57  @end
   30.58 +
   30.59 +#if SDL_IPHONE_KEYBOARD
   30.60 +SDL_bool UIKit_HasScreenKeyboardSupport(_THIS);
   30.61 +void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window);
   30.62 +void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window);
   30.63 +SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window);
   30.64 +void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect);
   30.65 +#endif
    31.1 --- a/src/video/uikit/SDL_uikitviewcontroller.m	Thu Apr 09 22:14:05 2015 +0200
    31.2 +++ b/src/video/uikit/SDL_uikitviewcontroller.m	Thu Apr 09 22:28:37 2015 -0400
    31.3 @@ -28,108 +28,389 @@
    31.4  #include "../SDL_sysvideo.h"
    31.5  #include "../../events/SDL_events_c.h"
    31.6  
    31.7 -#include "SDL_uikitviewcontroller.h"
    31.8 +#import "SDL_uikitviewcontroller.h"
    31.9 +#import "SDL_uikitmessagebox.h"
   31.10  #include "SDL_uikitvideo.h"
   31.11  #include "SDL_uikitmodes.h"
   31.12  #include "SDL_uikitwindow.h"
   31.13  
   31.14 +#if SDL_IPHONE_KEYBOARD
   31.15 +#include "keyinfotable.h"
   31.16 +#endif
   31.17  
   31.18 -@implementation SDL_uikitviewcontroller
   31.19 +@implementation SDL_uikitviewcontroller {
   31.20 +    CADisplayLink *displayLink;
   31.21 +    int animationInterval;
   31.22 +    void (*animationCallback)(void*);
   31.23 +    void *animationCallbackParam;
   31.24 +
   31.25 +#if SDL_IPHONE_KEYBOARD
   31.26 +    UITextField *textField;
   31.27 +#endif
   31.28 +}
   31.29  
   31.30  @synthesize window;
   31.31  
   31.32 -- (id)initWithSDLWindow:(SDL_Window *)_window
   31.33 +- (instancetype)initWithSDLWindow:(SDL_Window *)_window
   31.34  {
   31.35 -    self = [self init];
   31.36 -    if (self == nil) {
   31.37 -        return nil;
   31.38 +    if (self = [super initWithNibName:nil bundle:nil]) {
   31.39 +        self.window = _window;
   31.40 +
   31.41 +#if SDL_IPHONE_KEYBOARD
   31.42 +        [self initKeyboard];
   31.43 +#endif
   31.44      }
   31.45 -    self.window = _window;
   31.46 +    return self;
   31.47 +}
   31.48  
   31.49 -    return self;
   31.50 +- (void)dealloc
   31.51 +{
   31.52 +#if SDL_IPHONE_KEYBOARD
   31.53 +    [self deinitKeyboard];
   31.54 +#endif
   31.55 +}
   31.56 +
   31.57 +- (void)setAnimationCallback:(int)interval
   31.58 +                    callback:(void (*)(void*))callback
   31.59 +               callbackParam:(void*)callbackParam
   31.60 +{
   31.61 +    [self stopAnimation];
   31.62 +
   31.63 +    animationInterval = interval;
   31.64 +    animationCallback = callback;
   31.65 +    animationCallbackParam = callbackParam;
   31.66 +
   31.67 +    if (animationCallback) {
   31.68 +        [self startAnimation];
   31.69 +    }
   31.70 +}
   31.71 +
   31.72 +- (void)startAnimation
   31.73 +{
   31.74 +    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
   31.75 +    [displayLink setFrameInterval:animationInterval];
   31.76 +    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
   31.77 +}
   31.78 +
   31.79 +- (void)stopAnimation
   31.80 +{
   31.81 +    [displayLink invalidate];
   31.82 +    displayLink = nil;
   31.83 +}
   31.84 +
   31.85 +- (void)doLoop:(CADisplayLink*)sender
   31.86 +{
   31.87 +    /* Don't run the game loop while a messagebox is up */
   31.88 +    if (!UIKit_ShowingMessageBox()) {
   31.89 +        animationCallback(animationCallbackParam);
   31.90 +    }
   31.91  }
   31.92  
   31.93  - (void)loadView
   31.94  {
   31.95 -    /* do nothing. */
   31.96 +    /* Do nothing. */
   31.97  }
   31.98  
   31.99  - (void)viewDidLayoutSubviews
  31.100  {
  31.101 -    if (self->window->flags & SDL_WINDOW_RESIZABLE) {
  31.102 -        SDL_WindowData *data = self->window->driverdata;
  31.103 -        SDL_VideoDisplay *display = SDL_GetDisplayForWindow(self->window);
  31.104 -        SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
  31.105 -        const CGSize size = data->view.bounds.size;
  31.106 -        int w, h;
  31.107 +    const CGSize size = self.view.bounds.size;
  31.108 +    int w = (int) size.width;
  31.109 +    int h = (int) size.height;
  31.110  
  31.111 -        w = (int)(size.width * displaymodedata->scale);
  31.112 -        h = (int)(size.height * displaymodedata->scale);
  31.113 -
  31.114 -        SDL_SendWindowEvent(self->window, SDL_WINDOWEVENT_RESIZED, w, h);
  31.115 -    }
  31.116 +    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
  31.117  }
  31.118  
  31.119  - (NSUInteger)supportedInterfaceOrientations
  31.120  {
  31.121 -    NSUInteger orientationMask = 0;
  31.122 -
  31.123 -    const char *orientationsCString;
  31.124 -    if ((orientationsCString = SDL_GetHint(SDL_HINT_ORIENTATIONS)) != NULL) {
  31.125 -        BOOL rotate = NO;
  31.126 -        NSString *orientationsNSString = [NSString stringWithCString:orientationsCString
  31.127 -                                                            encoding:NSUTF8StringEncoding];
  31.128 -        NSArray *orientations = [orientationsNSString componentsSeparatedByCharactersInSet:
  31.129 -                                 [NSCharacterSet characterSetWithCharactersInString:@" "]];
  31.130 -
  31.131 -        if ([orientations containsObject:@"LandscapeLeft"]) {
  31.132 -            orientationMask |= UIInterfaceOrientationMaskLandscapeLeft;
  31.133 -        }
  31.134 -        if ([orientations containsObject:@"LandscapeRight"]) {
  31.135 -            orientationMask |= UIInterfaceOrientationMaskLandscapeRight;
  31.136 -        }
  31.137 -        if ([orientations containsObject:@"Portrait"]) {
  31.138 -            orientationMask |= UIInterfaceOrientationMaskPortrait;
  31.139 -        }
  31.140 -        if ([orientations containsObject:@"PortraitUpsideDown"]) {
  31.141 -            orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown;
  31.142 -        }
  31.143 -
  31.144 -    } else if (self->window->flags & SDL_WINDOW_RESIZABLE) {
  31.145 -        orientationMask = UIInterfaceOrientationMaskAll;  /* any orientation is okay. */
  31.146 -    } else {
  31.147 -        if (self->window->w >= self->window->h) {
  31.148 -            orientationMask |= UIInterfaceOrientationMaskLandscape;
  31.149 -        }
  31.150 -        if (self->window->h >= self->window->w) {
  31.151 -            orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
  31.152 -        }
  31.153 -    }
  31.154 -
  31.155 -    /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
  31.156 -    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
  31.157 -        orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
  31.158 -    }
  31.159 -    return orientationMask;
  31.160 +    return UIKit_GetSupportedOrientations(window);
  31.161  }
  31.162  
  31.163  - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
  31.164  {
  31.165 -    NSUInteger orientationMask = [self supportedInterfaceOrientations];
  31.166 -    return (orientationMask & (1 << orient));
  31.167 +    return ([self supportedInterfaceOrientations] & (1 << orient)) != 0;
  31.168  }
  31.169  
  31.170  - (BOOL)prefersStatusBarHidden
  31.171  {
  31.172 -    if (self->window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
  31.173 -        return YES;
  31.174 -    } else {
  31.175 -        return NO;
  31.176 +    return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0;
  31.177 +}
  31.178 +
  31.179 +- (UIStatusBarStyle)preferredStatusBarStyle
  31.180 +{
  31.181 +    /* We assume most SDL apps don't have a bright white background. */
  31.182 +    return UIStatusBarStyleLightContent;
  31.183 +}
  31.184 +
  31.185 +/*
  31.186 + ---- Keyboard related functionality below this line ----
  31.187 + */
  31.188 +#if SDL_IPHONE_KEYBOARD
  31.189 +
  31.190 +@synthesize textInputRect;
  31.191 +@synthesize keyboardHeight;
  31.192 +@synthesize keyboardVisible;
  31.193 +
  31.194 +/* Set ourselves up as a UITextFieldDelegate */
  31.195 +- (void)initKeyboard
  31.196 +{
  31.197 +    textField = [[UITextField alloc] initWithFrame:CGRectZero];
  31.198 +    textField.delegate = self;
  31.199 +    /* placeholder so there is something to delete! */
  31.200 +    textField.text = @" ";
  31.201 +
  31.202 +    /* set UITextInputTrait properties, mostly to defaults */
  31.203 +    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
  31.204 +    textField.autocorrectionType = UITextAutocorrectionTypeNo;
  31.205 +    textField.enablesReturnKeyAutomatically = NO;
  31.206 +    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
  31.207 +    textField.keyboardType = UIKeyboardTypeDefault;
  31.208 +    textField.returnKeyType = UIReturnKeyDefault;
  31.209 +    textField.secureTextEntry = NO;
  31.210 +
  31.211 +    textField.hidden = YES;
  31.212 +    keyboardVisible = NO;
  31.213 +
  31.214 +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  31.215 +    [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
  31.216 +    [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
  31.217 +}
  31.218 +
  31.219 +- (void)setView:(UIView *)view
  31.220 +{
  31.221 +    [super setView:view];
  31.222 +
  31.223 +    [view addSubview:textField];
  31.224 +
  31.225 +    if (keyboardVisible) {
  31.226 +        [self showKeyboard];
  31.227      }
  31.228  }
  31.229  
  31.230 +- (void)deinitKeyboard
  31.231 +{
  31.232 +    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  31.233 +    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
  31.234 +    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
  31.235 +}
  31.236 +
  31.237 +/* reveal onscreen virtual keyboard */
  31.238 +- (void)showKeyboard
  31.239 +{
  31.240 +    keyboardVisible = YES;
  31.241 +    if (textField.window) {
  31.242 +        [textField becomeFirstResponder];
  31.243 +    }
  31.244 +}
  31.245 +
  31.246 +/* hide onscreen virtual keyboard */
  31.247 +- (void)hideKeyboard
  31.248 +{
  31.249 +    keyboardVisible = NO;
  31.250 +    [textField resignFirstResponder];
  31.251 +}
  31.252 +
  31.253 +- (void)keyboardWillShow:(NSNotification *)notification
  31.254 +{
  31.255 +    CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
  31.256 +    UIView *view = self.view;
  31.257 +    int height = 0;
  31.258 +
  31.259 +    /* The keyboard rect is in the coordinate space of the screen, but we want
  31.260 +     * its height in the view's coordinate space. */
  31.261 +#ifdef __IPHONE_8_0
  31.262 +    if ([view respondsToSelector:@selector(convertRect:fromCoordinateSpace:)]) {
  31.263 +        UIScreen *screen = view.window.screen;
  31.264 +        kbrect = [view convertRect:kbrect fromCoordinateSpace:screen.coordinateSpace];
  31.265 +        height = kbrect.size.height;
  31.266 +    } else
  31.267 +#endif
  31.268 +    {
  31.269 +        /* In iOS 7 and below, the screen's coordinate space is never rotated. */
  31.270 +        if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
  31.271 +            height = kbrect.size.width;
  31.272 +        } else {
  31.273 +            height = kbrect.size.height;
  31.274 +        }
  31.275 +    }
  31.276 +
  31.277 +    [self setKeyboardHeight:height];
  31.278 +}
  31.279 +
  31.280 +- (void)keyboardWillHide:(NSNotification *)notification
  31.281 +{
  31.282 +    [self setKeyboardHeight:0];
  31.283 +}
  31.284 +
  31.285 +- (void)updateKeyboard
  31.286 +{
  31.287 +    SDL_Rect textrect = self.textInputRect;
  31.288 +    CGAffineTransform t = self.view.transform;
  31.289 +    CGPoint offset = CGPointMake(0.0, 0.0);
  31.290 +
  31.291 +    if (self.keyboardHeight) {
  31.292 +        int rectbottom = textrect.y + textrect.h;
  31.293 +        int kbottom = self.view.bounds.size.height - self.keyboardHeight;
  31.294 +        if (kbottom < rectbottom) {
  31.295 +            offset.y = kbottom - rectbottom;
  31.296 +        }
  31.297 +    }
  31.298 +
  31.299 +    /* Put the offset into the this view transform's coordinate space. */
  31.300 +    t.tx = 0.0;
  31.301 +    t.ty = 0.0;
  31.302 +    offset = CGPointApplyAffineTransform(offset, t);
  31.303 +
  31.304 +    t.tx = offset.x;
  31.305 +    t.ty = offset.y;
  31.306 +
  31.307 +    /* Move the view by applying the updated transform. */
  31.308 +    self.view.transform = t;
  31.309 +}
  31.310 +
  31.311 +- (void)setKeyboardHeight:(int)height
  31.312 +{
  31.313 +    keyboardVisible = height > 0;
  31.314 +    keyboardHeight = height;
  31.315 +    [self updateKeyboard];
  31.316 +}
  31.317 +
  31.318 +/* UITextFieldDelegate method.  Invoked when user types something. */
  31.319 +- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
  31.320 +{
  31.321 +    NSUInteger len = string.length;
  31.322 +
  31.323 +    if (len == 0) {
  31.324 +        /* it wants to replace text with nothing, ie a delete */
  31.325 +        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
  31.326 +        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
  31.327 +    } else {
  31.328 +        /* go through all the characters in the string we've been sent and
  31.329 +         * convert them to key presses */
  31.330 +        int i;
  31.331 +        for (i = 0; i < len; i++) {
  31.332 +            unichar c = [string characterAtIndex:i];
  31.333 +            Uint16 mod = 0;
  31.334 +            SDL_Scancode code;
  31.335 +
  31.336 +            if (c < 127) {
  31.337 +                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
  31.338 +                code = unicharToUIKeyInfoTable[c].code;
  31.339 +                mod  = unicharToUIKeyInfoTable[c].mod;
  31.340 +            } else {
  31.341 +                /* we only deal with ASCII right now */
  31.342 +                code = SDL_SCANCODE_UNKNOWN;
  31.343 +                mod = 0;
  31.344 +            }
  31.345 +
  31.346 +            if (mod & KMOD_SHIFT) {
  31.347 +                /* If character uses shift, press shift down */
  31.348 +                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
  31.349 +            }
  31.350 +
  31.351 +            /* send a keydown and keyup even for the character */
  31.352 +            SDL_SendKeyboardKey(SDL_PRESSED, code);
  31.353 +            SDL_SendKeyboardKey(SDL_RELEASED, code);
  31.354 +
  31.355 +            if (mod & KMOD_SHIFT) {
  31.356 +                /* If character uses shift, press shift back up */
  31.357 +                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
  31.358 +            }
  31.359 +        }
  31.360 +
  31.361 +        SDL_SendKeyboardText([string UTF8String]);
  31.362 +    }
  31.363 +
  31.364 +    return NO; /* don't allow the edit! (keep placeholder text there) */
  31.365 +}
  31.366 +
  31.367 +/* Terminates the editing session */
  31.368 +- (BOOL)textFieldShouldReturn:(UITextField*)_textField
  31.369 +{
  31.370 +    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
  31.371 +    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
  31.372 +    SDL_StopTextInput();
  31.373 +    return YES;
  31.374 +}
  31.375 +
  31.376 +#endif
  31.377 +
  31.378  @end
  31.379  
  31.380 +/* iPhone keyboard addition functions */
  31.381 +#if SDL_IPHONE_KEYBOARD
  31.382 +
  31.383 +static SDL_uikitviewcontroller *
  31.384 +GetWindowViewController(SDL_Window * window)
  31.385 +{
  31.386 +    if (!window || !window->driverdata) {
  31.387 +        SDL_SetError("Invalid window");
  31.388 +        return nil;
  31.389 +    }
  31.390 +
  31.391 +    SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
  31.392 +
  31.393 +    return data.viewcontroller;
  31.394 +}
  31.395 +
  31.396 +SDL_bool
  31.397 +UIKit_HasScreenKeyboardSupport(_THIS)
  31.398 +{
  31.399 +    return SDL_TRUE;
  31.400 +}
  31.401 +
  31.402 +void
  31.403 +UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
  31.404 +{
  31.405 +    @autoreleasepool {
  31.406 +        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
  31.407 +        [vc showKeyboard];
  31.408 +    }
  31.409 +}
  31.410 +
  31.411 +void
  31.412 +UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
  31.413 +{
  31.414 +    @autoreleasepool {
  31.415 +        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
  31.416 +        [vc hideKeyboard];
  31.417 +    }
  31.418 +}
  31.419 +
  31.420 +SDL_bool
  31.421 +UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
  31.422 +{
  31.423 +    @autoreleasepool {
  31.424 +        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
  31.425 +        if (vc != nil) {
  31.426 +            return vc.isKeyboardVisible;
  31.427 +        }
  31.428 +        return SDL_FALSE;
  31.429 +    }
  31.430 +}
  31.431 +
  31.432 +void
  31.433 +UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
  31.434 +{
  31.435 +    if (!rect) {
  31.436 +        SDL_InvalidParamError("rect");
  31.437 +        return;
  31.438 +    }
  31.439 +
  31.440 +    @autoreleasepool {
  31.441 +        SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow());
  31.442 +        if (vc != nil) {
  31.443 +            vc.textInputRect = *rect;
  31.444 +
  31.445 +            if (vc.keyboardVisible) {
  31.446 +                [vc updateKeyboard];
  31.447 +            }
  31.448 +        }
  31.449 +    }
  31.450 +}
  31.451 +
  31.452 +
  31.453 +#endif /* SDL_IPHONE_KEYBOARD */
  31.454 +
  31.455  #endif /* SDL_VIDEO_DRIVER_UIKIT */
  31.456  
  31.457  /* vi: set ts=4 sw=4 expandtab: */
    32.1 --- a/src/video/uikit/SDL_uikitwindow.h	Thu Apr 09 22:14:05 2015 +0200
    32.2 +++ b/src/video/uikit/SDL_uikitwindow.h	Thu Apr 09 22:28:37 2015 -0400
    32.3 @@ -23,28 +23,33 @@
    32.4  
    32.5  #include "../SDL_sysvideo.h"
    32.6  #import "SDL_uikitvideo.h"
    32.7 -#import "SDL_uikitopenglview.h"
    32.8 +#import "SDL_uikitview.h"
    32.9  #import "SDL_uikitviewcontroller.h"
   32.10  
   32.11 -typedef struct SDL_WindowData SDL_WindowData;
   32.12 -
   32.13  extern int UIKit_CreateWindow(_THIS, SDL_Window * window);
   32.14 +extern void UIKit_SetWindowTitle(_THIS, SDL_Window * window);
   32.15  extern void UIKit_ShowWindow(_THIS, SDL_Window * window);
   32.16  extern void UIKit_HideWindow(_THIS, SDL_Window * window);
   32.17  extern void UIKit_RaiseWindow(_THIS, SDL_Window * window);
   32.18 +extern void UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered);
   32.19  extern void UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
   32.20  extern void UIKit_DestroyWindow(_THIS, SDL_Window * window);
   32.21  extern SDL_bool UIKit_GetWindowWMInfo(_THIS, SDL_Window * window,
   32.22                                        struct SDL_SysWMinfo * info);
   32.23  
   32.24 +extern NSUInteger UIKit_GetSupportedOrientations(SDL_Window * window);
   32.25 +
   32.26  @class UIWindow;
   32.27  
   32.28 -struct SDL_WindowData
   32.29 -{
   32.30 -    UIWindow *uiwindow;
   32.31 -    SDL_uikitopenglview *view;
   32.32 -    SDL_uikitviewcontroller *viewcontroller;
   32.33 -};
   32.34 +@interface SDL_WindowData : NSObject
   32.35 +
   32.36 +@property (nonatomic, strong) UIWindow *uiwindow;
   32.37 +@property (nonatomic, strong) SDL_uikitviewcontroller *viewcontroller;
   32.38 +
   32.39 +/* Array of SDL_uikitviews owned by this window. */
   32.40 +@property (nonatomic, copy) NSMutableArray *views;
   32.41 +
   32.42 +@end
   32.43  
   32.44  #endif /* _SDL_uikitwindow_h */
   32.45  
    33.1 --- a/src/video/uikit/SDL_uikitwindow.m	Thu Apr 09 22:14:05 2015 +0200
    33.2 +++ b/src/video/uikit/SDL_uikitwindow.m	Thu Apr 09 22:28:37 2015 -0400
    33.3 @@ -37,263 +37,273 @@
    33.4  #include "SDL_uikitwindow.h"
    33.5  #import "SDL_uikitappdelegate.h"
    33.6  
    33.7 +#import "SDL_uikitview.h"
    33.8  #import "SDL_uikitopenglview.h"
    33.9  
   33.10  #include <Foundation/Foundation.h>
   33.11  
   33.12 +@implementation SDL_WindowData
   33.13  
   33.14 +@synthesize uiwindow;
   33.15 +@synthesize viewcontroller;
   33.16 +@synthesize views;
   33.17 +
   33.18 +- (instancetype)init
   33.19 +{
   33.20 +    if ((self = [super init])) {
   33.21 +        views = [NSMutableArray new];
   33.22 +    }
   33.23 +
   33.24 +    return self;
   33.25 +}
   33.26 +
   33.27 +@end
   33.28 +
   33.29 +@interface SDL_uikitwindow : UIWindow
   33.30 +
   33.31 +- (void)layoutSubviews;
   33.32 +
   33.33 +@end
   33.34 +
   33.35 +@implementation SDL_uikitwindow
   33.36 +
   33.37 +- (void)layoutSubviews
   33.38 +{
   33.39 +    /* Workaround to fix window orientation issues in iOS 8+. */
   33.40 +    self.frame = self.screen.bounds;
   33.41 +    [super layoutSubviews];
   33.42 +}
   33.43 +
   33.44 +@end
   33.45  
   33.46  
   33.47  static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
   33.48  {
   33.49      SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   33.50 -    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
   33.51 -    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
   33.52 -    SDL_WindowData *data;
   33.53 +    SDL_DisplayData *displaydata = (__bridge SDL_DisplayData *) display->driverdata;
   33.54 +    SDL_uikitview *view;
   33.55  
   33.56 -    /* Allocate the window data */
   33.57 -    data = (SDL_WindowData *)SDL_malloc(sizeof(*data));
   33.58 +    CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen);
   33.59 +    int width  = (int) frame.size.width;
   33.60 +    int height = (int) frame.size.height;
   33.61 +
   33.62 +    SDL_WindowData *data = [[SDL_WindowData alloc] init];
   33.63      if (!data) {
   33.64          return SDL_OutOfMemory();
   33.65      }
   33.66 -    data->uiwindow = uiwindow;
   33.67 -    data->viewcontroller = nil;
   33.68 -    data->view = nil;
   33.69  
   33.70 -    /* Fill in the SDL window with the window data */
   33.71 -    {
   33.72 -        window->x = 0;
   33.73 -        window->y = 0;
   33.74 +    window->driverdata = (void *) CFBridgingRetain(data);
   33.75  
   33.76 -        CGRect bounds;
   33.77 -        if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
   33.78 -            bounds = [displaydata->uiscreen bounds];
   33.79 -        } else {
   33.80 -            bounds = [displaydata->uiscreen applicationFrame];
   33.81 -        }
   33.82 +    data.uiwindow = uiwindow;
   33.83  
   33.84 -        /* Get frame dimensions in pixels */
   33.85 -        int width = (int)(bounds.size.width * displaymodedata->scale);
   33.86 -        int height = (int)(bounds.size.height * displaymodedata->scale);
   33.87 +    /* only one window on iOS, always shown */
   33.88 +    window->flags &= ~SDL_WINDOW_HIDDEN;
   33.89 +
   33.90 +    if (displaydata.uiscreen == [UIScreen mainScreen]) {
   33.91 +        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
   33.92 +    } else {
   33.93 +        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizable */
   33.94 +        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
   33.95 +        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
   33.96 +    }
   33.97 +
   33.98 +    if (displaydata.uiscreen == [UIScreen mainScreen]) {
   33.99 +        NSUInteger orients = UIKit_GetSupportedOrientations(window);
  33.100 +        BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0;
  33.101 +        BOOL supportsPortrait = (orients & (UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown)) != 0;
  33.102  
  33.103          /* Make sure the width/height are oriented correctly */
  33.104 -        if (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) {
  33.105 +        if ((width > height && !supportsLandscape) || (height > width && !supportsPortrait)) {
  33.106              int temp = width;
  33.107              width = height;
  33.108              height = temp;
  33.109          }
  33.110 -
  33.111 -        window->w = width;
  33.112 -        window->h = height;
  33.113      }
  33.114  
  33.115 -    window->driverdata = data;
  33.116 +    window->x = 0;
  33.117 +    window->y = 0;
  33.118 +    window->w = width;
  33.119 +    window->h = height;
  33.120  
  33.121 -    /* only one window on iOS, always shown */
  33.122 -    window->flags &= ~SDL_WINDOW_HIDDEN;
  33.123 +    /* The View Controller will handle rotating the view when the device
  33.124 +     * orientation changes. This will trigger resize events, if appropriate. */
  33.125 +    data.viewcontroller = [[SDL_uikitviewcontroller alloc] initWithSDLWindow:window];
  33.126  
  33.127 -    /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
  33.128 -     * This is only set if the window is on the main screen. Other screens
  33.129 -     *  just force the window to have the borderless flag.
  33.130 -     */
  33.131 -    if (displaydata->uiscreen == [UIScreen mainScreen]) {
  33.132 -        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
  33.133 +    /* The window will initially contain a generic view so resizes, touch events,
  33.134 +     * etc. can be handled without an active OpenGL view/context. */
  33.135 +    view = [[SDL_uikitview alloc] initWithFrame:frame];
  33.136  
  33.137 -        /* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application
  33.138 -        if ([UIApplication sharedApplication].statusBarHidden) {
  33.139 -            window->flags |= SDL_WINDOW_BORDERLESS;
  33.140 -        } else {
  33.141 -            window->flags &= ~SDL_WINDOW_BORDERLESS;
  33.142 -        }
  33.143 -        */
  33.144 -    } else {
  33.145 -        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizeable */
  33.146 -        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
  33.147 -        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
  33.148 +    /* Sets this view as the controller's view, and adds the view to the window
  33.149 +     * heirarchy. */
  33.150 +    [view setSDLWindow:window];
  33.151 +
  33.152 +    /* Make this window the current mouse focus for touch input */
  33.153 +    if (displaydata.uiscreen == [UIScreen mainScreen]) {
  33.154 +        SDL_SetMouseFocus(window);
  33.155 +        SDL_SetKeyboardFocus(window);
  33.156      }
  33.157  
  33.158 -    /* The View Controller will handle rotating the view when the
  33.159 -     * device orientation changes. This will trigger resize events, if
  33.160 -     * appropriate.
  33.161 -     */
  33.162 -    SDL_uikitviewcontroller *controller;
  33.163 -    controller = [SDL_uikitviewcontroller alloc];
  33.164 -    data->viewcontroller = [controller initWithSDLWindow:window];
  33.165 -    [data->viewcontroller setTitle:@"SDL App"];  /* !!! FIXME: hook up SDL_SetWindowTitle() */
  33.166 -
  33.167      return 0;
  33.168  }
  33.169  
  33.170  int
  33.171  UIKit_CreateWindow(_THIS, SDL_Window *window)
  33.172  {
  33.173 -    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  33.174 -    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
  33.175 -    const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
  33.176 -    const CGSize origsize = [[data->uiscreen currentMode] size];
  33.177 +    @autoreleasepool {
  33.178 +        SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  33.179 +        SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
  33.180 +        const CGSize origsize = data.uiscreen.currentMode.size;
  33.181  
  33.182 -    /* SDL currently puts this window at the start of display's linked list. We rely on this. */
  33.183 -    SDL_assert(_this->windows == window);
  33.184 +        /* SDL currently puts this window at the start of display's linked list. We rely on this. */
  33.185 +        SDL_assert(_this->windows == window);
  33.186  
  33.187 -    /* We currently only handle a single window per display on iOS */
  33.188 -    if (window->next != NULL) {
  33.189 -        return SDL_SetError("Only one window allowed per display.");
  33.190 -    }
  33.191 -
  33.192 -    /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
  33.193 -     * user, so it's in standby), try to force the display to a resolution
  33.194 -     * that most closely matches the desired window size.
  33.195 -     */
  33.196 -    if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
  33.197 -        if (display->num_display_modes == 0) {
  33.198 -            _this->GetDisplayModes(_this, display);
  33.199 +        /* We currently only handle a single window per display on iOS */
  33.200 +        if (window->next != NULL) {
  33.201 +            return SDL_SetError("Only one window allowed per display.");
  33.202          }
  33.203  
  33.204 -        int i;
  33.205 -        const SDL_DisplayMode *bestmode = NULL;
  33.206 -        for (i = display->num_display_modes; i >= 0; i--) {
  33.207 -            const SDL_DisplayMode *mode = &display->display_modes[i];
  33.208 -            if ((mode->w >= window->w) && (mode->h >= window->h))
  33.209 -                bestmode = mode;
  33.210 +        /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
  33.211 +         * user, so it's in standby), try to force the display to a resolution
  33.212 +         * that most closely matches the desired window size. */
  33.213 +        if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
  33.214 +            if (display->num_display_modes == 0) {
  33.215 +                _this->GetDisplayModes(_this, display);
  33.216 +            }
  33.217 +
  33.218 +            int i;
  33.219 +            const SDL_DisplayMode *bestmode = NULL;
  33.220 +            for (i = display->num_display_modes; i >= 0; i--) {
  33.221 +                const SDL_DisplayMode *mode = &display->display_modes[i];
  33.222 +                if ((mode->w >= window->w) && (mode->h >= window->h)) {
  33.223 +                    bestmode = mode;
  33.224 +                }
  33.225 +            }
  33.226 +
  33.227 +            if (bestmode) {
  33.228 +                SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)bestmode->driverdata;
  33.229 +                [data.uiscreen setCurrentMode:modedata.uiscreenmode];
  33.230 +
  33.231 +                /* desktop_mode doesn't change here (the higher level will
  33.232 +                 * use it to set all the screens back to their defaults
  33.233 +                 * upon window destruction, SDL_Quit(), etc. */
  33.234 +                display->current_mode = *bestmode;
  33.235 +            }
  33.236          }
  33.237  
  33.238 -        if (bestmode) {
  33.239 -            SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
  33.240 -            [data->uiscreen setCurrentMode:modedata->uiscreenmode];
  33.241 +        if (data.uiscreen == [UIScreen mainScreen]) {
  33.242 +            NSUInteger orientations = UIKit_GetSupportedOrientations(window);
  33.243 +            UIApplication *app = [UIApplication sharedApplication];
  33.244  
  33.245 -            /* desktop_mode doesn't change here (the higher level will
  33.246 -             * use it to set all the screens back to their defaults
  33.247 -             * upon window destruction, SDL_Quit(), etc.
  33.248 -             */
  33.249 -            display->current_mode = *bestmode;
  33.250 +            if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
  33.251 +                app.statusBarHidden = YES;
  33.252 +            } else {
  33.253 +                app.statusBarHidden = NO;
  33.254 +            }
  33.255 +        }
  33.256 +
  33.257 +        /* ignore the size user requested, and make a fullscreen window */
  33.258 +        /* !!! FIXME: can we have a smaller view? */
  33.259 +        UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
  33.260 +
  33.261 +        /* put the window on an external display if appropriate. */
  33.262 +        if (data.uiscreen != [UIScreen mainScreen]) {
  33.263 +            [uiwindow setScreen:data.uiscreen];
  33.264 +        }
  33.265 +
  33.266 +        if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
  33.267 +            return -1;
  33.268          }
  33.269      }
  33.270  
  33.271 -    if (data->uiscreen == [UIScreen mainScreen]) {
  33.272 -        if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
  33.273 -            [UIApplication sharedApplication].statusBarHidden = YES;
  33.274 -        } else {
  33.275 -            [UIApplication sharedApplication].statusBarHidden = NO;
  33.276 -        }
  33.277 +    return 1;
  33.278 +}
  33.279 +
  33.280 +void
  33.281 +UIKit_SetWindowTitle(_THIS, SDL_Window * window)
  33.282 +{
  33.283 +    @autoreleasepool {
  33.284 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  33.285 +        data.viewcontroller.title = @(window->title);
  33.286      }
  33.287 -
  33.288 -    if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
  33.289 -        if (window->w > window->h) {
  33.290 -            if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
  33.291 -                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
  33.292 -            }
  33.293 -        } else if (window->w < window->h) {
  33.294 -            if (UIKit_IsDisplayLandscape(data->uiscreen)) {
  33.295 -                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
  33.296 -            }
  33.297 -        }
  33.298 -    }
  33.299 -
  33.300 -    /* ignore the size user requested, and make a fullscreen window */
  33.301 -    /* !!! FIXME: can we have a smaller view? */
  33.302 -    UIWindow *uiwindow = [UIWindow alloc];
  33.303 -    uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]];
  33.304 -
  33.305 -    /* put the window on an external display if appropriate. This implicitly
  33.306 -     * does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
  33.307 -     * main display, where we land by default, as that would eat the
  33.308 -     * status bar real estate.
  33.309 -     */
  33.310 -    if (external) {
  33.311 -        [uiwindow setScreen:data->uiscreen];
  33.312 -    }
  33.313 -
  33.314 -    if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
  33.315 -        [uiwindow release];
  33.316 -        return -1;
  33.317 -    }
  33.318 -
  33.319 -    return 1;
  33.320 -
  33.321  }
  33.322  
  33.323  void
  33.324  UIKit_ShowWindow(_THIS, SDL_Window * window)
  33.325  {
  33.326 -    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
  33.327 -
  33.328 -    [uiwindow makeKeyAndVisible];
  33.329 +    @autoreleasepool {
  33.330 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  33.331 +        [data.uiwindow makeKeyAndVisible];
  33.332 +    }
  33.333  }
  33.334  
  33.335  void
  33.336  UIKit_HideWindow(_THIS, SDL_Window * window)
  33.337  {
  33.338 -    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
  33.339 -
  33.340 -    uiwindow.hidden = YES;
  33.341 +    @autoreleasepool {
  33.342 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  33.343 +        data.uiwindow.hidden = YES;
  33.344 +    }
  33.345  }
  33.346  
  33.347  void
  33.348  UIKit_RaiseWindow(_THIS, SDL_Window * window)
  33.349  {
  33.350      /* We don't currently offer a concept of "raising" the SDL window, since
  33.351 -     *  we only allow one per display, in the iOS fashion.
  33.352 +     * we only allow one per display, in the iOS fashion.
  33.353       * However, we use this entry point to rebind the context to the view
  33.354 -     *  during OnWindowRestored processing.
  33.355 -     */
  33.356 +     * during OnWindowRestored processing. */
  33.357      _this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
  33.358  }
  33.359  
  33.360 +static void
  33.361 +UIKit_UpdateWindowBorder(_THIS, SDL_Window * window)
  33.362 +{
  33.363 +    SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  33.364 +    SDL_uikitviewcontroller *viewcontroller = data.viewcontroller;
  33.365 +
  33.366 +    if (data.uiwindow.screen == [UIScreen mainScreen]) {
  33.367 +        if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) {
  33.368 +            [UIApplication sharedApplication].statusBarHidden = YES;
  33.369 +        } else {
  33.370 +            [UIApplication sharedApplication].statusBarHidden = NO;
  33.371 +        }
  33.372 +
  33.373 +        /* iOS 7+ won't update the status bar until we tell it to. */
  33.374 +        if ([viewcontroller respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
  33.375 +            [viewcontroller setNeedsStatusBarAppearanceUpdate];
  33.376 +        }
  33.377 +    }
  33.378 +
  33.379 +    /* Update the view's frame to account for the status bar change. */
  33.380 +    viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
  33.381 +    [viewcontroller.view setNeedsLayout];
  33.382 +    [viewcontroller.view layoutIfNeeded];
  33.383 +}
  33.384 +
  33.385 +void
  33.386 +UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
  33.387 +{
  33.388 +    @autoreleasepool {
  33.389 +        UIKit_UpdateWindowBorder(_this, window);
  33.390 +    }
  33.391 +}
  33.392 +
  33.393  void
  33.394  UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
  33.395  {
  33.396 -    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
  33.397 -    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
  33.398 -    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
  33.399 -
  33.400 -    if (fullscreen) {
  33.401 -        [UIApplication sharedApplication].statusBarHidden = YES;
  33.402 -    } else {
  33.403 -        [UIApplication sharedApplication].statusBarHidden = NO;
  33.404 -    }
  33.405 -
  33.406 -    CGRect bounds;
  33.407 -    if (fullscreen) {
  33.408 -        bounds = [displaydata->uiscreen bounds];
  33.409 -    } else {
  33.410 -        bounds = [displaydata->uiscreen applicationFrame];
  33.411 -    }
  33.412 -
  33.413 -    /* Get frame dimensions in pixels */
  33.414 -    int width = (int)(bounds.size.width * displaymodedata->scale);
  33.415 -    int height = (int)(bounds.size.height * displaymodedata->scale);
  33.416 -
  33.417 -    /* We can pick either width or height here and we'll rotate the
  33.418 -       screen to match, so we pick the closest to what we wanted.
  33.419 -     */
  33.420 -    if (window->w >= window->h) {
  33.421 -        if (width > height) {
  33.422 -            window->w = width;
  33.423 -            window->h = height;
  33.424 -        } else {
  33.425 -            window->w = height;
  33.426 -            window->h = width;
  33.427 -        }
  33.428 -    } else {
  33.429 -        if (width > height) {
  33.430 -            window->w = height;
  33.431 -            window->h = width;
  33.432 -        } else {
  33.433 -            window->w = width;
  33.434 -            window->h = height;
  33.435 -        }
  33.436 +    @autoreleasepool {
  33.437 +        UIKit_UpdateWindowBorder(_this, window);
  33.438      }
  33.439  }
  33.440  
  33.441  void
  33.442  UIKit_DestroyWindow(_THIS, SDL_Window * window)
  33.443  {
  33.444 -    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
  33.445 -
  33.446 -    if (data) {
  33.447 -        [data->viewcontroller release];
  33.448 -        [data->uiwindow release];
  33.449 -        SDL_free(data);
  33.450 +    @autoreleasepool {
  33.451 +        if (window->driverdata != NULL) {
  33.452 +            SDL_WindowData *data = (SDL_WindowData *) CFBridgingRelease(window->driverdata);
  33.453 +            [data.viewcontroller stopAnimation];
  33.454 +        }
  33.455      }
  33.456      window->driverdata = NULL;
  33.457  }
  33.458 @@ -301,29 +311,97 @@
  33.459  SDL_bool
  33.460  UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  33.461  {
  33.462 -    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
  33.463 +    @autoreleasepool {
  33.464 +        SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
  33.465  
  33.466 -    if (info->version.major <= SDL_MAJOR_VERSION) {
  33.467 -        info->subsystem = SDL_SYSWM_UIKIT;
  33.468 -        info->info.uikit.window = uiwindow;
  33.469 -        return SDL_TRUE;
  33.470 -    } else {
  33.471 -        SDL_SetError("Application not compiled with SDL %d.%d\n",
  33.472 -                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  33.473 -        return SDL_FALSE;
  33.474 +        if (info->version.major <= SDL_MAJOR_VERSION) {
  33.475 +            int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch);
  33.476 +
  33.477 +            info->subsystem = SDL_SYSWM_UIKIT;
  33.478 +            info->info.uikit.window = data.uiwindow;
  33.479 +
  33.480 +            /* These struct members were added in SDL 2.0.4. */
  33.481 +            if (versionnum >= SDL_VERSIONNUM(2,0,4)) {
  33.482 +                if ([data.viewcontroller.view isKindOfClass:[SDL_uikitopenglview class]]) {
  33.483 +                    SDL_uikitopenglview *glview = (SDL_uikitopenglview *)data.viewcontroller.view;
  33.484 +                    info->info.uikit.framebuffer = glview.drawableFramebuffer;
  33.485 +                    info->info.uikit.colorbuffer = glview.drawableRenderbuffer;
  33.486 +                } else {
  33.487 +                    info->info.uikit.framebuffer = 0;
  33.488 +                    info->info.uikit.colorbuffer = 0;
  33.489 +                }
  33.490 +            }
  33.491 +
  33.492 +            return SDL_TRUE;
  33.493 +        } else {
  33.494 +            SDL_SetError("Application not compiled with SDL %d.%d\n",
  33.495 +                         SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  33.496 +            return SDL_FALSE;
  33.497 +        }
  33.498      }
  33.499  }
  33.500  
  33.501 +NSUInteger
  33.502 +UIKit_GetSupportedOrientations(SDL_Window * window)
  33.503 +{
  33.504 +    const char *hint = SDL_GetHint(SDL_HINT_ORIENTATIONS);
  33.505 +    NSUInteger orientationMask = 0;
  33.506 +
  33.507 +    @autoreleasepool {
  33.508 +        if (hint != NULL) {
  33.509 +            NSArray *orientations = [@(hint) componentsSeparatedByString:@" "];
  33.510 +
  33.511 +            if ([orientations containsObject:@"LandscapeLeft"]) {
  33.512 +                orientationMask |= UIInterfaceOrientationMaskLandscapeLeft;
  33.513 +            }
  33.514 +            if ([orientations containsObject:@"LandscapeRight"]) {
  33.515 +                orientationMask |= UIInterfaceOrientationMaskLandscapeRight;
  33.516 +            }
  33.517 +            if ([orientations containsObject:@"Portrait"]) {
  33.518 +                orientationMask |= UIInterfaceOrientationMaskPortrait;
  33.519 +            }
  33.520 +            if ([orientations containsObject:@"PortraitUpsideDown"]) {
  33.521 +                orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown;
  33.522 +            }
  33.523 +        }
  33.524 +
  33.525 +        if (orientationMask == 0 && (window->flags & SDL_WINDOW_RESIZABLE)) {
  33.526 +            /* any orientation is okay. */
  33.527 +            orientationMask = UIInterfaceOrientationMaskAll;
  33.528 +        }
  33.529 +
  33.530 +        if (orientationMask == 0) {
  33.531 +            if (window->w >= window->h) {
  33.532 +                orientationMask |= UIInterfaceOrientationMaskLandscape;
  33.533 +            }
  33.534 +            if (window->h >= window->w) {
  33.535 +                orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
  33.536 +            }
  33.537 +        }
  33.538 +
  33.539 +        /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */
  33.540 +        if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
  33.541 +            orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown;
  33.542 +        }
  33.543 +    }
  33.544 +
  33.545 +    return orientationMask;
  33.546 +}
  33.547 +
  33.548  int
  33.549  SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
  33.550  {
  33.551 -    SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL;
  33.552 -
  33.553 -    if (!data || !data->view) {
  33.554 -        return SDL_SetError("Invalid window or view not set");
  33.555 +    if (!window || !window->driverdata) {
  33.556 +        return SDL_SetError("Invalid window");
  33.557      }
  33.558  
  33.559 -    [data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
  33.560 +    @autoreleasepool {
  33.561 +        SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
  33.562 +        [data.viewcontroller setAnimationCallback:interval
  33.563 +                                         callback:callback
  33.564 +                                    callbackParam:callbackParam];
  33.565 +    }
  33.566 +
  33.567      return 0;
  33.568  }
  33.569