Revision control
Copy as Markdown
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qiosapplicationdelegate.h"
#include "qiosglobal.h"
#include "qiosintegration.h"
#include "qiosservices.h"
#include "qiosviewcontroller.h"
#include "qioswindow.h"
#include "qiosscreen.h"
#include "quiwindow.h"
#include <qpa/qplatformintegration.h>
#include <QtCore/QtCore>
#include <QtCore/private/qdarwinsecurityscopedfileengine_p.h>
@interface QIOSWindowSceneDelegate : NSObject<UIWindowSceneDelegate>
@property (nullable, nonatomic, strong) UIWindow *window;
@end
@implementation QIOSApplicationDelegate
- (UISceneConfiguration *)application:(UIApplication *)application
configurationForConnectingSceneSession:(UISceneSession *)session
options:(UISceneConnectionOptions *)options
{
qCDebug(lcQpaWindowScene) << "Configuring scene for" << session << "with options" << options;
auto *sceneConfig = session.configuration;
if ([sceneConfig.role hasPrefix:@"CPTemplateApplication"]) {
qCDebug(lcQpaWindowScene) << "Not touching CarPlay scene with role" << sceneConfig.role
<< "and existing delegate class" << sceneConfig.delegateClass;
// FIXME: Consider ignoring any scene with an existing sceneClass, delegateClass, or
// storyboard. But for visionOS the default delegate is SwiftUI.AppSceneDelegate.
} else {
sceneConfig.delegateClass = QIOSWindowSceneDelegate.class;
}
return sceneConfig;
}
@end
@implementation QIOSWindowSceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
{
qCDebug(lcQpaWindowScene) << "Connecting" << scene << "to" << session;
// Handle connection options, even if we return early
const auto handleConnectionOptions = qScopeGuard([&]{
if (connectionOptions.URLContexts.count > 0)
[self scene:scene openURLContexts:connectionOptions.URLContexts];
// Handle universal link (https) application cold-launch case
for (NSUserActivity *activity in connectionOptions.userActivities)
[self scene:scene continueUserActivity:activity];
});
#if defined(Q_OS_VISIONOS)
// CPImmersiveScene is a UIWindowScene, most likely so it can handle its internal
// CPSceneLayerEventWindow and UITextEffectsWindow, but we don't want a QUIWindow
// for these scenes, so bail out early.
if ([scene.session.role isEqualToString:@"CPSceneSessionRoleImmersiveSpaceApplication"]) {
qCDebug(lcQpaWindowScene) << "Skipping UIWindow creation for immersive scene";
return;
}
#endif
if (![scene isKindOfClass:UIWindowScene.class]) {
qCWarning(lcQpaWindowScene) << "Unexpectedly encountered non-window scene";
return;
}
UIWindowScene *windowScene = static_cast<UIWindowScene*>(scene);
QUIWindow *window = [[QUIWindow alloc] initWithWindowScene:windowScene];
window.rootViewController = [[[QIOSViewController alloc] initWithWindow:window] autorelease];
self.window = [window autorelease];
}
- (void)windowScene:(UIWindowScene *)windowScene
didUpdateCoordinateSpace:(id<UICoordinateSpace>)previousCoordinateSpace
interfaceOrientation:(UIInterfaceOrientation)previousInterfaceOrientation
traitCollection:(UITraitCollection *)previousTraitCollection
{
qCDebug(lcQpaWindowScene) << "Scene" << windowScene << "did update properties";
if (!self.window)
return;
Q_ASSERT([self.window isKindOfClass:QUIWindow.class]);
auto *viewController = static_cast<QIOSViewController*>(self.window.rootViewController);
[viewController updatePlatformScreen];
}
- (void)sceneDidDisconnect:(UIScene *)scene
{
qCDebug(lcQpaWindowScene) << "Disconnecting" << scene;
self.window = nil;
}
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
{
qCDebug(lcQpaWindowScene) << "Handling openURLContexts for scene" << scene;
QIOSIntegration *iosIntegration = QIOSIntegration::instance();
Q_ASSERT(iosIntegration);
QIOSServices *iosServices = static_cast<QIOSServices *>(iosIntegration->services());
for (UIOpenURLContext *urlContext in URLContexts) {
QUrl url = qt_apple_urlFromPossiblySecurityScopedURL(urlContext.URL);
if (url.isLocalFile())
QWindowSystemInterface::handleFileOpenEvent(url);
else
iosServices->handleUrl(url);
}
}
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity
{
qCDebug(lcQpaWindowScene) << "Handling user activity for scene" << scene;
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
QIOSIntegration *iosIntegration = QIOSIntegration::instance();
Q_ASSERT(iosIntegration);
QIOSServices *iosServices = static_cast<QIOSServices *>(iosIntegration->services());
iosServices->handleUrl(QUrl::fromNSURL(userActivity.webpageURL));
}
}
@end