src/video/uikit/SDL_uikitmodes.m
author Sam Lantinga
Fri, 27 Jan 2017 06:05:50 -0800
changeset 10856 486aa38c6a88
parent 10737 3406a0f8b041
child 11086 7b1c534105d5
permissions -rw-r--r--
Added Thrustmaster Wheel FFB entry to the list of wheels
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 !TARGET_OS_TV
   160     if (uiscreen == [UIScreen mainScreen]) {
   161         return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
   162     } else
   163 #endif /* !TARGET_OS_TV */
   164     {
   165         CGSize size = uiscreen.bounds.size;
   166         return (size.width > size.height);
   167     }
   168 }
   169 
   170 int
   171 UIKit_InitModes(_THIS)
   172 {
   173     @autoreleasepool {
   174         for (UIScreen *uiscreen in [UIScreen screens]) {
   175             if (UIKit_AddDisplay(uiscreen) < 0) {
   176                 return -1;
   177             }
   178         }
   179     }
   180 
   181     return 0;
   182 }
   183 
   184 void
   185 UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
   186 {
   187     @autoreleasepool {
   188         SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
   189 
   190         SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
   191         SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
   192         CGFloat scale = data.uiscreen.scale;
   193         NSArray *availableModes = nil;
   194 
   195 #if TARGET_OS_TV
   196         addRotation = SDL_FALSE;
   197         availableModes = @[data.uiscreen.currentMode];
   198 #else
   199         availableModes = data.uiscreen.availableModes;
   200 #endif
   201 
   202 #ifdef __IPHONE_8_0
   203         /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than
   204          * 1242x2208 (414x736@3x), so we should use the native scale. */
   205         if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) {
   206             scale = data.uiscreen.nativeScale;
   207         }
   208 #endif
   209 
   210         for (UIScreenMode *uimode in availableModes) {
   211             /* The size of a UIScreenMode is in pixels, but we deal exclusively
   212              * in points (except in SDL_GL_GetDrawableSize.) */
   213             int w = (int)(uimode.size.width / scale);
   214             int h = (int)(uimode.size.height / scale);
   215 
   216             /* Make sure the width/height are oriented correctly */
   217             if (isLandscape != (w > h)) {
   218                 int tmp = w;
   219                 w = h;
   220                 h = tmp;
   221             }
   222 
   223             UIKit_AddDisplayMode(display, w, h, uimode, addRotation);
   224         }
   225     }
   226 }
   227 
   228 int
   229 UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   230 {
   231     @autoreleasepool {
   232         SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
   233 
   234 #if !TARGET_OS_TV
   235         SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
   236         [data.uiscreen setCurrentMode:modedata.uiscreenmode];
   237 #endif
   238 
   239         if (data.uiscreen == [UIScreen mainScreen]) {
   240             /* [UIApplication setStatusBarOrientation:] no longer works reliably
   241              * in recent iOS versions, so we can't rotate the screen when setting
   242              * the display mode. */
   243             if (mode->w > mode->h) {
   244                 if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
   245                     return SDL_SetError("Screen orientation does not match display mode size");
   246                 }
   247             } else if (mode->w < mode->h) {
   248                 if (UIKit_IsDisplayLandscape(data.uiscreen)) {
   249                     return SDL_SetError("Screen orientation does not match display mode size");
   250                 }
   251             }
   252         }
   253     }
   254 
   255     return 0;
   256 }
   257 
   258 int
   259 UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
   260 {
   261     @autoreleasepool {
   262         int displayIndex = (int) (display - _this->displays);
   263         SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
   264 
   265         /* the default function iterates displays to make a fake offset,
   266          as if all the displays were side-by-side, which is fine for iOS. */
   267         if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
   268             return -1;
   269         }
   270 
   271         CGRect frame = data.uiscreen.bounds;
   272 
   273 #if !TARGET_OS_TV
   274         if (!UIKit_IsSystemVersionAtLeast(7.0)) {
   275             frame = [data.uiscreen applicationFrame];
   276         }
   277 #endif
   278 
   279         rect->x += frame.origin.x;
   280         rect->y += frame.origin.y;
   281         rect->w = frame.size.width;
   282         rect->h = frame.size.height;
   283     }
   284 
   285     return 0;
   286 }
   287 
   288 void
   289 UIKit_QuitModes(_THIS)
   290 {
   291     /* Release Objective-C objects, so higher level doesn't free() them. */
   292     int i, j;
   293     @autoreleasepool {
   294         for (i = 0; i < _this->num_displays; i++) {
   295             SDL_VideoDisplay *display = &_this->displays[i];
   296 
   297             UIKit_FreeDisplayModeData(&display->desktop_mode);
   298             for (j = 0; j < display->num_display_modes; j++) {
   299                 SDL_DisplayMode *mode = &display->display_modes[j];
   300                 UIKit_FreeDisplayModeData(mode);
   301             }
   302 
   303             if (display->driverdata != NULL) {
   304                 CFRelease(display->driverdata);
   305                 display->driverdata = NULL;
   306             }
   307         }
   308     }
   309 }
   310 
   311 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   312 
   313 /* vi: set ts=4 sw=4 expandtab: */