From 690eae7d227cbd94664564353bdc7504c9b82166 Mon Sep 17 00:00:00 2001 From: Ravbug Date: Sun, 23 Jul 2023 23:11:09 -0700 Subject: [PATCH] Implement visionOS support --- .github/workflows/visionos.yml | 22 +++++++ CMakeLists.txt | 34 ++++++----- cmake/sdlplatform.cmake | 3 + include/SDL3/SDL_platform_defines.h | 3 + src/misc/ios/SDL_sysurl.m | 4 ++ src/video/uikit/SDL_uikitappdelegate.m | 37 +++++++++--- src/video/uikit/SDL_uikitevents.m | 4 +- src/video/uikit/SDL_uikitmessagebox.m | 4 ++ src/video/uikit/SDL_uikitmetalview.m | 2 + src/video/uikit/SDL_uikitmodes.h | 17 +++++- src/video/uikit/SDL_uikitmodes.m | 73 +++++++++++++++++++++-- src/video/uikit/SDL_uikitvideo.h | 4 ++ src/video/uikit/SDL_uikitvideo.m | 13 +++- src/video/uikit/SDL_uikitviewcontroller.m | 8 ++- src/video/uikit/SDL_uikitwindow.m | 30 ++++++++-- 15 files changed, 217 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/visionos.yml diff --git a/.github/workflows/visionos.yml b/.github/workflows/visionos.yml new file mode 100644 index 000000000..6eebf13ed --- /dev/null +++ b/.github/workflows/visionos.yml @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index eb9d1b718..e4971e577 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,7 @@ endif() # so we'll just use libusb when it's available. libusb does not support iOS, # so we default to yes on iOS. # 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) else() 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_DUMMYVIDEO "Use dummy video driver" ON) dep_option(SDL_IBUS "Enable IBus support" ON ${UNIX_SYS} OFF) -set_option(SDL_OPENGL "Include OpenGL support" ON) -set_option(SDL_OPENGLES "Include OpenGL ES support" ON) +dep_option(SDL_OPENGL "Include OpenGL support" ON "NOT VISIONOS" OFF) +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}) 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) @@ -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) 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) -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_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) @@ -2031,7 +2031,7 @@ elseif(APPLE) endif() if(SDL_MISC) - if(IOS OR TVOS) + if(IOS OR TVOS OR VISIONOS) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/ios/*.m") else() sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/macos/*.m") @@ -2054,10 +2054,10 @@ elseif(APPLE) if(SDL_JOYSTICK) 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") set(SDL_JOYSTICK_MFI 1) - if(IOS) + if(IOS OR VISIONOS) set(SDL_FRAMEWORK_COREMOTION 1) endif() set(SDL_FRAMEWORK_GAMECONTROLLER 1) @@ -2089,15 +2089,17 @@ elseif(APPLE) set(SDL_FRAMEWORK_GAMECONTROLLER 1) set(SDL_FRAMEWORK_COREHAPTICS 1) endif() - set(SDL_JOYSTICK_IOKIT 1) - set(SDL_FRAMEWORK_IOKIT 1) + if(NOT VISIONOS) + set(SDL_JOYSTICK_IOKIT 1) + set(SDL_FRAMEWORK_IOKIT 1) + endif() set(SDL_FRAMEWORK_FF 1) endif() set(HAVE_SDL_JOYSTICK TRUE) endif() if(SDL_HAPTIC) - if (IOS OR TVOS) + if (IOS OR TVOS OR VISIONOS) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/dummy/*.c") set(SDL_HAPTIC_DUMMY 1) else() @@ -2110,7 +2112,7 @@ elseif(APPLE) endif() if(SDL_POWER) - if (IOS OR TVOS) + if (IOS OR TVOS OR VISIONOS) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/uikit/*.m") set(SDL_POWER_UIKIT 1) else() @@ -2139,7 +2141,7 @@ elseif(APPLE) endif() if(SDL_SENSOR) - if(IOS) + if(IOS OR VISIONOS) set(SDL_SENSOR_COREMOTION 1) set(HAVE_SDL_SENSORS TRUE) 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/ ? if(SDL_VIDEO) - if (IOS OR TVOS) + if (IOS OR TVOS OR VISIONOS) set(SDL_VIDEO_DRIVER_UIKIT 1) set(SDL_FRAMEWORK_COREGRAPHICS 1) set(SDL_FRAMEWORK_QUARTZCORE 1) @@ -2168,7 +2170,7 @@ elseif(APPLE) endif() if(SDL_OPENGLES) - if(IOS OR TVOS) + if(IOS OR TVOS OR VISIONOS) set(SDL_FRAMEWORK_OPENGLES 1) set(SDL_VIDEO_OPENGL_ES 1) else() @@ -2253,7 +2255,7 @@ elseif(APPLE) endif() endif() if(SDL_FRAMEWORK_METAL) - if(IOS OR TVOS) + if(IOS OR TVOS OR VISIONOS) sdl_link_dependency(metal LINK_OPTIONS "-Wl,-framework,Metal") else() 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") endif() if(SDL_FRAMEWORK_QUARTZCORE) - if(IOS OR TVOS) + if(IOS OR TVOS OR VISIONOS) sdl_link_dependency(quartz_core LINK_OPTIONS "-Wl,-framework,QuartzCore") else() sdl_link_dependency(metal LINK_OPTIONS "-Wl,-weak_framework,QuartzCore") diff --git a/cmake/sdlplatform.cmake b/cmake/sdlplatform.cmake index ebb2077fb..b402cc038 100644 --- a/cmake/sdlplatform.cmake +++ b/cmake/sdlplatform.cmake @@ -14,6 +14,9 @@ macro(SDL_DetectCMakePlatform) set(SDL_CMAKE_PLATFORM tvOS) elseif(CMAKE_SYSTEM_NAME MATCHES ".*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() elseif(CMAKE_SYSTEM_NAME MATCHES "Haiku.*") set(SDL_CMAKE_PLATFORM Haiku) diff --git a/include/SDL3/SDL_platform_defines.h b/include/SDL3/SDL_platform_defines.h index e84fd8d86..565a09437 100644 --- a/include/SDL3/SDL_platform_defines.h +++ b/include/SDL3/SDL_platform_defines.h @@ -94,6 +94,9 @@ #ifndef TARGET_OS_SIMULATOR #define TARGET_OS_SIMULATOR 0 #endif +#ifndef TARGET_OS_XR +#define TARGET_OS_XR 0 +#endif #if TARGET_OS_TV #undef __TVOS__ diff --git a/src/misc/ios/SDL_sysurl.m b/src/misc/ios/SDL_sysurl.m index 8261e43cb..7db7f48db 100644 --- a/src/misc/ios/SDL_sysurl.m +++ b/src/misc/ios/SDL_sysurl.m @@ -30,9 +30,13 @@ int SDL_SYS_OpenURL(const char *url) { @autoreleasepool { +#if TARGET_OS_XR + return SDL_Unsupported(); // openURL is not suported on visionOS +#else NSString *nsstr = [NSString stringWithUTF8String:url]; NSURL *nsurl = [NSURL URLWithString:nsstr]; return [[UIApplication sharedApplication] openURL:nsurl] ? 0 : -1; +#endif } } diff --git a/src/video/uikit/SDL_uikitappdelegate.m b/src/video/uikit/SDL_uikitappdelegate.m index 4b93b8d2c..e9d6ca337 100644 --- a/src/video/uikit/SDL_uikitappdelegate.m +++ b/src/video/uikit/SDL_uikitappdelegate.m @@ -79,7 +79,7 @@ int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserv 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. */ 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 didMoveToParentViewController:self]; +#if !TARGET_OS_XR UIApplication.sharedApplication.statusBarHidden = self.prefersStatusBarHidden; UIApplication.sharedApplication.statusBarStyle = self.preferredStatusBarStyle; +#endif } - (BOOL)prefersStatusBarHidden @@ -210,11 +212,18 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"]; NSString *imagename = 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 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; /* 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; NSString *orientstring = dict[@"UILaunchImageOrientation"]; @@ -273,7 +282,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) image = [UIImage imageNamed:imagename]; } } -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_XR else { imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"]; @@ -288,10 +297,15 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) #endif 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; -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_XR /* Bugs observed / workaround tested in iOS 8.3. */ if (UIInterfaceOrientationIsLandscape(curorient)) { if (image.size.width < image.size.height) { @@ -420,7 +434,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) NSString *screenname = nil; /* tvOS only uses a plain launch image. */ -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_XR screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; if (screenname) { @@ -443,7 +457,12 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) } 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 * window is shown - we fade it out ourselves when we're ready. */ diff --git a/src/video/uikit/SDL_uikitevents.m b/src/video/uikit/SDL_uikitevents.m index 4bec9685a..8913c3dab 100644 --- a/src/video/uikit/SDL_uikitevents.m +++ b/src/video/uikit/SDL_uikitevents.m @@ -57,7 +57,7 @@ static BOOL UIKit_EventPumpEnabled = YES; [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(applicationDidReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_XR [notificationCenter addObserver:self selector:@selector(applicationDidChangeStatusBarOrientation) name:UIApplicationDidChangeStatusBarOrientationNotification @@ -99,7 +99,7 @@ static BOOL UIKit_EventPumpEnabled = YES; SDL_OnApplicationDidReceiveMemoryWarning(); } -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_XR - (void)applicationDidChangeStatusBarOrientation { SDL_OnApplicationDidChangeStatusBarOrientation(); diff --git a/src/video/uikit/SDL_uikitmessagebox.m b/src/video/uikit/SDL_uikitmessagebox.m index b0b612a16..e7d80ef76 100644 --- a/src/video/uikit/SDL_uikitmessagebox.m +++ b/src/video/uikit/SDL_uikitmessagebox.m @@ -98,7 +98,11 @@ static BOOL UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messag } if (window == nil || window.rootViewController == nil) { +#if TARGET_OS_XR + alertwindow = [[UIWindow alloc] init]; +#else alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; +#endif alertwindow.rootViewController = [UIViewController new]; alertwindow.windowLevel = UIWindowLevelAlert; diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m index c82a4dcec..c5317ebd9 100644 --- a/src/video/uikit/SDL_uikitmetalview.m +++ b/src/video/uikit/SDL_uikitmetalview.m @@ -81,6 +81,7 @@ SDL_MetalView UIKit_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window) CGFloat scale = 1.0; SDL_uikitmetalview *metalview; +#if !TARGET_OS_XR if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { /* Set the scale to the natural scale factor of the screen - then * 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; } +#endif metalview = [[SDL_uikitmetalview alloc] initWithFrame:data.uiwindow.bounds scale:scale]; diff --git a/src/video/uikit/SDL_uikitmodes.h b/src/video/uikit/SDL_uikitmodes.h index a744febb2..b92f19011 100644 --- a/src/video/uikit/SDL_uikitmodes.h +++ b/src/video/uikit/SDL_uikitmodes.h @@ -27,26 +27,39 @@ @interface SDL_UIKitDisplayData : NSObject +#if !TARGET_OS_XR - (instancetype)initWithScreen:(UIScreen *)screen; - @property(nonatomic, strong) UIScreen *uiscreen; +#endif @end @interface SDL_UIKitDisplayModeData : NSObject - +#if !TARGET_OS_XR @property(nonatomic, strong) UIScreenMode *uiscreenmode; +#endif @end +#if !TARGET_OS_XR extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen); +#endif extern int UIKit_InitModes(SDL_VideoDevice *_this); +#if !TARGET_OS_XR extern int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event); extern void UIKit_DelDisplay(UIScreen *uiscreen); +#endif extern int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display); extern int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode); extern void UIKit_QuitModes(SDL_VideoDevice *_this); 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_ */ diff --git a/src/video/uikit/SDL_uikitmodes.m b/src/video/uikit/SDL_uikitmodes.m index bc13c0df8..e397e97a6 100644 --- a/src/video/uikit/SDL_uikitmodes.m +++ b/src/video/uikit/SDL_uikitmodes.m @@ -30,6 +30,7 @@ @implementation SDL_UIKitDisplayData +#if !TARGET_OS_XR - (instancetype)initWithScreen:(UIScreen *)screen { if (self = [super init]) { @@ -37,20 +38,23 @@ } return self; } - @synthesize uiscreen; +#endif @end @implementation SDL_UIKitDisplayModeData +#if !TARGET_OS_XR @synthesize uiscreenmode; +#endif @end @interface SDL_DisplayWatch : NSObject @end +#if !TARGET_OS_XR @implementation SDL_DisplayWatch + (void)start @@ -92,7 +96,9 @@ } @end +#endif +#if !TARGET_OS_XR static int UIKit_AllocateDisplayModeData(SDL_DisplayMode *mode, UIScreenMode *uiscreenmode) { @@ -112,6 +118,7 @@ static int UIKit_AllocateDisplayModeData(SDL_DisplayMode *mode, return 0; } +#endif 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) { #ifdef __IPHONE_10_3 @@ -235,7 +243,11 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event) display.desktop_mode = mode; /* Allocate the display data */ +#if TARGET_OS_XR + SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] init]; +#else SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] initWithScreen:uiscreen]; +#endif if (!data) { UIKit_FreeDisplayModeData(&display.desktop_mode); return SDL_OutOfMemory(); @@ -247,6 +259,41 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event) } 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) { @@ -281,20 +328,27 @@ SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen) return (size.width > size.height); } } - +#endif int UIKit_InitModes(SDL_VideoDevice *_this) { @autoreleasepool { +#if TARGET_OS_XR + UIKit_AddDisplay(SDL_FALSE); +#else for (UIScreen *uiscreen in [UIScreen screens]) { if (UIKit_AddDisplay(uiscreen, SDL_FALSE) < 0) { return -1; } } -#if !TARGET_OS_TV +#endif + +#if !TARGET_OS_TV && !TARGET_OS_XR SDL_OnApplicationDidChangeStatusBarOrientation(); #endif +#if !TARGET_OS_XR [SDL_DisplayWatch start]; +#endif } return 0; @@ -302,6 +356,7 @@ int UIKit_InitModes(SDL_VideoDevice *_this) int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display) { +#if !TARGET_OS_XR @autoreleasepool { 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); } } +#endif return 0; } int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode) { +#if !TARGET_OS_XR @autoreleasepool { 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; } @@ -367,7 +424,11 @@ int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *displ { @autoreleasepool { 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; +#endif /* the default function iterates displays to make a fake offset, 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) { +#if !TARGET_OS_XR [SDL_DisplayWatch stop]; +#endif /* Release Objective-C objects, so higher level doesn't free() them. */ 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) { BOOL isLandscape = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation); diff --git a/src/video/uikit/SDL_uikitvideo.h b/src/video/uikit/SDL_uikitvideo.h index 60ee2a9f2..f13822299 100644 --- a/src/video/uikit/SDL_uikitvideo.h +++ b/src/video/uikit/SDL_uikitvideo.h @@ -33,7 +33,11 @@ @end +#if TARGET_OS_XR +CGRect UIKit_ComputeViewFrame(SDL_Window *window); +#else CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen); +#endif #endif /* __OBJC__ */ diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m index 51bef011f..0b07afb05 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -52,7 +52,9 @@ static void UIKit_VideoQuit(SDL_VideoDevice *_this); static void UIKit_DeleteDevice(SDL_VideoDevice *device) { @autoreleasepool { - CFRelease(device->driverdata); + if (device->driverdata){ + CFRelease(device->driverdata); + } SDL_free(device); } } @@ -183,6 +185,7 @@ SDL_bool UIKit_IsSystemVersionAtLeast(double version) SDL_SystemTheme UIKit_GetSystemTheme(void) { +#if !TARGET_OS_XR if (@available(iOS 12.0, tvOS 10.0, *)) { switch ([UIScreen mainScreen].traitCollection.userInterfaceStyle) { case UIUserInterfaceStyleDark: @@ -193,9 +196,15 @@ SDL_SystemTheme UIKit_GetSystemTheme(void) break; } } +#endif 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) { SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata; @@ -234,6 +243,8 @@ CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen) return frame; } +#endif + void UIKit_ForceUpdateHomeIndicator(void) { #if !TARGET_OS_TV diff --git a/src/video/uikit/SDL_uikitviewcontroller.m b/src/video/uikit/SDL_uikitviewcontroller.m index 4d0b96a54..dfebb0862 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.m +++ b/src/video/uikit/SDL_uikitviewcontroller.m @@ -162,7 +162,9 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char { 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; 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; 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); +#endif if (self.keyboardHeight) { int rectbottom = self.textInputRect.y + self.textInputRect.h; diff --git a/src/video/uikit/SDL_uikitwindow.m b/src/video/uikit/SDL_uikitwindow.m index 13aa86462..ed8c6dcd1 100644 --- a/src/video/uikit/SDL_uikitwindow.m +++ b/src/video/uikit/SDL_uikitwindow.m @@ -65,6 +65,7 @@ - (void)layoutSubviews { +#if !TARGET_OS_XR /* Workaround to fix window orientation issues in iOS 8. */ /* 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 @@ -74,6 +75,7 @@ if (!UIKit_IsSystemVersionAtLeast(9.0)) { self.frame = self.screen.bounds; } +#endif [super layoutSubviews]; } @@ -84,8 +86,13 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); SDL_UIKitDisplayData *displaydata = (__bridge SDL_UIKitDisplayData *)display->driverdata; SDL_uikitview *view; - + +#if TARGET_OS_XR + CGRect frame = UIKit_ComputeViewFrame(window); +#else CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen); +#endif + int width = (int)frame.size.width; int height = (int)frame.size.height; @@ -98,13 +105,15 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow data.uiwindow = uiwindow; +#if !TARGET_OS_XR if (displaydata.uiscreen != [UIScreen mainScreen]) { window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizable */ window->flags &= ~SDL_WINDOW_INPUT_FOCUS; /* never has input focus */ 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]) { /* 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 @@ -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 * user, so it's in standby), try to force the display to a resolution * 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; if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) { 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 */ /* !!! 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]; +#endif /* put the window on an external display if appropriate. */ +#if !TARGET_OS_XR if (data.uiscreen != [UIScreen mainScreen]) { [uiwindow setScreen:data.uiscreen]; } +#endif if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) { 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 */ SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); 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_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_uikitviewcontroller *viewcontroller = data.viewcontroller; -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_XR if (data.uiwindow.screen == [UIScreen mainScreen]) { if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) { [UIApplication sharedApplication].statusBarHidden = YES; @@ -354,9 +372,11 @@ void UIKit_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int CGSize size = view.bounds.size; CGFloat scale = 1.0; +#if !TARGET_OS_XR if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { scale = windata.uiwindow.screen.nativeScale; } +#endif /* Integer truncation of fractional values matches SDL_uikitmetalview and * SDL_uikitopenglview. */