src/video/uikit/SDL_uikitwindow.m
author Sam Lantinga <slouken@libsdl.org>
Tue, 08 Nov 2011 00:17:41 -0500
changeset 6064 498e0234dfe6
parent 6044 35448a5ea044
child 6073 9738f2a8eee4
permissions -rw-r--r--
To answer the FIXME, no, we shouldn't force this. The fullscreen flag implies borderless behavior even though the flag isn't set on the window (in case fullscreen is toggled)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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_uikitwindow.h"
    37 #import "SDL_uikitappdelegate.h"
    38 
    39 #import "SDL_uikitopenglview.h"
    40 
    41 #include <Foundation/Foundation.h>
    42 
    43 
    44 
    45 
    46 static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
    47 {
    48     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    49     UIScreen *uiscreen = (UIScreen *) display->driverdata;
    50     SDL_WindowData *data;
    51 
    52     /* Allocate the window data */
    53     data = (SDL_WindowData *)SDL_malloc(sizeof(*data));
    54     if (!data) {
    55         SDL_OutOfMemory();
    56         return -1;
    57     }
    58     data->uiwindow = uiwindow;
    59     data->viewcontroller = nil;
    60     data->view = nil;
    61 
    62     /* Fill in the SDL window with the window data */
    63     {
    64         window->x = 0;
    65         window->y = 0;
    66         window->w = (int)uiwindow.frame.size.width;
    67         window->h = (int)uiwindow.frame.size.height;
    68     }
    69 
    70     window->driverdata = data;
    71 
    72     window->flags |= SDL_WINDOW_SHOWN;            /* only one window on iOS, always shown */
    73 
    74     // SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
    75     // This is only set if the window is on the main screen. Other screens
    76     //  just force the window to have the borderless flag.
    77     if ([UIScreen mainScreen] != uiscreen) {
    78         window->flags &= ~SDL_WINDOW_RESIZABLE;  // window is NEVER resizeable
    79         window->flags &= ~SDL_WINDOW_INPUT_FOCUS;  // never has input focus
    80         window->flags |= SDL_WINDOW_BORDERLESS;  // never has a status bar.
    81     } else {
    82         window->flags |= SDL_WINDOW_INPUT_FOCUS;  // always has input focus
    83 
    84         if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
    85             [UIApplication sharedApplication].statusBarHidden = YES;
    86         } else {
    87             [UIApplication sharedApplication].statusBarHidden = NO;
    88         }
    89 
    90         //const UIDeviceOrientation o = [[UIDevice currentDevice] orientation];
    91         //const BOOL landscape = (o == UIDeviceOrientationLandscapeLeft) ||
    92         //                           (o == UIDeviceOrientationLandscapeRight);
    93         //const BOOL rotate = ( ((window->w > window->h) && (!landscape)) ||
    94         //                      ((window->w < window->h) && (landscape)) );
    95 
    96         // The View Controller will handle rotating the view when the
    97         //  device orientation changes. This will trigger resize events, if
    98         //  appropriate.
    99         SDL_uikitviewcontroller *controller;
   100         controller = [SDL_uikitviewcontroller alloc];
   101         data->viewcontroller = [controller initWithSDLWindow:window];
   102         [data->viewcontroller setTitle:@"SDL App"];  // !!! FIXME: hook up SDL_SetWindowTitle()
   103         // !!! FIXME: if (rotate), force a "resize" right at the start
   104     }
   105 
   106     return 0;
   107 }
   108 
   109 int
   110 UIKit_CreateWindow(_THIS, SDL_Window *window)
   111 {
   112     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   113     UIScreen *uiscreen = (UIScreen *) display->driverdata;
   114     const BOOL external = ([UIScreen mainScreen] != uiscreen);
   115 
   116     // SDL currently puts this window at the start of display's linked list. We rely on this.
   117     SDL_assert(_this->windows == window);
   118 
   119     /* We currently only handle a single window per display on iOS */
   120     if (window->next != NULL) {
   121         SDL_SetError("Only one window allowed per display.");
   122         return -1;
   123     }
   124 
   125     // Non-mainscreen windows must be force to borderless, as there's no
   126     //  status bar there, and we want to get the right dimensions later in
   127     //  this function.
   128     if (external) {
   129         window->flags |= SDL_WINDOW_BORDERLESS;
   130     }
   131 
   132     // If monitor has a resolution of 0x0 (hasn't been explicitly set by the
   133     //  user, so it's in standby), try to force the display to a resolution
   134     //  that most closely matches the desired window size.
   135     if (SDL_UIKit_supports_multiple_displays) {
   136         const CGSize origsize = [[uiscreen currentMode] size];
   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                 UIScreenMode *uimode = (UIScreenMode *) bestmode->driverdata;
   152                 [uiscreen setCurrentMode:uimode];
   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                 [((UIScreenMode *) display->current_mode.driverdata) release];
   158                 display->current_mode = *bestmode;
   159                 [((UIScreenMode *) display->current_mode.driverdata) retain];
   160             }
   161         }
   162     }
   163 
   164     /* ignore the size user requested, and make a fullscreen window */
   165     // !!! FIXME: can we have a smaller view?
   166     UIWindow *uiwindow = [UIWindow alloc];
   167     if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS))
   168         uiwindow = [uiwindow initWithFrame:[uiscreen bounds]];
   169     else
   170         uiwindow = [uiwindow initWithFrame:[uiscreen applicationFrame]];
   171 
   172     // put the window on an external display if appropriate. This implicitly
   173     //  does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
   174     //  main display, where we land by default, as that would eat the
   175     //  status bar real estate.
   176     if (external) {
   177         [uiwindow setScreen:uiscreen];
   178     }
   179 
   180     if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
   181         [uiwindow release];
   182         return -1;
   183     }
   184 
   185     return 1;
   186 
   187 }
   188 
   189 void
   190 UIKit_DestroyWindow(_THIS, SDL_Window * window)
   191 {
   192     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   193     if (data) {
   194         [data->viewcontroller release];
   195         [data->uiwindow release];
   196         SDL_free(data);
   197         window->driverdata = NULL;
   198     }
   199 }
   200 
   201 SDL_bool
   202 UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   203 {
   204     UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
   205 
   206     if (info->version.major <= SDL_MAJOR_VERSION) {
   207         info->subsystem = SDL_SYSWM_UIKIT;
   208         info->info.uikit.window = uiwindow;
   209         return SDL_TRUE;
   210     } else {
   211         SDL_SetError("Application not compiled with SDL %d.%d\n",
   212                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   213         return SDL_FALSE;
   214     }
   215 }
   216 
   217 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   218 
   219 /* vi: set ts=4 sw=4 expandtab: */