Skip to content

Latest commit

 

History

History
541 lines (471 loc) · 16.3 KB

SDL_uikitmodes.m

File metadata and controls

541 lines (471 loc) · 16.3 KB
 
1
2
/*
Simple DirectMedia Layer
Jan 17, 2020
Jan 17, 2020
3
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_UIKIT
#include "SDL_assert.h"
#include "SDL_uikitmodes.h"
Aug 23, 2018
Aug 23, 2018
28
29
#include "../../events/SDL_events_c.h"
Dec 8, 2019
Dec 8, 2019
30
31
#import <sys/utsname.h>
32
33
@implementation SDL_DisplayData
Dec 8, 2019
Dec 8, 2019
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
- (instancetype)initWithScreen:(UIScreen*)screen
{
if (self = [super init]) {
self.uiscreen = screen;
/*
* A well up to date list of device info can be found here:
* https://github.com/lmirosevic/GBDeviceInfo/blob/master/GBDeviceInfo/GBDeviceInfo_iOS.m
*/
NSDictionary* devices = @{
@"iPhone1,1": @163,
@"iPhone1,2": @163,
@"iPhone2,1": @163,
@"iPhone3,1": @326,
@"iPhone3,2": @326,
@"iPhone3,3": @326,
@"iPhone4,1": @326,
@"iPhone5,1": @326,
@"iPhone5,2": @326,
@"iPhone5,3": @326,
@"iPhone5,4": @326,
@"iPhone6,1": @326,
@"iPhone6,2": @326,
@"iPhone7,1": @401,
@"iPhone7,2": @326,
@"iPhone8,1": @326,
@"iPhone8,2": @401,
@"iPhone8,4": @326,
@"iPhone9,1": @326,
@"iPhone9,2": @401,
@"iPhone9,3": @326,
@"iPhone9,4": @401,
@"iPhone10,1": @326,
@"iPhone10,2": @401,
@"iPhone10,3": @458,
@"iPhone10,4": @326,
@"iPhone10,5": @401,
@"iPhone10,6": @458,
@"iPhone11,2": @458,
@"iPhone11,4": @458,
@"iPhone11,6": @458,
@"iPhone11,8": @326,
@"iPhone12,1": @326,
@"iPhone12,3": @458,
@"iPhone12,5": @458,
@"iPad1,1": @132,
@"iPad2,1": @132,
@"iPad2,2": @132,
@"iPad2,3": @132,
@"iPad2,4": @132,
@"iPad2,5": @163,
@"iPad2,6": @163,
@"iPad2,7": @163,
@"iPad3,1": @264,
@"iPad3,2": @264,
@"iPad3,3": @264,
@"iPad3,4": @264,
@"iPad3,5": @264,
@"iPad3,6": @264,
@"iPad4,1": @264,
@"iPad4,2": @264,
@"iPad4,3": @264,
@"iPad4,4": @326,
@"iPad4,5": @326,
@"iPad4,6": @326,
@"iPad4,7": @326,
@"iPad4,8": @326,
@"iPad4,9": @326,
@"iPad5,1": @326,
@"iPad5,2": @326,
@"iPad5,3": @264,
@"iPad5,4": @264,
@"iPad6,3": @264,
@"iPad6,4": @264,
@"iPad6,7": @264,
@"iPad6,8": @264,
@"iPad6,11": @264,
@"iPad6,12": @264,
@"iPad7,1": @264,
@"iPad7,2": @264,
@"iPad7,3": @264,
@"iPad7,4": @264,
@"iPad7,5": @264,
@"iPad7,6": @264,
@"iPad7,11": @264,
@"iPad7,12": @264,
@"iPad8,1": @264,
@"iPad8,2": @264,
@"iPad8,3": @264,
@"iPad8,4": @264,
@"iPad8,5": @264,
@"iPad8,6": @264,
@"iPad8,7": @264,
@"iPad8,8": @264,
@"iPad11,1": @326,
@"iPad11,2": @326,
@"iPad11,3": @326,
@"iPad11,4": @326,
@"iPod1,1": @163,
@"iPod2,1": @163,
@"iPod3,1": @163,
@"iPod4,1": @326,
@"iPod5,1": @326,
@"iPod7,1": @326,
@"iPod9,1": @326,
};
struct utsname systemInfo;
uname(&systemInfo);
NSString* deviceName =
[NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
id foundDPI = devices[deviceName];
if (foundDPI) {
self.screenDPI = (float)[foundDPI integerValue];
} else {
/*
* Estimate the DPI based on the screen scale multiplied by the base DPI for the device
* type (e.g. based on iPhone 1 and iPad 1)
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000
float scale = (float)screen.nativeScale;
#else
float scale = (float)screen.scale;
#endif
float defaultDPI;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
defaultDPI = 132.0f;
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
defaultDPI = 163.0f;
} else {
defaultDPI = 160.0f;
}
self.screenDPI = scale * defaultDPI;
}
}
return self;
}
172
@synthesize uiscreen;
Dec 8, 2019
Dec 8, 2019
173
@synthesize screenDPI;
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
@end
@implementation SDL_DisplayModeData
@synthesize uiscreenmode;
@end
static int
UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode,
UIScreenMode * uiscreenmode)
{
SDL_DisplayModeData *data = nil;
if (uiscreenmode != nil) {
/* Allocate the display mode data */
data = [[SDL_DisplayModeData alloc] init];
if (!data) {
return SDL_OutOfMemory();
}
data.uiscreenmode = uiscreenmode;
}
mode->driverdata = (void *) CFBridgingRetain(data);
return 0;
}
static void
UIKit_FreeDisplayModeData(SDL_DisplayMode * mode)
{
if (mode->driverdata != NULL) {
CFRelease(mode->driverdata);
mode->driverdata = NULL;
}
}
Jun 11, 2017
Jun 11, 2017
214
215
216
217
218
219
220
221
222
223
224
static NSUInteger
UIKit_GetDisplayModeRefreshRate(UIScreen *uiscreen)
{
#ifdef __IPHONE_10_3
if ([uiscreen respondsToSelector:@selector(maximumFramesPerSecond)]) {
return uiscreen.maximumFramesPerSecond;
}
#endif
return 0;
}
225
226
static int
UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h,
Jun 11, 2017
Jun 11, 2017
227
UIScreen * uiscreen, UIScreenMode * uiscreenmode)
228
229
230
231
232
233
234
235
{
SDL_DisplayMode mode;
SDL_zero(mode);
if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
return -1;
}
Jun 11, 2017
Jun 11, 2017
236
237
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.refresh_rate = (int) UIKit_GetDisplayModeRefreshRate(uiscreen);
238
239
mode.w = w;
mode.h = h;
Jun 11, 2017
Jun 11, 2017
240
241
242
243
244
245
246
247
248
249
if (SDL_AddDisplayMode(display, &mode)) {
return 0;
} else {
UIKit_FreeDisplayModeData(&mode);
return -1;
}
}
static int
Jun 11, 2017
Jun 11, 2017
250
UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, UIScreen * uiscreen,
251
252
UIScreenMode * uiscreenmode, SDL_bool addRotation)
{
Jun 11, 2017
Jun 11, 2017
253
if (UIKit_AddSingleDisplayMode(display, w, h, uiscreen, uiscreenmode) < 0) {
254
255
256
257
258
return -1;
}
if (addRotation) {
/* Add the rotated version */
Jun 11, 2017
Jun 11, 2017
259
if (UIKit_AddSingleDisplayMode(display, h, w, uiscreen, uiscreenmode) < 0) {
260
261
262
263
264
265
266
267
268
269
return -1;
}
}
return 0;
}
static int
UIKit_AddDisplay(UIScreen *uiscreen)
{
Jun 11, 2017
Jun 11, 2017
270
UIScreenMode *uiscreenmode = uiscreen.currentMode;
271
CGSize size = uiscreen.bounds.size;
Jun 11, 2017
Jun 11, 2017
272
273
274
SDL_VideoDisplay display;
SDL_DisplayMode mode;
SDL_zero(mode);
275
276
277
278
279
280
281
282
283
/* Make sure the width/height are oriented correctly */
if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) {
CGFloat height = size.width;
size.width = size.height;
size.height = height;
}
mode.format = SDL_PIXELFORMAT_ABGR8888;
Jun 11, 2017
Jun 11, 2017
284
mode.refresh_rate = (int) UIKit_GetDisplayModeRefreshRate(uiscreen);
285
286
287
288
289
290
291
292
293
294
295
296
mode.w = (int) size.width;
mode.h = (int) size.height;
if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) {
return -1;
}
SDL_zero(display);
display.desktop_mode = mode;
display.current_mode = mode;
/* Allocate the display data */
Dec 8, 2019
Dec 8, 2019
297
SDL_DisplayData *data = [[SDL_DisplayData alloc] initWithScreen:uiscreen];
298
299
300
301
302
303
304
305
306
307
308
309
310
311
if (!data) {
UIKit_FreeDisplayModeData(&display.desktop_mode);
return SDL_OutOfMemory();
}
display.driverdata = (void *) CFBridgingRetain(data);
SDL_AddVideoDisplay(&display);
return 0;
}
SDL_bool
UIKit_IsDisplayLandscape(UIScreen *uiscreen)
{
Sep 14, 2016
Sep 14, 2016
312
#if !TARGET_OS_TV
313
314
if (uiscreen == [UIScreen mainScreen]) {
return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
Sep 14, 2016
Sep 14, 2016
315
316
317
} else
#endif /* !TARGET_OS_TV */
{
318
319
320
321
322
323
324
325
326
327
328
329
330
331
CGSize size = uiscreen.bounds.size;
return (size.width > size.height);
}
}
int
UIKit_InitModes(_THIS)
{
@autoreleasepool {
for (UIScreen *uiscreen in [UIScreen screens]) {
if (UIKit_AddDisplay(uiscreen) < 0) {
return -1;
}
}
Aug 23, 2018
Aug 23, 2018
332
#if !TARGET_OS_TV
Sep 24, 2018
Sep 24, 2018
333
SDL_OnApplicationDidChangeStatusBarOrientation();
Aug 23, 2018
Aug 23, 2018
334
#endif
335
336
337
338
339
340
341
342
343
344
345
346
347
348
}
return 0;
}
void
UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
@autoreleasepool {
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
CGFloat scale = data.uiscreen.scale;
Sep 14, 2016
Sep 14, 2016
349
350
351
352
353
354
355
356
NSArray *availableModes = nil;
#if TARGET_OS_TV
addRotation = SDL_FALSE;
availableModes = @[data.uiscreen.currentMode];
#else
availableModes = data.uiscreen.availableModes;
#endif
Sep 14, 2016
Sep 14, 2016
358
for (UIScreenMode *uimode in availableModes) {
359
/* The size of a UIScreenMode is in pixels, but we deal exclusively
Apr 5, 2019
Apr 5, 2019
360
361
362
363
364
365
366
367
368
369
* in points (except in SDL_GL_GetDrawableSize.)
*
* For devices such as iPhone 6/7/8 Plus, the UIScreenMode reported
* by iOS is not in physical pixels of the display, but rather the
* point size times the scale. For example, on iOS 12.2 on iPhone 8
* Plus the uimode.size is 1242x2208 and the uiscreen.scale is 3
* thus this will give the size in points which is 414x736. The code
* used to use the nativeScale, assuming UIScreenMode returned raw
* physical pixels (as suggested by its documentation, but in
* practice it is returning the retina pixels). */
370
371
372
373
374
375
376
377
378
379
int w = (int)(uimode.size.width / scale);
int h = (int)(uimode.size.height / scale);
/* Make sure the width/height are oriented correctly */
if (isLandscape != (w > h)) {
int tmp = w;
w = h;
h = tmp;
}
Jun 11, 2017
Jun 11, 2017
380
UIKit_AddDisplayMode(display, w, h, data.uiscreen, uimode, addRotation);
Dec 8, 2019
Dec 8, 2019
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
int
UIKit_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
{
@autoreleasepool {
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
float dpi = data.screenDPI;
if (ddpi) {
*ddpi = dpi * (float)SDL_sqrt(2.0);
}
if (hdpi) {
*hdpi = dpi;
}
if (vdpi) {
*vdpi = dpi;
}
}
return 0;
}
406
407
408
409
410
411
int
UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
@autoreleasepool {
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
Sep 14, 2016
Sep 14, 2016
412
413
#if !TARGET_OS_TV
SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
414
[data.uiscreen setCurrentMode:modedata.uiscreenmode];
Sep 14, 2016
Sep 14, 2016
415
#endif
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
if (data.uiscreen == [UIScreen mainScreen]) {
/* [UIApplication setStatusBarOrientation:] no longer works reliably
* in recent iOS versions, so we can't rotate the screen when setting
* the display mode. */
if (mode->w > mode->h) {
if (!UIKit_IsDisplayLandscape(data.uiscreen)) {
return SDL_SetError("Screen orientation does not match display mode size");
}
} else if (mode->w < mode->h) {
if (UIKit_IsDisplayLandscape(data.uiscreen)) {
return SDL_SetError("Screen orientation does not match display mode size");
}
}
}
}
return 0;
}
Jan 5, 2016
Jan 5, 2016
436
437
438
int
UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
{
Sep 14, 2016
Sep 14, 2016
439
440
441
@autoreleasepool {
int displayIndex = (int) (display - _this->displays);
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
Jul 15, 2017
Jul 15, 2017
442
CGRect frame = data.uiscreen.bounds;
Sep 14, 2016
Sep 14, 2016
443
444
445
446
447
448
449
/* the default function iterates displays to make a fake offset,
as if all the displays were side-by-side, which is fine for iOS. */
if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
return -1;
}
Jul 15, 2017
Jul 15, 2017
450
#if !TARGET_OS_TV && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
Sep 14, 2016
Sep 14, 2016
451
452
453
454
455
456
457
458
459
if (!UIKit_IsSystemVersionAtLeast(7.0)) {
frame = [data.uiscreen applicationFrame];
}
#endif
rect->x += frame.origin.x;
rect->y += frame.origin.y;
rect->w = frame.size.width;
rect->h = frame.size.height;
Jan 5, 2016
Jan 5, 2016
460
461
462
463
464
}
return 0;
}
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
void
UIKit_QuitModes(_THIS)
{
/* Release Objective-C objects, so higher level doesn't free() them. */
int i, j;
@autoreleasepool {
for (i = 0; i < _this->num_displays; i++) {
SDL_VideoDisplay *display = &_this->displays[i];
UIKit_FreeDisplayModeData(&display->desktop_mode);
for (j = 0; j < display->num_display_modes; j++) {
SDL_DisplayMode *mode = &display->display_modes[j];
UIKit_FreeDisplayModeData(mode);
}
if (display->driverdata != NULL) {
CFRelease(display->driverdata);
display->driverdata = NULL;
}
}
}
}
Sep 11, 2018
Sep 11, 2018
488
#if !TARGET_OS_TV
Aug 23, 2018
Aug 23, 2018
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
void SDL_OnApplicationDidChangeStatusBarOrientation()
{
BOOL isLandscape = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
SDL_VideoDisplay *display = SDL_GetDisplay(0);
if (display) {
SDL_DisplayMode *desktopmode = &display->desktop_mode;
SDL_DisplayMode *currentmode = &display->current_mode;
SDL_DisplayOrientation orientation = SDL_ORIENTATION_UNKNOWN;
/* The desktop display mode should be kept in sync with the screen
* orientation so that updating a window's fullscreen state to
* SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the
* correct orientation. */
if (isLandscape != (desktopmode->w > desktopmode->h)) {
int height = desktopmode->w;
desktopmode->w = desktopmode->h;
desktopmode->h = height;
}
/* Same deal with the current mode + SDL_GetCurrentDisplayMode. */
if (isLandscape != (currentmode->w > currentmode->h)) {
int height = currentmode->w;
currentmode->w = currentmode->h;
currentmode->h = height;
}
switch ([UIApplication sharedApplication].statusBarOrientation) {
case UIInterfaceOrientationPortrait:
orientation = SDL_ORIENTATION_PORTRAIT;
break;
case UIInterfaceOrientationPortraitUpsideDown:
orientation = SDL_ORIENTATION_PORTRAIT_FLIPPED;
break;
case UIInterfaceOrientationLandscapeLeft:
/* Bug: UIInterfaceOrientationLandscapeLeft/Right are reversed - http://openradar.appspot.com/7216046 */
orientation = SDL_ORIENTATION_LANDSCAPE_FLIPPED;
break;
case UIInterfaceOrientationLandscapeRight:
/* Bug: UIInterfaceOrientationLandscapeLeft/Right are reversed - http://openradar.appspot.com/7216046 */
orientation = SDL_ORIENTATION_LANDSCAPE;
break;
default:
break;
}
SDL_SendDisplayEvent(display, SDL_DISPLAYEVENT_ORIENTATION, orientation);
}
}
Sep 11, 2018
Sep 11, 2018
537
#endif /* !TARGET_OS_TV */
Aug 23, 2018
Aug 23, 2018
538
539
540
541
#endif /* SDL_VIDEO_DRIVER_UIKIT */
/* vi: set ts=4 sw=4 expandtab: */