cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_uikitwindow.m (11117B)


      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_syswm.h"
     26#include "SDL_video.h"
     27#include "SDL_mouse.h"
     28#include "SDL_assert.h"
     29#include "SDL_hints.h"
     30#include "../SDL_sysvideo.h"
     31#include "../SDL_pixels_c.h"
     32#include "../../events/SDL_events_c.h"
     33
     34#include "SDL_uikitvideo.h"
     35#include "SDL_uikitevents.h"
     36#include "SDL_uikitmodes.h"
     37#include "SDL_uikitwindow.h"
     38#import "SDL_uikitappdelegate.h"
     39
     40#import "SDL_uikitopenglview.h"
     41
     42#include <Foundation/Foundation.h>
     43
     44
     45
     46
     47static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
     48{
     49    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
     50    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
     51    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
     52    SDL_WindowData *data;
     53
     54    /* Allocate the window data */
     55    data = (SDL_WindowData *)SDL_malloc(sizeof(*data));
     56    if (!data) {
     57        return SDL_OutOfMemory();
     58    }
     59    data->uiwindow = uiwindow;
     60    data->viewcontroller = nil;
     61    data->view = nil;
     62
     63    /* Fill in the SDL window with the window data */
     64    {
     65        window->x = 0;
     66        window->y = 0;
     67
     68        CGRect bounds;
     69        if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
     70            bounds = [displaydata->uiscreen bounds];
     71        } else {
     72            bounds = [displaydata->uiscreen applicationFrame];
     73        }
     74
     75        /* Get frame dimensions in pixels */
     76        int width = (int)(bounds.size.width * displaymodedata->scale);
     77        int height = (int)(bounds.size.height * displaymodedata->scale);
     78
     79        /* Make sure the width/height are oriented correctly */
     80        if (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) {
     81            int temp = width;
     82            width = height;
     83            height = temp;
     84        }
     85
     86        window->w = width;
     87        window->h = height;
     88    }
     89
     90    window->driverdata = data;
     91
     92    /* only one window on iOS, always shown */
     93    window->flags &= ~SDL_WINDOW_HIDDEN;
     94
     95    /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
     96     * This is only set if the window is on the main screen. Other screens
     97     *  just force the window to have the borderless flag.
     98     */
     99    if (displaydata->uiscreen == [UIScreen mainScreen]) {
    100        window->flags |= SDL_WINDOW_INPUT_FOCUS;  /* always has input focus */
    101
    102        /* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application
    103        if ([UIApplication sharedApplication].statusBarHidden) {
    104            window->flags |= SDL_WINDOW_BORDERLESS;
    105        } else {
    106            window->flags &= ~SDL_WINDOW_BORDERLESS;
    107        }
    108        */
    109    } else {
    110        window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizeable */
    111        window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
    112        window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
    113    }
    114
    115    /* The View Controller will handle rotating the view when the
    116     * device orientation changes. This will trigger resize events, if
    117     * appropriate.
    118     */
    119    SDL_uikitviewcontroller *controller;
    120    controller = [SDL_uikitviewcontroller alloc];
    121    data->viewcontroller = [controller initWithSDLWindow:window];
    122    [data->viewcontroller setTitle:@"SDL App"];  /* !!! FIXME: hook up SDL_SetWindowTitle() */
    123
    124    return 0;
    125}
    126
    127int
    128UIKit_CreateWindow(_THIS, SDL_Window *window)
    129{
    130    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    131    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
    132    const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
    133    const CGSize origsize = [[data->uiscreen currentMode] size];
    134
    135    /* SDL currently puts this window at the start of display's linked list. We rely on this. */
    136    SDL_assert(_this->windows == window);
    137
    138    /* We currently only handle a single window per display on iOS */
    139    if (window->next != NULL) {
    140        return SDL_SetError("Only one window allowed per display.");
    141    }
    142
    143    /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
    144     * user, so it's in standby), try to force the display to a resolution
    145     * that most closely matches the desired window size.
    146     */
    147    if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
    148        if (display->num_display_modes == 0) {
    149            _this->GetDisplayModes(_this, display);
    150        }
    151
    152        int i;
    153        const SDL_DisplayMode *bestmode = NULL;
    154        for (i = display->num_display_modes; i >= 0; i--) {
    155            const SDL_DisplayMode *mode = &display->display_modes[i];
    156            if ((mode->w >= window->w) && (mode->h >= window->h))
    157                bestmode = mode;
    158        }
    159
    160        if (bestmode) {
    161            SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
    162            [data->uiscreen setCurrentMode:modedata->uiscreenmode];
    163
    164            /* desktop_mode doesn't change here (the higher level will
    165             * use it to set all the screens back to their defaults
    166             * upon window destruction, SDL_Quit(), etc.
    167             */
    168            display->current_mode = *bestmode;
    169        }
    170    }
    171
    172    if (data->uiscreen == [UIScreen mainScreen]) {
    173        if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
    174            [UIApplication sharedApplication].statusBarHidden = YES;
    175        } else {
    176            [UIApplication sharedApplication].statusBarHidden = NO;
    177        }
    178    }
    179
    180    if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
    181        if (window->w > window->h) {
    182            if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
    183                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
    184            }
    185        } else if (window->w < window->h) {
    186            if (UIKit_IsDisplayLandscape(data->uiscreen)) {
    187                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
    188            }
    189        }
    190    }
    191
    192    /* ignore the size user requested, and make a fullscreen window */
    193    /* !!! FIXME: can we have a smaller view? */
    194    UIWindow *uiwindow = [UIWindow alloc];
    195    uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]];
    196
    197    /* put the window on an external display if appropriate. This implicitly
    198     * does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
    199     * main display, where we land by default, as that would eat the
    200     * status bar real estate.
    201     */
    202    if (external) {
    203        [uiwindow setScreen:data->uiscreen];
    204    }
    205
    206    if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
    207        [uiwindow release];
    208        return -1;
    209    }
    210
    211    return 1;
    212
    213}
    214
    215void
    216UIKit_ShowWindow(_THIS, SDL_Window * window)
    217{
    218    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
    219
    220    [uiwindow makeKeyAndVisible];
    221}
    222
    223void
    224UIKit_HideWindow(_THIS, SDL_Window * window)
    225{
    226    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
    227
    228    uiwindow.hidden = YES;
    229}
    230
    231void
    232UIKit_RaiseWindow(_THIS, SDL_Window * window)
    233{
    234    /* We don't currently offer a concept of "raising" the SDL window, since
    235     *  we only allow one per display, in the iOS fashion.
    236     * However, we use this entry point to rebind the context to the view
    237     *  during OnWindowRestored processing.
    238     */
    239    _this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
    240}
    241
    242void
    243UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
    244{
    245    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
    246    SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
    247    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
    248
    249    if (fullscreen) {
    250        [UIApplication sharedApplication].statusBarHidden = YES;
    251    } else {
    252        [UIApplication sharedApplication].statusBarHidden = NO;
    253    }
    254
    255    CGRect bounds;
    256    if (fullscreen) {
    257        bounds = [displaydata->uiscreen bounds];
    258    } else {
    259        bounds = [displaydata->uiscreen applicationFrame];
    260    }
    261
    262    /* Get frame dimensions in pixels */
    263    int width = (int)(bounds.size.width * displaymodedata->scale);
    264    int height = (int)(bounds.size.height * displaymodedata->scale);
    265
    266    /* We can pick either width or height here and we'll rotate the
    267       screen to match, so we pick the closest to what we wanted.
    268     */
    269    if (window->w >= window->h) {
    270        if (width > height) {
    271            window->w = width;
    272            window->h = height;
    273        } else {
    274            window->w = height;
    275            window->h = width;
    276        }
    277    } else {
    278        if (width > height) {
    279            window->w = height;
    280            window->h = width;
    281        } else {
    282            window->w = width;
    283            window->h = height;
    284        }
    285    }
    286}
    287
    288void
    289UIKit_DestroyWindow(_THIS, SDL_Window * window)
    290{
    291    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
    292
    293    if (data) {
    294        [data->viewcontroller release];
    295        [data->uiwindow release];
    296        SDL_free(data);
    297    }
    298    window->driverdata = NULL;
    299}
    300
    301SDL_bool
    302UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
    303{
    304    UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
    305
    306    if (info->version.major <= SDL_MAJOR_VERSION) {
    307        info->subsystem = SDL_SYSWM_UIKIT;
    308        info->info.uikit.window = uiwindow;
    309        return SDL_TRUE;
    310    } else {
    311        SDL_SetError("Application not compiled with SDL %d.%d\n",
    312                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
    313        return SDL_FALSE;
    314    }
    315}
    316
    317int
    318SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
    319{
    320    SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL;
    321
    322    if (!data || !data->view) {
    323        return SDL_SetError("Invalid window or view not set");
    324    }
    325
    326    [data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
    327    return 0;
    328}
    329
    330#endif /* SDL_VIDEO_DRIVER_UIKIT */
    331
    332/* vi: set ts=4 sw=4 expandtab: */