src/video/uikit/SDL_uikitwindow.m
author Alex Szpakowski <slime73@gmail.com>
Wed, 23 Jul 2014 21:55:42 -0300
branchiOS-improvements
changeset 9502 933ed557b7c1
parent 9501 574db299498f
child 9505 6fc615dfc93f
permissions -rw-r--r--
Fixed SDL_SetWindowFullscreen on iOS for the last time, hopefully.

Fixed iOS version checking code.
slouken@2765
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@2765
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@2765
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@2765
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@2765
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@2765
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_UIKIT
slouken@6044
    24
slouken@5056
    25
#include "SDL_syswm.h"
slouken@2765
    26
#include "SDL_video.h"
slouken@2765
    27
#include "SDL_mouse.h"
icculus@4446
    28
#include "SDL_assert.h"
tim@5554
    29
#include "SDL_hints.h"
slouken@2765
    30
#include "../SDL_sysvideo.h"
slouken@2765
    31
#include "../SDL_pixels_c.h"
slouken@2765
    32
#include "../../events/SDL_events_c.h"
slouken@2765
    33
slouken@2765
    34
#include "SDL_uikitvideo.h"
slouken@2765
    35
#include "SDL_uikitevents.h"
slouken@6518
    36
#include "SDL_uikitmodes.h"
slouken@2765
    37
#include "SDL_uikitwindow.h"
slouken@2765
    38
#import "SDL_uikitappdelegate.h"
slouken@2765
    39
slouken@2765
    40
#import "SDL_uikitopenglview.h"
slouken@2765
    41
slouken@2765
    42
#include <Foundation/Foundation.h>
slouken@2765
    43
icculus@5520
    44
icculus@4446
    45
static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
icculus@4446
    46
{
slouken@5246
    47
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
tim@6267
    48
    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
slouken@2765
    49
    SDL_WindowData *data;
kees@6001
    50
slouken@2765
    51
    /* Allocate the window data */
slouken@2765
    52
    data = (SDL_WindowData *)SDL_malloc(sizeof(*data));
slouken@2765
    53
    if (!data) {
icculus@7037
    54
        return SDL_OutOfMemory();
slouken@2765
    55
    }
slouken@2765
    56
    data->uiwindow = uiwindow;
icculus@5520
    57
    data->viewcontroller = nil;
slouken@3685
    58
    data->view = nil;
slouken@3685
    59
slouken@2765
    60
    /* Fill in the SDL window with the window data */
slouken@3685
    61
    {
slouken@2765
    62
        window->x = 0;
slouken@2765
    63
        window->y = 0;
slouken@6077
    64
slime73@9502
    65
        CGRect frame = UIKit_ComputeViewFrame(window, displaydata->uiscreen);
slouken@6437
    66
slime73@9488
    67
        /* Get frame dimensions */
slime73@9502
    68
        int width = (int) frame.size.width;
slime73@9502
    69
        int height = (int) frame.size.height;
slouken@6520
    70
slouken@7191
    71
        /* Make sure the width/height are oriented correctly */
slouken@6520
    72
        if (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) {
slouken@6520
    73
            int temp = width;
slouken@6520
    74
            width = height;
slouken@6520
    75
            height = temp;
slouken@6077
    76
        }
slouken@6520
    77
slouken@6520
    78
        window->w = width;
slouken@6520
    79
        window->h = height;
slouken@2765
    80
    }
kees@6001
    81
slouken@3685
    82
    window->driverdata = data;
icculus@5520
    83
slouken@6262
    84
    /* only one window on iOS, always shown */
slouken@6262
    85
    window->flags &= ~SDL_WINDOW_HIDDEN;
slouken@2765
    86
slouken@7191
    87
    /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
slouken@7191
    88
     * This is only set if the window is on the main screen. Other screens
slouken@7191
    89
     *  just force the window to have the borderless flag.
slouken@7191
    90
     */
slouken@6520
    91
    if (displaydata->uiscreen == [UIScreen mainScreen]) {
slouken@7191
    92
        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
slouken@7191
    93
slouken@7862
    94
        /* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application
slouken@6520
    95
        if ([UIApplication sharedApplication].statusBarHidden) {
slouken@6520
    96
            window->flags |= SDL_WINDOW_BORDERLESS;
icculus@4446
    97
        } else {
slouken@6520
    98
            window->flags &= ~SDL_WINDOW_BORDERLESS;
icculus@4446
    99
        }
slouken@7862
   100
        */
slouken@6511
   101
    } else {
slouken@7191
   102
        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizeable */
slouken@7191
   103
        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
slouken@7191
   104
        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
slouken@6511
   105
    }
icculus@5518
   106
slouken@7191
   107
    /* The View Controller will handle rotating the view when the
slouken@7191
   108
     * device orientation changes. This will trigger resize events, if
slouken@7191
   109
     * appropriate.
slouken@7191
   110
     */
slime73@9495
   111
    data->viewcontroller = [[SDL_uikitviewcontroller alloc] initWithSDLWindow:window];
slouken@7191
   112
    [data->viewcontroller setTitle:@"SDL App"];  /* !!! FIXME: hook up SDL_SetWindowTitle() */
icculus@5518
   113
slouken@2765
   114
    return 0;
slouken@2765
   115
}
slouken@2765
   116
slouken@5056
   117
int
slouken@5246
   118
UIKit_CreateWindow(_THIS, SDL_Window *window)
slouken@5246
   119
{
slouken@5246
   120
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
tim@6267
   121
    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
tim@6267
   122
    const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
slouken@8891
   123
    const CGSize origsize = [[data->uiscreen currentMode] size];
icculus@4446
   124
slouken@7191
   125
    /* SDL currently puts this window at the start of display's linked list. We rely on this. */
slouken@5251
   126
    SDL_assert(_this->windows == window);
icculus@4446
   127
icculus@5520
   128
    /* We currently only handle a single window per display on iOS */
icculus@4446
   129
    if (window->next != NULL) {
icculus@7037
   130
        return SDL_SetError("Only one window allowed per display.");
slouken@3685
   131
    }
icculus@4446
   132
slouken@7191
   133
    /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
slouken@7191
   134
     * user, so it's in standby), try to force the display to a resolution
slouken@7191
   135
     * that most closely matches the desired window size.
slouken@7191
   136
     */
slouken@8891
   137
    if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
slouken@8891
   138
        if (display->num_display_modes == 0) {
slouken@8891
   139
            _this->GetDisplayModes(_this, display);
slouken@8891
   140
        }
icculus@4446
   141
slouken@8891
   142
        int i;
slouken@8891
   143
        const SDL_DisplayMode *bestmode = NULL;
slouken@8891
   144
        for (i = display->num_display_modes; i >= 0; i--) {
slouken@8891
   145
            const SDL_DisplayMode *mode = &display->display_modes[i];
slouken@8891
   146
            if ((mode->w >= window->w) && (mode->h >= window->h))
slouken@8891
   147
                bestmode = mode;
slouken@8891
   148
        }
icculus@4446
   149
slouken@8891
   150
        if (bestmode) {
slouken@8891
   151
            SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
slouken@8891
   152
            [data->uiscreen setCurrentMode:modedata->uiscreenmode];
icculus@5997
   153
slouken@8891
   154
            /* desktop_mode doesn't change here (the higher level will
slouken@8891
   155
             * use it to set all the screens back to their defaults
slouken@8891
   156
             * upon window destruction, SDL_Quit(), etc.
slouken@8891
   157
             */
slouken@8891
   158
            display->current_mode = *bestmode;
icculus@4446
   159
        }
icculus@4446
   160
    }
slouken@7191
   161
slouken@6520
   162
    if (data->uiscreen == [UIScreen mainScreen]) {
slouken@6520
   163
        if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
slouken@6520
   164
            [UIApplication sharedApplication].statusBarHidden = YES;
slouken@6520
   165
        } else {
slouken@6520
   166
            [UIApplication sharedApplication].statusBarHidden = NO;
slouken@6520
   167
        }
slouken@6520
   168
    }
slouken@7191
   169
slouken@6520
   170
    if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
slouken@6520
   171
        if (window->w > window->h) {
slouken@6520
   172
            if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
slouken@6520
   173
                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
slouken@6520
   174
            }
slouken@6520
   175
        } else if (window->w < window->h) {
slouken@6520
   176
            if (UIKit_IsDisplayLandscape(data->uiscreen)) {
slouken@6520
   177
                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
slouken@6520
   178
            }
slouken@6520
   179
        }
slouken@6520
   180
    }
icculus@4446
   181
slouken@3685
   182
    /* ignore the size user requested, and make a fullscreen window */
slouken@7191
   183
    /* !!! FIXME: can we have a smaller view? */
slime73@9488
   184
    UIWindow *uiwindow = [[UIWindow alloc] initWithFrame:[data->uiscreen bounds]];
kees@6001
   185
slouken@7191
   186
    /* put the window on an external display if appropriate. This implicitly
slouken@7191
   187
     * does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
slouken@7191
   188
     * main display, where we land by default, as that would eat the
slouken@7191
   189
     * status bar real estate.
slouken@7191
   190
     */
icculus@5529
   191
    if (external) {
tim@6267
   192
        [uiwindow setScreen:data->uiscreen];
icculus@4446
   193
    }
slouken@7862
   194
slouken@3685
   195
    if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
slouken@2765
   196
        [uiwindow release];
slouken@2765
   197
        return -1;
kees@6001
   198
    }
kees@6001
   199
slouken@3685
   200
    return 1;
kees@6001
   201
slouken@2765
   202
}
slouken@2765
   203
slouken@5056
   204
void
slouken@6379
   205
UIKit_ShowWindow(_THIS, SDL_Window * window)
slouken@6379
   206
{
slouken@6379
   207
    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
slouken@6379
   208
slouken@6379
   209
    [uiwindow makeKeyAndVisible];
slouken@6379
   210
}
slouken@6379
   211
slouken@6379
   212
void
slouken@6379
   213
UIKit_HideWindow(_THIS, SDL_Window * window)
slouken@6379
   214
{
slouken@6379
   215
    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
slouken@6379
   216
slouken@6379
   217
    uiwindow.hidden = YES;
slouken@6379
   218
}
slouken@6379
   219
slouken@6379
   220
void
icculus@6419
   221
UIKit_RaiseWindow(_THIS, SDL_Window * window)
icculus@6419
   222
{
slouken@7191
   223
    /* We don't currently offer a concept of "raising" the SDL window, since
slouken@7191
   224
     *  we only allow one per display, in the iOS fashion.
slouken@7191
   225
     * However, we use this entry point to rebind the context to the view
slouken@7191
   226
     *  during OnWindowRestored processing.
slouken@7191
   227
     */
icculus@6419
   228
    _this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
icculus@6419
   229
}
icculus@6419
   230
icculus@6419
   231
void
slouken@6073
   232
UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
slouken@6073
   233
{
tim@6267
   234
    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
slime73@9491
   235
    SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
slime73@9491
   236
    SDL_uikitviewcontroller *viewcontroller = windowdata->viewcontroller;
slime73@9502
   237
    CGRect frame;
slouken@6073
   238
slime73@9495
   239
    if (fullscreen || (window->flags & SDL_WINDOW_BORDERLESS)) {
slouken@6073
   240
        [UIApplication sharedApplication].statusBarHidden = YES;
slouken@6073
   241
    } else {
slouken@6073
   242
        [UIApplication sharedApplication].statusBarHidden = NO;
slouken@6437
   243
    }
slouken@6437
   244
slime73@9500
   245
    /* iOS 7+ won't update the status bar until we tell it to. */
slime73@9491
   246
    if ([viewcontroller respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
slime73@9491
   247
        [viewcontroller setNeedsStatusBarAppearanceUpdate];
slime73@9491
   248
    }
slime73@9491
   249
slime73@9497
   250
    /* Update the view's frame to account for the status bar change. */
slime73@9502
   251
    frame = UIKit_ComputeViewFrame(window, displaydata->uiscreen);
slime73@9502
   252
    windowdata->view.frame = frame;
slime73@9497
   253
    [windowdata->view setNeedsLayout];
slime73@9497
   254
    [windowdata->view layoutIfNeeded];
slime73@9497
   255
slime73@9488
   256
    /* Get frame dimensions */
slime73@9502
   257
    int width = (int) frame.size.width;
slime73@9502
   258
    int height = (int) frame.size.height;
tim@6267
   259
slouken@6077
   260
    /* We can pick either width or height here and we'll rotate the
slouken@6077
   261
       screen to match, so we pick the closest to what we wanted.
slouken@6077
   262
     */
slouken@6077
   263
    if (window->w >= window->h) {
slime73@9497
   264
        window->w = SDL_max(width, height);
slime73@9497
   265
        window->h = SDL_min(width, height);
slouken@6077
   266
    } else {
slime73@9497
   267
        window->w = SDL_min(width, height);
slime73@9497
   268
        window->h = SDL_max(width, height);
slouken@6077
   269
    }
slouken@6073
   270
}
slouken@6073
   271
slouken@6073
   272
void
kees@6003
   273
UIKit_DestroyWindow(_THIS, SDL_Window * window)
kees@6003
   274
{
slouken@3685
   275
    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
slouken@8905
   276
slouken@3685
   277
    if (data) {
icculus@5520
   278
        [data->viewcontroller release];
icculus@4446
   279
        [data->uiwindow release];
icculus@4446
   280
        SDL_free(data);
slouken@3685
   281
    }
slouken@8978
   282
    window->driverdata = NULL;
slouken@2765
   283
}
slouken@2765
   284
slouken@5056
   285
SDL_bool
slouken@5056
   286
UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
slouken@5056
   287
{
slouken@5056
   288
    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
slouken@5056
   289
slouken@5056
   290
    if (info->version.major <= SDL_MAJOR_VERSION) {
slouken@5056
   291
        info->subsystem = SDL_SYSWM_UIKIT;
slouken@5056
   292
        info->info.uikit.window = uiwindow;
slouken@5056
   293
        return SDL_TRUE;
slouken@5056
   294
    } else {
slouken@5056
   295
        SDL_SetError("Application not compiled with SDL %d.%d\n",
slouken@5056
   296
                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
slouken@5056
   297
        return SDL_FALSE;
slouken@5056
   298
    }
slouken@5056
   299
}
slouken@5056
   300
slouken@6342
   301
int
slouken@6342
   302
SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
slouken@6342
   303
{
slouken@6342
   304
    SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL;
slouken@6342
   305
slouken@6342
   306
    if (!data || !data->view) {
icculus@7037
   307
        return SDL_SetError("Invalid window or view not set");
slouken@6342
   308
    }
slouken@6342
   309
slouken@6342
   310
    [data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
slouken@6342
   311
    return 0;
slouken@6342
   312
}
slouken@6342
   313
slouken@6044
   314
#endif /* SDL_VIDEO_DRIVER_UIKIT */
slouken@6044
   315
slouken@2765
   316
/* vi: set ts=4 sw=4 expandtab: */