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