src/video/uikit/SDL_uikitmodes.m
author Ryan C. Gordon <icculus@icculus.org>
Mon, 04 Jan 2016 23:52:40 -0500
changeset 10019 36f7e8084508
parent 9998 f67cf37e9cd4
child 10033 03a8adcb6460
permissions -rw-r--r--
Added SDL_GetDisplayUsableBounds().
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_UIKIT
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_uikitmodes.h"
    27 
    28 @implementation SDL_DisplayData
    29 
    30 @synthesize uiscreen;
    31 
    32 @end
    33 
    34 @implementation SDL_DisplayModeData
    35 
    36 @synthesize uiscreenmode;
    37 
    38 @end
    39 
    40 
    41 static int
    42 UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode,
    43     UIScreenMode * uiscreenmode)
    44 {
    45     SDL_DisplayModeData *data = nil;
    46 
    47     if (uiscreenmode != nil) {
    48         /* Allocate the display mode data */
    49         data = [[SDL_DisplayModeData alloc] init];
    50         if (!data) {
    51             return SDL_OutOfMemory();
    52         }
    53 
    54         data.uiscreenmode = uiscreenmode;
    55     }
    56 
    57     mode->driverdata = (void *) CFBridgingRetain(data);
    58 
    59     return 0;
    60 }
    61 
    62 static void
    63 UIKit_FreeDisplayModeData(SDL_DisplayMode * mode)
    64 {
    65     if (mode->driverdata != NULL) {
    66         CFRelease(mode->driverdata);
    67         mode->driverdata = NULL;
    68     }
    69 }
    70 
    71 static int
    72 UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
    73     UIScreenMode * uiscreenmode)
    74 {
    75     SDL_DisplayMode mode;
    76     SDL_zero(mode);
    77 
    78     mode.format = SDL_PIXELFORMAT_ABGR8888;
    79     mode.refresh_rate = 0;
    80     if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
    81         return -1;
    82     }
    83 
    84     mode.w = w;
    85     mode.h = h;
    86     if (SDL_AddDisplayMode(display, &mode)) {
    87         return 0;
    88     } else {
    89         UIKit_FreeDisplayModeData(&mode);
    90         return -1;
    91     }
    92 }
    93 
    94 static int
    95 UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h,
    96                      UIScreenMode * uiscreenmode, SDL_bool addRotation)
    97 {
    98     if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode) < 0) {
    99         return -1;
   100     }
   101 
   102     if (addRotation) {
   103         /* Add the rotated version */
   104         if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode) < 0) {
   105             return -1;
   106         }
   107     }
   108 
   109     return 0;
   110 }
   111 
   112 static int
   113 UIKit_AddDisplay(UIScreen *uiscreen)
   114 {
   115     CGSize size = uiscreen.bounds.size;
   116 
   117     /* Make sure the width/height are oriented correctly */
   118     if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
   119         CGFloat height = size.width;
   120         size.width = size.height;
   121         size.height = height;
   122     }
   123 
   124     SDL_VideoDisplay display;
   125     SDL_DisplayMode mode;
   126     SDL_zero(mode);
   127     mode.format = SDL_PIXELFORMAT_ABGR8888;
   128     mode.w = (int) size.width;
   129     mode.h = (int) size.height;
   130 
   131     UIScreenMode *uiscreenmode = uiscreen.currentMode;
   132 
   133     if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
   134         return -1;
   135     }
   136 
   137     SDL_zero(display);
   138     display.desktop_mode = mode;
   139     display.current_mode = mode;
   140 
   141     /* Allocate the display data */
   142     SDL_DisplayData *data = [[SDL_DisplayData alloc] init];
   143     if (!data) {
   144         UIKit_FreeDisplayModeData(&display.desktop_mode);
   145         return SDL_OutOfMemory();
   146     }
   147 
   148     data.uiscreen = uiscreen;
   149 
   150     display.driverdata = (void *) CFBridgingRetain(data);
   151     SDL_AddVideoDisplay(&display);
   152 
   153     return 0;
   154 }
   155 
   156 SDL_bool
   157 UIKit_IsDisplayLandscape(UIScreen *uiscreen)
   158 {
   159     if (uiscreen == [UIScreen mainScreen]) {
   160         return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
   161     } else {
   162         CGSize size = uiscreen.bounds.size;
   163         return (size.width > size.height);
   164     }
   165 }
   166 
   167 int
   168 UIKit_InitModes(_THIS)
   169 {
   170     @autoreleasepool {
   171         for (UIScreen *uiscreen in [UIScreen screens]) {
   172             if (UIKit_AddDisplay(uiscreen) < 0) {
   173                 return -1;
   174             }
   175         }
   176     }
   177 
   178     return 0;
   179 }
   180 
   181 void
   182 UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
   183 {
   184     @autoreleasepool {
   185         SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
   186 
   187         SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
   188         SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
   189         CGFloat scale = data.uiscreen.scale;
   190 
   191 #ifdef __IPHONE_8_0
   192         /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than
   193          * 1242x2208 (414x736@3x), so we should use the native scale. */
   194         if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) {
   195             scale = data.uiscreen.nativeScale;
   196         }
   197 #endif
   198 
   199         for (UIScreenMode *uimode in data.uiscreen.availableModes) {
   200             /* The size of a UIScreenMode is in pixels, but we deal exclusively
   201              * in points (except in SDL_GL_GetDrawableSize.) */
   202             int w = (int)(uimode.size.width / scale);
   203             int h = (int)(uimode.size.height / scale);
   204 
   205             /* Make sure the width/height are oriented correctly */
   206             if (isLandscape != (w > h)) {
   207                 int tmp = w;
   208                 w = h;
   209                 h = tmp;
   210             }
   211 
   212             UIKit_AddDisplayMode(display, w, h, uimode, addRotation);
   213         }
   214     }
   215 }
   216 
   217 int
   218 UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   219 {
   220     @autoreleasepool {
   221         SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
   222         SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
   223 
   224         [data.uiscreen setCurrentMode:modedata.uiscreenmode];
   225 
   226         if (data.uiscreen == [UIScreen mainScreen]) {
   227             /* [UIApplication setStatusBarOrientation:] no longer works reliably
   228              * in recent iOS versions, so we can't rotate the screen when setting
   229              * the display mode. */
   230             if (mode->w > mode->h) {
   231                 if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
   232                     return SDL_SetError("Screen orientation does not match display mode size");
   233                 }
   234             } else if (mode->w < mode->h) {
   235                 if (UIKit_IsDisplayLandscape(data.uiscreen)) {
   236                     return SDL_SetError("Screen orientation does not match display mode size");
   237                 }
   238             }
   239         }
   240     }
   241 
   242     return 0;
   243 }
   244 
   245 int
   246 UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
   247 {
   248     /* the default function iterates displays to make a fake offset,
   249        as if all the displays were side-by-side, which is fine for iOS. */
   250     const int displayIndex = (int) (display - _this->displays);
   251     if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
   252         return -1;
   253     }
   254 
   255     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   256     const CGRect frame = [data->uiscreen applicationFrame];
   257     const float scale = (float) data->scale;
   258     rect->x += (int) (frame.origin.x * scale);
   259     rect->y += (int) (frame.origin.y * scale);
   260     rect->w = (int) (frame.size.width * scale);
   261     rect->h = (int) (frame.size.height * scale);
   262     return 0;
   263 }
   264 
   265 void
   266 UIKit_QuitModes(_THIS)
   267 {
   268     /* Release Objective-C objects, so higher level doesn't free() them. */
   269     int i, j;
   270     @autoreleasepool {
   271         for (i = 0; i < _this->num_displays; i++) {
   272             SDL_VideoDisplay *display = &_this->displays[i];
   273 
   274             UIKit_FreeDisplayModeData(&display->desktop_mode);
   275             for (j = 0; j < display->num_display_modes; j++) {
   276                 SDL_DisplayMode *mode = &display->display_modes[j];
   277                 UIKit_FreeDisplayModeData(mode);
   278             }
   279 
   280             if (display->driverdata != NULL) {
   281                 CFRelease(display->driverdata);
   282                 display->driverdata = NULL;
   283             }
   284         }
   285     }
   286 }
   287 
   288 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   289 
   290 /* vi: set ts=4 sw=4 expandtab: */