Implement visionOS support

This commit is contained in:
Ravbug 2023-07-23 23:11:09 -07:00 committed by Sam Lantinga
parent e385d6da0a
commit 690eae7d22
15 changed files with 217 additions and 41 deletions

22
.github/workflows/visionos.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Build (visionOS)
# FIXME: CMake 3.28 is not yet available on the github runner
# on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
Build:
name: visionOS
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Configure
run: |
cmake -B build -GXcode -DCMAKE_SYSTEM_NAME=visionOS
- name: Build
run: |
cmake --build build

View File

@ -131,7 +131,7 @@ endif()
# so we'll just use libusb when it's available. libusb does not support iOS, # so we'll just use libusb when it's available. libusb does not support iOS,
# so we default to yes on iOS. # so we default to yes on iOS.
# TODO: Windows can support libusb, the hid.c file just depends on Unix APIs # TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
if((WINDOWS AND NOT WINDOWS_STORE) OR IOS OR TVOS OR ANDROID) if((WINDOWS AND NOT WINDOWS_STORE) OR IOS OR TVOS OR VISIONOS OR ANDROID)
set(SDL_HIDAPI_LIBUSB_AVAILABLE FALSE) set(SDL_HIDAPI_LIBUSB_AVAILABLE FALSE)
else() else()
set(SDL_HIDAPI_LIBUSB_AVAILABLE TRUE) set(SDL_HIDAPI_LIBUSB_AVAILABLE TRUE)
@ -303,8 +303,8 @@ set_option(SDL_DISKAUDIO "Support the disk writer audio driver" ON)
set_option(SDL_DUMMYAUDIO "Support the dummy audio driver" ON) set_option(SDL_DUMMYAUDIO "Support the dummy audio driver" ON)
set_option(SDL_DUMMYVIDEO "Use dummy video driver" ON) set_option(SDL_DUMMYVIDEO "Use dummy video driver" ON)
dep_option(SDL_IBUS "Enable IBus support" ON ${UNIX_SYS} OFF) dep_option(SDL_IBUS "Enable IBus support" ON ${UNIX_SYS} OFF)
set_option(SDL_OPENGL "Include OpenGL support" ON) dep_option(SDL_OPENGL "Include OpenGL support" ON "NOT VISIONOS" OFF)
set_option(SDL_OPENGLES "Include OpenGL ES support" ON) dep_option(SDL_OPENGLES "Include OpenGL ES support" ON "NOT VISIONOS" OFF)
set_option(SDL_PTHREADS "Use POSIX threads for multi-threading" ${SDL_PTHREADS_DEFAULT}) set_option(SDL_PTHREADS "Use POSIX threads for multi-threading" ${SDL_PTHREADS_DEFAULT})
dep_option(SDL_PTHREADS_SEM "Use pthread semaphores" ON "SDL_PTHREADS" OFF) dep_option(SDL_PTHREADS_SEM "Use pthread semaphores" ON "SDL_PTHREADS" OFF)
dep_option(SDL_OSS "Support the OSS audio API" ON "UNIX_SYS OR RISCOS" OFF) dep_option(SDL_OSS "Support the OSS audio API" ON "UNIX_SYS OR RISCOS" OFF)
@ -348,7 +348,7 @@ dep_option(SDL_KMSDRM_SHARED "Dynamically load KMS DRM support" ON "SDL_KM
set_option(SDL_OFFSCREEN "Use offscreen video driver" ON) set_option(SDL_OFFSCREEN "Use offscreen video driver" ON)
option_string(SDL_BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" OFF) option_string(SDL_BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" OFF)
option_string(SDL_FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" OFF) option_string(SDL_FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" OFF)
set_option(SDL_HIDAPI "Enable the HIDAPI subsystem" ON) dep_option(SDL_HIDAPI "Enable the HIDAPI subsystem" ON "NOT VISIONOS" OFF)
dep_option(SDL_HIDAPI_LIBUSB "Use libusb for low level joystick drivers" ${SDL_HIDAPI_LIBUSB_DEFAULT} "SDL_HIDAPI;${SDL_HIDAPI_LIBUSB_AVAILABLE}" OFF) dep_option(SDL_HIDAPI_LIBUSB "Use libusb for low level joystick drivers" ${SDL_HIDAPI_LIBUSB_DEFAULT} "SDL_HIDAPI;${SDL_HIDAPI_LIBUSB_AVAILABLE}" OFF)
dep_option(SDL_HIDAPI_JOYSTICK "Use HIDAPI for low level joystick drivers" ON SDL_HIDAPI OFF) dep_option(SDL_HIDAPI_JOYSTICK "Use HIDAPI for low level joystick drivers" ON SDL_HIDAPI OFF)
dep_option(SDL_VIRTUAL_JOYSTICK "Enable the virtual-joystick driver" ON SDL_HIDAPI OFF) dep_option(SDL_VIRTUAL_JOYSTICK "Enable the virtual-joystick driver" ON SDL_HIDAPI OFF)
@ -2031,7 +2031,7 @@ elseif(APPLE)
endif() endif()
if(SDL_MISC) if(SDL_MISC)
if(IOS OR TVOS) if(IOS OR TVOS OR VISIONOS)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/ios/*.m") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/ios/*.m")
else() else()
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/macos/*.m") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/macos/*.m")
@ -2054,10 +2054,10 @@ elseif(APPLE)
if(SDL_JOYSTICK) if(SDL_JOYSTICK)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/apple/*.m") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/apple/*.m")
if(IOS OR TVOS) if(IOS OR TVOS OR VISIONOS)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/steam/*.c") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/steam/*.c")
set(SDL_JOYSTICK_MFI 1) set(SDL_JOYSTICK_MFI 1)
if(IOS) if(IOS OR VISIONOS)
set(SDL_FRAMEWORK_COREMOTION 1) set(SDL_FRAMEWORK_COREMOTION 1)
endif() endif()
set(SDL_FRAMEWORK_GAMECONTROLLER 1) set(SDL_FRAMEWORK_GAMECONTROLLER 1)
@ -2089,15 +2089,17 @@ elseif(APPLE)
set(SDL_FRAMEWORK_GAMECONTROLLER 1) set(SDL_FRAMEWORK_GAMECONTROLLER 1)
set(SDL_FRAMEWORK_COREHAPTICS 1) set(SDL_FRAMEWORK_COREHAPTICS 1)
endif() endif()
set(SDL_JOYSTICK_IOKIT 1) if(NOT VISIONOS)
set(SDL_FRAMEWORK_IOKIT 1) set(SDL_JOYSTICK_IOKIT 1)
set(SDL_FRAMEWORK_IOKIT 1)
endif()
set(SDL_FRAMEWORK_FF 1) set(SDL_FRAMEWORK_FF 1)
endif() endif()
set(HAVE_SDL_JOYSTICK TRUE) set(HAVE_SDL_JOYSTICK TRUE)
endif() endif()
if(SDL_HAPTIC) if(SDL_HAPTIC)
if (IOS OR TVOS) if (IOS OR TVOS OR VISIONOS)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/dummy/*.c") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/dummy/*.c")
set(SDL_HAPTIC_DUMMY 1) set(SDL_HAPTIC_DUMMY 1)
else() else()
@ -2110,7 +2112,7 @@ elseif(APPLE)
endif() endif()
if(SDL_POWER) if(SDL_POWER)
if (IOS OR TVOS) if (IOS OR TVOS OR VISIONOS)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/uikit/*.m") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/uikit/*.m")
set(SDL_POWER_UIKIT 1) set(SDL_POWER_UIKIT 1)
else() else()
@ -2139,7 +2141,7 @@ elseif(APPLE)
endif() endif()
if(SDL_SENSOR) if(SDL_SENSOR)
if(IOS) if(IOS OR VISIONOS)
set(SDL_SENSOR_COREMOTION 1) set(SDL_SENSOR_COREMOTION 1)
set(HAVE_SDL_SENSORS TRUE) set(HAVE_SDL_SENSORS TRUE)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/sensor/coremotion/*.m") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/sensor/coremotion/*.m")
@ -2148,7 +2150,7 @@ elseif(APPLE)
# iOS hack needed - http://code.google.com/p/ios-cmake/ ? # iOS hack needed - http://code.google.com/p/ios-cmake/ ?
if(SDL_VIDEO) if(SDL_VIDEO)
if (IOS OR TVOS) if (IOS OR TVOS OR VISIONOS)
set(SDL_VIDEO_DRIVER_UIKIT 1) set(SDL_VIDEO_DRIVER_UIKIT 1)
set(SDL_FRAMEWORK_COREGRAPHICS 1) set(SDL_FRAMEWORK_COREGRAPHICS 1)
set(SDL_FRAMEWORK_QUARTZCORE 1) set(SDL_FRAMEWORK_QUARTZCORE 1)
@ -2168,7 +2170,7 @@ elseif(APPLE)
endif() endif()
if(SDL_OPENGLES) if(SDL_OPENGLES)
if(IOS OR TVOS) if(IOS OR TVOS OR VISIONOS)
set(SDL_FRAMEWORK_OPENGLES 1) set(SDL_FRAMEWORK_OPENGLES 1)
set(SDL_VIDEO_OPENGL_ES 1) set(SDL_VIDEO_OPENGL_ES 1)
else() else()
@ -2253,7 +2255,7 @@ elseif(APPLE)
endif() endif()
endif() endif()
if(SDL_FRAMEWORK_METAL) if(SDL_FRAMEWORK_METAL)
if(IOS OR TVOS) if(IOS OR TVOS OR VISIONOS)
sdl_link_dependency(metal LINK_OPTIONS "-Wl,-framework,Metal") sdl_link_dependency(metal LINK_OPTIONS "-Wl,-framework,Metal")
else() else()
sdl_link_dependency(metal LINK_OPTIONS "-Wl,-weak_framework,Metal") sdl_link_dependency(metal LINK_OPTIONS "-Wl,-weak_framework,Metal")
@ -2263,7 +2265,7 @@ elseif(APPLE)
sdl_link_dependency(opengles LINK_OPTIONS "-Wl,-framework,OpenGLES") sdl_link_dependency(opengles LINK_OPTIONS "-Wl,-framework,OpenGLES")
endif() endif()
if(SDL_FRAMEWORK_QUARTZCORE) if(SDL_FRAMEWORK_QUARTZCORE)
if(IOS OR TVOS) if(IOS OR TVOS OR VISIONOS)
sdl_link_dependency(quartz_core LINK_OPTIONS "-Wl,-framework,QuartzCore") sdl_link_dependency(quartz_core LINK_OPTIONS "-Wl,-framework,QuartzCore")
else() else()
sdl_link_dependency(metal LINK_OPTIONS "-Wl,-weak_framework,QuartzCore") sdl_link_dependency(metal LINK_OPTIONS "-Wl,-weak_framework,QuartzCore")

View File

@ -14,6 +14,9 @@ macro(SDL_DetectCMakePlatform)
set(SDL_CMAKE_PLATFORM tvOS) set(SDL_CMAKE_PLATFORM tvOS)
elseif(CMAKE_SYSTEM_NAME MATCHES ".*iOS.*") elseif(CMAKE_SYSTEM_NAME MATCHES ".*iOS.*")
set(SDL_CMAKE_PLATFORM iOS) set(SDL_CMAKE_PLATFORM iOS)
elseif (CMAKE_SYSTEM_NAME MATCHES "visionOS")
set(SDL_CMAKE_PLATFORM visionOS)
set(VISIONOS ON) # CMAKE does not set this automatically yet
endif() endif()
elseif(CMAKE_SYSTEM_NAME MATCHES "Haiku.*") elseif(CMAKE_SYSTEM_NAME MATCHES "Haiku.*")
set(SDL_CMAKE_PLATFORM Haiku) set(SDL_CMAKE_PLATFORM Haiku)

View File

@ -94,6 +94,9 @@
#ifndef TARGET_OS_SIMULATOR #ifndef TARGET_OS_SIMULATOR
#define TARGET_OS_SIMULATOR 0 #define TARGET_OS_SIMULATOR 0
#endif #endif
#ifndef TARGET_OS_XR
#define TARGET_OS_XR 0
#endif
#if TARGET_OS_TV #if TARGET_OS_TV
#undef __TVOS__ #undef __TVOS__

View File

@ -30,9 +30,13 @@ int SDL_SYS_OpenURL(const char *url)
{ {
@autoreleasepool { @autoreleasepool {
#if TARGET_OS_XR
return SDL_Unsupported(); // openURL is not suported on visionOS
#else
NSString *nsstr = [NSString stringWithUTF8String:url]; NSString *nsstr = [NSString stringWithUTF8String:url];
NSURL *nsurl = [NSURL URLWithString:nsstr]; NSURL *nsurl = [NSURL URLWithString:nsstr];
return [[UIApplication sharedApplication] openURL:nsurl] ? 0 : -1; return [[UIApplication sharedApplication] openURL:nsurl] ? 0 : -1;
#endif
} }
} }

View File

@ -79,7 +79,7 @@ int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserv
return exit_status; return exit_status;
} }
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
/* Load a launch image using the old UILaunchImageFile-era naming rules. */ /* Load a launch image using the old UILaunchImageFile-era naming rules. */
static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
{ {
@ -142,8 +142,10 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
self.storyboardViewController.view.frame = self.view.bounds; self.storyboardViewController.view.frame = self.view.bounds;
[self.storyboardViewController didMoveToParentViewController:self]; [self.storyboardViewController didMoveToParentViewController:self];
#if !TARGET_OS_XR
UIApplication.sharedApplication.statusBarHidden = self.prefersStatusBarHidden; UIApplication.sharedApplication.statusBarHidden = self.prefersStatusBarHidden;
UIApplication.sharedApplication.statusBarStyle = self.preferredStatusBarStyle; UIApplication.sharedApplication.statusBarStyle = self.preferredStatusBarStyle;
#endif
} }
- (BOOL)prefersStatusBarHidden - (BOOL)prefersStatusBarHidden
@ -211,10 +213,17 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
NSString *imagename = nil; NSString *imagename = nil;
UIImage *image = nil; UIImage *image = nil;
#if TARGET_OS_XR
int screenw = SDL_XR_SCREENWIDTH;
int screenh = SDL_XR_SCREENHEIGHT;
#else
int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5); int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5); int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
#endif
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
/* We always want portrait-oriented size, to match UILaunchImageSize. */ /* We always want portrait-oriented size, to match UILaunchImageSize. */
@ -244,7 +253,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
} }
} }
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
NSString *orientstring = dict[@"UILaunchImageOrientation"]; NSString *orientstring = dict[@"UILaunchImageOrientation"];
@ -273,7 +282,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
image = [UIImage imageNamed:imagename]; image = [UIImage imageNamed:imagename];
} }
} }
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
else { else {
imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"]; imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
@ -288,10 +297,15 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
#endif #endif
if (image) { if (image) {
UIImageView *view = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds]; #if TARGET_OS_XR
CGRect viewFrame = CGRectMake(0, 0, screenw, screenh);
#else
CGRect viewFrame = [UIScreen mainScreen].bounds;
#endif
UIImageView *view = [[UIImageView alloc] initWithFrame:viewFrame];
UIImageOrientation imageorient = UIImageOrientationUp; UIImageOrientation imageorient = UIImageOrientationUp;
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
/* Bugs observed / workaround tested in iOS 8.3. */ /* Bugs observed / workaround tested in iOS 8.3. */
if (UIInterfaceOrientationIsLandscape(curorient)) { if (UIInterfaceOrientationIsLandscape(curorient)) {
if (image.size.width < image.size.height) { if (image.size.width < image.size.height) {
@ -420,7 +434,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
NSString *screenname = nil; NSString *screenname = nil;
/* tvOS only uses a plain launch image. */ /* tvOS only uses a plain launch image. */
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
if (screenname) { if (screenname) {
@ -443,7 +457,12 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
} }
if (vc.view) { if (vc.view) {
launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; #if TARGET_OS_XR
CGRect viewFrame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT);
#else
CGRect viewFrame = [UIScreen mainScreen].bounds;
#endif
launchWindow = [[UIWindow alloc] initWithFrame:viewFrame];
/* We don't want the launch window immediately hidden when a real SDL /* We don't want the launch window immediately hidden when a real SDL
* window is shown - we fade it out ourselves when we're ready. */ * window is shown - we fade it out ourselves when we're ready. */

View File

@ -57,7 +57,7 @@ static BOOL UIKit_EventPumpEnabled = YES;
[notificationCenter addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; [notificationCenter addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
[notificationCenter addObserver:self selector:@selector(applicationWillTerminate) name:UIApplicationWillTerminateNotification object:nil]; [notificationCenter addObserver:self selector:@selector(applicationWillTerminate) name:UIApplicationWillTerminateNotification object:nil];
[notificationCenter addObserver:self selector:@selector(applicationDidReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; [notificationCenter addObserver:self selector:@selector(applicationDidReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
[notificationCenter addObserver:self [notificationCenter addObserver:self
selector:@selector(applicationDidChangeStatusBarOrientation) selector:@selector(applicationDidChangeStatusBarOrientation)
name:UIApplicationDidChangeStatusBarOrientationNotification name:UIApplicationDidChangeStatusBarOrientationNotification
@ -99,7 +99,7 @@ static BOOL UIKit_EventPumpEnabled = YES;
SDL_OnApplicationDidReceiveMemoryWarning(); SDL_OnApplicationDidReceiveMemoryWarning();
} }
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
- (void)applicationDidChangeStatusBarOrientation - (void)applicationDidChangeStatusBarOrientation
{ {
SDL_OnApplicationDidChangeStatusBarOrientation(); SDL_OnApplicationDidChangeStatusBarOrientation();

View File

@ -98,7 +98,11 @@ static BOOL UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messag
} }
if (window == nil || window.rootViewController == nil) { if (window == nil || window.rootViewController == nil) {
#if TARGET_OS_XR
alertwindow = [[UIWindow alloc] init];
#else
alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
#endif
alertwindow.rootViewController = [UIViewController new]; alertwindow.rootViewController = [UIViewController new];
alertwindow.windowLevel = UIWindowLevelAlert; alertwindow.windowLevel = UIWindowLevelAlert;

View File

@ -81,6 +81,7 @@ SDL_MetalView UIKit_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
CGFloat scale = 1.0; CGFloat scale = 1.0;
SDL_uikitmetalview *metalview; SDL_uikitmetalview *metalview;
#if !TARGET_OS_XR
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
/* Set the scale to the natural scale factor of the screen - then /* Set the scale to the natural scale factor of the screen - then
* the backing dimensions of the Metal view will match the pixel * the backing dimensions of the Metal view will match the pixel
@ -89,6 +90,7 @@ SDL_MetalView UIKit_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
*/ */
scale = data.uiwindow.screen.nativeScale; scale = data.uiwindow.screen.nativeScale;
} }
#endif
metalview = [[SDL_uikitmetalview alloc] initWithFrame:data.uiwindow.bounds metalview = [[SDL_uikitmetalview alloc] initWithFrame:data.uiwindow.bounds
scale:scale]; scale:scale];

View File

@ -27,26 +27,39 @@
@interface SDL_UIKitDisplayData : NSObject @interface SDL_UIKitDisplayData : NSObject
#if !TARGET_OS_XR
- (instancetype)initWithScreen:(UIScreen *)screen; - (instancetype)initWithScreen:(UIScreen *)screen;
@property(nonatomic, strong) UIScreen *uiscreen; @property(nonatomic, strong) UIScreen *uiscreen;
#endif
@end @end
@interface SDL_UIKitDisplayModeData : NSObject @interface SDL_UIKitDisplayModeData : NSObject
#if !TARGET_OS_XR
@property(nonatomic, strong) UIScreenMode *uiscreenmode; @property(nonatomic, strong) UIScreenMode *uiscreenmode;
#endif
@end @end
#if !TARGET_OS_XR
extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen); extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen);
#endif
extern int UIKit_InitModes(SDL_VideoDevice *_this); extern int UIKit_InitModes(SDL_VideoDevice *_this);
#if !TARGET_OS_XR
extern int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event); extern int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event);
extern void UIKit_DelDisplay(UIScreen *uiscreen); extern void UIKit_DelDisplay(UIScreen *uiscreen);
#endif
extern int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display); extern int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode); extern int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
extern void UIKit_QuitModes(SDL_VideoDevice *_this); extern void UIKit_QuitModes(SDL_VideoDevice *_this);
extern int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect); extern int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
// because visionOS does not have a screen
// we create a fake 1080p display to maintain compatibility.
#if TARGET_OS_XR
#define SDL_XR_SCREENWIDTH 1920
#define SDL_XR_SCREENHEIGHT 1080
#endif
#endif /* SDL_uikitmodes_h_ */ #endif /* SDL_uikitmodes_h_ */

View File

@ -30,6 +30,7 @@
@implementation SDL_UIKitDisplayData @implementation SDL_UIKitDisplayData
#if !TARGET_OS_XR
- (instancetype)initWithScreen:(UIScreen *)screen - (instancetype)initWithScreen:(UIScreen *)screen
{ {
if (self = [super init]) { if (self = [super init]) {
@ -37,20 +38,23 @@
} }
return self; return self;
} }
@synthesize uiscreen; @synthesize uiscreen;
#endif
@end @end
@implementation SDL_UIKitDisplayModeData @implementation SDL_UIKitDisplayModeData
#if !TARGET_OS_XR
@synthesize uiscreenmode; @synthesize uiscreenmode;
#endif
@end @end
@interface SDL_DisplayWatch : NSObject @interface SDL_DisplayWatch : NSObject
@end @end
#if !TARGET_OS_XR
@implementation SDL_DisplayWatch @implementation SDL_DisplayWatch
+ (void)start + (void)start
@ -92,7 +96,9 @@
} }
@end @end
#endif
#if !TARGET_OS_XR
static int UIKit_AllocateDisplayModeData(SDL_DisplayMode *mode, static int UIKit_AllocateDisplayModeData(SDL_DisplayMode *mode,
UIScreenMode *uiscreenmode) UIScreenMode *uiscreenmode)
{ {
@ -112,6 +118,7 @@ static int UIKit_AllocateDisplayModeData(SDL_DisplayMode *mode,
return 0; return 0;
} }
#endif
static void UIKit_FreeDisplayModeData(SDL_DisplayMode *mode) static void UIKit_FreeDisplayModeData(SDL_DisplayMode *mode)
{ {
@ -121,6 +128,7 @@ static void UIKit_FreeDisplayModeData(SDL_DisplayMode *mode)
} }
} }
#if !TARGET_OS_XR
static float UIKit_GetDisplayModeRefreshRate(UIScreen *uiscreen) static float UIKit_GetDisplayModeRefreshRate(UIScreen *uiscreen)
{ {
#ifdef __IPHONE_10_3 #ifdef __IPHONE_10_3
@ -235,7 +243,11 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event)
display.desktop_mode = mode; display.desktop_mode = mode;
/* Allocate the display data */ /* Allocate the display data */
#if TARGET_OS_XR
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] init];
#else
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] initWithScreen:uiscreen]; SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] initWithScreen:uiscreen];
#endif
if (!data) { if (!data) {
UIKit_FreeDisplayModeData(&display.desktop_mode); UIKit_FreeDisplayModeData(&display.desktop_mode);
return SDL_OutOfMemory(); return SDL_OutOfMemory();
@ -247,6 +259,41 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event)
} }
return 0; return 0;
} }
#endif
#if TARGET_OS_XR
int UIKit_AddDisplay(SDL_bool send_event){
CGSize size = CGSizeMake(SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT);
SDL_VideoDisplay display;
SDL_DisplayMode mode;
SDL_zero(mode);
mode.w = (int)size.width;
mode.h = (int)size.height;
mode.pixel_density = 1;
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.refresh_rate = 60;
display.natural_orientation = SDL_ORIENTATION_LANDSCAPE;
display.desktop_mode = mode;
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] init];
if (!data) {
UIKit_FreeDisplayModeData(&display.desktop_mode);
return SDL_OutOfMemory();
}
display.driverdata = (SDL_DisplayData *)CFBridgingRetain(data);
if (SDL_AddVideoDisplay(&display, send_event) == 0) {
return -1;
}
return 0;
}
#endif
#if !TARGET_OS_XR
void UIKit_DelDisplay(UIScreen *uiscreen) void UIKit_DelDisplay(UIScreen *uiscreen)
{ {
@ -281,20 +328,27 @@ SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen)
return (size.width > size.height); return (size.width > size.height);
} }
} }
#endif
int UIKit_InitModes(SDL_VideoDevice *_this) int UIKit_InitModes(SDL_VideoDevice *_this)
{ {
@autoreleasepool { @autoreleasepool {
#if TARGET_OS_XR
UIKit_AddDisplay(SDL_FALSE);
#else
for (UIScreen *uiscreen in [UIScreen screens]) { for (UIScreen *uiscreen in [UIScreen screens]) {
if (UIKit_AddDisplay(uiscreen, SDL_FALSE) < 0) { if (UIKit_AddDisplay(uiscreen, SDL_FALSE) < 0) {
return -1; return -1;
} }
} }
#if !TARGET_OS_TV #endif
#if !TARGET_OS_TV && !TARGET_OS_XR
SDL_OnApplicationDidChangeStatusBarOrientation(); SDL_OnApplicationDidChangeStatusBarOrientation();
#endif #endif
#if !TARGET_OS_XR
[SDL_DisplayWatch start]; [SDL_DisplayWatch start];
#endif
} }
return 0; return 0;
@ -302,6 +356,7 @@ int UIKit_InitModes(SDL_VideoDevice *_this)
int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display) int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
{ {
#if !TARGET_OS_XR
@autoreleasepool { @autoreleasepool {
SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata; SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata;
@ -331,11 +386,13 @@ int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
UIKit_AddDisplayMode(display, w, h, data.uiscreen, uimode, addRotation); UIKit_AddDisplayMode(display, w, h, data.uiscreen, uimode, addRotation);
} }
} }
#endif
return 0; return 0;
} }
int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode) int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
{ {
#if !TARGET_OS_XR
@autoreleasepool { @autoreleasepool {
SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata; SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata;
@ -359,7 +416,7 @@ int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_
} }
} }
} }
#endif
return 0; return 0;
} }
@ -367,7 +424,11 @@ int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *displ
{ {
@autoreleasepool { @autoreleasepool {
SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata; SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata;
#if TARGET_OS_XR
CGRect frame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT);
#else
CGRect frame = data.uiscreen.bounds; CGRect frame = data.uiscreen.bounds;
#endif
/* the default function iterates displays to make a fake offset, /* the default function iterates displays to make a fake offset,
as if all the displays were side-by-side, which is fine for iOS. */ as if all the displays were side-by-side, which is fine for iOS. */
@ -386,7 +447,9 @@ int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *displ
void UIKit_QuitModes(SDL_VideoDevice *_this) void UIKit_QuitModes(SDL_VideoDevice *_this)
{ {
#if !TARGET_OS_XR
[SDL_DisplayWatch stop]; [SDL_DisplayWatch stop];
#endif
/* Release Objective-C objects, so higher level doesn't free() them. */ /* Release Objective-C objects, so higher level doesn't free() them. */
int i, j; int i, j;
@ -408,7 +471,7 @@ void UIKit_QuitModes(SDL_VideoDevice *_this)
} }
} }
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
void SDL_OnApplicationDidChangeStatusBarOrientation(void) void SDL_OnApplicationDidChangeStatusBarOrientation(void)
{ {
BOOL isLandscape = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation); BOOL isLandscape = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);

View File

@ -33,7 +33,11 @@
@end @end
#if TARGET_OS_XR
CGRect UIKit_ComputeViewFrame(SDL_Window *window);
#else
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen); CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen);
#endif
#endif /* __OBJC__ */ #endif /* __OBJC__ */

View File

@ -52,7 +52,9 @@ static void UIKit_VideoQuit(SDL_VideoDevice *_this);
static void UIKit_DeleteDevice(SDL_VideoDevice *device) static void UIKit_DeleteDevice(SDL_VideoDevice *device)
{ {
@autoreleasepool { @autoreleasepool {
CFRelease(device->driverdata); if (device->driverdata){
CFRelease(device->driverdata);
}
SDL_free(device); SDL_free(device);
} }
} }
@ -183,6 +185,7 @@ SDL_bool UIKit_IsSystemVersionAtLeast(double version)
SDL_SystemTheme UIKit_GetSystemTheme(void) SDL_SystemTheme UIKit_GetSystemTheme(void)
{ {
#if !TARGET_OS_XR
if (@available(iOS 12.0, tvOS 10.0, *)) { if (@available(iOS 12.0, tvOS 10.0, *)) {
switch ([UIScreen mainScreen].traitCollection.userInterfaceStyle) { switch ([UIScreen mainScreen].traitCollection.userInterfaceStyle) {
case UIUserInterfaceStyleDark: case UIUserInterfaceStyleDark:
@ -193,9 +196,15 @@ SDL_SystemTheme UIKit_GetSystemTheme(void)
break; break;
} }
} }
#endif
return SDL_SYSTEM_THEME_UNKNOWN; return SDL_SYSTEM_THEME_UNKNOWN;
} }
#if TARGET_OS_XR
CGRect UIKit_ComputeViewFrame(SDL_Window *window){
return CGRectMake(window->x, window->y, window->w, window->h);
}
#else
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen) CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
{ {
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata; SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata;
@ -234,6 +243,8 @@ CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
return frame; return frame;
} }
#endif
void UIKit_ForceUpdateHomeIndicator(void) void UIKit_ForceUpdateHomeIndicator(void)
{ {
#if !TARGET_OS_TV #if !TARGET_OS_TV

View File

@ -162,7 +162,9 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
{ {
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)]; displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
#ifdef __IPHONE_10_3 #if TARGET_OS_XR
displayLink.preferredFramesPerSecond = 90 / animationInterval; //TODO: Get frame max frame rate on visionOS
#elif defined(__IPHONE_10_3)
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata; SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata;
if ([displayLink respondsToSelector:@selector(preferredFramesPerSecond)] && data != nil && data.uiwindow != nil && [data.uiwindow.screen respondsToSelector:@selector(maximumFramesPerSecond)]) { if ([displayLink respondsToSelector:@selector(preferredFramesPerSecond)] && data != nil && data.uiwindow != nil && [data.uiwindow.screen respondsToSelector:@selector(maximumFramesPerSecond)]) {
@ -511,7 +513,11 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
{ {
CGAffineTransform t = self.view.transform; CGAffineTransform t = self.view.transform;
CGPoint offset = CGPointMake(0.0, 0.0); CGPoint offset = CGPointMake(0.0, 0.0);
#if TARGET_OS_XR
CGRect frame = UIKit_ComputeViewFrame(window);
#else
CGRect frame = UIKit_ComputeViewFrame(window, self.view.window.screen); CGRect frame = UIKit_ComputeViewFrame(window, self.view.window.screen);
#endif
if (self.keyboardHeight) { if (self.keyboardHeight) {
int rectbottom = self.textInputRect.y + self.textInputRect.h; int rectbottom = self.textInputRect.y + self.textInputRect.h;

View File

@ -65,6 +65,7 @@
- (void)layoutSubviews - (void)layoutSubviews
{ {
#if !TARGET_OS_XR
/* Workaround to fix window orientation issues in iOS 8. */ /* Workaround to fix window orientation issues in iOS 8. */
/* As of July 1 2019, I haven't been able to reproduce any orientation /* As of July 1 2019, I haven't been able to reproduce any orientation
* issues with this disabled on iOS 12. The issue this is meant to fix might * issues with this disabled on iOS 12. The issue this is meant to fix might
@ -74,6 +75,7 @@
if (!UIKit_IsSystemVersionAtLeast(9.0)) { if (!UIKit_IsSystemVersionAtLeast(9.0)) {
self.frame = self.screen.bounds; self.frame = self.screen.bounds;
} }
#endif
[super layoutSubviews]; [super layoutSubviews];
} }
@ -85,7 +87,12 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow
SDL_UIKitDisplayData *displaydata = (__bridge SDL_UIKitDisplayData *)display->driverdata; SDL_UIKitDisplayData *displaydata = (__bridge SDL_UIKitDisplayData *)display->driverdata;
SDL_uikitview *view; SDL_uikitview *view;
#if TARGET_OS_XR
CGRect frame = UIKit_ComputeViewFrame(window);
#else
CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen); CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen);
#endif
int width = (int)frame.size.width; int width = (int)frame.size.width;
int height = (int)frame.size.height; int height = (int)frame.size.height;
@ -98,13 +105,15 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow
data.uiwindow = uiwindow; data.uiwindow = uiwindow;
#if !TARGET_OS_XR
if (displaydata.uiscreen != [UIScreen mainScreen]) { if (displaydata.uiscreen != [UIScreen mainScreen]) {
window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizable */ window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizable */
window->flags &= ~SDL_WINDOW_INPUT_FOCUS; /* never has input focus */ window->flags &= ~SDL_WINDOW_INPUT_FOCUS; /* never has input focus */
window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */ window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */
} }
#endif
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
if (displaydata.uiscreen == [UIScreen mainScreen]) { if (displaydata.uiscreen == [UIScreen mainScreen]) {
/* SDL_CreateWindow sets the window w&h to the display's bounds if the /* SDL_CreateWindow sets the window w&h to the display's bounds if the
* fullscreen flag is set. But the display bounds orientation might not * fullscreen flag is set. But the display bounds orientation might not
@ -166,7 +175,7 @@ int UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
/* If monitor has a resolution of 0x0 (hasn't been explicitly set by the /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
* user, so it's in standby), try to force the display to a resolution * user, so it's in standby), try to force the display to a resolution
* that most closely matches the desired window size. */ * that most closely matches the desired window size. */
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
const CGSize origsize = data.uiscreen.currentMode.size; const CGSize origsize = data.uiscreen.currentMode.size;
if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) { if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
const SDL_DisplayMode *bestmode; const SDL_DisplayMode *bestmode;
@ -197,12 +206,18 @@ int UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
/* ignore the size user requested, and make a fullscreen window */ /* ignore the size user requested, and make a fullscreen window */
/* !!! FIXME: can we have a smaller view? */ /* !!! FIXME: can we have a smaller view? */
#if TARGET_OS_XR
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:CGRectMake(window->x, window->y, window->w, window->h)];
#else
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds]; UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
#endif
/* put the window on an external display if appropriate. */ /* put the window on an external display if appropriate. */
#if !TARGET_OS_XR
if (data.uiscreen != [UIScreen mainScreen]) { if (data.uiscreen != [UIScreen mainScreen]) {
[uiwindow setScreen:data.uiscreen]; [uiwindow setScreen:data.uiscreen];
} }
#endif
if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) { if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
return -1; return -1;
@ -229,7 +244,10 @@ void UIKit_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
/* Make this window the current mouse focus for touch input */ /* Make this window the current mouse focus for touch input */
SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
SDL_UIKitDisplayData *displaydata = (__bridge SDL_UIKitDisplayData *)display->driverdata; SDL_UIKitDisplayData *displaydata = (__bridge SDL_UIKitDisplayData *)display->driverdata;
if (displaydata.uiscreen == [UIScreen mainScreen]) { #if !TARGET_OS_XR
if (displaydata.uiscreen == [UIScreen mainScreen])
#endif
{
SDL_SetMouseFocus(window); SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window); SDL_SetKeyboardFocus(window);
} }
@ -258,7 +276,7 @@ static void UIKit_UpdateWindowBorder(SDL_VideoDevice *_this, SDL_Window *window)
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata; SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata;
SDL_uikitviewcontroller *viewcontroller = data.viewcontroller; SDL_uikitviewcontroller *viewcontroller = data.viewcontroller;
#if !TARGET_OS_TV #if !TARGET_OS_TV && !TARGET_OS_XR
if (data.uiwindow.screen == [UIScreen mainScreen]) { if (data.uiwindow.screen == [UIScreen mainScreen]) {
if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) { if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) {
[UIApplication sharedApplication].statusBarHidden = YES; [UIApplication sharedApplication].statusBarHidden = YES;
@ -354,9 +372,11 @@ void UIKit_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int
CGSize size = view.bounds.size; CGSize size = view.bounds.size;
CGFloat scale = 1.0; CGFloat scale = 1.0;
#if !TARGET_OS_XR
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
scale = windata.uiwindow.screen.nativeScale; scale = windata.uiwindow.screen.nativeScale;
} }
#endif
/* Integer truncation of fractional values matches SDL_uikitmetalview and /* Integer truncation of fractional values matches SDL_uikitmetalview and
* SDL_uikitopenglview. */ * SDL_uikitopenglview. */