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: */