refactor: adopt UIScene lifecycle
feat: add initial support for pip feat: add setting toggle for pip fix: let os handle invokation of pip which is more reliable fix: UIScene compatibility with airplay fix: black screen on external display when on app view and streaming fix: incorrect window size when launched directly on external display fix: wrong resolution shown in settings when in stream session Enable gamemode flag for iOS18+ Explicitly enters pip mode when in background
This commit is contained in:
1 parent
51e915b598
commit
b5ce7a8ff7
24 files changed
+480
-144
No files matched your search
@@ -570,7 +570,7 @@ ICAgICAgICAgICAgIA
|
||||
<color key="selectedSegmentTintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Local Mouse Pointer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VGn-Oc-mKc">
|
||||
<rect key="frame" x="22" y="2007" width="165" height="21"/>
|
||||
<rect key="frame" x="20" y="2008" width="165" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -635,6 +635,23 @@ ICAgICAgICAgICAgIA
|
||||
<action selector="backToStreamingButtonTapped:" destination="rYd-e6-cQU" eventType="touchUpInside" id="9P0-Yw-T4W"/>
|
||||
</connections>
|
||||
</button>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="dcP-yB-6Un" userLabel="PiP Selector">
|
||||
<rect key="frame" x="18" y="2102" width="459" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="No"/>
|
||||
<segment title="Yes"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Enable PiP" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ELc-8r-KSB">
|
||||
<rect key="frame" x="20" y="2075" width="86" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.12156862745098039" green="0.12941176470588237" blue="0.14117647058823529" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
@@ -664,6 +681,7 @@ ICAgICAgICAgICAgIA
|
||||
<outlet property="optimizeSettingsSelector" destination="Gob-Lu-b1y" id="9Wl-yp-0Ou"/>
|
||||
<outlet property="oscTapExlusionAreaSizeLabel" destination="Dfl-gL-00M" id="Jbg-64-P3M"/>
|
||||
<outlet property="oscTapExlusionAreaSizeSlider" destination="TSt-Hj-uTR" id="h9l-ap-AVd"/>
|
||||
<outlet property="pipSelector" destination="dcP-yB-6Un" id="rrB-dR-2Bq"/>
|
||||
<outlet property="pointerVelocityModeDividerSlider" destination="xet-C9-l5y" id="GnQ-xU-e0N"/>
|
||||
<outlet property="pointerVelocityModeDividerUILabel" destination="VlN-ZW-1gm" id="vbe-QK-hZb"/>
|
||||
<outlet property="resolutionDisplayView" destination="Dej-Bj-F6i" id="bi4-N6-snx"/>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow * window;
|
||||
|
||||
+ (void)setExternalDisplayRenderView:(UIView *)renderView;
|
||||
+ (void)clearExternalDisplayRenderView;
|
||||
- (void)updatePreferredDisplayMode:(BOOL)streamActive withRenderView:(UIView *)renderView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#import "SceneDelegate.h"
|
||||
#import "StreamFrameViewController.h"
|
||||
|
||||
@implementation SceneDelegate
|
||||
|
||||
static UIView *_sharedStreamVideoRenderView = nil;
|
||||
static UIWindow *_externalSceneWindow = nil;
|
||||
|
||||
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
|
||||
if (![scene isKindOfClass:[UIWindowScene class]]) {
|
||||
return;
|
||||
}
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
if ([session.role isEqualToString:UIWindowSceneSessionRoleApplication]) {
|
||||
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
NSString *storyboardName;
|
||||
if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
|
||||
storyboardName = @"iPad";
|
||||
} else {
|
||||
storyboardName = @"iPhone";
|
||||
}
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
|
||||
UIViewController *initialViewController = [storyboard instantiateInitialViewController];
|
||||
self.window.rootViewController = initialViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
Log(LOG_I, @"SceneDelegate: Main app scene connected.");
|
||||
|
||||
} else if ([session.role isEqualToString:UIWindowSceneSessionRoleExternalDisplay]) {
|
||||
Log(LOG_I, @"SceneDelegate: External display scene connecting for screen: %@", ((UIWindowScene *)scene).screen.description);
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
_externalSceneWindow = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
UIViewController *externalVC = [[UIViewController alloc] init];
|
||||
externalVC.view.backgroundColor = [UIColor blackColor]; // Set a default background
|
||||
_externalSceneWindow.rootViewController = externalVC;
|
||||
|
||||
if (_sharedStreamVideoRenderView) {
|
||||
_sharedStreamVideoRenderView.frame = _externalSceneWindow.bounds;
|
||||
[_externalSceneWindow.rootViewController.view addSubview:_sharedStreamVideoRenderView];
|
||||
Log(LOG_I, @"SceneDelegate: External display scene connected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Method for StreamFrameViewController to provide its render view
|
||||
+ (void)setExternalDisplayRenderView:(UIView *)renderView {
|
||||
_sharedStreamVideoRenderView = renderView;
|
||||
if (_externalSceneWindow && _externalSceneWindow.rootViewController && _sharedStreamVideoRenderView) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Ensure it's removed from any previous parent (should have been done by StreamFrameVC)
|
||||
[_sharedStreamVideoRenderView removeFromSuperview];
|
||||
_sharedStreamVideoRenderView.frame = _externalSceneWindow.bounds; // Set frame for external window
|
||||
[_externalSceneWindow.rootViewController.view addSubview:_sharedStreamVideoRenderView];
|
||||
_externalSceneWindow.hidden = NO;
|
||||
Log(LOG_I, @"SceneDelegate: Added render view to external window's root view.");
|
||||
});
|
||||
} else {
|
||||
Log(LOG_E, @"SceneDelegate: External display window or root view controller not available.");
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)clearExternalDisplayRenderView {
|
||||
if (_sharedStreamVideoRenderView) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_sharedStreamVideoRenderView removeFromSuperview];
|
||||
Log(LOG_I, @"SceneDelegate: Removed render view from external display.");
|
||||
});
|
||||
}
|
||||
_sharedStreamVideoRenderView = nil;
|
||||
}
|
||||
|
||||
- (void)sceneDidDisconnect:(UIScene *)scene {
|
||||
Log(LOG_I, @"SceneDelegate: Scene disconnected: %@, role: %@", scene.title, scene.session.role);
|
||||
|
||||
if ([scene.session.role isEqualToString:UIWindowSceneSessionRoleExternalDisplay]) {
|
||||
if ([scene isKindOfClass:[UIWindowScene class]]) {
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
if (_externalSceneWindow == windowScene.windows.firstObject) { // Compare with the window from the disconnecting scene
|
||||
[SceneDelegate clearExternalDisplayRenderView]; // Clears the shared view
|
||||
_externalSceneWindow = nil;
|
||||
Log(LOG_I, @"SceneDelegate: External display scene fully disconnected and cleaned up.");
|
||||
} else {
|
||||
Log(LOG_W, @"SceneDelegate: Disconnecting scene is not the one holding our _externalSceneWindow.");
|
||||
}
|
||||
} else {
|
||||
Log(LOG_W, @"SceneDelegate: Disconnecting scene is not a UIWindowScene.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -30,6 +30,7 @@
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *audioOnPCSelector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *codecSelector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *yuv444Selector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *pipSelector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *hdrSelector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *framePacingSelector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *btMouseSelector;
|
||||
|
||||
@@ -228,7 +228,7 @@ BOOL isCustomResolution(CGSize res) {
|
||||
}
|
||||
|
||||
- (void)updateResolutionTable{
|
||||
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
|
||||
UIWindow *window = self.view.window;
|
||||
CGFloat screenScale = window.screen.scale;
|
||||
CGFloat safeAreaWidth = (window.frame.size.width - window.safeAreaInsets.left - window.safeAreaInsets.right) * screenScale;
|
||||
CGFloat appWindowWidth = window.frame.size.width * screenScale;
|
||||
@@ -465,6 +465,7 @@ BOOL isCustomResolution(CGSize res) {
|
||||
}
|
||||
|
||||
[self.yuv444Selector setSelectedSegmentIndex:currentSettings.enableYUV444 ? 1 : 0];
|
||||
[self.pipSelector setSelectedSegmentIndex:currentSettings.enablePIP ? 1 : 0];
|
||||
[self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue];
|
||||
[self.btMouseSelector setSelectedSegmentIndex:currentSettings.btMouseSupport ? 1 : 0];
|
||||
[self.optimizeSettingsSelector setSelectedSegmentIndex:currentSettings.optimizeGames ? 1 : 0];
|
||||
@@ -1079,6 +1080,7 @@ BOOL isCustomResolution(CGSize res) {
|
||||
BOOL audioOnPC = [self.audioOnPCSelector selectedSegmentIndex] == 1;
|
||||
uint32_t preferredCodec = [self getChosenCodecPreference];
|
||||
BOOL enableYUV444 = [self.yuv444Selector selectedSegmentIndex] == 1;
|
||||
BOOL enablePIP = [self.pipSelector selectedSegmentIndex] == 1;
|
||||
BOOL btMouseSupport = [self.btMouseSelector selectedSegmentIndex] == 1;
|
||||
BOOL useFramePacing = [self.framePacingSelector selectedSegmentIndex] == 1;
|
||||
// BOOL absoluteTouchMode = [self.touchModeSelector selectedSegmentIndex] == 1;
|
||||
@@ -1116,6 +1118,7 @@ BOOL isCustomResolution(CGSize res) {
|
||||
audioOnPC:audioOnPC
|
||||
preferredCodec:preferredCodec
|
||||
enableYUV444:enableYUV444
|
||||
enablePIP:enablePIP
|
||||
useFramePacing:useFramePacing
|
||||
enableHdr:enableHdr
|
||||
btMouseSupport:btMouseSupport
|
||||
|
||||
Reference in new issue
Block a user