src/video/uikit/SDL_uikitwindow.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 14 Jul 2013 11:28:44 -0700
changeset 7776 d4a39491577f
parent 7192 4d862d2ab3bf
child 7862 d20e37f08533
child 8477 ad08f0d710f3
permissions -rw-r--r--
Added the platform specific messagebox function to the video function list
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.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 
    47 static 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         if ([UIApplication sharedApplication].statusBarHidden) {
   103             window->flags |= SDL_WINDOW_BORDERLESS;
   104         } else {
   105             window->flags &= ~SDL_WINDOW_BORDERLESS;
   106         }
   107     } else {
   108         window->flags &= ~SDL_WINDOW_RESIZABLE;  /* window is NEVER resizeable */
   109         window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  /* never has input focus */
   110         window->flags |= SDL_WINDOW_BORDERLESS;  /* never has a status bar. */
   111     }
   112 
   113     /* The View Controller will handle rotating the view when the
   114      * device orientation changes. This will trigger resize events, if
   115      * appropriate.
   116      */
   117     SDL_uikitviewcontroller *controller;
   118     controller = [SDL_uikitviewcontroller alloc];
   119     data->viewcontroller = [controller initWithSDLWindow:window];
   120     [data->viewcontroller setTitle:@"SDL App"];  /* !!! FIXME: hook up SDL_SetWindowTitle() */
   121 
   122     return 0;
   123 }
   124 
   125 int
   126 UIKit_CreateWindow(_THIS, SDL_Window *window)
   127 {
   128     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   129     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   130     const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
   131 
   132     /* SDL currently puts this window at the start of display's linked list. We rely on this. */
   133     SDL_assert(_this->windows == window);
   134 
   135     /* We currently only handle a single window per display on iOS */
   136     if (window->next != NULL) {
   137         return SDL_SetError("Only one window allowed per display.");
   138     }
   139 
   140     /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
   141      * user, so it's in standby), try to force the display to a resolution
   142      * that most closely matches the desired window size.
   143      */
   144     if (SDL_UIKit_supports_multiple_displays) {
   145         const CGSize origsize = [[data->uiscreen currentMode] size];
   146         if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
   147             if (display->num_display_modes == 0) {
   148                 _this->GetDisplayModes(_this, display);
   149             }
   150 
   151             int i;
   152             const SDL_DisplayMode *bestmode = NULL;
   153             for (i = display->num_display_modes; i >= 0; i--) {
   154                 const SDL_DisplayMode *mode = &display->display_modes[i];
   155                 if ((mode->w >= window->w) && (mode->h >= window->h))
   156                     bestmode = mode;
   157             }
   158 
   159             if (bestmode) {
   160                 SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
   161                 [data->uiscreen setCurrentMode:modedata->uiscreenmode];
   162 
   163                 /* desktop_mode doesn't change here (the higher level will
   164                  * use it to set all the screens back to their defaults
   165                  * upon window destruction, SDL_Quit(), etc.
   166                  */
   167                 display->current_mode = *bestmode;
   168             }
   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 
   215 void
   216 UIKit_ShowWindow(_THIS, SDL_Window * window)
   217 {
   218     UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
   219 
   220     [uiwindow makeKeyAndVisible];
   221 }
   222 
   223 void
   224 UIKit_HideWindow(_THIS, SDL_Window * window)
   225 {
   226     UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
   227 
   228     uiwindow.hidden = YES;
   229 }
   230 
   231 void
   232 UIKit_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 
   242 void
   243 UIKit_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 
   288 void
   289 UIKit_DestroyWindow(_THIS, SDL_Window * window)
   290 {
   291     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   292     if (data) {
   293         [data->viewcontroller release];
   294         [data->uiwindow release];
   295         SDL_free(data);
   296         window->driverdata = NULL;
   297     }
   298 }
   299 
   300 SDL_bool
   301 UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   302 {
   303     UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
   304 
   305     if (info->version.major <= SDL_MAJOR_VERSION) {
   306         info->subsystem = SDL_SYSWM_UIKIT;
   307         info->info.uikit.window = uiwindow;
   308         return SDL_TRUE;
   309     } else {
   310         SDL_SetError("Application not compiled with SDL %d.%d\n",
   311                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   312         return SDL_FALSE;
   313     }
   314 }
   315 
   316 int
   317 SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
   318 {
   319     SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL;
   320 
   321     if (!data || !data->view) {
   322         return SDL_SetError("Invalid window or view not set");
   323     }
   324 
   325     [data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
   326     return 0;
   327 }
   328 
   329 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   330 
   331 /* vi: set ts=4 sw=4 expandtab: */