diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 4ef998c915..3b0212eb64 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -2539,7 +2539,7 @@ static u32 sceKernelLoadModuleDNAS(const char *name, u32 flags) } // Pretty sure this is a badly brute-forced function name... -static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, u32 lmoptionPtr) +SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, u32 lmoptionPtr) { if (flags != 0) { WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModuleBufferUsbWlan: unsupported flags: %08x", flags); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 1787301c2e..e0b978f4c2 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1165,6 +1165,14 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { switchMode->OnChoice.Add([](EventParams &e) { System_Notify(SystemNotification::APP_SWITCH_MODE_CHANGED); }); + + { + // Note: On iPhone, iOS hides the status bar in landscape no matter what this is set to. + DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation()); + systemSettings->Add(new CheckBox(&config.bImmersiveMode, sy->T("Hide status bar")))->OnClick.Add([](EventParams &e) { + System_Notify(SystemNotification::IMMERSIVE_MODE_CHANGE); + }); + } #endif #if PPSSPP_PLATFORM(ANDROID) diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 109d0d8a35..2f7d45b472 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -1424,6 +1424,7 @@ Default tab = Default tab Dynarec/JIT (recommended) = Dynarec/JIT (recommended) Final processed image = Final processed image Hide navigation bar = Hide navigation bar +Hide status bar = Hide status bar I/O timing method = I/O timing method JIT using IR = JIT using IR Loaded plugin: %1 = Loaded plugin: %1 diff --git a/ios/ViewControllerCommon.h b/ios/ViewControllerCommon.h index 5ba55cd34d..77427673a6 100644 --- a/ios/ViewControllerCommon.h +++ b/ios/ViewControllerCommon.h @@ -26,6 +26,7 @@ - (void)startVideo:(int)width height:(int)height; - (void)stopVideo; - (void)appSwitchModeChanged; +- (void)immersiveModeChanged; - (void)setupController:(GCController *)controller; // Forwarded from the AppDelegate diff --git a/ios/ViewControllerCommon.mm b/ios/ViewControllerCommon.mm index 4964db869a..855f17de51 100644 --- a/ios/ViewControllerCommon.mm +++ b/ios/ViewControllerCommon.mm @@ -481,26 +481,24 @@ extern float g_safeInsetBottom; #endif #pragma mark - Status Bar Control -// iOS calls this to determine whether to hide the status bar -- (BOOL)prefersStatusBarHidden { - UIInterfaceOrientation orientation; - +// The immersive mode setting is per-orientation, so we need to know which way we're facing. +// Can't just use g_display for this, since it lags behind during rotation. +// Note: Using viewIfLoaded, since this can get called before the view exists, and we don't want to force it into existence. +- (DeviceOrientation)currentDeviceOrientation { if (@available(iOS 13.0, *)) { - UIWindowScene *scene = self.view.window.windowScene; + UIWindowScene *scene = self.viewIfLoaded.window.windowScene; if (scene != nil) { - orientation = scene.interfaceOrientation; - } else { - orientation = UIApplication.sharedApplication.statusBarOrientation; + return UIInterfaceOrientationIsPortrait(scene.interfaceOrientation) ? DeviceOrientation::Portrait : DeviceOrientation::Landscape; } - } else { - orientation = UIApplication.sharedApplication.statusBarOrientation; } + CGSize size = self.viewIfLoaded.bounds.size; + return size.height > size.width ? DeviceOrientation::Portrait : DeviceOrientation::Landscape; +} - BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation); - - bool userWantsStatusBar = true; // g_Config.bShowStatusBar; - // return isLandscape || !userWantsStatusBar; - return false; +// iOS calls this to determine whether to hide the status bar. +// Note that on iPhone, iOS hides it in landscape regardless of what we return here. +- (BOOL)prefersStatusBarHidden { + return g_Config.GetDisplayLayoutConfig([self currentDeviceOrientation]).bImmersiveMode ? YES : NO; } // Optional: choose light/dark text for the status bar @@ -508,11 +506,22 @@ extern float g_safeInsetBottom; return UIStatusBarStyleLightContent; } -// This should also be called when the user preference changes. - (void)onOrientationChanged { [self setNeedsStatusBarAppearanceUpdate]; } +// Called from the C++ side when the user toggles the immersive mode setting. +- (void)immersiveModeChanged { + [self setNeedsStatusBarAppearanceUpdate]; +} + +- (void)viewWillTransitionToSize:(CGSize)size + withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + // The immersive mode setting is per-orientation, so the status bar may need to change along with the rotation. + [self setNeedsStatusBarAppearanceUpdate]; +} + - (void)updateResolutionWithView:(UIView *)view { // 1. Get the scale from the window scene (safest for Metal) CGFloat scale = 1.0; diff --git a/ios/main.mm b/ios/main.mm index 989e50f5d3..d1dc5f2795 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -432,6 +432,13 @@ void System_Notify(SystemNotification notification) { } }); break; + case SystemNotification::IMMERSIVE_MODE_CHANGE: + dispatch_async(dispatch_get_main_queue(), ^{ + if (sharedViewController) { + [sharedViewController immersiveModeChanged]; + } + }); + break; case SystemNotification::UI_STATE_CHANGED: dispatch_async(dispatch_get_main_queue(), ^{ if (sharedViewController) { @@ -452,6 +459,7 @@ void System_Notify(SystemNotification notification) { [UIViewController attemptRotationToDeviceOrientation]; } }); + break; default: break; }