From 1ceed02c99a8ac30c8ebd36339eaaf116b4bc6c3 Mon Sep 17 00:00:00 2001 From: Patrick Baran Date: Thu, 24 Sep 2026 21:18:26 +0100 Subject: [PATCH 1/2] Add Window::setAllowedOrientations Implement runtime orientation masks on iOS while preserving the app orientation settings. Reevaluate changes on the UIKit stack and restore defaults when a native window is reused. Other backends retain the default no-op. --- Engine/system/api/iosapi.h | 1 + Engine/system/api/iosapi.mm | 45 +++++++++++++++++++++++++++++++------ Engine/system/systemapi.cpp | 7 ++++++ Engine/system/systemapi.h | 2 ++ Engine/ui/window.cpp | 4 ++++ Engine/ui/window.h | 17 ++++++++++++++ 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Engine/system/api/iosapi.h b/Engine/system/api/iosapi.h index c9f837dc..c1c9d327 100644 --- a/Engine/system/api/iosapi.h +++ b/Engine/system/api/iosapi.h @@ -28,6 +28,7 @@ class iOSApi final: SystemApi { void implProcessEvents(AppCallBack& cb) override; void implSetWindowTitle(SystemApi::Window *w, const char* utf8) override; + void implSetAllowedOrientations(SystemApi::Window *w, uint8_t orientations) override; friend class SystemApi; }; diff --git a/Engine/system/api/iosapi.mm b/Engine/system/api/iosapi.mm index 0f78f751..4df6fe3a 100644 --- a/Engine/system/api/iosapi.mm +++ b/Engine/system/api/iosapi.mm @@ -238,16 +238,20 @@ static void discardPendingEvent(TempestWindow* window) { @interface ViewController:UIViewController{} -(id)init; +-(void)setAllowedOrientations:(UIInterfaceOrientationMask)mask; @end @implementation ViewController { bool fullScreen; + UIInterfaceOrientationMask allowedOrientations; } -(id)init { self = [super init]; - if(self!=nil) + if(self!=nil) { fullScreen = true; + allowedOrientations = UIInterfaceOrientationMaskAll; + } return self; } @@ -274,7 +278,19 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface } -(UIInterfaceOrientationMask)supportedInterfaceOrientations { - return UIInterfaceOrientationMaskAll; + return allowedOrientations; + } + +-(void)setAllowedOrientations:(UIInterfaceOrientationMask)mask { + if(allowedOrientations==mask) + return; + allowedOrientations = mask; + // Reevaluate on UIKit's stack after the engine yields. + dispatch_async(dispatch_get_main_queue(), ^{ + if(@available(iOS 16.0, *)) + [self setNeedsUpdateOfSupportedInterfaceOrientations]; else + [UIViewController attemptRotationToDeviceOrientation]; + }); } -(bool)setAsFullscreen: (bool)value { @@ -386,11 +402,6 @@ - (UISceneConfiguration *)application:(UIApplication *)application return configuration; } -- (UIInterfaceOrientationMask)application:(UIApplication *)application - supportedInterfaceOrientationsForWindow:(UIWindow *)window { - return UIInterfaceOrientationMaskAll; - } - - (void)applicationWillTerminate:(UIApplication *)application { (void)application; } @@ -492,6 +503,8 @@ static void appleMain(void*) { auto delegate = (TempestSceneDelegate*)windowScene.delegate; delegate.window = window; + auto controller = (ViewController*)window.rootViewController; + [controller setAllowedOrientations:UIInterfaceOrientationMaskAll]; [window makeKeyAndVisible]; window->owner = owner; @@ -549,6 +562,24 @@ static void appleMain(void*) { return [ctrl isFullscreen]; } +void iOSApi::implSetAllowedOrientations(Window* w, uint8_t orientations) { + UIInterfaceOrientationMask mask = 0; + if(orientations & Tempest::Window::Portrait) + mask |= UIInterfaceOrientationMaskPortrait; + if(orientations & Tempest::Window::PortraitUpsideDown) + mask |= UIInterfaceOrientationMaskPortraitUpsideDown; + if(orientations & Tempest::Window::LandscapeLeft) + mask |= UIInterfaceOrientationMaskLandscapeLeft; + if(orientations & Tempest::Window::LandscapeRight) + mask |= UIInterfaceOrientationMaskLandscapeRight; + if(mask==0) + return; + + auto wx = reinterpret_cast(w); + auto ctrl = (ViewController*)wx.rootViewController; + [ctrl setAllowedOrientations:mask]; + } + void iOSApi::implSetCursorPosition(Window* w, int x, int y) { } diff --git a/Engine/system/systemapi.cpp b/Engine/system/systemapi.cpp index 04e3d1dd..43a6f474 100644 --- a/Engine/system/systemapi.cpp +++ b/Engine/system/systemapi.cpp @@ -33,6 +33,9 @@ void SystemApi::implSetWindowTitle(Window *w, const char *utf8) { // TODO } +void SystemApi::implSetAllowedOrientations(Window*, uint8_t) { + } + void SystemApi::setupKeyTranslate(const TranslateKeyPair k[], uint16_t funcCount ) { m.keys.clear(); m.a. clear(); @@ -200,6 +203,10 @@ void SystemApi::setWindowTitle(Window *w, const char *utf8) { return inst().implSetWindowTitle(w, utf8); } +void SystemApi::setAllowedOrientations(Window *w, uint8_t orientations) { + return inst().implSetAllowedOrientations(w, orientations); + } + void SystemApi::setCursorPosition(SystemApi::Window *w, int x, int y) { return inst().implSetCursorPosition(w,x,y); } diff --git a/Engine/system/systemapi.h b/Engine/system/systemapi.h index 31482d0f..0340b5cb 100644 --- a/Engine/system/systemapi.h +++ b/Engine/system/systemapi.h @@ -51,6 +51,7 @@ class SystemApi { static bool isFullscreen(SystemApi::Window *w); static void setWindowTitle(SystemApi::Window *w, const char* utf8); + static void setAllowedOrientations(SystemApi::Window *w, uint8_t orientations); static float uiScale(SystemApi::Window *w); static uint16_t translateKey(uint64_t scancode); @@ -86,6 +87,7 @@ class SystemApi { virtual void implProcessEvents(AppCallBack& cb) = 0; virtual void implSetWindowTitle(SystemApi::Window *w, const char* utf8) = 0; + virtual void implSetAllowedOrientations(SystemApi::Window *w, uint8_t orientations); static void setCursorPosition(SystemApi::Window *w, int x, int y); static void showCursor(SystemApi::Window *w, CursorShape c); diff --git a/Engine/ui/window.cpp b/Engine/ui/window.cpp index de00eb2c..10962f97 100644 --- a/Engine/ui/window.cpp +++ b/Engine/ui/window.cpp @@ -31,6 +31,10 @@ void Window::setWindowTitle(const char* utf8) { Tempest::SystemApi::setWindowTitle(hwnd(), utf8); } +void Window::setAllowedOrientations(Orientation orientations) { + Tempest::SystemApi::setAllowedOrientations(hwnd(), uint8_t(orientations)); + } + void Window::render() { } diff --git a/Engine/ui/window.h b/Engine/ui/window.h index 9217073e..a221de66 100644 --- a/Engine/ui/window.h +++ b/Engine/ui/window.h @@ -17,12 +17,25 @@ class Window : public Widget { FullScreen, }; + enum Orientation : uint8_t { + Portrait = 1 << 0, + PortraitUpsideDown = 1 << 1, + LandscapeLeft = 1 << 2, + LandscapeRight = 1 << 3, + Landscape = LandscapeLeft | LandscapeRight, + AllOrientations = Portrait | PortraitUpsideDown | Landscape, + }; + Window(); Window( ShowMode sm ); ~Window() override; void setWindowTitle(const char* utf8); + // App and platform restrictions still apply. AllOrientations restores the + // app defaults. Has no effect on platforms without orientation support. + void setAllowedOrientations(Orientation orientations); + protected: virtual void render(); using Widget::dispatchPaintEvent; @@ -46,4 +59,8 @@ class Window : public Widget { friend class SystemApi; }; +inline Window::Orientation operator | (Window::Orientation a, const Window::Orientation& b) { + return Window::Orientation(uint8_t(a)|uint8_t(b)); + } + } From 7d25d2ac7c566c79ad9a717db1697ceb19a7c40c Mon Sep 17 00:00:00 2001 From: Patrick Baran Date: Sat, 26 Sep 2026 22:20:04 +0100 Subject: [PATCH 2/2] Use typed orientation flags and extract UIKit conversion --- Engine/system/api/iosapi.h | 2 +- Engine/system/api/iosapi.mm | 25 +++++++++++++++---------- Engine/system/systemapi.cpp | 4 ++-- Engine/system/systemapi.h | 13 +++++++++++-- Engine/ui/window.cpp | 2 +- Engine/ui/window.h | 4 ++++ 6 files changed, 34 insertions(+), 16 deletions(-) diff --git a/Engine/system/api/iosapi.h b/Engine/system/api/iosapi.h index c1c9d327..440917bc 100644 --- a/Engine/system/api/iosapi.h +++ b/Engine/system/api/iosapi.h @@ -28,7 +28,7 @@ class iOSApi final: SystemApi { void implProcessEvents(AppCallBack& cb) override; void implSetWindowTitle(SystemApi::Window *w, const char* utf8) override; - void implSetAllowedOrientations(SystemApi::Window *w, uint8_t orientations) override; + void implSetAllowedOrientations(SystemApi::Window *w, Orientation orientations) override; friend class SystemApi; }; diff --git a/Engine/system/api/iosapi.mm b/Engine/system/api/iosapi.mm index 4df6fe3a..8539dbd0 100644 --- a/Engine/system/api/iosapi.mm +++ b/Engine/system/api/iosapi.mm @@ -15,6 +15,19 @@ using namespace Tempest; +static UIInterfaceOrientationMask nativeFormat(SystemApi::Orientation orientations) { + UIInterfaceOrientationMask mask = 0; + if(orientations & SystemApi::Portrait) + mask |= UIInterfaceOrientationMaskPortrait; + if(orientations & SystemApi::PortraitUpsideDown) + mask |= UIInterfaceOrientationMaskPortraitUpsideDown; + if(orientations & SystemApi::LandscapeLeft) + mask |= UIInterfaceOrientationMaskLandscapeLeft; + if(orientations & SystemApi::LandscapeRight) + mask |= UIInterfaceOrientationMaskLandscapeRight; + return mask; + } + #if TARGET_CPU_X86_64 # define FUNCTION_CALL_ALIGNMENT 16 # define SET_STACK_POINTER "movq %0, %%rsp" @@ -562,16 +575,8 @@ static void appleMain(void*) { return [ctrl isFullscreen]; } -void iOSApi::implSetAllowedOrientations(Window* w, uint8_t orientations) { - UIInterfaceOrientationMask mask = 0; - if(orientations & Tempest::Window::Portrait) - mask |= UIInterfaceOrientationMaskPortrait; - if(orientations & Tempest::Window::PortraitUpsideDown) - mask |= UIInterfaceOrientationMaskPortraitUpsideDown; - if(orientations & Tempest::Window::LandscapeLeft) - mask |= UIInterfaceOrientationMaskLandscapeLeft; - if(orientations & Tempest::Window::LandscapeRight) - mask |= UIInterfaceOrientationMaskLandscapeRight; +void iOSApi::implSetAllowedOrientations(Window* w, Orientation orientations) { + const auto mask = nativeFormat(orientations); if(mask==0) return; diff --git a/Engine/system/systemapi.cpp b/Engine/system/systemapi.cpp index 43a6f474..217b241a 100644 --- a/Engine/system/systemapi.cpp +++ b/Engine/system/systemapi.cpp @@ -33,7 +33,7 @@ void SystemApi::implSetWindowTitle(Window *w, const char *utf8) { // TODO } -void SystemApi::implSetAllowedOrientations(Window*, uint8_t) { +void SystemApi::implSetAllowedOrientations(Window*, Orientation) { } void SystemApi::setupKeyTranslate(const TranslateKeyPair k[], uint16_t funcCount ) { @@ -203,7 +203,7 @@ void SystemApi::setWindowTitle(Window *w, const char *utf8) { return inst().implSetWindowTitle(w, utf8); } -void SystemApi::setAllowedOrientations(Window *w, uint8_t orientations) { +void SystemApi::setAllowedOrientations(Window *w, Orientation orientations) { return inst().implSetAllowedOrientations(w, orientations); } diff --git a/Engine/system/systemapi.h b/Engine/system/systemapi.h index 0340b5cb..6234b226 100644 --- a/Engine/system/systemapi.h +++ b/Engine/system/systemapi.h @@ -34,6 +34,15 @@ class SystemApi { Hidden, //internal }; + enum Orientation : uint8_t { + Portrait = 1 << 0, + PortraitUpsideDown = 1 << 1, + LandscapeLeft = 1 << 2, + LandscapeRight = 1 << 3, + Landscape = LandscapeLeft | LandscapeRight, + AllOrientations = Portrait | PortraitUpsideDown | Landscape, + }; + struct TranslateKeyPair final { uint16_t src; uint16_t result; @@ -51,7 +60,7 @@ class SystemApi { static bool isFullscreen(SystemApi::Window *w); static void setWindowTitle(SystemApi::Window *w, const char* utf8); - static void setAllowedOrientations(SystemApi::Window *w, uint8_t orientations); + static void setAllowedOrientations(SystemApi::Window *w, Orientation orientations); static float uiScale(SystemApi::Window *w); static uint16_t translateKey(uint64_t scancode); @@ -87,7 +96,7 @@ class SystemApi { virtual void implProcessEvents(AppCallBack& cb) = 0; virtual void implSetWindowTitle(SystemApi::Window *w, const char* utf8) = 0; - virtual void implSetAllowedOrientations(SystemApi::Window *w, uint8_t orientations); + virtual void implSetAllowedOrientations(SystemApi::Window *w, Orientation orientations); static void setCursorPosition(SystemApi::Window *w, int x, int y); static void showCursor(SystemApi::Window *w, CursorShape c); diff --git a/Engine/ui/window.cpp b/Engine/ui/window.cpp index 10962f97..255fd8d7 100644 --- a/Engine/ui/window.cpp +++ b/Engine/ui/window.cpp @@ -32,7 +32,7 @@ void Window::setWindowTitle(const char* utf8) { } void Window::setAllowedOrientations(Orientation orientations) { - Tempest::SystemApi::setAllowedOrientations(hwnd(), uint8_t(orientations)); + Tempest::SystemApi::setAllowedOrientations(hwnd(), SystemApi::Orientation(orientations)); } void Window::render() { diff --git a/Engine/ui/window.h b/Engine/ui/window.h index a221de66..2b030565 100644 --- a/Engine/ui/window.h +++ b/Engine/ui/window.h @@ -63,4 +63,8 @@ inline Window::Orientation operator | (Window::Orientation a, const Window::Orie return Window::Orientation(uint8_t(a)|uint8_t(b)); } +inline Window::Orientation operator & (Window::Orientation a, const Window::Orientation& b) { + return Window::Orientation(uint8_t(a)&uint8_t(b)); + } + }