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