SDL 2.0
SDL_uikitmodes.m
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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_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{
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{
90
91 if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
92 return -1;
93 }
94
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;
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
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
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
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
195#endif
196 }
197
198 return 0;
199}
200
201void
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 for (UIScreenMode *uimode in availableModes) {
220 /* The size of a UIScreenMode is in pixels, but we deal exclusively
221 * in points (except in SDL_GL_GetDrawableSize.)
222 *
223 * For devices such as iPhone 6/7/8 Plus, the UIScreenMode reported
224 * by iOS is not in physical pixels of the display, but rather the
225 * point size times the scale. For example, on iOS 12.2 on iPhone 8
226 * Plus the uimode.size is 1242x2208 and the uiscreen.scale is 3
227 * thus this will give the size in points which is 414x736. The code
228 * used to use the nativeScale, assuming UIScreenMode returned raw
229 * physical pixels (as suggested by its documentation, but in
230 * practice it is returning the retina pixels). */
231 int w = (int)(uimode.size.width / scale);
232 int h = (int)(uimode.size.height / scale);
233
234 /* Make sure the width/height are oriented correctly */
235 if (isLandscape != (w > h)) {
236 int tmp = w;
237 w = h;
238 h = tmp;
239 }
240
241 UIKit_AddDisplayMode(display, w, h, data.uiscreen, uimode, addRotation);
242 }
243 }
244}
245
246int
248{
249 @autoreleasepool {
250 SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
251
252#if !TARGET_OS_TV
253 SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
254 [data.uiscreen setCurrentMode:modedata.uiscreenmode];
255#endif
256
257 if (data.uiscreen == [UIScreen mainScreen]) {
258 /* [UIApplication setStatusBarOrientation:] no longer works reliably
259 * in recent iOS versions, so we can't rotate the screen when setting
260 * the display mode. */
261 if (mode->w > mode->h) {
262 if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
263 return SDL_SetError("Screen orientation does not match display mode size");
264 }
265 } else if (mode->w < mode->h) {
266 if (UIKit_IsDisplayLandscape(data.uiscreen)) {
267 return SDL_SetError("Screen orientation does not match display mode size");
268 }
269 }
270 }
271 }
272
273 return 0;
274}
275
276int
278{
279 @autoreleasepool {
280 int displayIndex = (int) (display - _this->displays);
281 SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
282 CGRect frame = data.uiscreen.bounds;
283
284 /* the default function iterates displays to make a fake offset,
285 as if all the displays were side-by-side, which is fine for iOS. */
286 if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
287 return -1;
288 }
289
290#if !TARGET_OS_TV && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
292 frame = [data.uiscreen applicationFrame];
293 }
294#endif
295
296 rect->x += frame.origin.x;
297 rect->y += frame.origin.y;
298 rect->w = frame.size.width;
299 rect->h = frame.size.height;
300 }
301
302 return 0;
303}
304
305void
307{
308 /* Release Objective-C objects, so higher level doesn't free() them. */
309 int i, j;
310 @autoreleasepool {
311 for (i = 0; i < _this->num_displays; i++) {
312 SDL_VideoDisplay *display = &_this->displays[i];
313
314 UIKit_FreeDisplayModeData(&display->desktop_mode);
315 for (j = 0; j < display->num_display_modes; j++) {
316 SDL_DisplayMode *mode = &display->display_modes[j];
317 UIKit_FreeDisplayModeData(mode);
318 }
319
320 if (display->driverdata != NULL) {
321 CFRelease(display->driverdata);
322 display->driverdata = NULL;
323 }
324 }
325 }
326}
327
328#if !TARGET_OS_TV
330{
331 BOOL isLandscape = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
332 SDL_VideoDisplay *display = SDL_GetDisplay(0);
333
334 if (display) {
335 SDL_DisplayMode *desktopmode = &display->desktop_mode;
336 SDL_DisplayMode *currentmode = &display->current_mode;
338
339 /* The desktop display mode should be kept in sync with the screen
340 * orientation so that updating a window's fullscreen state to
341 * SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the
342 * correct orientation. */
343 if (isLandscape != (desktopmode->w > desktopmode->h)) {
344 int height = desktopmode->w;
345 desktopmode->w = desktopmode->h;
346 desktopmode->h = height;
347 }
348
349 /* Same deal with the current mode + SDL_GetCurrentDisplayMode. */
350 if (isLandscape != (currentmode->w > currentmode->h)) {
351 int height = currentmode->w;
352 currentmode->w = currentmode->h;
353 currentmode->h = height;
354 }
355
356 switch ([UIApplication sharedApplication].statusBarOrientation) {
357 case UIInterfaceOrientationPortrait:
358 orientation = SDL_ORIENTATION_PORTRAIT;
359 break;
360 case UIInterfaceOrientationPortraitUpsideDown:
362 break;
363 case UIInterfaceOrientationLandscapeLeft:
364 /* Bug: UIInterfaceOrientationLandscapeLeft/Right are reversed - http://openradar.appspot.com/7216046 */
366 break;
367 case UIInterfaceOrientationLandscapeRight:
368 /* Bug: UIInterfaceOrientationLandscapeLeft/Right are reversed - http://openradar.appspot.com/7216046 */
369 orientation = SDL_ORIENTATION_LANDSCAPE;
370 break;
371 default:
372 break;
373 }
375 }
376}
377#endif /* !TARGET_OS_TV */
378
379#endif /* SDL_VIDEO_DRIVER_UIKIT */
380
381/* vi: set ts=4 sw=4 expandtab: */
#define _THIS
int SDL_SendDisplayEvent(SDL_VideoDisplay *display, Uint8 displayevent, int data1)
#define SDL_SetError
#define SDL_GetDisplayBounds
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
GLenum mode
GLenum GLenum GLenum GLenum GLenum scale
GLuint in
GLsizeiptr size
GLfloat GLfloat GLfloat GLfloat h
GLubyte GLubyte GLubyte GLubyte w
@ SDL_PIXELFORMAT_ABGR8888
Definition: SDL_pixels.h:254
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_VideoDisplay * SDL_GetDisplay(int displayIndex)
Definition: SDL_video.c:1021
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:603
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:751
void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
void UIKit_QuitModes(_THIS)
int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
void SDL_OnApplicationDidChangeStatusBarOrientation(void)
SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen)
int UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
int UIKit_InitModes(_THIS)
SDL_bool UIKit_IsSystemVersionAtLeast(double version)
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
@ SDL_DISPLAYEVENT_ORIENTATION
Definition: SDL_video.h:178
SDL_DisplayOrientation
Definition: SDL_video.h:182
@ SDL_ORIENTATION_LANDSCAPE
Definition: SDL_video.h:184
@ SDL_ORIENTATION_PORTRAIT
Definition: SDL_video.h:186
@ SDL_ORIENTATION_PORTRAIT_FLIPPED
Definition: SDL_video.h:187
@ SDL_ORIENTATION_LANDSCAPE_FLIPPED
Definition: SDL_video.h:185
@ SDL_ORIENTATION_UNKNOWN
Definition: SDL_video.h:183
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
UIScreen * uiscreen
UIScreenMode * uiscreenmode
The structure that defines a display mode.
Definition: SDL_video.h:54
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
int h
Definition: SDL_rect.h:80
int w
Definition: SDL_rect.h:80
int y
Definition: SDL_rect.h:79
int x
Definition: SDL_rect.h:79
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:316
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:131
SDL_DisplayMode * display_modes
Definition: SDL_sysvideo.h:130
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
SDL_Rect rect
Definition: testrelative.c:27
int frame
Definition: teststreaming.c:60