Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickwindowmodule.cpp
Go to the documentation of this file.
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
7#include "qquickscreen_p.h"
8#include "qquickview_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
22
23using namespace Qt::StringLiterals;
24
26
28
33
35 : QQuickWindow(dd, parent)
36{
38 connect(this, &QWindow::visibilityChanged, this, [&]{
40 // Update the window's actual visibility and turn off visibilityExplicitlySet,
41 // so that future applyWindowVisibility() calls do not apply both window state
42 // and visible state, unless setVisibility() is called again by the user.
43 d->visibility = QWindow::visibility();
44 d->visibilityExplicitlySet = false;
46 });
48
49 // We shadow the x and y properties, so that we can re-map them in case
50 // we have an Item as our visual parent, which will result in creating an
51 // implicit window container that we control. Ensure that signals still work,
52 // and that they reflect the mapped values if a window container is used.
53 QObject::connect(this, &QWindow::xChanged, this, [this] { emit xChanged(x()); });
54 QObject::connect(this, &QWindow::yChanged, this, [this] { emit yChanged(y()); });
55}
56
58{
59 // Destroy the window while we are still alive, so that any signals
60 // emitted by the destruction can be delivered properly.
61 destroy();
62}
63
65{
67 qCDebug(lcQuickWindow) << "Class begin for" << this;
68 d->componentComplete = false;
69
70 QQmlEngine* e = qmlEngine(this);
71
73
74 //Give QQuickView behavior when created from QML with QQmlApplicationEngine
75 if (QCoreApplication::instance()->property("__qml_using_qqmlapplicationengine") == QVariant(true)) {
76 if (e && !e->incubationController())
77 e->setIncubationController(incubationController());
78 }
79 {
80 // The content item has CppOwnership policy (set in QQuickWindow). Ensure the presence of a JS
81 // wrapper so that the garbage collector can see the policy.
83 QV4::QObjectWrapper::ensureWrapper(v4, d->contentItem);
84 }
85}
86
88{
90 qCDebug(lcQuickWindow) << "Component completed for" << this;
91 d->componentComplete = true;
92
93 applyVisualParent();
94
95 // Apply automatic transient parent if needed, and opt in to future
96 // parent change events, so we can keep the transient parent in sync.
97 updateTransientParent();
98 d->receiveParentEvents = true;
99
100 applyWindowVisibility();
101
102 // If the transient parent changes, and we've deferred making
103 // the window visible, we need to re-evaluate our decision.
104 connect(this, &QWindow::transientParentChanged,
105 this, &QQuickWindowQmlImpl::applyWindowVisibility);
106}
107
109{
111 d->visible = visible;
112 d->visibleExplicitlySet = true;
113 if (d->componentComplete)
114 applyWindowVisibility();
115}
116
117void QQuickWindowQmlImpl::setVisibility(Visibility visibility)
118{
120 d->visibility = visibility;
121 d->visibilityExplicitlySet = true;
122 if (d->componentComplete)
123 applyWindowVisibility();
124}
125
127{
129
130 if (event->type() == QEvent::ParentWindowChange) {
131 qCDebug(lcQuickWindow) << "Parent of" << this << "changed to" << parent();
132 if (d->visualParent) {
133 // If the window parent changes, and we've deferred making
134 // the window visible, we need to re-evaluate our decision.
135 applyWindowVisibility();
136 } else {
137 QObject::disconnect(d->itemParentWindowChangeListener);
138 updateTransientParent();
139 }
140 }
142}
143
144/*
145 Update the transient parent of the window based on its
146 QObject parent (Item or Window), unless the user has
147 set an explicit transient parent.
148*/
149void QQuickWindowQmlImpl::updateTransientParent()
150{
152
153 // We defer updating the transient parent until the component
154 // has been fully completed, and we know whether an explicit
155 // transient parent has been set.
156 if (!d->componentComplete)
157 return;
158
159 // If an explicit transient parent has been set,
160 // we don't want to apply our magic.
161 if (d->transientParentPropertySet)
162 return;
163
164 // Nor if we have a visual parent that makes this a true child window
165 if (d->visualParent)
166 return;
167
168 auto *objectParent = QObject::parent();
169 qCDebug(lcTransient) << "Applying transient parent magic to"
170 << this << "based on object parent" << objectParent << "🪄";
171
172 QWindow *transientParent = nullptr;
173 if (auto *windowParent = qmlobject_cast<QWindow *>(objectParent)) {
174 transientParent = windowParent;
175 } else if (auto *itemParent = qmlobject_cast<QQuickItem *>(objectParent)) {
176 if (!d->itemParentWindowChangeListener) {
177 d->itemParentWindowChangeListener = connect(
178 itemParent, &QQuickItem::windowChanged,
179 this, &QQuickWindowQmlImpl::updateTransientParent);
180 }
181 transientParent = itemParent->window();
182 }
183
184 if (!transientParent) {
185 qCDebug(lcTransient) << "No transient parent resolved from object parent";
186 return;
187 }
188
189 qCDebug(lcTransient) << "Setting" << transientParent << "as transient parent of" << this;
190 setTransientParent(transientParent);
191
192 // We want to keep applying the automatic transient parent
193 d->transientParentPropertySet = false;
194}
195
196void QQuickWindowQmlImpl::applyWindowVisibility()
197{
199
200 Q_ASSERT(d->componentComplete);
201
202 const bool visible = d->visibilityExplicitlySet
203 ? d->visibility != Hidden : d->visible;
204
205 qCDebug(lcQuickWindow) << "Applying visible" << visible << "for" << this;
206
207 if (visible) {
208 if (d->visualParent) {
209 // Even though we're complete, and have a visual parent set,
210 // we may not be part of a window yet, or we may have been
211 // removed from a window that's going away. Showing this window
212 // now would make it a top level, which is not what we want.
213 if (!QWindow::parent()) {
214 qCDebug(lcQuickWindow) << "Waiting for visual parent to reparent us into a window";
215 // We apply the visibility again on ParentWindowChange
216 return;
217 }
218 } else {
219 // Handle deferred visibility due to possible transient parent
220 auto *itemParent = qmlobject_cast<QQuickItem *>(QObject::parent());
221 if (!d->transientParentPropertySet && itemParent && !itemParent->window()) {
222 qCDebug(lcTransient) << "Waiting for parent" << itemParent << "to resolve"
223 << "its window. Deferring visibility";
224 return;
225 }
226
227 const QWindow *transientParent = QWindow::transientParent();
228 if (transientParent && !transientParentVisible()) {
229 // Defer visibility of this window until the transient parent has
230 // been made visible, or we've get a new transient parent.
231 qCDebug(lcTransient) << "Transient parent" << transientParent
232 << "not visible yet. Deferring visibility";
233
234 // QWindowPrivate::setVisible emits visibleChanged _before_ actually
235 // propagating the visibility to the platform window, so we can't use
236 // a direct connection here, as that would result in showing this
237 // window before the transient parent.
238 connect(transientParent, &QQuickWindow::visibleChanged, this,
239 &QQuickWindowQmlImpl::applyWindowVisibility,
241 return;
242 }
243 }
244 }
245
246 if (d->visibleExplicitlySet && d->visibilityExplicitlySet &&
247 ((d->visibility == Hidden && d->visible) ||
248 (d->visibility > AutomaticVisibility && !d->visible))) {
249 // FIXME: Should we bail out in this case?
250 qmlWarning(this) << "Conflicting properties 'visible' and 'visibility'";
251 }
252
253 if (d->visibility == AutomaticVisibility) {
254 // We're either showing for the first time, with the default
255 // visibility of AutomaticVisibility, or the user has called
256 // setVisibility with AutomaticVisibility at some point, so
257 // apply both window state and visible.
258 if (QWindow::parent() || visualParent())
260 else
262 QQuickWindow::setVisible(d->visible);
263 } else if (d->visibilityExplicitlySet) {
264 // We're not AutomaticVisibility, but the user has requested
265 // an explicit visibility, so apply both window state and visible.
266 QQuickWindow::setVisibility(d->visibility);
267 } else {
268 // Our window state should be up to date, so only apply visible
269 QQuickWindow::setVisible(d->visible);
270 }
271}
272
273bool QQuickWindowQmlImpl::transientParentVisible()
274{
275 Q_ASSERT(transientParent());
276 if (!transientParent()->isVisible()) {
277 // handle case where transient parent is offscreen window
278 QWindow *rw = QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow*>(transientParent()));
279 return rw && rw->isVisible();
280 }
281 return true;
282}
283
284// -------------------------- Visual Parent ---------------------------
285
313{
315 if (visualParent == d->visualParent)
316 return;
317
318 qCDebug(lcQuickWindow) << "Setting visual parent of" << this << "to" << visualParent;
319
320 if (d->visualParent) {
321 // Disconnect from deferred window listener
322 d->visualParent->disconnect(this);
323 }
324
325 d->visualParent = visualParent;
326
327 if (d->componentComplete)
328 applyVisualParent();
329
330 emit visualParentChanged(d->visualParent);
331}
332
333void QQuickWindowQmlImpl::applyVisualParent()
334{
336 Q_ASSERT(d->componentComplete);
337
338 qCDebug(lcQuickWindow) << "Applying" << this << "visual parent" << d->visualParent;
339
340 if (!d->visualParent) {
341 if (d->windowContainer) {
342 d->windowContainer->setContainedWindow(nullptr);
343 delete std::exchange(d->windowContainer, nullptr);
344 }
346 return;
347 }
348
349 QQuickItem *parentItem = nullptr;
350 if ((parentItem = qobject_cast<QQuickItem*>(d->visualParent)))
351 ; // All good, can use directly
352 else if (auto *parentWindow = qobject_cast<QWindow*>(d->visualParent)) {
353 if (auto *parentQuickWindow = qobject_cast<QQuickWindow*>(parentWindow)) {
354 parentItem = parentQuickWindow->contentItem();
355 } else {
356 qmlWarning(this) << "Parenting into non-Quick window. "
357 << "Stacking, position, and destruction must be handled manually";
358 QQuickWindow::setParent(parentWindow); // Try our best
359 return;
360 }
361 }
362
363 if (!parentItem) {
364 qmlWarning(this) << "Unsupported visual parent type"
365 << d->visualParent->metaObject()->className();
366 return;
367 }
368
369 if (!parentItem->window()) {
370 qCDebug(lcQuickWindow) << "No window yet. Deferring.";
371 connect(parentItem, &QQuickItem::windowChanged, this, [this]{
372 qCDebug(lcQuickWindow) << "Got window. Applying deferred visual parent item.";
373 applyVisualParent();
375 return;
376 }
377
378 if (qobject_cast<QQuickWindowContainer*>(d->visualParent)) {
379 qCDebug(lcQuickWindow) << "Visual parent is window container, everything is in order";
380 return;
381 }
382
383 if (!d->windowContainer) {
384 d->windowContainer = new QQuickWindowContainer(parentItem,
386 d->windowContainer->setObjectName(objectName() + "Container"_L1);
387
388 auto *objectParent = this->QObject::parent();
389 if (objectParent == parentItem) {
390 // We want to reflect the QML document order of sibling windows in the
391 // resulting stacking order of the windows. We can do so by carefully
392 // using the the information we have about the child object order.
393
394 // We know that the window's object child index is correct in relation
395 // to the other child windows of the parent. Since the window container
396 // is going to represent the window from now on, make the window container
397 // take the window's place in the parent's child object list.
398 auto &objectChildren = QObjectPrivate::get(objectParent)->children;
399 auto windowIndex = objectChildren.indexOf(this);
400 auto containerIndex = objectChildren.indexOf(d->windowContainer);
401 objectChildren.move(containerIndex, windowIndex);
402 containerIndex = windowIndex;
403
404 // The parent's item children are unfortunately managed separately from
405 // the object children. But thanks to the logic above we can use the now
406 // correct object order of the window container in the object children list
407 // to also ensure a correct stacking order between the sibling child items.
408 for (int i = containerIndex + 1; i < objectChildren.size(); ++i) {
409 if (auto *childItem = qobject_cast<QQuickItem*>(objectChildren.at(i))) {
410 qCDebug(lcQuickWindow) << "Stacking" << d->windowContainer
411 << "below" << childItem;
412 d->windowContainer->stackBefore(childItem);
413 break;
414 }
415 }
416 } else {
417 // Having another visual parent than the direct object parent will
418 // mess up the stacking order. This is also the case for normal items.
419 qCDebug(lcQuickWindow) << "Visual parent is not object parent."
420 << "Can not reflect document order as stacking order.";
421 }
422
423 QQmlEngine::setContextForObject(d->windowContainer, qmlContext(this));
424
425 d->windowContainer->classBegin();
426 d->windowContainer->setContainedWindow(this);
427 // Once the window has a window container, all x/y/z changes of
428 // the window will go through the container, and ensure the
429 // correct mapping. But any changes that happened prior to
430 // this have not been mapped yet, so do that now.
431 d->windowContainer->setPosition(position());
432 d->windowContainer->setZ(d->z);
433 d->windowContainer->componentComplete();
434
435 QObject::connect(d->windowContainer, &QQuickItem::zChanged,
436 this, &QQuickWindowQmlImpl::zChanged);
437 } else {
438 d->windowContainer->setParentItem(parentItem);
439 }
440}
441
443{
444 Q_D(const QQuickWindowQmlImpl);
445 return d->visualParent;
446}
447
448// We shadow the x and y properties of the Window, so that in case
449// the window has an Item as its visual parent we can re-map the
450// coordinates via the corresponding window container. We need to
451// do this also for the signal emissions, as otherwise the Window's
452// change signals will reflect different values than what we report
453// via the accessors. It would be nicer if this logic was contained
454// in the window container, for example via meta object property
455// interception, but that does not allow intercepting signal emissions.
456
458{
460 if (Q_UNLIKELY(d->windowContainer && d->windowContainer->window()))
461 d->windowContainer->setX(x);
462 else
464}
465
467{
468 Q_D(const QQuickWindowQmlImpl);
469 if (Q_UNLIKELY(d->windowContainer && d->windowContainer->window()))
470 return d->windowContainer->x();
471 else
472 return QQuickWindow::x();
473}
474
476{
478 if (Q_UNLIKELY(d->windowContainer && d->windowContainer->window()))
479 d->windowContainer->setY(y);
480 else
482}
483
485{
486 Q_D(const QQuickWindowQmlImpl);
487 if (Q_UNLIKELY(d->windowContainer && d->windowContainer->window()))
488 return d->windowContainer->y();
489 else
490 return QQuickWindow::y();
491}
492
511{
513 if (Q_UNLIKELY(d->windowContainer && d->windowContainer->window()))
514 d->windowContainer->setZ(z);
515 else
516 d->z = z;
517}
518
520{
521 Q_D(const QQuickWindowQmlImpl);
522 if (Q_UNLIKELY(d->windowContainer && d->windowContainer->window()))
523 return d->windowContainer->z();
524 else
525 return d->z;
526}
527
528// --------------------------------------------------------------------
529
531{
532 return new QQuickScreenInfo(const_cast<QQuickWindowQmlImpl *>(this), QWindow::screen());
533}
534
536{
537 QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(screen);
538 QWindow::setScreen(screenWrapper ? screenWrapper->wrappedScreen() : nullptr);
539}
540
545
547
548#include "moc_qquickwindowmodule_p.cpp"
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
\inmodule QtCore
Definition qcoreevent.h:45
@ ParentWindowChange
Definition qcoreevent.h:292
static QPlatformIntegration * platformIntegration()
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:298
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QString objectName
the name of this object
Definition qobject.h:107
void setParent(QObject *parent)
Makes the object a child of parent.
Definition qobject.cpp:2195
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QQmlIncubationController * incubationController() const
Returns the currently set incubation controller, or 0 if no controller has been set.
static void setContextForObject(QObject *, QQmlContext *)
Sets the QQmlContext for the object to context.
void setIncubationController(QQmlIncubationController *)
Sets the engine's incubation controller.
QQmlContext * rootContext() const
Returns the engine's root context.
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void zChanged()
QQuickWindow * window() const
Returns the window in which this item is rendered.
static QWindow * renderWindowFor(QQuickWindow *win, QPoint *offset=nullptr)
Returns the real window that win is being rendered to, if any.
bool event(QEvent *) override
\reimp
void setVisible(bool visible)
QWindow::Visibility visibility
void visibleChanged(bool arg)
void setVisualParent(QObject *parent)
\qmlproperty var QtQuick::Window::parent
void classBegin() override
Invoked after class creation, but before any properties have been set.
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void setVisibility(QWindow::Visibility visibility)
void visibilityChanged(QWindow::Visibility visibility)
static QQuickWindowAttached * qmlAttachedProperties(QObject *object)
void yChanged(int arg)
void setScreen(QObject *screen)
void setZ(qreal arg)
\qmlproperty real QtQuick::Window::z \preliminary
QObject * visualParent() const
void xChanged(int arg)
QQuickWindowQmlImpl(QWindow *parent=nullptr)
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
QQuickItem * contentItem
\qmlattachedproperty Item Window::contentItem
bool event(QEvent *) override
\reimp
\inmodule QtCore
Definition qvariant.h:65
\inmodule QtGui
Definition qwindow.h:63
int x
the x position of the window's geometry
Definition qwindow.h:80
void xChanged(int arg)
Qt::WindowFlags flags
the window flags of the window
Definition qwindow.h:79
void setX(int arg)
Definition qwindow.cpp:1661
void visibleChanged(bool arg)
void yChanged(int arg)
int y
the y position of the window's geometry
Definition qwindow.h:81
void setY(int arg)
Definition qwindow.cpp:1674
Visibility visibility
the screen-occupation state of the window
Definition qwindow.h:93
void screenChanged(QScreen *screen)
This signal is emitted when a window's screen changes, either by being set explicitly with setScreen(...
void setVisible(bool visible)
Definition qwindow.cpp:689
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
Combined button and popup list for selecting options.
@ WindowNoState
Definition qnamespace.h:252
ConnectionType
@ SingleShotConnection
@ QueuedConnection
#define Q_UNLIKELY(x)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLint y
struct _cl_event * event
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
QQuickItem * qmlobject_cast< QQuickItem * >(QObject *object)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScreen * screen
[1]
Definition main.cpp:29
#define emit
double qreal
Definition qtypes.h:187
const char property[13]
Definition qwizard.cpp:101
edit isVisible()
w setWindowState(w->windowState() ^ Qt::WindowFullScreen)
[0]
static void ensureWrapper(ExecutionEngine *engine, QObject *object)