summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios/qiosapplicationdelegate.mm
blob: 990409f2d176896300fc449871920aed8b625042 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 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

#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>

@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 URL contexts, even if we return early
    const auto handleUrlContexts = qScopeGuard([&]{
        if (connectionOptions.URLContexts.count > 0)
            [self scene:scene openURLContexts:connectionOptions.URLContexts];
    });

#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)
        iosServices->handleUrl(QUrl::fromNSURL(urlContext.URL));
}

- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity
{
    qCDebug(lcQpaWindowScene) << "Handling continueUserActivity 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