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