Skip to content

Commit

Permalink
display(iOS): hide home indicator and mouse cursor
Browse files Browse the repository at this point in the history
Fixes #4390
  • Loading branch information
osy committed Sep 10, 2022
1 parent 7f0247f commit 1627154
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 25 deletions.
2 changes: 2 additions & 0 deletions Platform/Main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class Main {
if jb_increase_memlimit() {
logger.info("MEM: successfully removed memory limits")
}
// UIViewController patches
UIViewController.patch()
#endif
UTMApp.main()
}
Expand Down
9 changes: 2 additions & 7 deletions Platform/iOS/Display/VMDisplayMetalViewController+Pointer.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ - (void)initGCMouse {
}
}

- (BOOL)prefersPointerLocked {
return _mouseCaptured;
}

- (void)mouseDidBecomeCurrent:(NSNotification *)notification API_AVAILABLE(ios(14)) {
GCMouse *mouse = notification.object;
Expand Down Expand Up @@ -88,9 +85,8 @@ - (void)mouseDidBecomeCurrent:(NSNotification *)notification API_AVAILABLE(ios(1
};
}
// no handler to the gcmouse scroll event, gestureScroll works fine.
_mouseCaptured = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsUpdateOfPrefersPointerLocked];
self.prefersPointerLocked = YES;
});
}

Expand All @@ -104,9 +100,8 @@ - (void)mouseDidStopBeingCurrent:(NSNotification *)notification API_AVAILABLE(io
for (int i = 0; i < MIN(4, mouse.mouseInput.auxiliaryButtons.count); i++) {
mouse.mouseInput.auxiliaryButtons[i].pressedChangedHandler = nil;
}
_mouseCaptured = NO;
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsUpdateOfPrefersPointerLocked];
self.prefersPointerLocked = NO;
});
}

Expand Down
1 change: 0 additions & 1 deletion Platform/iOS/Display/VMDisplayMetalViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ NS_ASSUME_NONNULL_BEGIN
BOOL _pencilForceRightClickOnce;
VMCursor *_cursor;
VMScroll *_scroll;
BOOL _mouseCaptured;

// Gestures
UISwipeGestureRecognizer *_swipeUp;
Expand Down
2 changes: 1 addition & 1 deletion Platform/iOS/Display/VMDisplayMetalViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ - (void)viewDidLoad {

- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.prefersStatusBarHidden = YES;
self.prefersHomeIndicatorAutoHidden = YES;
}

- (void)viewDidAppear:(BOOL)animated {
Expand Down
3 changes: 2 additions & 1 deletion Platform/iOS/Display/VMDisplayViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
@property (weak, nonatomic) id<VMDisplayViewControllerDelegate> delegate;

@property (nonatomic) BOOL hasAutoSave;
@property (nonatomic, readwrite) BOOL prefersStatusBarHidden;
@property (nonatomic, readwrite) BOOL prefersHomeIndicatorAutoHidden;
@property (nonatomic, readwrite) BOOL prefersPointerLocked;

- (void)showKeyboard;
- (void)hideKeyboard;
Expand Down
20 changes: 13 additions & 7 deletions Platform/iOS/Display/VMDisplayViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,25 @@ @implementation VMDisplayViewController

#pragma mark - Properties

@synthesize prefersStatusBarHidden = _prefersStatusBarHidden;
@synthesize prefersHomeIndicatorAutoHidden = _prefersHomeIndicatorAutoHidden;
@synthesize prefersPointerLocked = _prefersPointerLocked;

- (BOOL)prefersHomeIndicatorAutoHidden {
return YES; // always hide home indicator
return _prefersHomeIndicatorAutoHidden;
}

- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
- (void)setPrefersHomeIndicatorAutoHidden:(BOOL)prefersHomeIndicatorAutoHidden {
_prefersHomeIndicatorAutoHidden = prefersHomeIndicatorAutoHidden;
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}

- (void)setPrefersStatusBarHidden:(BOOL)prefersStatusBarHidden {
_prefersStatusBarHidden = prefersStatusBarHidden;
[self setNeedsStatusBarAppearanceUpdate];
- (BOOL)prefersPointerLocked {
return _prefersPointerLocked;
}

- (void)setPrefersPointerLocked:(BOOL)prefersPointerLocked {
_prefersPointerLocked = prefersPointerLocked;
[self setNeedsUpdateOfPrefersPointerLocked];
}

- (void)showKeyboard {
Expand Down
20 changes: 12 additions & 8 deletions Platform/iOS/Display/VMDisplayViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ import SwiftUI
private var memoryAlertOnce = false

@objc public extension VMDisplayViewController {
var largeScreen: Bool {
traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass == .regular
}

var runInBackground: Bool {
boolForSetting("RunInBackground")
}
Expand All @@ -36,19 +32,27 @@ private var memoryAlertOnce = false
public extension VMDisplayViewController {
override func viewDidLoad() {
super.viewDidLoad()

if largeScreen {
prefersStatusBarHidden = true
}
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let root = view.window?.rootViewController {
root.setChildForHomeIndicatorAutoHidden(nil)
root.setChildViewControllerForPointerLock(nil)
}
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let root = view.window?.rootViewController {
root.setChildForHomeIndicatorAutoHidden(self)
root.setChildViewControllerForPointerLock(self)
}
if runInBackground {
logger.info("Start location tracking to enable running in background")
UTMLocationManager.sharedInstance().startUpdatingLocation()
Expand Down
55 changes: 55 additions & 0 deletions Platform/iOS/UIViewControllerPatch.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// Copyright © 2022 osy. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import UIKit

/// We need to set these when the VM starts running since there is no way to do it from SwiftUI right now
extension UIViewController {
private static var _childForHomeIndicatorAutoHiddenStorage: [UIViewController: UIViewController?] = [:]

@objc private dynamic var _childForHomeIndicatorAutoHidden: UIViewController? {
Self._childForHomeIndicatorAutoHiddenStorage[self] ?? nil
}

@objc dynamic func setChildForHomeIndicatorAutoHidden(_ value: UIViewController?) {
Self._childForHomeIndicatorAutoHiddenStorage[self] = value
setNeedsUpdateOfHomeIndicatorAutoHidden()
}

private static var _childViewControllerForPointerLockStorage: [UIViewController: UIViewController?] = [:]

@objc private dynamic var _childViewControllerForPointerLock: UIViewController? {
Self._childViewControllerForPointerLockStorage[self] ?? nil
}

@objc dynamic func setChildViewControllerForPointerLock(_ value: UIViewController?) {
Self._childViewControllerForPointerLockStorage[self] = value
setNeedsUpdateOfPrefersPointerLocked()
}

static func patch() {
let originalChildForHomeIndicatorAutoHidden = #selector(getter: Self.childForHomeIndicatorAutoHidden)
let swizzleChildForHomeIndicatorAutoHidden = #selector(getter: Self._childForHomeIndicatorAutoHidden)
let originalChildForHomeIndicatorAutoHiddenMethod = class_getInstanceMethod(Self.self, originalChildForHomeIndicatorAutoHidden)!
let swizzleChildForHomeIndicatorAutoHiddenMethod = class_getInstanceMethod(Self.self, swizzleChildForHomeIndicatorAutoHidden)!
method_exchangeImplementations(originalChildForHomeIndicatorAutoHiddenMethod, swizzleChildForHomeIndicatorAutoHiddenMethod)
let originalChildViewControllerForPointerLock = #selector(getter: Self.childViewControllerForPointerLock)
let swizzleChildViewControllerForPointerLock = #selector(getter: Self._childViewControllerForPointerLock)
let originalChildViewControllerForPointerLockMethod = class_getInstanceMethod(Self.self, originalChildViewControllerForPointerLock)!
let swizzleChildViewControllerForPointerLockMethod = class_getInstanceMethod(Self.self, swizzleChildViewControllerForPointerLock)!
method_exchangeImplementations(originalChildViewControllerForPointerLockMethod, swizzleChildViewControllerForPointerLockMethod)
}
}
6 changes: 6 additions & 0 deletions UTM.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
841E999928AC817D003C6CB6 /* UTMQemuVirtualMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841E999728AC817D003C6CB6 /* UTMQemuVirtualMachine.swift */; };
841E999A28AC817D003C6CB6 /* UTMQemuVirtualMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841E999728AC817D003C6CB6 /* UTMQemuVirtualMachine.swift */; };
84258C42288F806400C66366 /* VMToolbarUSBMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84258C41288F806400C66366 /* VMToolbarUSBMenuView.swift */; };
842B9F8D28CC58B700031EE7 /* UIViewControllerPatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842B9F8C28CC58B700031EE7 /* UIViewControllerPatch.swift */; };
842B9F8E28CC58B700031EE7 /* UIViewControllerPatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842B9F8C28CC58B700031EE7 /* UIViewControllerPatch.swift */; };
8432329028C2CDAD00CFBC97 /* VMNavigationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432328F28C2CDAD00CFBC97 /* VMNavigationListView.swift */; };
8432329128C2CDAD00CFBC97 /* VMNavigationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432328F28C2CDAD00CFBC97 /* VMNavigationListView.swift */; };
8432329228C2CDAD00CFBC97 /* VMNavigationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432328F28C2CDAD00CFBC97 /* VMNavigationListView.swift */; };
Expand Down Expand Up @@ -1628,6 +1630,7 @@
841E999628AC80CA003C6CB6 /* UTMQemuVirtualMachine-Protected.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UTMQemuVirtualMachine-Protected.h"; sourceTree = "<group>"; };
841E999728AC817D003C6CB6 /* UTMQemuVirtualMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMQemuVirtualMachine.swift; sourceTree = "<group>"; };
84258C41288F806400C66366 /* VMToolbarUSBMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMToolbarUSBMenuView.swift; sourceTree = "<group>"; };
842B9F8C28CC58B700031EE7 /* UIViewControllerPatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerPatch.swift; sourceTree = "<group>"; };
8432328F28C2CDAD00CFBC97 /* VMNavigationListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMNavigationListView.swift; sourceTree = "<group>"; };
8432329328C2ED9000CFBC97 /* FileBrowseField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileBrowseField.swift; sourceTree = "<group>"; };
8432329728C3017F00CFBC97 /* GlobalFileImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalFileImporter.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2709,6 +2712,7 @@
CE7BED4D22600F5000A1E1B6 /* Display */,
CE8813D224CD230300532628 /* ActivityView.swift */,
CED814EE24C7EB760042F0F1 /* ImagePicker.swift */,
842B9F8C28CC58B700031EE7 /* UIViewControllerPatch.swift */,
841E58D02893AF5400137A20 /* UTMApp.swift */,
CEBBF1A424B56A2900C15049 /* UTMDataExtension.swift */,
841E58CA28937EE200137A20 /* UTMExternalSceneDelegate.swift */,
Expand Down Expand Up @@ -3682,6 +3686,7 @@
CE2D92B324AD46670059923A /* qapi-events-net.c in Sources */,
CE2D92B424AD46670059923A /* qapi-visit-run-state.c in Sources */,
CED814E924C79F070042F0F1 /* VMConfigDriveCreateView.swift in Sources */,
842B9F8D28CC58B700031EE7 /* UIViewControllerPatch.swift in Sources */,
CE2D92B524AD46670059923A /* qapi-commands-tpm.c in Sources */,
CE19392626DCB094005CEC17 /* RAMSlider.swift in Sources */,
CE2D92B724AD46670059923A /* qapi-visit-common.c in Sources */,
Expand Down Expand Up @@ -4248,6 +4253,7 @@
CEA45E6B263519B5002FA97D /* UTMLegacyQemuConfiguration+Display.m in Sources */,
CEA45E6C263519B5002FA97D /* UTMVirtualMachine.swift in Sources */,
84B36D2A27B790BE00C22685 /* DestructiveButton.swift in Sources */,
842B9F8E28CC58B700031EE7 /* UIViewControllerPatch.swift in Sources */,
CEA45E6D263519B5002FA97D /* qapi-visit-block-core.c in Sources */,
CEE7E937287CFDB100282049 /* UTMLegacyQemuConfiguration+Constants.m in Sources */,
841619AB284315F9000034B2 /* UTMConfigurationInfo.swift in Sources */,
Expand Down

0 comments on commit 1627154

Please sign in to comment.