1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qquickwindowmodule_p.h" |
5 | #include "qquickwindowattached_p.h" |
6 | #include "qquickrendercontrol.h" |
7 | #include "qquickscreen_p.h" |
8 | #include "qquickview_p.h" |
9 | #include "qquickwindowmodule_p_p.h" |
10 | #include "qquickitem_p.h" |
11 | #include <QtQuick/QQuickWindow> |
12 | #include <QtCore/QCoreApplication> |
13 | #include <QtQml/QQmlEngine> |
14 | |
15 | #include <private/qguiapplication_p.h> |
16 | #include <private/qqmlengine_p.h> |
17 | #include <private/qv4qobjectwrapper_p.h> |
18 | #include <private/qqmlglobal_p.h> |
19 | #include <qpa/qplatformintegration.h> |
20 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | Q_DECLARE_LOGGING_CATEGORY(lcTransient) |
24 | |
25 | QQuickWindowQmlImplPrivate::QQuickWindowQmlImplPrivate() = default; |
26 | |
27 | QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent) |
28 | : QQuickWindowQmlImpl(*(new QQuickWindowQmlImplPrivate), parent) |
29 | { |
30 | } |
31 | |
32 | void QQuickWindowQmlImpl::setVisible(bool visible) |
33 | { |
34 | Q_D(QQuickWindowQmlImpl); |
35 | d->visible = visible; |
36 | d->visibleExplicitlySet = true; |
37 | if (d->componentComplete && (!transientParent() || transientParentVisible())) |
38 | QQuickWindow::setVisible(visible); |
39 | } |
40 | |
41 | void QQuickWindowQmlImpl::setVisibility(Visibility visibility) |
42 | { |
43 | Q_D(QQuickWindowQmlImpl); |
44 | d->visibility = visibility; |
45 | if (d->componentComplete) |
46 | QQuickWindow::setVisibility(visibility); |
47 | } |
48 | |
49 | QQuickWindowAttached *QQuickWindowQmlImpl::qmlAttachedProperties(QObject *object) |
50 | { |
51 | return new QQuickWindowAttached(object); |
52 | } |
53 | |
54 | void QQuickWindowQmlImpl::classBegin() |
55 | { |
56 | Q_D(QQuickWindowQmlImpl); |
57 | d->componentComplete = false; |
58 | QQmlEngine* e = qmlEngine(this); |
59 | |
60 | QQmlEngine::setContextForObject(contentItem(), e->rootContext()); |
61 | |
62 | //Give QQuickView behavior when created from QML with QQmlApplicationEngine |
63 | if (QCoreApplication::instance()->property(name: "__qml_using_qqmlapplicationengine" ) == QVariant(true)) { |
64 | if (e && !e->incubationController()) |
65 | e->setIncubationController(incubationController()); |
66 | } |
67 | { |
68 | // The content item has CppOwnership policy (set in QQuickWindow). Ensure the presence of a JS |
69 | // wrapper so that the garbage collector can see the policy. |
70 | QV4::ExecutionEngine *v4 = e->handle(); |
71 | QV4::QObjectWrapper::wrap(engine: v4, object: d->contentItem); |
72 | } |
73 | } |
74 | |
75 | void QQuickWindowQmlImpl::componentComplete() |
76 | { |
77 | Q_D(QQuickWindowQmlImpl); |
78 | d->componentComplete = true; |
79 | |
80 | QQuickItem *itemParent = qmlobject_cast<QQuickItem *>(object: QObject::parent()); |
81 | const bool transientParentAlreadySet = QQuickWindowPrivate::get(c: this)->transientParentPropertySet; |
82 | if (!transientParentAlreadySet && itemParent && !itemParent->window()) { |
83 | qCDebug(lcTransient) << "window" << title() << "has invisible Item parent" << itemParent << "transientParent" |
84 | << transientParent() << "declared visibility" << d->visibility << "; delaying show" ; |
85 | connect(sender: itemParent, signal: &QQuickItem::windowChanged, context: this, |
86 | slot: &QQuickWindowQmlImpl::setWindowVisibility, type: Qt::QueuedConnection); |
87 | } else if (transientParent() && !transientParent()->isVisible()) { |
88 | connect(sender: transientParent(), signal: &QQuickWindow::visibleChanged, context: this, |
89 | slot: &QQuickWindowQmlImpl::setWindowVisibility, type: Qt::QueuedConnection); |
90 | } else { |
91 | setWindowVisibility(); |
92 | } |
93 | } |
94 | |
95 | QQuickWindowQmlImpl::QQuickWindowQmlImpl(QQuickWindowQmlImplPrivate &dd, QWindow *parent) |
96 | : QQuickWindow(dd, parent) |
97 | { |
98 | // These two signals are called during QWindow's dtor, thus they have to be queued connections |
99 | // or else our slots will be called instantly when our destructor has already run but our |
100 | // connections haven't been removed yet. |
101 | connect(sender: this, signal: &QWindow::visibleChanged, context: this, slot: &QQuickWindowQmlImpl::visibleChanged, |
102 | type: Qt::QueuedConnection); |
103 | connect(sender: this, signal: &QWindow::visibilityChanged, context: this, slot: &QQuickWindowQmlImpl::visibilityChanged, |
104 | type: Qt::QueuedConnection); |
105 | |
106 | connect(sender: this, signal: &QWindow::screenChanged, context: this, slot: &QQuickWindowQmlImpl::screenChanged); |
107 | } |
108 | |
109 | void QQuickWindowQmlImpl::setWindowVisibility() |
110 | { |
111 | Q_D(QQuickWindowQmlImpl); |
112 | if (transientParent() && !transientParentVisible()) |
113 | return; |
114 | |
115 | if (QQuickItem *senderItem = qmlobject_cast<QQuickItem *>(object: sender())) { |
116 | disconnect(sender: senderItem, signal: &QQuickItem::windowChanged, receiver: this, slot: &QQuickWindowQmlImpl::setWindowVisibility); |
117 | } else if (sender()) { |
118 | disconnect(sender: transientParent(), signal: &QWindow::visibleChanged, receiver: this, slot: &QQuickWindowQmlImpl::setWindowVisibility); |
119 | } |
120 | |
121 | // We have deferred window creation until we have the full picture of what |
122 | // the user wanted in terms of window state, geometry, visibility, etc. |
123 | |
124 | if (d->visibleExplicitlySet && ((d->visibility == Hidden && d->visible) || |
125 | (d->visibility > AutomaticVisibility && !d->visible))) { |
126 | QQmlData *data = QQmlData::get(object: this); |
127 | Q_ASSERT(data && data->context); |
128 | |
129 | QQmlError error; |
130 | error.setObject(this); |
131 | |
132 | QQmlRefPointer<QQmlContextData> urlContext = data->context; |
133 | while (urlContext && urlContext->url().isEmpty()) |
134 | urlContext = urlContext->parent(); |
135 | error.setUrl(urlContext ? urlContext->url() : QUrl()); |
136 | |
137 | QString objectId = data->context->findObjectId(obj: this); |
138 | if (!objectId.isEmpty()) |
139 | error.setDescription(QCoreApplication::translate(context: "QQuickWindowQmlImpl" , |
140 | key: "Conflicting properties 'visible' and 'visibility' for Window '%1'" ).arg(a: objectId)); |
141 | else |
142 | error.setDescription(QCoreApplication::translate(context: "QQuickWindowQmlImpl" , |
143 | key: "Conflicting properties 'visible' and 'visibility'" )); |
144 | |
145 | QQmlEnginePrivate::get(e: data->context->engine())->warning(error); |
146 | } |
147 | |
148 | if (d->visibility == AutomaticVisibility) { |
149 | setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags())); |
150 | setVisible(d->visible); |
151 | } else { |
152 | setVisibility(d->visibility); |
153 | } |
154 | } |
155 | |
156 | QObject *QQuickWindowQmlImpl::screen() const |
157 | { |
158 | return new QQuickScreenInfo(const_cast<QQuickWindowQmlImpl *>(this), QWindow::screen()); |
159 | } |
160 | |
161 | void QQuickWindowQmlImpl::setScreen(QObject *screen) |
162 | { |
163 | QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(object: screen); |
164 | QWindow::setScreen(screenWrapper ? screenWrapper->wrappedScreen() : nullptr); |
165 | } |
166 | |
167 | bool QQuickWindowQmlImpl::transientParentVisible() |
168 | { |
169 | Q_ASSERT(transientParent()); |
170 | if (!transientParent()->isVisible()) { |
171 | // handle case where transient parent is offscreen window |
172 | QWindow *rw = QQuickRenderControl::renderWindowFor(win: qobject_cast<QQuickWindow*>(object: transientParent())); |
173 | return rw && rw->isVisible(); |
174 | } |
175 | return true; |
176 | } |
177 | |
178 | QT_END_NAMESPACE |
179 | |
180 | #include "moc_qquickwindowmodule_p.cpp" |
181 | |