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