src/video/uikit/SDL_uikitmodes.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8891 7b6472f1b7ba
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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 
    29 BOOL SDL_UIKit_supports_multiple_displays = NO;
    30 
    31 
    32 static int
    33 UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode,
    34     UIScreenMode * uiscreenmode, CGFloat scale)
    35 {
    36     SDL_DisplayModeData *data = NULL;
    37 
    38     if (uiscreenmode != nil) {
    39         /* Allocate the display mode data */
    40         data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
    41         if (!data) {
    42             return SDL_OutOfMemory();
    43         }
    44 
    45         data->uiscreenmode = uiscreenmode;
    46         [data->uiscreenmode retain];
    47 
    48         data->scale = scale;
    49     }
    50 
    51     mode->driverdata = data;
    52 
    53     return 0;
    54 }
    55 
    56 static void
    57 UIKit_FreeDisplayModeData(SDL_DisplayMode * mode)
    58 {
    59     if (!SDL_UIKit_supports_multiple_displays) {
    60         /* Not on at least iPhoneOS 3.2 (versions prior to iPad). */
    61         SDL_assert(mode->driverdata == NULL);
    62     } else if (mode->driverdata != NULL) {
    63         SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
    64         [data->uiscreenmode release];
    65         SDL_free(data);
    66         mode->driverdata = NULL;
    67     }
    68 }
    69 
    70 static int
    71 UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
    72     UIScreenMode * uiscreenmode, CGFloat scale)
    73 {
    74     SDL_DisplayMode mode;
    75     SDL_zero(mode);
    76 
    77     mode.format = SDL_PIXELFORMAT_ABGR8888;
    78     mode.refresh_rate = 0;
    79     if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
    80         return -1;
    81     }
    82 
    83     mode.w = w;
    84     mode.h = h;
    85     if (SDL_AddDisplayMode(display, &mode)) {
    86         return 0;
    87     } else {
    88         UIKit_FreeDisplayModeData(&mode);
    89         return -1;
    90     }
    91 }
    92 
    93 static int
    94 UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale,
    95                      UIScreenMode * uiscreenmode, SDL_bool addRotation)
    96 {
    97     if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode, scale) < 0) {
    98         return -1;
    99     }
   100 
   101     if (addRotation) {
   102         /* Add the rotated version */
   103         if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode, scale) < 0) {
   104             return -1;
   105         }
   106     }
   107 
   108     return 0;
   109 }
   110 
   111 static int
   112 UIKit_AddDisplay(UIScreen *uiscreen)
   113 {
   114     CGSize size = [uiscreen bounds].size;
   115 
   116     /* Make sure the width/height are oriented correctly */
   117     if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
   118         CGFloat height = size.width;
   119         size.width = size.height;
   120         size.height = height;
   121     }
   122 
   123     /* When dealing with UIKit all coordinates are specified in terms of
   124      * what Apple refers to as points. On earlier devices without the
   125      * so called "Retina" display, there is a one to one mapping between
   126      * points and pixels. In other cases [UIScreen scale] indicates the
   127      * relationship between points and pixels. Since SDL has no notion
   128      * of points, we must compensate in all cases where dealing with such
   129      * units.
   130      */
   131     CGFloat scale;
   132     if ([UIScreen instancesRespondToSelector:@selector(scale)]) {
   133         scale = [uiscreen scale]; /* iOS >= 4.0 */
   134     } else {
   135         scale = 1.0f; /* iOS < 4.0 */
   136     }
   137 
   138     SDL_VideoDisplay display;
   139     SDL_DisplayMode mode;
   140     SDL_zero(mode);
   141     mode.format = SDL_PIXELFORMAT_ABGR8888;
   142     mode.w = (int)(size.width * scale);
   143     mode.h = (int)(size.height * scale);
   144 
   145     UIScreenMode * uiscreenmode = nil;
   146     /* UIScreenMode showed up in 3.2 (the iPad and later). We're
   147      * misusing this supports_multiple_displays flag here for that.
   148      */
   149     if (SDL_UIKit_supports_multiple_displays) {
   150         uiscreenmode = [uiscreen currentMode];
   151     }
   152 
   153     if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) {
   154         return -1;
   155     }
   156 
   157     SDL_zero(display);
   158     display.desktop_mode = mode;
   159     display.current_mode = mode;
   160 
   161     /* Allocate the display data */
   162     SDL_DisplayData *data = (SDL_DisplayData *) SDL_malloc(sizeof(*data));
   163     if (!data) {
   164         UIKit_FreeDisplayModeData(&display.desktop_mode);
   165         return SDL_OutOfMemory();
   166     }
   167 
   168     [uiscreen retain];
   169     data->uiscreen = uiscreen;
   170     data->scale = scale;
   171 
   172     display.driverdata = data;
   173     SDL_AddVideoDisplay(&display);
   174 
   175     return 0;
   176 }
   177 
   178 SDL_bool
   179 UIKit_IsDisplayLandscape(UIScreen *uiscreen)
   180 {
   181     if (uiscreen == [UIScreen mainScreen]) {
   182         return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
   183     } else {
   184         CGSize size = [uiscreen bounds].size;
   185         return (size.width > size.height);
   186     }
   187 }
   188 
   189 int
   190 UIKit_InitModes(_THIS)
   191 {
   192     /* this tells us whether we are running on ios >= 3.2 */
   193     SDL_UIKit_supports_multiple_displays = [UIScreen instancesRespondToSelector:@selector(currentMode)];
   194 
   195     /* Add the main screen. */
   196     if (UIKit_AddDisplay([UIScreen mainScreen]) < 0) {
   197         return -1;
   198     }
   199 
   200     /* If this is iPhoneOS < 3.2, all devices are one screen, 320x480 pixels. */
   201     /*  The iPad added both a larger main screen and the ability to use
   202      *  external displays. So, add the other displays (screens in UI speak).
   203      */
   204     if (SDL_UIKit_supports_multiple_displays) {
   205         for (UIScreen *uiscreen in [UIScreen screens]) {
   206             /* Only add the other screens */
   207             if (uiscreen != [UIScreen mainScreen]) {
   208                 if (UIKit_AddDisplay(uiscreen) < 0) {
   209                     return -1;
   210                 }
   211             }
   212         }
   213     }
   214 
   215     /* We're done! */
   216     return 0;
   217 }
   218 
   219 void
   220 UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
   221 {
   222     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   223 
   224     SDL_bool isLandscape = UIKit_IsDisplayLandscape(data->uiscreen);
   225     SDL_bool addRotation = (data->uiscreen == [UIScreen mainScreen]);
   226 
   227     if (SDL_UIKit_supports_multiple_displays) {
   228         /* availableModes showed up in 3.2 (the iPad and later). We should only
   229          * land here for at least that version of the OS.
   230          */
   231         for (UIScreenMode *uimode in [data->uiscreen availableModes]) {
   232             CGSize size = [uimode size];
   233             int w = (int)size.width;
   234             int h = (int)size.height;
   235 
   236             /* Make sure the width/height are oriented correctly */
   237             if (isLandscape != (w > h)) {
   238                 int tmp = w;
   239                 w = h;
   240                 h = tmp;
   241             }
   242 
   243             /* Add the native screen resolution. */
   244             UIKit_AddDisplayMode(display, w, h, data->scale, uimode, addRotation);
   245 
   246             if (data->scale != 1.0f) {
   247                 /* Add the native screen resolution divided by its scale.
   248                  * This is so devices capable of e.g. 640x960 also advertise 320x480.
   249                  */
   250                 UIKit_AddDisplayMode(display,
   251                     (int)(size.width / data->scale),
   252                     (int)(size.height / data->scale),
   253                     1.0f, uimode, addRotation);
   254             }
   255         }
   256     } else {
   257         const CGSize size = [data->uiscreen bounds].size;
   258         int w = (int)size.width;
   259         int h = (int)size.height;
   260 
   261         /* Make sure the width/height are oriented correctly */
   262         if (isLandscape != (w > h)) {
   263             int tmp = w;
   264             w = h;
   265             h = tmp;
   266         }
   267 
   268         UIKit_AddDisplayMode(display, w, h, 1.0f, nil, addRotation);
   269     }
   270 }
   271 
   272 int
   273 UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   274 {
   275     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   276 
   277     if (!SDL_UIKit_supports_multiple_displays) {
   278         /* Not on at least iPhoneOS 3.2 (versions prior to iPad). */
   279         SDL_assert(mode->driverdata == NULL);
   280     } else {
   281         SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
   282         [data->uiscreen setCurrentMode:modedata->uiscreenmode];
   283 
   284         if (data->uiscreen == [UIScreen mainScreen]) {
   285             if (mode->w > mode->h) {
   286                 if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
   287                     [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
   288                 }
   289             } else if (mode->w < mode->h) {
   290                 if (UIKit_IsDisplayLandscape(data->uiscreen)) {
   291                     [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
   292                 }
   293             }
   294         }
   295     }
   296     return 0;
   297 }
   298 
   299 void
   300 UIKit_QuitModes(_THIS)
   301 {
   302     /* Release Objective-C objects, so higher level doesn't free() them. */
   303     int i, j;
   304     for (i = 0; i < _this->num_displays; i++) {
   305         SDL_VideoDisplay *display = &_this->displays[i];
   306 
   307         UIKit_FreeDisplayModeData(&display->desktop_mode);
   308         for (j = 0; j < display->num_display_modes; j++) {
   309             SDL_DisplayMode *mode = &display->display_modes[j];
   310             UIKit_FreeDisplayModeData(mode);
   311         }
   312 
   313         SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   314         [data->uiscreen release];
   315         SDL_free(data);
   316         display->driverdata = NULL;
   317     }
   318 }
   319 
   320 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   321 
   322 /* vi: set ts=4 sw=4 expandtab: */