diff options
-rw-r--r-- | src/quick/items/qquickitem.cpp | 17 | ||||
-rw-r--r-- | src/quick/items/qquickitemsmodule.cpp | 21 | ||||
-rw-r--r-- | src/quick/items/qquickloader.cpp | 15 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 16 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquickwindowmodule.cpp | 173 | ||||
-rw-r--r-- | src/quick/items/qquickwindowmodule_p.h | 6 | ||||
-rw-r--r-- | src/quick/items/qquickwindowmodule_p_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/data/createObject.qml | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/data/createQmlObject.qml | 21 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/data/windowattached.qml | 4 |
12 files changed, 159 insertions, 122 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index f45faa6966..8d0ddb438b 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3255,23 +3255,6 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o) } QQuickItemPrivate::get(that)->addPointerHandler(pointerHandler); } else { - if (QQuickWindow *quickWindow = qmlobject_cast<QQuickWindow *>(o)) { - QQuickItem *item = that; - QQuickWindow *itemWindow = that->window(); - while (!itemWindow && item && item->parentItem()) { - item = item->parentItem(); - itemWindow = item->window(); - } - - if (itemWindow) { - qCDebug(lcTransient) << "Setting" << itemWindow << "as transient parent of" << quickWindow; - quickWindow->setTransientParent(itemWindow); - } else { - QObject::connect(item, &QQuickItem::windowChanged, - quickWindow, &QQuickWindow::setTransientParent_helper); - } - } - o->setParent(that); resources_append(prop, o); } diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 8b4fba31d4..569a0ad74d 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -93,22 +93,11 @@ QT_END_NAMESPACE static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent) { - // When setting a parent (especially during dynamic object creation) in QML, - // also try to set up the analogous item/window relationship. if (QQuickItem *parentItem = qmlobject_cast<QQuickItem *>(parent)) { - QQuickItem *item = qmlobject_cast<QQuickItem *>(obj); - if (item) { + if (QQuickItem *item = qmlobject_cast<QQuickItem *>(obj)) { // An Item has another Item item->setParentItem(parentItem); return QQmlPrivate::Parented; - } else if (parentItem->window()) { - QQuickWindow *win = qmlobject_cast<QQuickWindow *>(obj); - if (win) { - // A Window inside an Item should be transient for that item's window - qCDebug(lcTransient) << "Setting" << parentItem->window() << "as transient parent of" << win; - win->setTransientParent(parentItem->window()); - return QQmlPrivate::Parented; - } } else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(obj)) { QQuickItemPrivate::get(parentItem)->addPointerHandler(handler); handler->setParent(parent); @@ -116,13 +105,7 @@ static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject } return QQmlPrivate::IncompatibleObject; } else if (QQuickWindow *parentWindow = qmlobject_cast<QQuickWindow *>(parent)) { - QQuickWindow *win = qmlobject_cast<QQuickWindow *>(obj); - if (win) { - // A Window inside a Window should be transient for it - qCDebug(lcTransient) << "Setting" << parentWindow << "as transient parent of" << win; - win->setTransientParent(parentWindow); - return QQmlPrivate::Parented; - } else if (QQuickItem *item = qmlobject_cast<QQuickItem *>(obj)) { + if (QQuickItem *item = qmlobject_cast<QQuickItem *>(obj)) { // The parent of an Item inside a Window is actually the implicit content Item item->setParentItem(parentWindow->contentItem()); return QQmlPrivate::Parented; diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 572f484ec5..ed3813c9f4 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -673,13 +673,6 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status) if (status == QQmlIncubator::Ready) { object = incubator->object(); item = qmlobject_cast<QQuickItem*>(object); - if (!item) { - QQuickWindow *window = qmlobject_cast<QQuickWindow*>(object); - if (window) { - qCDebug(lcTransient) << "Setting" << q->window() << "as transient parent of" << window; - window->setTransientParent(q->window()); - } - } emit q->itemChanged(); initResize(); incubator->clear(); @@ -805,14 +798,6 @@ void QQuickLoader::componentComplete() void QQuickLoader::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) { switch (change) { - case ItemSceneChange: { - QQuickWindow *loadedWindow = qmlobject_cast<QQuickWindow *>(item()); - if (loadedWindow) { - qCDebug(lcTransient) << "Setting" << value.window << "as transient parent of" << loadedWindow; - loadedWindow->setTransientParent(value.window); - } - break; - } case ItemChildAddedChange: Q_ASSERT(value.item); if (value.item->flags().testFlag(QQuickItem::ItemObservesViewport)) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 756abc3669..1d85fe8164 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -62,6 +62,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcMouse) Q_DECLARE_LOGGING_CATEGORY(lcTouch) Q_DECLARE_LOGGING_CATEGORY(lcPtr) Q_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty") +Q_LOGGING_CATEGORY(lcQuickWindow, "qt.quick.window") Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient") bool QQuickWindowPrivate::defaultAlphaBuffer = false; @@ -1764,10 +1765,6 @@ void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObje if (!o) return; QQuickWindow *that = static_cast<QQuickWindow *>(property->object); - if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o)) { - qCDebug(lcTransient) << "Setting" << that << "as transient parent of" << window; - window->setTransientParent(that); - } QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data(); itemProperty.append(&itemProperty, o); } @@ -2231,14 +2228,6 @@ void QQuickWindow::cleanupSceneGraph() d->runAndClearJobs(&d->afterSwapJobs); } -void QQuickWindow::setTransientParent_helper(QQuickWindow *window) -{ - qCDebug(lcTransient) << "Setting" << window << "as transient parent of" << this; - setTransientParent(window); - disconnect(sender(), SIGNAL(windowChanged(QQuickWindow*)), - this, SLOT(setTransientParent_helper(QQuickWindow*))); -} - QOpenGLContext *QQuickWindowPrivate::openglContext() { #if QT_CONFIG(opengl) @@ -3568,7 +3557,8 @@ void QQuickWindow::endExternalCommands() shown, that minimizing the parent window will also minimize the transient window, and so on; however results vary somewhat from platform to platform. - Declaring a Window inside an Item or inside another Window will automatically + Declaring a Window inside an Item or inside another Window, either via the + \l{Window::data}{default property} or a dedicated property, will automatically set up a transient parent relationship to the containing Item or Window, unless the \l transientParent property is explicitly set. This applies when creating Window items via \l Qt.createComponent or \l Qt.createQmlObject diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 556cb996d2..1a184e7c34 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -229,7 +229,6 @@ private Q_SLOTS: void cleanupSceneGraph(); void physicalDpiChanged(); void handleScreenChanged(QScreen *screen); - void setTransientParent_helper(QQuickWindow *window); void runJobsAfterSwap(); void handleApplicationStateChanged(Qt::ApplicationState state); void handleFontDatabaseChanged(); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 90b5da26aa..fae3e76659 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -56,6 +56,8 @@ class QRhiRenderBuffer; class QRhiRenderPassDescriptor; class QRhiTexture; +Q_DECLARE_LOGGING_CATEGORY(lcQuickWindow) + //Make it easy to identify and customize the root item if needed class Q_QUICK_PRIVATE_EXPORT QQuickRootItem : public QQuickItem { diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index 6a1600bb4c..df761d0d0e 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -34,8 +34,8 @@ void QQuickWindowQmlImpl::setVisible(bool visible) Q_D(QQuickWindowQmlImpl); d->visible = visible; d->visibleExplicitlySet = true; - if (d->componentComplete && (!transientParent() || transientParentVisible())) - QQuickWindow::setVisible(visible); + if (d->componentComplete) + applyWindowVisibility(); } void QQuickWindowQmlImpl::setVisibility(Visibility visibility) @@ -43,7 +43,7 @@ void QQuickWindowQmlImpl::setVisibility(Visibility visibility) Q_D(QQuickWindowQmlImpl); d->visibility = visibility; if (d->componentComplete) - QQuickWindow::setVisibility(visibility); + applyWindowVisibility(); } QQuickWindowAttached *QQuickWindowQmlImpl::qmlAttachedProperties(QObject *object) @@ -54,6 +54,7 @@ QQuickWindowAttached *QQuickWindowQmlImpl::qmlAttachedProperties(QObject *object void QQuickWindowQmlImpl::classBegin() { Q_D(QQuickWindowQmlImpl); + qCDebug(lcQuickWindow) << "Class begin for" << this; d->componentComplete = false; QQmlEngine* e = qmlEngine(this); @@ -75,20 +76,20 @@ void QQuickWindowQmlImpl::classBegin() void QQuickWindowQmlImpl::componentComplete() { Q_D(QQuickWindowQmlImpl); + qCDebug(lcQuickWindow) << "Component completed for" << this; d->componentComplete = true; - QQuickItem *itemParent = qmlobject_cast<QQuickItem *>(QObject::parent()); - if (!d->transientParentPropertySet && itemParent && !itemParent->window()) { - qCDebug(lcTransient) << "window" << title() << "has invisible Item parent" << itemParent << "transientParent" - << transientParent() << "declared visibility" << d->visibility << "; delaying show"; - connect(itemParent, &QQuickItem::windowChanged, this, - &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection); - } else if (transientParent() && !transientParent()->isVisible()) { - connect(transientParent(), &QQuickWindow::visibleChanged, this, - &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection); - } else { - setWindowVisibility(); - } + // Apply automatic transient parent if needed, and opt in to future + // parent change events, so we can keep the transient parent in sync. + updateTransientParent(); + d->receiveParentEvents = true; + + applyWindowVisibility(); + + // If the transient parent changes, and we've deferred making + // the window visible, we need to re-evaluate our decision. + connect(this, &QWindow::transientParentChanged, + this, &QQuickWindowQmlImpl::applyWindowVisibility); } QQuickWindowQmlImpl::QQuickWindowQmlImpl(QQuickWindowQmlImplPrivate &dd, QWindow *parent) @@ -105,21 +106,129 @@ QQuickWindowQmlImpl::QQuickWindowQmlImpl(QQuickWindowQmlImplPrivate &dd, QWindow connect(this, &QWindow::screenChanged, this, &QQuickWindowQmlImpl::screenChanged); } -void QQuickWindowQmlImpl::setWindowVisibility() +bool QQuickWindowQmlImpl::event(QEvent *event) +{ + Q_D(QQuickWindowQmlImpl); + + if (event->type() == QEvent::ParentChange) { + qCDebug(lcQuickWindow) << "Parent of" << this << "changed to" << QObject::parent(); + QObject::disconnect(d->itemParentWindowChangeListener); + updateTransientParent(); + } + return QQuickWindow::event(event); +} + +/* + Update the transient parent of the window based on its + QObject parent (Item or Window), unless the user has + set an explicit transient parent. +*/ +void QQuickWindowQmlImpl::updateTransientParent() { Q_D(QQuickWindowQmlImpl); - if (transientParent() && !transientParentVisible()) + + // We defer updating the transient parent until the component + // has been fully completed, and we know whether an explicit + // transient parent has been set. + if (!d->componentComplete) + return; + + // If an explicit transient parent has been set, + // we don't want to apply our magic. + if (d->transientParentPropertySet) + return; + + auto *objectParent = QObject::parent(); + qCDebug(lcTransient) << "Applying transient parent magic to" + << this << "based on object parent" << objectParent << "🪄"; + + QWindow *transientParent = nullptr; + if (auto *windowParent = qmlobject_cast<QWindow *>(objectParent)) { + transientParent = windowParent; + } else if (auto *itemParent = qmlobject_cast<QQuickItem *>(objectParent)) { + if (!d->itemParentWindowChangeListener) { + d->itemParentWindowChangeListener = connect( + itemParent, &QQuickItem::windowChanged, + this, &QQuickWindowQmlImpl::updateTransientParent); + } + transientParent = itemParent->window(); + } + + if (!transientParent) { + qCDebug(lcTransient) << "No transient parent resolved from object parent"; return; + } + + qCDebug(lcTransient) << "Setting" << transientParent << "as transient parent of" << this; + setTransientParent(transientParent); + + // We want to keep applying the automatic transient parent + d->transientParentPropertySet = false; +} + +void QQuickWindowQmlImpl::applyWindowVisibility() +{ + Q_D(QQuickWindowQmlImpl); + qCDebug(lcQuickWindow) << "Applying" << this << "visibility"; + + const bool isAboutToShow = d->visibility == AutomaticVisibility + ? d->visible : d->visibility != Hidden; + + if (isAboutToShow) { + auto *itemParent = qmlobject_cast<QQuickItem *>(QObject::parent()); + if (!d->transientParentPropertySet && itemParent && !itemParent->window()) { + qCDebug(lcTransient) << "Waiting for parent Item to resolve" + "its transient parent. Deferring visibility"; + return; + } + + const QWindow *transientParent = QWindow::transientParent(); + if (transientParent && !transientParentVisible()) { + // Defer visibility of this window until the transient parent has + // been made visible, or we've get a new transient parent. + qCDebug(lcTransient) << "Transient parent" << transientParent + << "not visible yet. Deferring visibility"; + + // QWindowPrivate::setVisible emits visibleChanged _before_ actually + // propagating the visibility to the platform window, so we can't use + // a direct connection here, as that would result in showing this + // window before the transient parent. + connect(transientParent, &QQuickWindow::visibleChanged, this, + &QQuickWindowQmlImpl::applyWindowVisibility, + Qt::ConnectionType(Qt::QueuedConnection | Qt::SingleShotConnection)); + return; + } + } + + // FIXME: Should we bail out in this case? + checkForConflictingVisibilityProperties(); - if (QQuickItem *senderItem = qmlobject_cast<QQuickItem *>(sender())) { - disconnect(senderItem, &QQuickItem::windowChanged, this, &QQuickWindowQmlImpl::setWindowVisibility); - } else if (sender()) { - disconnect(transientParent(), &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::setWindowVisibility); + if (d->visibility == AutomaticVisibility) { + setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags())); + QQuickWindow::setVisible(d->visible); + } else { + QQuickWindow::setVisibility(d->visibility); } +} - // We have deferred window creation until we have the full picture of what - // the user wanted in terms of window state, geometry, visibility, etc. +bool QQuickWindowQmlImpl::transientParentVisible() +{ + Q_ASSERT(transientParent()); + if (!transientParent()->isVisible()) { + // handle case where transient parent is offscreen window + QWindow *rw = QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow*>(transientParent())); + return rw && rw->isVisible(); + } + return true; +} +/* + Let the user know if they've assigned conflicting values to + the visible and visibility properties. +*/ +void QQuickWindowQmlImpl::checkForConflictingVisibilityProperties() +{ + Q_D(QQuickWindowQmlImpl); if (d->visibleExplicitlySet && ((d->visibility == Hidden && d->visible) || (d->visibility > AutomaticVisibility && !d->visible))) { QQmlData *data = QQmlData::get(this); @@ -143,13 +252,6 @@ void QQuickWindowQmlImpl::setWindowVisibility() QQmlEnginePrivate::get(data->context->engine())->warning(error); } - - if (d->visibility == AutomaticVisibility) { - setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags())); - setVisible(d->visible); - } else { - setVisibility(d->visibility); - } } QObject *QQuickWindowQmlImpl::screen() const @@ -163,17 +265,6 @@ void QQuickWindowQmlImpl::setScreen(QObject *screen) QWindow::setScreen(screenWrapper ? screenWrapper->wrappedScreen() : nullptr); } -bool QQuickWindowQmlImpl::transientParentVisible() -{ - Q_ASSERT(transientParent()); - if (!transientParent()->isVisible()) { - // handle case where transient parent is offscreen window - QWindow *rw = QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow*>(transientParent())); - return rw && rw->isVisible(); - } - return true; -} - QT_END_NAMESPACE #include "moc_qquickwindowmodule_p.cpp" diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h index c64ed537f7..6303a195f5 100644 --- a/src/quick/items/qquickwindowmodule_p.h +++ b/src/quick/items/qquickwindowmodule_p.h @@ -65,12 +65,16 @@ protected: void classBegin() override; void componentComplete() override; + bool event(QEvent *) override; + QQuickWindowQmlImpl(QQuickWindowQmlImplPrivate &dd, QWindow *parent); private Q_SLOTS: - void setWindowVisibility(); + void applyWindowVisibility(); + void updateTransientParent(); private: + void checkForConflictingVisibilityProperties(); bool transientParentVisible(); private: diff --git a/src/quick/items/qquickwindowmodule_p_p.h b/src/quick/items/qquickwindowmodule_p_p.h index cda45b9157..22b7435e0c 100644 --- a/src/quick/items/qquickwindowmodule_p_p.h +++ b/src/quick/items/qquickwindowmodule_p_p.h @@ -28,6 +28,8 @@ public: bool visibleExplicitlySet = false; QQuickWindow::Visibility visibility = QQuickWindow::AutomaticVisibility; QV4::PersistentValue rootItemMarker; + + QMetaObject::Connection itemParentWindowChangeListener; }; QT_END_NAMESPACE diff --git a/tests/auto/qml/qqmlcomponent/data/createObject.qml b/tests/auto/qml/qqmlcomponent/data/createObject.qml index afd9e71229..c9ca605f8f 100644 --- a/tests/auto/qml/qqmlcomponent/data/createObject.qml +++ b/tests/auto/qml/qqmlcomponent/data/createObject.qml @@ -1,5 +1,4 @@ -import QtQuick 2.0 -import QtQuick.Window 2.0 +import QtQuick Item { property QtObject qtobjectParent: QtObject { } diff --git a/tests/auto/qml/qqmlcomponent/data/createQmlObject.qml b/tests/auto/qml/qqmlcomponent/data/createQmlObject.qml index 282ab509f0..480835a5b1 100644 --- a/tests/auto/qml/qqmlcomponent/data/createQmlObject.qml +++ b/tests/auto/qml/qqmlcomponent/data/createQmlObject.qml @@ -1,5 +1,4 @@ -import QtQuick 2.0 -import QtQuick.Window 2.0 +import QtQuick Item { property QtObject qtobjectParent: QtObject { } @@ -19,14 +18,14 @@ Item { property QtObject window_window : null Component.onCompleted: { - qtobject_qtobject = Qt.createQmlObject("import QtQuick 2.0; QtObject{}", qtobjectParent); - qtobject_item = Qt.createQmlObject("import QtQuick 2.0; Item{}", qtobjectParent); - qtobject_window = Qt.createQmlObject("import QtQuick.Window 2.0; Window{}", qtobjectParent); - item_qtobject = Qt.createQmlObject("import QtQuick 2.0; QtObject{}", itemParent); - item_item = Qt.createQmlObject("import QtQuick 2.0; Item{}", itemParent); - item_window = Qt.createQmlObject("import QtQuick.Window 2.0; Window{}", itemParent); - window_qtobject = Qt.createQmlObject("import QtQuick 2.0; QtObject{}", windowParent); - window_item = Qt.createQmlObject("import QtQuick 2.0; Item{}", windowParent); - window_window = Qt.createQmlObject("import QtQuick.Window 2.0; Window{}", windowParent); + qtobject_qtobject = Qt.createQmlObject("import QtQuick; QtObject{}", qtobjectParent); + qtobject_item = Qt.createQmlObject("import QtQuick; Item{}", qtobjectParent); + qtobject_window = Qt.createQmlObject("import QtQuick; Window{}", qtobjectParent); + item_qtobject = Qt.createQmlObject("import QtQuick; QtObject{}", itemParent); + item_item = Qt.createQmlObject("import QtQuick; Item{}", itemParent); + item_window = Qt.createQmlObject("import QtQuick; Window{}", itemParent); + window_qtobject = Qt.createQmlObject("import QtQuick; QtObject{}", windowParent); + window_item = Qt.createQmlObject("import QtQuick; Item{}", windowParent); + window_window = Qt.createQmlObject("import QtQuick; Window{}", windowParent); } } diff --git a/tests/auto/quick/qquickwindow/data/windowattached.qml b/tests/auto/quick/qquickwindow/data/windowattached.qml index 66083db428..2f0d08984f 100644 --- a/tests/auto/quick/qquickwindow/data/windowattached.qml +++ b/tests/auto/quick/qquickwindow/data/windowattached.qml @@ -1,5 +1,4 @@ -import QtQuick 2.4 -import QtQuick.Window 2.2 +import QtQuick Rectangle { id: root @@ -19,6 +18,7 @@ Rectangle { property Window extraWindow: Window { objectName: "extraWindow" title: "extra window" + transientParent: null Text { objectName: "extraWindowText" anchors.centerIn: parent |