SDL  2.0
SDL_uikitmodes.m
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 @implementation SDL_DisplayData
29 
30 @synthesize uiscreen;
31 
32 @end
33 
34 @implementation SDL_DisplayModeData
35 
36 @synthesize uiscreenmode;
37 
38 @end
39 
40 
41 static int
42 UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode,
43  UIScreenMode * uiscreenmode)
44 {
46 
47  if (uiscreenmode != nil) {
48  /* Allocate the display mode data */
49  data = [[SDL_DisplayModeData alloc] init];
50  if (!data) {
51  return SDL_OutOfMemory();
52  }
53 
55  }
56 
57  mode->driverdata = (void *) CFBridgingRetain(data);
58 
59  return 0;
60 }
61 
62 static void
63 UIKit_FreeDisplayModeData(SDL_DisplayMode * mode)
64 {
65  if (mode->driverdata != NULL) {
66  CFRelease(mode->driverdata);
67  mode->driverdata = NULL;
68  }
69 }
70 
71 static NSUInteger
72 UIKit_GetDisplayModeRefreshRate(UIScreen *uiscreen)
73 {
74 #ifdef __IPHONE_10_3
75  if ([uiscreen respondsToSelector:@selector(maximumFramesPerSecond)]) {
76  return uiscreen.maximumFramesPerSecond;
77  }
78 #endif
79  return 0;
80 }
81 
82 static int
83 UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
84  UIScreen * uiscreen, UIScreenMode * uiscreenmode)
85 {
87  SDL_zero(mode);
88 
89  if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
90  return -1;
91  }
92 
94  mode.refresh_rate = (int) UIKit_GetDisplayModeRefreshRate(uiscreen);
95  mode.w = w;
96  mode.h = h;
97 
98  if (SDL_AddDisplayMode(display, &mode)) {
99  return 0;
100  } else {
101  UIKit_FreeDisplayModeData(&mode);
102  return -1;
103  }
104 }
105 
106 static int
107 UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, UIScreen * uiscreen,
108  UIScreenMode * uiscreenmode, SDL_bool addRotation)
109 {
110  if (UIKit_AddSingleDisplayMode(display, w, h, uiscreen, uiscreenmode) < 0) {
111  return -1;
112  }
113 
114  if (addRotation) {
115  /* Add the rotated version */
116  if (UIKit_AddSingleDisplayMode(display, h, w, uiscreen, uiscreenmode) < 0) {
117  return -1;
118  }
119  }
120 
121  return 0;
122 }
123 
124 static int
125 UIKit_AddDisplay(UIScreen *uiscreen)
126 {
127  UIScreenMode *uiscreenmode = uiscreen.currentMode;
128  CGSize size = uiscreen.bounds.size;
129  SDL_VideoDisplay display;
131  SDL_zero(mode);
132 
133  /* Make sure the width/height are oriented correctly */
134  if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
135  CGFloat height = size.width;
136  size.width = size.height;
137  size.height = height;
138  }
139 
141  mode.refresh_rate = (int) UIKit_GetDisplayModeRefreshRate(uiscreen);
142  mode.w = (int) size.width;
143  mode.h = (int) size.height;
144 
145  if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
146  return -1;
147  }
148 
149  SDL_zero(display);
150  display.desktop_mode = mode;
151  display.current_mode = mode;
152 
153  /* Allocate the display data */
154  SDL_DisplayData *data = [[SDL_DisplayData alloc] init];
155  if (!data) {
156  UIKit_FreeDisplayModeData(&display.desktop_mode);
157  return SDL_OutOfMemory();
158  }
159 
160  data.uiscreen = uiscreen;
161 
162  display.driverdata = (void *) CFBridgingRetain(data);
163  SDL_AddVideoDisplay(&display);
164 
165  return 0;
166 }
167 
168 SDL_bool
169 UIKit_IsDisplayLandscape(UIScreen *uiscreen)
170 {
171 #if !TARGET_OS_TV
172  if (uiscreen == [UIScreen mainScreen]) {
173  return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
174  } else
175 #endif /* !TARGET_OS_TV */
176  {
177  CGSize size = uiscreen.bounds.size;
178  return (size.width > size.height);
179  }
180 }
181 
182 int
184 {
185  @autoreleasepool {
186  for (UIScreen *uiscreen in [UIScreen screens]) {
187  if (UIKit_AddDisplay(uiscreen) < 0) {
188  return -1;
189  }
190  }
191  }
192 
193  return 0;
194 }
195 
196 void
198 {
199  @autoreleasepool {
200  SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
201 
202  SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
203  SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
204  CGFloat scale = data.uiscreen.scale;
205  NSArray *availableModes = nil;
206 
207 #if TARGET_OS_TV
208  addRotation = SDL_FALSE;
209  availableModes = @[data.uiscreen.currentMode];
210 #else
211  availableModes = data.uiscreen.availableModes;
212 #endif
213 
214 #ifdef __IPHONE_8_0
215  /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than
216  * 1242x2208 (414x736@3x), so we should use the native scale. */
217  if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) {
218  scale = data.uiscreen.nativeScale;
219  }
220 #endif
221 
222  for (UIScreenMode *uimode in availableModes) {
223  /* The size of a UIScreenMode is in pixels, but we deal exclusively
224  * in points (except in SDL_GL_GetDrawableSize.) */
225  int w = (int)(uimode.size.width / scale);
226  int h = (int)(uimode.size.height / scale);
227 
228  /* Make sure the width/height are oriented correctly */
229  if (isLandscape != (w > h)) {
230  int tmp = w;
231  w = h;
232  h = tmp;
233  }
234 
235  UIKit_AddDisplayMode(display, w, h, data.uiscreen, uimode, addRotation);
236  }
237  }
238 }
239 
240 int
242 {
243  @autoreleasepool {
244  SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
245 
246 #if !TARGET_OS_TV
247  SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
248  [data.uiscreen setCurrentMode:modedata.uiscreenmode];
249 #endif
250 
251  if (data.uiscreen == [UIScreen mainScreen]) {
252  /* [UIApplication setStatusBarOrientation:] no longer works reliably
253  * in recent iOS versions, so we can't rotate the screen when setting
254  * the display mode. */
255  if (mode->w > mode->h) {
256  if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
257  return SDL_SetError("Screen orientation does not match display mode size");
258  }
259  } else if (mode->w < mode->h) {
261  return SDL_SetError("Screen orientation does not match display mode size");
262  }
263  }
264  }
265  }
266 
267  return 0;
268 }
269 
270 int
272 {
273  @autoreleasepool {
274  int displayIndex = (int) (display - _this->displays);
275  SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
276  CGRect frame = data.uiscreen.bounds;
277 
278  /* the default function iterates displays to make a fake offset,
279  as if all the displays were side-by-side, which is fine for iOS. */
280  if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
281  return -1;
282  }
283 
284 #if !TARGET_OS_TV && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
285  if (!UIKit_IsSystemVersionAtLeast(7.0)) {
286  frame = [data.uiscreen applicationFrame];
287  }
288 #endif
289 
290  rect->x += frame.origin.x;
291  rect->y += frame.origin.y;
292  rect->w = frame.size.width;
293  rect->h = frame.size.height;
294  }
295 
296  return 0;
297 }
298 
299 void
301 {
302  /* Release Objective-C objects, so higher level doesn't free() them. */
303  int i, j;
304  @autoreleasepool {
305  for (i = 0; i < _this->num_displays; i++) {
306  SDL_VideoDisplay *display = &_this->displays[i];
307 
308  UIKit_FreeDisplayModeData(&display->desktop_mode);
309  for (j = 0; j < display->num_display_modes; j++) {
310  SDL_DisplayMode *mode = &display->display_modes[j];
311  UIKit_FreeDisplayModeData(mode);
312  }
313 
314  if (display->driverdata != NULL) {
315  CFRelease(display->driverdata);
316  display->driverdata = NULL;
317  }
318  }
319  }
320 }
321 
322 #endif /* SDL_VIDEO_DRIVER_UIKIT */
323 
324 /* vi: set ts=4 sw=4 expandtab: */
int UIKit_InitModes(_THIS)
GLenum GLenum GLenum GLenum GLenum scale
SDL_bool UIKit_IsSystemVersionAtLeast(double version)
void UIKit_QuitModes(_THIS)
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen)
SDL_Rect rect
Definition: testrelative.c:27
GLfloat GLfloat GLfloat GLfloat h
The structure that defines a display mode.
Definition: SDL_video.h:53
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:606
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
UIScreen * uiscreen
#define _THIS
int frame
Definition: teststreaming.c:60
void * driverdata
Definition: SDL_video.h:59
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
SDL_DisplayMode * display_modes
Definition: SDL_sysvideo.h:130
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
GLenum mode
GLubyte GLubyte GLubyte GLubyte w
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:312
#define SDL_GetDisplayBounds
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
int x
Definition: SDL_rect.h:66
int w
Definition: SDL_rect.h:67
GLsizeiptr size
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
int UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:131
#define SDL_SetError
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
UIScreenMode * uiscreenmode
int h
Definition: SDL_rect.h:67
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:743
Uint32 format
Definition: SDL_video.h:55
GLuint in
int y
Definition: SDL_rect.h:66
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)