iOS: show message boxes using the new UIAlertController APIs when supported, rather than the deprecated UIAlertView.
authorAlex Szpakowski <slime73@gmail.com>
Fri, 25 Sep 2015 15:17:20 -0300
changeset 9879 8465a79c9f85
parent 9878 63f03a567fe3
child 9880 3bbeb623181c
iOS: show message boxes using the new UIAlertController APIs when supported, rather than the deprecated UIAlertView. UIAlertController is also supported on tvOS, whereas UIAlertView is not.
src/joystick/iphoneos/SDL_sysjoystick.m
src/video/uikit/SDL_uikitmessagebox.m
src/video/uikit/SDL_uikitopengles.m
src/video/uikit/SDL_uikitviewcontroller.h
src/video/uikit/SDL_uikitviewcontroller.m
--- a/src/joystick/iphoneos/SDL_sysjoystick.m	Mon Sep 21 21:19:37 2015 +0200
+++ b/src/joystick/iphoneos/SDL_sysjoystick.m	Fri Sep 25 15:17:20 2015 -0300
@@ -181,7 +181,7 @@
 #endif /* !SDL_EVENTS_DISABLED */
 }
 
-SDL_JoystickDeviceItem *
+static SDL_JoystickDeviceItem *
 SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
 {
     SDL_JoystickDeviceItem *prev = NULL;
@@ -374,12 +374,14 @@
 }
 
 /* Function to determine if this joystick is attached to the system right now */
-SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
+SDL_bool
+SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
 {
     return joystick->hwdata != NULL;
 }
 
-static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
+static void
+SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
 {
     const float maxgforce = SDL_IPHONE_MAX_GFORCE;
     const SInt16 maxsint16 = 0x7FFF;
@@ -579,7 +581,8 @@
     numjoysticks = 0;
 }
 
-SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
+SDL_JoystickGUID
+SDL_SYS_JoystickGetDeviceGUID( int device_index )
 {
     SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
     SDL_JoystickGUID guid;
@@ -591,7 +594,8 @@
     return guid;
 }
 
-SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
+SDL_JoystickGUID
+SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
 {
     SDL_JoystickGUID guid;
     if (joystick->hwdata) {
--- a/src/video/uikit/SDL_uikitmessagebox.m	Mon Sep 21 21:19:37 2015 +0200
+++ b/src/video/uikit/SDL_uikitmessagebox.m	Fri Sep 25 15:17:20 2015 -0300
@@ -24,68 +24,166 @@
 
 #include "SDL.h"
 #include "SDL_uikitvideo.h"
-
+#include "SDL_uikitwindow.h"
 
 /* Display a UIKit message box */
 
 static SDL_bool s_showingMessageBox = SDL_FALSE;
 
-@interface SDLAlertViewDelegate : NSObject <UIAlertViewDelegate>
-
-@property (nonatomic, assign) int clickedIndex;
-
-@end
-
-@implementation SDLAlertViewDelegate
-
-- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
-{
-    _clickedIndex = (int)buttonIndex;
-}
-
-@end
-
-
 SDL_bool
 UIKit_ShowingMessageBox()
 {
     return s_showingMessageBox;
 }
 
+static void
+UIKit_WaitUntilMessageBoxClosed(const SDL_MessageBoxData *messageboxdata, int *clickedindex)
+{
+    *clickedindex = messageboxdata->numbuttons;
+
+    @autoreleasepool {
+        /* Run the main event loop until the alert has finished */
+        /* Note that this needs to be done on the main thread */
+        s_showingMessageBox = SDL_TRUE;
+        while ((*clickedindex) == messageboxdata->numbuttons) {
+            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+        }
+        s_showingMessageBox = SDL_FALSE;
+    }
+}
+
+static BOOL
+UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messageboxdata, int *buttonid)
+{
+#ifdef __IPHONE_8_0
+    int i;
+    int __block clickedindex = messageboxdata->numbuttons;
+    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
+    UIWindow *window = nil;
+    UIWindow *alertwindow = nil;
+
+    if (![UIAlertController class]) {
+        return NO;
+    }
+
+    UIAlertController *alert;
+    alert = [UIAlertController alertControllerWithTitle:@(messageboxdata->title)
+                                                message:@(messageboxdata->message)
+                                         preferredStyle:UIAlertControllerStyleAlert];
+
+    for (i = 0; i < messageboxdata->numbuttons; i++) {
+        UIAlertAction *action;
+        UIAlertActionStyle style = UIAlertActionStyleDefault;
+
+        if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
+            style = UIAlertActionStyleCancel;
+        }
+
+        action = [UIAlertAction actionWithTitle:@(buttons[i].text)
+                                          style:style
+                                        handler:^(UIAlertAction *action) {
+                                            clickedindex = i;
+                                        }];
+        [alert addAction:action];
+    }
+
+    if (messageboxdata->window) {
+        SDL_WindowData *data = (__bridge SDL_WindowData *) messageboxdata->window->driverdata;
+        window = data.uiwindow;
+    }
+
+    if (window == nil || window.rootViewController == nil) {
+        alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+        alertwindow.rootViewController = [UIViewController new];
+        alertwindow.windowLevel = UIWindowLevelAlert;
+
+        window = alertwindow;
+
+        [alertwindow makeKeyAndVisible];
+    }
+
+    [window.rootViewController presentViewController:alert animated:YES completion:nil];
+    UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex);
+
+    if (alertwindow) {
+        alertwindow.hidden = YES;
+    }
+
+    *buttonid = messageboxdata->buttons[clickedindex].buttonid;
+    return YES;
+#else
+    return NO;
+#endif /* __IPHONE_8_0 */
+}
+
+/* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000
+@interface SDLAlertViewDelegate : NSObject <UIAlertViewDelegate>
+
+@property (nonatomic, assign) int *clickedIndex;
+
+@end
+
+@implementation SDLAlertViewDelegate
+
+- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
+{
+    if (_clickedIndex != NULL) {
+        *_clickedIndex = (int) buttonIndex;
+    }
+}
+
+@end
+#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */
+
+static BOOL
+UIKit_ShowMessageBoxAlertView(const SDL_MessageBoxData *messageboxdata, int *buttonid)
+{
+    /* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000
+    int i;
+    int clickedindex = messageboxdata->numbuttons;
+    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
+    UIAlertView *alert = [[UIAlertView alloc] init];
+    SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init];
+
+    alert.delegate = delegate;
+    alert.title = @(messageboxdata->title);
+    alert.message = @(messageboxdata->message);
+
+    for (i = 0; i < messageboxdata->numbuttons; i++) {
+        [alert addButtonWithTitle:@(buttons[i].text)];
+    }
+
+    delegate.clickedIndex = &clickedindex;
+
+    [alert show];
+
+    UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex);
+
+    alert.delegate = nil;
+
+    *buttonid = messageboxdata->buttons[clickedindex].buttonid;
+    return YES;
+#else
+    return NO;
+#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */
+}
+
 int
 UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
 {
-    int i;
-    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
+    BOOL success = NO;
 
     @autoreleasepool {
-        UIAlertView *alert = [[UIAlertView alloc] init];
-        SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init];
-
-        alert.delegate = delegate;
-        alert.title = @(messageboxdata->title);
-        alert.message = @(messageboxdata->message);
-
-        for (i = 0; i < messageboxdata->numbuttons; ++i) {
-            [alert addButtonWithTitle:@(buttons[i].text)];
+        success = UIKit_ShowMessageBoxAlertController(messageboxdata, buttonid);
+        if (!success) {
+            success = UIKit_ShowMessageBoxAlertView(messageboxdata, buttonid);
         }
-
-        /* Set up for showing the alert */
-        delegate.clickedIndex = messageboxdata->numbuttons;
+    }
 
-        [alert show];
-
-        /* Run the main event loop until the alert has finished */
-        /* Note that this needs to be done on the main thread */
-        s_showingMessageBox = SDL_TRUE;
-        while (delegate.clickedIndex == messageboxdata->numbuttons) {
-            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
-        }
-        s_showingMessageBox = SDL_FALSE;
-
-        *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid;
-
-        alert.delegate = nil;
+    if (!success) {
+        return SDL_SetError("Could not show message box.");
     }
 
     return 0;
--- a/src/video/uikit/SDL_uikitopengles.m	Mon Sep 21 21:19:37 2015 +0200
+++ b/src/video/uikit/SDL_uikitopengles.m	Fri Sep 25 15:17:20 2015 -0300
@@ -52,8 +52,6 @@
 
 @end
 
-static int UIKit_GL_Initialize(_THIS);
-
 void *
 UIKit_GL_GetProcAddress(_THIS, const char *proc)
 {
--- a/src/video/uikit/SDL_uikitviewcontroller.h	Mon Sep 21 21:19:37 2015 +0200
+++ b/src/video/uikit/SDL_uikitviewcontroller.h	Fri Sep 25 15:17:20 2015 -0300
@@ -47,9 +47,7 @@
 - (void)loadView;
 - (void)viewDidLayoutSubviews;
 - (NSUInteger)supportedInterfaceOrientations;
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient;
 - (BOOL)prefersStatusBarHidden;
-- (UIStatusBarStyle)preferredStatusBarStyle;
 
 #if SDL_IPHONE_KEYBOARD
 - (void)showKeyboard;
--- a/src/video/uikit/SDL_uikitviewcontroller.m	Mon Sep 21 21:19:37 2015 +0200
+++ b/src/video/uikit/SDL_uikitviewcontroller.m	Fri Sep 25 15:17:20 2015 -0300
@@ -135,12 +135,6 @@
     return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0;
 }
 
-- (UIStatusBarStyle)preferredStatusBarStyle
-{
-    /* We assume most SDL apps don't have a bright white background. */
-    return UIStatusBarStyleLightContent;
-}
-
 /*
  ---- Keyboard related functionality below this line ----
  */