From 61ff13620413d481d869fc92f36d90ddf9c9d119 Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Wed, 17 Mar 2021 22:10:30 -0600 Subject: [PATCH 1/8] implements optimized airplay support --- DeltaCore/UI/Game/GameViewController.swift | 134 +++++++++++++++++++-- 1 file changed, 127 insertions(+), 7 deletions(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index c18a4de..a4b5995 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -96,6 +96,10 @@ open class GameViewController: UIViewController, GameControllerReceiver private var _previousControllerSkin: ControllerSkinProtocol? private var _previousControllerSkinTraits: ControllerSkin.Traits? + // Screen Mirroing + public var mirroredWindow: UIWindow? + public var mirroredScreen: UIScreen? + /// UIViewController open override var prefersStatusBarHidden: Bool { return true @@ -123,6 +127,10 @@ open class GameViewController: UIViewController, GameControllerReceiver NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.keyboardWillShow(with:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.keyboardWillChangeFrame(with:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.keyboardWillHide(with:)), name: UIResponder.keyboardWillHideNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.screenDidConnect), name: UIScreen.didConnectNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.screenDidDisconnect), name: UIScreen.didDisconnectNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.screenModeDidChange), name: UIScreen.modeDidChangeNotification, object: nil) } deinit @@ -263,12 +271,29 @@ open class GameViewController: UIViewController, GameControllerReceiver if intrinsicContentSize.height != UIView.noIntrinsicMetric && intrinsicContentSize.width != UIView.noIntrinsicMetric { let controllerViewHeight = (self.view.bounds.width / intrinsicContentSize.width) * intrinsicContentSize.height - (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: controllerViewHeight, from: .maxYEdge) + + if let mirroredScreen = mirroredScreen + { + availableGameFrame = mirroredScreen.bounds + (controllerViewFrame, _) = self.view.bounds.divided(atDistance: controllerViewHeight, from: .maxYEdge) + } + else + { + (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: controllerViewHeight, from: .maxYEdge) + } } else { controllerViewFrame = self.view.bounds - availableGameFrame = self.view.bounds + + if let mirroredScreen = mirroredScreen + { + availableGameFrame = mirroredScreen.bounds + } + else + { + availableGameFrame = self.view.bounds + } } case _?: @@ -286,7 +311,14 @@ open class GameViewController: UIViewController, GameControllerReceiver controllerViewFrame = self.view.bounds } - availableGameFrame = self.view.bounds + if let mirroredScreen = mirroredScreen + { + availableGameFrame = mirroredScreen.bounds + } + else + { + availableGameFrame = self.view.bounds + } } self.controllerView.frame = controllerViewFrame @@ -300,8 +332,11 @@ open class GameViewController: UIViewController, GameControllerReceiver { for (screen, gameView) in zip(screens, self.gameViews) { - let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) - gameView.frame = outputFrame + if mirroredScreen == nil + { + let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) + gameView.frame = outputFrame + } } } else @@ -392,8 +427,17 @@ extension GameViewController gameView.filter = filterChain } - let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) - gameView.frame = outputFrame + if let mirroredScreen = mirroredScreen + { + let screenAspectRatio = self.emulatorCore?.preferredRenderingSize ?? CGSize(width: 1, height: 1) + let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatio, insideRect: mirroredScreen.bounds) + self.gameView.frame = gameViewFrame + } + else + { + let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) + gameView.frame = outputFrame + } gameViews.append(gameView) } @@ -589,3 +633,79 @@ private extension GameViewController animator.startAnimation() } } + +//MARK: - Screen Mirroring - +private extension GameViewController +{ + @objc func screenDidConnect() + { + self.setupMirroringIfApplicable() + } + + @objc func screenDidDisconnect() + { + self.disableMirroring() + } + + @objc func screenModeDidChange() + { + self.disableMirroring() + self.setupMirroringIfApplicable() + } +} + +public extension GameViewController +{ + func setupMirroringIfApplicable() + { + guard UIScreen.screens.count > 1, let externalScreen = UIScreen.screens.last else { return } + self.mirroredScreen = externalScreen + + // Find max resolution + var max = CGSize(width: 0, height: 0) + var maxScreenMode: UIScreenMode? = nil + if let mirroredScreen = mirroredScreen + { + for mode in mirroredScreen.availableModes + { + if (maxScreenMode == nil || mode.size.height > max.height || mode.size.width > max.width) + { + max = mode.size + maxScreenMode = mode + } + } + } + self.mirroredScreen?.currentMode = maxScreenMode + + // Setup window in external screen + if let mirroredScreen = mirroredScreen + { + self.mirroredWindow = UIWindow(frame: mirroredScreen.bounds) + self.mirroredWindow?.isHidden = false + self.mirroredWindow?.layer.contentsGravity = .resizeAspect + self.mirroredWindow?.screen = mirroredScreen + } + + self.gameView.removeFromSuperview() + + self.mirroredWindow?.addSubview(self.gameView) + self.gameView.frame = mirroredWindow?.frame ?? .zero + + self.gameView.setNeedsLayout() + self.mirroredWindow?.layoutIfNeeded() + } + + func disableMirroring() + { + self.gameView.removeFromSuperview() + self.view.insertSubview(self.gameView, belowSubview: self.controllerView) + + self.mirroredScreen = nil + self.mirroredWindow = nil + + self.gameView.setNeedsLayout() + self.gameView.layoutIfNeeded() + self.view.setNeedsLayout() + self.view.layoutIfNeeded() + } +} From 1e56a6f8bfddcf0f33c491a2c3ea416afae32a36 Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Thu, 18 Mar 2021 00:14:36 -0600 Subject: [PATCH 2/8] handles case when external controller is attached --- DeltaCore/UI/Game/GameViewController.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index a4b5995..b3e8cd2 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -259,8 +259,16 @@ open class GameViewController: UIViewController, GameControllerReceiver // Controller View Hidden: // - Controller View should have a height of 0. // - Game View should be centered in self.view. - - (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: 0, from: .maxYEdge) + + if let mirroredScreen = mirroredScreen + { + availableGameFrame = mirroredScreen.bounds + (controllerViewFrame, _) = self.view.bounds.divided(atDistance: 0, from: .maxYEdge) + } + else + { + (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: 0, from: .maxYEdge) + } case let traits? where traits.orientation == .portrait: // Portrait: From 056ee94a135ef5c71666dda7cfda3b6981f0c65c Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Thu, 18 Mar 2021 00:19:56 -0600 Subject: [PATCH 3/8] better naming semantics --- DeltaCore/UI/Game/GameViewController.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index b3e8cd2..345113f 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -647,7 +647,7 @@ private extension GameViewController { @objc func screenDidConnect() { - self.setupMirroringIfApplicable() + self.enableMirroringIfApplicable() } @objc func screenDidDisconnect() @@ -658,13 +658,13 @@ private extension GameViewController @objc func screenModeDidChange() { self.disableMirroring() - self.setupMirroringIfApplicable() + self.enableMirroringIfApplicable() } } public extension GameViewController { - func setupMirroringIfApplicable() + func enableMirroringIfApplicable() { guard UIScreen.screens.count > 1, let externalScreen = UIScreen.screens.last else { return } self.mirroredScreen = externalScreen From 167eb1f6986e41a397d2f7c86d8e650da6b4b38d Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Wed, 21 Apr 2021 21:48:18 -0600 Subject: [PATCH 4/8] simplifies mirrored screen frame selection logic --- DeltaCore/UI/Game/GameViewController.swift | 60 +++++----------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index 345113f..78f53c4 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -259,16 +259,8 @@ open class GameViewController: UIViewController, GameControllerReceiver // Controller View Hidden: // - Controller View should have a height of 0. // - Game View should be centered in self.view. - - if let mirroredScreen = mirroredScreen - { - availableGameFrame = mirroredScreen.bounds - (controllerViewFrame, _) = self.view.bounds.divided(atDistance: 0, from: .maxYEdge) - } - else - { - (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: 0, from: .maxYEdge) - } + + (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: 0, from: .maxYEdge) case let traits? where traits.orientation == .portrait: // Portrait: @@ -279,29 +271,12 @@ open class GameViewController: UIViewController, GameControllerReceiver if intrinsicContentSize.height != UIView.noIntrinsicMetric && intrinsicContentSize.width != UIView.noIntrinsicMetric { let controllerViewHeight = (self.view.bounds.width / intrinsicContentSize.width) * intrinsicContentSize.height - - if let mirroredScreen = mirroredScreen - { - availableGameFrame = mirroredScreen.bounds - (controllerViewFrame, _) = self.view.bounds.divided(atDistance: controllerViewHeight, from: .maxYEdge) - } - else - { - (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: controllerViewHeight, from: .maxYEdge) - } + (controllerViewFrame, availableGameFrame) = self.view.bounds.divided(atDistance: controllerViewHeight, from: .maxYEdge) } else { controllerViewFrame = self.view.bounds - - if let mirroredScreen = mirroredScreen - { - availableGameFrame = mirroredScreen.bounds - } - else - { - availableGameFrame = self.view.bounds - } + availableGameFrame = self.view.bounds } case _?: @@ -319,20 +294,14 @@ open class GameViewController: UIViewController, GameControllerReceiver controllerViewFrame = self.view.bounds } - if let mirroredScreen = mirroredScreen - { - availableGameFrame = mirroredScreen.bounds - } - else - { - availableGameFrame = self.view.bounds - } + availableGameFrame = self.view.bounds } self.controllerView.frame = controllerViewFrame /* Game View */ if + mirroredScreen == nil, let controllerSkin = self.controllerView.controllerSkin, let traits = self.controllerView.controllerSkinTraits, let screens = controllerSkin.screens(for: traits), @@ -340,16 +309,13 @@ open class GameViewController: UIViewController, GameControllerReceiver { for (screen, gameView) in zip(screens, self.gameViews) { - if mirroredScreen == nil - { - let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) - gameView.frame = outputFrame - } + let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) + gameView.frame = outputFrame } } else { - let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatio, insideRect: availableGameFrame) + let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatio, insideRect: (mirroredScreen != nil) ? mirroredScreen!.bounds : availableGameFrame) self.gameView.frame = gameViewFrame } @@ -435,17 +401,15 @@ extension GameViewController gameView.filter = filterChain } + let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) + gameView.frame = outputFrame + if let mirroredScreen = mirroredScreen { let screenAspectRatio = self.emulatorCore?.preferredRenderingSize ?? CGSize(width: 1, height: 1) let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatio, insideRect: mirroredScreen.bounds) self.gameView.frame = gameViewFrame } - else - { - let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) - gameView.frame = outputFrame - } gameViews.append(gameView) } From fb5b557922b9ebaa349a6528aaef58cb3cf16d8b Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Wed, 21 Apr 2021 22:25:15 -0600 Subject: [PATCH 5/8] corrects melonDS aspect ratio when mirroring --- DeltaCore/UI/Game/GameViewController.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index 78f53c4..e4b4433 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -315,7 +315,17 @@ open class GameViewController: UIViewController, GameControllerReceiver } else { - let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatio, insideRect: (mirroredScreen != nil) ? mirroredScreen!.bounds : availableGameFrame) + var screenAspectRatioToUse = screenAspectRatio + var availableGameFrameToUse = availableGameFrame + if let mirroredScreen = mirroredScreen { + availableGameFrameToUse = mirroredScreen.bounds + if screenAspectRatio.height > screenAspectRatio.width { + // the only VideoFormat where height > width (for now) is melonDS; correct height for non-touch screen + screenAspectRatioToUse = CGSize(width: screenAspectRatio.width, height: screenAspectRatio.height / 2) + } + } + + let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatioToUse, insideRect: availableGameFrameToUse) self.gameView.frame = gameViewFrame } From aa1e59bfc8671e3795000bf05f51a18c4135e66f Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Wed, 21 Jul 2021 13:17:51 -0600 Subject: [PATCH 6/8] makes optimized airplay togglable via settings toggle --- DeltaCore/UI/Game/GameViewController.swift | 107 +++++++++++---------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index e4b4433..7a1144a 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -96,9 +96,8 @@ open class GameViewController: UIViewController, GameControllerReceiver private var _previousControllerSkin: ControllerSkinProtocol? private var _previousControllerSkinTraits: ControllerSkin.Traits? - // Screen Mirroing - public var mirroredWindow: UIWindow? - public var mirroredScreen: UIScreen? + public var isAirplayEnabled: Bool = false + public var airplayWindow: UIWindow? /// UIViewController open override var prefersStatusBarHidden: Bool { @@ -170,6 +169,8 @@ open class GameViewController: UIViewController, GameControllerReceiver let tapGestureRecognizer = UITapGestureRecognizer(target: self.controllerView, action: #selector(ControllerView.becomeFirstResponder)) self.view.addGestureRecognizer(tapGestureRecognizer) + self.handleAirplayScreen() + self.prepareForGame() } @@ -301,7 +302,7 @@ open class GameViewController: UIViewController, GameControllerReceiver /* Game View */ if - mirroredScreen == nil, + self.airplayWindow == nil, let controllerSkin = self.controllerView.controllerSkin, let traits = self.controllerView.controllerSkinTraits, let screens = controllerSkin.screens(for: traits), @@ -317,9 +318,11 @@ open class GameViewController: UIViewController, GameControllerReceiver { var screenAspectRatioToUse = screenAspectRatio var availableGameFrameToUse = availableGameFrame - if let mirroredScreen = mirroredScreen { - availableGameFrameToUse = mirroredScreen.bounds - if screenAspectRatio.height > screenAspectRatio.width { + if let airplayWindow = self.airplayWindow + { + availableGameFrameToUse = airplayWindow.bounds + if screenAspectRatio.height > screenAspectRatio.width + { // the only VideoFormat where height > width (for now) is melonDS; correct height for non-touch screen screenAspectRatioToUse = CGSize(width: screenAspectRatio.width, height: screenAspectRatio.height / 2) } @@ -343,7 +346,7 @@ open class GameViewController: UIViewController, GameControllerReceiver // MARK: - KVO - /// KVO open dynamic override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) - { + { guard context == &kvoContext else { return super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } // Ensures the value is actually different, or else we might potentially run into an infinite loop if subclasses hide/show controllerView in viewDidLayoutSubviews() @@ -414,10 +417,10 @@ extension GameViewController let outputFrame = screen.outputFrame.applying(.init(scaleX: self.view.bounds.width, y: self.view.bounds.height)) gameView.frame = outputFrame - if let mirroredScreen = mirroredScreen + if let airplayWindow = self.airplayWindow { let screenAspectRatio = self.emulatorCore?.preferredRenderingSize ?? CGSize(width: 1, height: 1) - let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatio, insideRect: mirroredScreen.bounds) + let gameViewFrame = AVMakeRect(aspectRatio: screenAspectRatio, insideRect: airplayWindow.bounds) self.gameView.frame = gameViewFrame } @@ -553,7 +556,7 @@ private extension GameViewController } } -// MARK: - Notifications - +// MARK: - Notifications - private extension GameViewController { @objc func willResignActive(with notification: Notification) @@ -616,78 +619,76 @@ private extension GameViewController } } -//MARK: - Screen Mirroring - +//MARK: - AirPlay - private extension GameViewController { @objc func screenDidConnect() { - self.enableMirroringIfApplicable() + self.handleAirplayScreen() } @objc func screenDidDisconnect() { - self.disableMirroring() + self.handleAirplayScreen() } @objc func screenModeDidChange() { - self.disableMirroring() - self.enableMirroringIfApplicable() + self.handleAirplayScreen() } } public extension GameViewController { - func enableMirroringIfApplicable() + func handleAirplayScreen() { - guard UIScreen.screens.count > 1, let externalScreen = UIScreen.screens.last else { return } - self.mirroredScreen = externalScreen + // perform teardown first if already AirPlaying and screens are being switched + if self.airplayWindow != nil + { + self.gameView.removeFromSuperview() + self.view.insertSubview(self.gameView, belowSubview: self.controllerView) + + self.airplayWindow = nil + + self.gameView.setNeedsLayout() + self.gameView.layoutIfNeeded() + self.view.setNeedsLayout() + self.view.layoutIfNeeded() + } + + // now perform setup of AirPlay screen + guard + self.isAirplayEnabled, + UIScreen.screens.count > 1 + else { return } + + let secondScreen = UIScreen.screens[1] - // Find max resolution + // find max resolution var max = CGSize(width: 0, height: 0) var maxScreenMode: UIScreenMode? = nil - if let mirroredScreen = mirroredScreen + for mode in secondScreen.availableModes { - for mode in mirroredScreen.availableModes + if (maxScreenMode == nil || mode.size.height > max.height || mode.size.width > max.width) { - if (maxScreenMode == nil || mode.size.height > max.height || mode.size.width > max.width) - { - max = mode.size - maxScreenMode = mode - } + max = mode.size + maxScreenMode = mode } } - self.mirroredScreen?.currentMode = maxScreenMode + secondScreen.currentMode = maxScreenMode - // Setup window in external screen - if let mirroredScreen = mirroredScreen - { - self.mirroredWindow = UIWindow(frame: mirroredScreen.bounds) - self.mirroredWindow?.isHidden = false - self.mirroredWindow?.layer.contentsGravity = .resizeAspect - self.mirroredWindow?.screen = mirroredScreen - } + // setup window on second screen + self.airplayWindow = UIWindow(frame: secondScreen.bounds) + self.airplayWindow?.isHidden = false + self.airplayWindow?.layer.contentsGravity = .resizeAspect + self.airplayWindow?.screen = secondScreen self.gameView.removeFromSuperview() - self.mirroredWindow?.addSubview(self.gameView) - self.gameView.frame = mirroredWindow?.frame ?? .zero + self.airplayWindow?.addSubview(self.gameView) + self.gameView.frame = self.airplayWindow?.frame ?? .zero self.gameView.setNeedsLayout() - self.mirroredWindow?.layoutIfNeeded() - } - - func disableMirroring() - { - self.gameView.removeFromSuperview() - self.view.insertSubview(self.gameView, belowSubview: self.controllerView) - - self.mirroredScreen = nil - self.mirroredWindow = nil - - self.gameView.setNeedsLayout() - self.gameView.layoutIfNeeded() - self.view.setNeedsLayout() - self.view.layoutIfNeeded() + self.airplayWindow?.layoutIfNeeded() } } From 6d08a3261afa60d37df1d5864f4ce9d11d986635 Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Sat, 25 Sep 2021 03:04:42 -0600 Subject: [PATCH 7/8] simplifies logic, adds delegates which can be used by main Delta's GameViewController to dynamically add or remove airplay ui --- DeltaCore/UI/Game/GameViewController.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index 7a1144a..75f546b 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -35,6 +35,9 @@ public protocol GameViewControllerDelegate: class func gameViewController(_ gameViewController: GameViewController, handleMenuInputFrom gameController: GameController) func gameViewControllerDidUpdate(_ gameViewController: GameViewController) + + func gameViewControllerDidEnterAirplay(_ gameViewController: GameViewController) + func gameViewControllerDidExitAirplay(_ gameViewController: GameViewController) } public extension GameViewControllerDelegate @@ -45,6 +48,9 @@ public extension GameViewControllerDelegate func gameViewController(_ gameViewController: GameViewController, handleMenuInputFrom gameController: GameController) {} func gameViewControllerDidUpdate(_ gameViewController: GameViewController) {} + + func gameViewControllerDidEnterAirplay(_ gameViewController: GameViewController) {} + func gameViewControllerDidExitAirplay(_ gameViewController: GameViewController) {} } private var kvoContext = 0 @@ -645,7 +651,6 @@ public extension GameViewController // perform teardown first if already AirPlaying and screens are being switched if self.airplayWindow != nil { - self.gameView.removeFromSuperview() self.view.insertSubview(self.gameView, belowSubview: self.controllerView) self.airplayWindow = nil @@ -654,6 +659,8 @@ public extension GameViewController self.gameView.layoutIfNeeded() self.view.setNeedsLayout() self.view.layoutIfNeeded() + + self.delegate?.gameViewControllerDidExitAirplay(self) } // now perform setup of AirPlay screen @@ -683,12 +690,12 @@ public extension GameViewController self.airplayWindow?.layer.contentsGravity = .resizeAspect self.airplayWindow?.screen = secondScreen - self.gameView.removeFromSuperview() - self.airplayWindow?.addSubview(self.gameView) self.gameView.frame = self.airplayWindow?.frame ?? .zero self.gameView.setNeedsLayout() self.airplayWindow?.layoutIfNeeded() + + self.delegate?.gameViewControllerDidEnterAirplay(self) } } From a88f36d18b174f319b3a5a2d73e4c760db5369b3 Mon Sep 17 00:00:00 2001 From: Ian Clawson Date: Fri, 29 Oct 2021 01:08:15 -0600 Subject: [PATCH 8/8] adds ability to return the calculated game frame previously exclusive to didLayoutSubviews so that the subclassed version in Delta can insert the AirPlay view appropriately --- DeltaCore/UI/Game/GameViewController.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/DeltaCore/UI/Game/GameViewController.swift b/DeltaCore/UI/Game/GameViewController.swift index 75f546b..f02d680 100644 --- a/DeltaCore/UI/Game/GameViewController.swift +++ b/DeltaCore/UI/Game/GameViewController.swift @@ -245,6 +245,11 @@ open class GameViewController: UIViewController, GameControllerReceiver { super.viewDidLayoutSubviews() + self.calculateGameFrame() + } + + @discardableResult public func calculateGameFrame(returnFrame: Bool = false) -> CGRect? + { let screenAspectRatio = self.emulatorCore?.preferredRenderingSize ?? CGSize(width: 1, height: 1) let controllerViewFrame: CGRect @@ -307,7 +312,11 @@ open class GameViewController: UIViewController, GameControllerReceiver self.controllerView.frame = controllerViewFrame /* Game View */ - if + if returnFrame + { + return AVMakeRect(aspectRatio: screenAspectRatio, insideRect: availableGameFrame) + } + else if self.airplayWindow == nil, let controllerSkin = self.controllerView.controllerSkin, let traits = self.controllerView.controllerSkinTraits, @@ -347,6 +356,8 @@ open class GameViewController: UIViewController, GameControllerReceiver } self.setNeedsUpdateOfHomeIndicatorAutoHidden() + + return nil } // MARK: - KVO -