Atlas - SDL_uikitmodes.m
Home / ext / SDL2 / src / video / uikit Lines: 1 | Size: 11401 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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_assert.h" 26#include "SDL_uikitmodes.h" 27 28#include "../../events/SDL_events_c.h" 29 30@implementation SDL_DisplayData 31 32@synthesize uiscreen; 33 34@end 35 36@implementation SDL_DisplayModeData 37 38@synthesize uiscreenmode; 39 40@end 41 42 43static int 44UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode, 45 UIScreenMode * uiscreenmode) 46{ 47 SDL_DisplayModeData *data = nil; 48 49 if (uiscreenmode != nil) { 50 /* Allocate the display mode data */ 51 data = [[SDL_DisplayModeData alloc] init]; 52 if (!data) { 53 return SDL_OutOfMemory(); 54 } 55 56 data.uiscreenmode = uiscreenmode; 57 } 58 59 mode->driverdata = (void *) CFBridgingRetain(data); 60 61 return 0; 62} 63 64static void 65UIKit_FreeDisplayModeData(SDL_DisplayMode * mode) 66{ 67 if (mode->driverdata != NULL) { 68 CFRelease(mode->driverdata); 69 mode->driverdata = NULL; 70 } 71} 72 73static NSUInteger 74UIKit_GetDisplayModeRefreshRate(UIScreen *uiscreen) 75{ 76#ifdef __IPHONE_10_3 77 if ([uiscreen respondsToSelector:@selector(maximumFramesPerSecond)]) { 78 return uiscreen.maximumFramesPerSecond; 79 } 80#endif 81 return 0; 82} 83 84static int 85UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h, 86 UIScreen * uiscreen, UIScreenMode * uiscreenmode) 87{ 88 SDL_DisplayMode mode; 89 SDL_zero(mode); 90 91 if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) { 92 return -1; 93 } 94 95 mode.format = SDL_PIXELFORMAT_ABGR8888; 96 mode.refresh_rate = (int) UIKit_GetDisplayModeRefreshRate(uiscreen); 97 mode.w = w; 98 mode.h = h; 99 100 if (SDL_AddDisplayMode(display, &mode)) { 101 return 0; 102 } else { 103 UIKit_FreeDisplayModeData(&mode); 104 return -1; 105 } 106} 107 108static int 109UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, UIScreen * uiscreen, 110 UIScreenMode * uiscreenmode, SDL_bool addRotation) 111{ 112 if (UIKit_AddSingleDisplayMode(display, w, h, uiscreen, uiscreenmode) < 0) { 113 return -1; 114 } 115 116 if (addRotation) { 117 /* Add the rotated version */ 118 if (UIKit_AddSingleDisplayMode(display, h, w, uiscreen, uiscreenmode) < 0) { 119 return -1; 120 } 121 } 122 123 return 0; 124} 125 126static int 127UIKit_AddDisplay(UIScreen *uiscreen) 128{ 129 UIScreenMode *uiscreenmode = uiscreen.currentMode; 130 CGSize size = uiscreen.bounds.size; 131 SDL_VideoDisplay display; 132 SDL_DisplayMode mode; 133 SDL_zero(mode); 134 135 /* Make sure the width/height are oriented correctly */ 136 if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) { 137 CGFloat height = size.width; 138 size.width = size.height; 139 size.height = height; 140 } 141 142 mode.format = SDL_PIXELFORMAT_ABGR8888; 143 mode.refresh_rate = (int) UIKit_GetDisplayModeRefreshRate(uiscreen); 144 mode.w = (int) size.width; 145 mode.h = (int) size.height; 146 147 if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) { 148 return -1; 149 } 150 151 SDL_zero(display); 152 display.desktop_mode = mode; 153 display.current_mode = mode; 154 155 /* Allocate the display data */ 156 SDL_DisplayData *data = [[SDL_DisplayData alloc] init]; 157 if (!data) { 158 UIKit_FreeDisplayModeData(&display.desktop_mode); 159 return SDL_OutOfMemory(); 160 } 161 162 data.uiscreen = uiscreen; 163 164 display.driverdata = (void *) CFBridgingRetain(data); 165 SDL_AddVideoDisplay(&display); 166 167 return 0; 168} 169 170SDL_bool 171UIKit_IsDisplayLandscape(UIScreen *uiscreen) 172{ 173#if !TARGET_OS_TV 174 if (uiscreen == [UIScreen mainScreen]) { 175 return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation); 176 } else 177#endif /* !TARGET_OS_TV */ 178 { 179 CGSize size = uiscreen.bounds.size; 180 return (size.width > size.height); 181 } 182} 183 184int 185UIKit_InitModes(_THIS) 186{ 187 @autoreleasepool { 188 for (UIScreen *uiscreen in [UIScreen screens]) { 189 if (UIKit_AddDisplay(uiscreen) < 0) { 190 return -1; 191 } 192 } 193#if !TARGET_OS_TV 194 SDL_OnApplicationDidChangeStatusBarOrientation(); 195#endif 196 } 197 198 return 0; 199} 200 201void 202UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) 203{ 204 @autoreleasepool { 205 SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; 206 207 SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen); 208 SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]); 209 CGFloat scale = data.uiscreen.scale; 210 NSArray *availableModes = nil; 211 212#if TARGET_OS_TV 213 addRotation = SDL_FALSE; 214 availableModes = @[data.uiscreen.currentMode]; 215#else 216 availableModes = data.uiscreen.availableModes; 217#endif 218 219#ifdef __IPHONE_8_0 220 /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than 221 * 1242x2208 (414x736@3x), so we should use the native scale. */ 222 if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) { 223 scale = data.uiscreen.nativeScale; 224 } 225#endif 226 227 for (UIScreenMode *uimode in availableModes) { 228 /* The size of a UIScreenMode is in pixels, but we deal exclusively 229 * in points (except in SDL_GL_GetDrawableSize.) */ 230 int w = (int)(uimode.size.width / scale); 231 int h = (int)(uimode.size.height / scale); 232 233 /* Make sure the width/height are oriented correctly */ 234 if (isLandscape != (w > h)) { 235 int tmp = w; 236 w = h; 237 h = tmp; 238 } 239 240 UIKit_AddDisplayMode(display, w, h, data.uiscreen, uimode, addRotation); 241 } 242 } 243} 244 245int 246UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) 247{ 248 @autoreleasepool { 249 SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; 250 251#if !TARGET_OS_TV 252 SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata; 253 [data.uiscreen setCurrentMode:modedata.uiscreenmode]; 254#endif 255 256 if (data.uiscreen == [UIScreen mainScreen]) { 257 /* [UIApplication setStatusBarOrientation:] no longer works reliably 258 * in recent iOS versions, so we can't rotate the screen when setting 259 * the display mode. */ 260 if (mode->w > mode->h) { 261 if (!UIKit_IsDisplayLandscape(data.uiscreen)) { 262 return SDL_SetError("Screen orientation does not match display mode size"); 263 } 264 } else if (mode->w < mode->h) { 265 if (UIKit_IsDisplayLandscape(data.uiscreen)) { 266 return SDL_SetError("Screen orientation does not match display mode size"); 267 } 268 } 269 } 270 } 271 272 return 0; 273} 274 275int 276UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) 277{ 278 @autoreleasepool { 279 int displayIndex = (int) (display - _this->displays); 280 SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; 281 CGRect frame = data.uiscreen.bounds; 282 283 /* the default function iterates displays to make a fake offset, 284 as if all the displays were side-by-side, which is fine for iOS. */ 285 if (SDL_GetDisplayBounds(displayIndex, rect) < 0) { 286 return -1; 287 } 288 289#if !TARGET_OS_TV && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 290 if (!UIKit_IsSystemVersionAtLeast(7.0)) { 291 frame = [data.uiscreen applicationFrame]; 292 } 293#endif 294 295 rect->x += frame.origin.x; 296 rect->y += frame.origin.y; 297 rect->w = frame.size.width; 298 rect->h = frame.size.height; 299 } 300 301 return 0; 302} 303 304void 305UIKit_QuitModes(_THIS) 306{ 307 /* Release Objective-C objects, so higher level doesn't free() them. */ 308 int i, j; 309 @autoreleasepool { 310 for (i = 0; i < _this->num_displays; i++) { 311 SDL_VideoDisplay *display = &_this->displays[i]; 312 313 UIKit_FreeDisplayModeData(&display->desktop_mode); 314 for (j = 0; j < display->num_display_modes; j++) { 315 SDL_DisplayMode *mode = &display->display_modes[j]; 316 UIKit_FreeDisplayModeData(mode); 317 } 318 319 if (display->driverdata != NULL) { 320 CFRelease(display->driverdata); 321 display->driverdata = NULL; 322 } 323 } 324 } 325} 326 327void SDL_OnApplicationDidChangeStatusBarOrientation() 328{ 329 BOOL isLandscape = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation); 330 SDL_VideoDisplay *display = SDL_GetDisplay(0); 331 332 if (display) { 333 SDL_DisplayMode *desktopmode = &display->desktop_mode; 334 SDL_DisplayMode *currentmode = &display->current_mode; 335 SDL_DisplayOrientation orientation = SDL_ORIENTATION_UNKNOWN; 336 337 /* The desktop display mode should be kept in sync with the screen 338 * orientation so that updating a window's fullscreen state to 339 * SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the 340 * correct orientation. */ 341 if (isLandscape != (desktopmode->w > desktopmode->h)) { 342 int height = desktopmode->w; 343 desktopmode->w = desktopmode->h; 344 desktopmode->h = height; 345 } 346 347 /* Same deal with the current mode + SDL_GetCurrentDisplayMode. */ 348 if (isLandscape != (currentmode->w > currentmode->h)) { 349 int height = currentmode->w; 350 currentmode->w = currentmode->h; 351 currentmode->h = height; 352 } 353 354 switch ([UIApplication sharedApplication].statusBarOrientation) { 355 case UIInterfaceOrientationPortrait: 356 orientation = SDL_ORIENTATION_PORTRAIT; 357 break; 358 case UIInterfaceOrientationPortraitUpsideDown: 359 orientation = SDL_ORIENTATION_PORTRAIT_FLIPPED; 360 break; 361 case UIInterfaceOrientationLandscapeLeft: 362 /* Bug: UIInterfaceOrientationLandscapeLeft/Right are reversed - http://openradar.appspot.com/7216046 */ 363 orientation = SDL_ORIENTATION_LANDSCAPE_FLIPPED; 364 break; 365 case UIInterfaceOrientationLandscapeRight: 366 /* Bug: UIInterfaceOrientationLandscapeLeft/Right are reversed - http://openradar.appspot.com/7216046 */ 367 orientation = SDL_ORIENTATION_LANDSCAPE; 368 break; 369 default: 370 break; 371 } 372 SDL_SendDisplayEvent(display, SDL_DISPLAYEVENT_ORIENTATION, orientation); 373 } 374} 375 376#endif /* SDL_VIDEO_DRIVER_UIKIT */ 377 378/* vi: set ts=4 sw=4 expandtab: */ 379[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.