From 39172d0c8b108e1e055820ce28ec9a623ebb87c1 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 24 Oct 2026 06:10:33 +0300 Subject: [PATCH 1/2] iOS: tell UIKit when unlockOrientation() changes the supported mask (#6089) Co-Authored-By: Claude Opus 5.5 --- Ports/iOSPort/nativeSources/IOSNative.m | 67 +++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/Ports/iOSPort/nativeSources/IOSNative.m b/Ports/iOSPort/nativeSources/IOSNative.m index 661230b19b1..d31d03737e2 100644 --- a/Ports/iOSPort/nativeSources/IOSNative.m +++ b/Ports/iOSPort/nativeSources/IOSNative.m @@ -4459,9 +4459,76 @@ void com_codename1_impl_ios_IOSNative_lockOrientation___boolean(CN1_THREAD_STATE #endif } +#if !TARGET_OS_OSX && !TARGET_OS_WATCH && !TARGET_OS_TV +// Tells UIKit that the root controller's supportedInterfaceOrientations +// answer changed. Changing orientationLock alone changes nothing UIKit can +// see: since iOS 16 it caches the mask and re-reads it only when asked, so an +// unlock after a lock (issue #6089, a lock held across the native camera) +// left autorotation off until the process was restarted. Must run on the +// main thread. +static void cn1RefreshSupportedOrientations(void) { + UIViewController *root = [CodenameOne_GLViewController instance]; + if (root == nil) { + return; + } + if (@available(iOS 16.0, *)) { + [root setNeedsUpdateOfSupportedInterfaceOrientations]; + // While a native modal (the camera, a picker) is up it owns the + // interface orientation, and UIKit re-reads the root's mask when it + // is dismissed. A geometry request now would rotate under it. + if (root.presentedViewController != nil) { + return; + } + UIWindowScene *scene = root.view.window.windowScene; + if (scene == nil) { + return; + } + // Ask for the orientation the device is physically held in, when it + // is known and allowed, so the interface follows the hand at once + // instead of waiting for the next physical rotation. + UIInterfaceOrientationMask wanted = 0; + switch ([[UIDevice currentDevice] orientation]) { + case UIDeviceOrientationPortrait: + wanted = UIInterfaceOrientationMaskPortrait; + break; + case UIDeviceOrientationPortraitUpsideDown: + wanted = UIInterfaceOrientationMaskPortraitUpsideDown; + break; + // Device and interface landscape are mirrored. + case UIDeviceOrientationLandscapeLeft: + wanted = UIInterfaceOrientationMaskLandscapeRight; + break; + case UIDeviceOrientationLandscapeRight: + wanted = UIInterfaceOrientationMaskLandscapeLeft; + break; + default: + break; + } + UIInterfaceOrientationMask allowed = [root supportedInterfaceOrientations] + & [[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:root.view.window]; + if ((wanted & allowed) == 0) { + return; + } + UIWindowSceneGeometryPreferencesIOS *prefs = + [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:wanted]; + [scene requestGeometryUpdateWithPreferences:prefs errorHandler:^(NSError *error) { + NSLog(@"CN1: orientation geometry request failed: %@", error); + }]; + [prefs release]; + } else { + [UIViewController attemptRotationToDeviceOrientation]; + } +} +#endif + void com_codename1_impl_ios_IOSNative_unlockOrientation__(CN1_THREAD_STATE_MULTI_ARG JAVA_OBJECT instanceObject) { orientationLock = 0; +#if !TARGET_OS_OSX && !TARGET_OS_WATCH && !TARGET_OS_TV + dispatch_async(dispatch_get_main_queue(), ^{ + cn1RefreshSupportedOrientations(); + }); +#endif } void com_codename1_impl_ios_IOSNative_lockScreen__(CN1_THREAD_STATE_MULTI_ARG JAVA_OBJECT instanceObject) From 28bddf924c2c50b48fd09c81601ebb0ada1c9108 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 24 Oct 2026 06:15:18 +0300 Subject: [PATCH 2/2] iOS: skip the orientation geometry request on Catalyst Co-Authored-By: Claude Opus 5.5 --- Ports/iOSPort/nativeSources/IOSNative.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Ports/iOSPort/nativeSources/IOSNative.m b/Ports/iOSPort/nativeSources/IOSNative.m index d31d03737e2..709e5727b57 100644 --- a/Ports/iOSPort/nativeSources/IOSNative.m +++ b/Ports/iOSPort/nativeSources/IOSNative.m @@ -4479,6 +4479,11 @@ static void cn1RefreshSupportedOrientations(void) { if (root.presentedViewController != nil) { return; } +#if TARGET_OS_MACCATALYST + // A Mac window has no interface orientation to request, and the + // iOS geometry preferences are refused there. + return; +#endif UIWindowScene *scene = root.view.window.windowScene; if (scene == nil) { return;