From bbc5e0f2d25618b1e170b5f92fda3089e5f3965a Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 9 Oct 2019 10:30:24 +0200 Subject: [PATCH 01/13] Doc: Add a \note about the (broken) Binding value restoration policy Task-number: QTBUG-78566 Change-Id: Ic76b6212f4ccc3ce8b9199166223e92c203272a5 Reviewed-by: Venugopal Shivashankar --- src/qml/types/qqmlbind.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index 513f7f2997..4aed0f2fee 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -174,6 +174,10 @@ QQmlBind::~QQmlBind() When the binding becomes inactive again, any direct bindings that were previously set on the property will be restored. + + \note A previously set literal value is not restored when the Binding becomes inactive. Rather, + the last value set by the now inactive Binding is retained. This behavior will change in future + versions of Qt. */ bool QQmlBind::when() const { From 0ee5414e58c9c48401bb0361657dd9d252cb6ad9 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 14 Oct 2019 09:41:32 +0200 Subject: [PATCH 02/13] Bump version Change-Id: I7345dd5dc9684c19e075d4d81c6a4df7421cae27 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 16ea641bd2..451a93ee59 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.13.1 +MODULE_VERSION = 5.13.2 From 2affb0408e5a6647d6ec4692a2447276ac0c8fc8 Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Mon, 14 Oct 2019 10:28:56 +0300 Subject: [PATCH 03/13] Add changes file for Qt 5.13.2 Change-Id: Ibfc31704442f9a911f37cdda3baa48e2ccb34c42 Reviewed-by: Shawn Rutledge Reviewed-by: Ulf Hermann --- dist/changes-5.13.2 | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 dist/changes-5.13.2 diff --git a/dist/changes-5.13.2 b/dist/changes-5.13.2 new file mode 100644 index 0000000000..6936f38721 --- /dev/null +++ b/dist/changes-5.13.2 @@ -0,0 +1,63 @@ +Qt 5.13.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.13.0 through 5.13.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* QtQml * +**************************************************************************** + + - [QTBUG-77761] EcmaScript modules are loaded correctly now when using the + Qt Quick Compiler. + - [QTBUG-74087] Various JavaScript list-like constructs are parsed + iteratively rather than recursively now, avoiding stack overflows. + - [QTBUG-78554] Exceptions thrown from a promise's resolve or reject + handler are forwarded correctly now. + - [QTBUG-78996] MakeDay() and getDay() now behave more correctly. + +**************************************************************************** +* QtQuick * +**************************************************************************** + + - [QTBUG-79084] The QQuickWindow::afterAnimating signal is now emitted + properly when using QQuickRenderControl. + - [QTBUG-79011] Fix an odd 1px offset when rendering an Image with + fillMode: PreserveAspectFit. + - [QTBUG-78468] Fixed the hanging native pictures dialog on iOS. + + - Item Views: + + * [QTBUG-77074] Fixed a bug when TableView columnWidthProvider calculates + the widths of columns after a previously-hidden row is shown again. + * [QTBUG-77173] If you click or tap a PathView while it's moving, + it will come to rest with the nearest delegate aligned properly. + * [QTBUG-77418] ListView highlightRangeMode works correctly after + currentIndex is changed. + + - Text: + + * If the alpha of a text background is 0, the background rectangle node + is now omitted from the scene graph. + * [QTBUG-77389] Fixed TextEdit paragraph-selection triple click feature. + + - OpenVG rendering: + + * [QTBUG-77019] Fixed sprites leaking textures. + * [QTBUG-76526] Fixed per-frame delivery of touch events. + * [QTBUG-76806] The sceneGraphInitialized and sceneGraphInvalidated + signals are now emitted properly. + * [QTBUG-76589] Fixed rendering of non-affine transformed rectangles. From 4876b0b60a92cd028a821c7c1c095ed55fb15f68 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 10 Oct 2019 16:11:07 +0200 Subject: [PATCH 04/13] Handle null in QQuickPointerEvent and QQEventPoint debug operators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example qDebug() << event->asMouseEvent() could crash if the event is not a mouse event. Change-Id: I34ffadeb9fc23f42d1d6939190c43a6486eea533 Reviewed-by: Jan Arve Sæther --- src/quick/items/qquickevents.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 8303c3fed1..7d128b4a16 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -1937,6 +1937,10 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *e { QDebugStateSaver saver(dbg); dbg.nospace(); + if (!event) { + dbg << "QQuickPointerEvent(0)"; + return dbg; + } dbg << "QQuickPointerEvent("; dbg << event->timestamp(); dbg << " dev:"; @@ -1957,6 +1961,10 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *eve { QDebugStateSaver saver(dbg); dbg.nospace(); + if (!event) { + dbg << "QQuickEventPoint(0)"; + return dbg; + } dbg << "QQuickEventPoint(accepted:" << event->isAccepted() << " state:"; QtDebugUtils::formatQEnum(dbg, event->state()); From 4080025fed9d43a78b578bcab67397712459d28c Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 9 Oct 2019 11:09:51 +0200 Subject: [PATCH 05/13] Set the screen on the QOpenGLContext to be the same as the window This ensures that the QOpenGLContext has the right screen information and can create a compatible context for use with QQuickWidget. Change-Id: I9d78ff2b616e5c1d1c11d1da438ce336a0f24953 Reviewed-by: Laszlo Agocs --- src/quickwidgets/qquickwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index b63f7de9f1..55c095af8e 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -878,7 +878,9 @@ void QQuickWidgetPrivate::createContext() context = new QOpenGLContext; context->setFormat(offscreenWindow->requestedFormat()); - + const QWindow *win = q->window()->windowHandle(); + if (win && win->screen()) + context->setScreen(win->screen()); QOpenGLContext *shareContext = qt_gl_global_share_context(); if (!shareContext) shareContext = QWidgetPrivate::get(q->window())->shareContext(); From 8bc05e07c8bafb8d9eb64839234305fc7fffdd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Fri, 11 Oct 2019 15:17:00 +0200 Subject: [PATCH 06/13] Rename some variables and a function to improve clarity * Rename firstVisibleItem() to firstItemInView() to reflect its behavior, as the comment requested ;) * Likewise, rename some related variables Change-Id: I98e25d5d47a4acb56a2b4f2bd75bec062ff770ee Reviewed-by: Richard Moe Gustavsen --- src/quick/items/qquickitemview.cpp | 34 +++++++++++++--------------- src/quick/items/qquickitemview_p_p.h | 2 +- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index b37fb69fae..120eeb13d5 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1575,9 +1575,7 @@ FxViewItem *QQuickItemViewPrivate::visibleItem(int modelIndex) const { return nullptr; } -// should rename to firstItemInView() to avoid confusion with other "*visible*" methods -// that don't look at the view position and size -FxViewItem *QQuickItemViewPrivate::firstVisibleItem() const { +FxViewItem *QQuickItemViewPrivate::firstItemInView() const { const qreal pos = isContentFlowReversed() ? -position()-size() : position(); for (FxViewItem *item : visibleItems) { if (item->index != -1 && item->endPosition() > pos) @@ -1949,22 +1947,22 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult bool viewportChanged = !currentChanges.pendingChanges.removes().isEmpty() || !currentChanges.pendingChanges.inserts().isEmpty(); - FxViewItem *prevFirstVisible = firstVisibleItem(); - QQmlNullableValue prevViewPos; - int prevFirstVisibleIndex = -1; - if (prevFirstVisible) { - prevViewPos = prevFirstVisible->position(); - prevFirstVisibleIndex = prevFirstVisible->index; + FxViewItem *prevFirstItemInView = firstItemInView(); + QQmlNullableValue prevFirstItemInViewPos; + int prevFirstItemInViewIndex = -1; + if (prevFirstItemInView) { + prevFirstItemInViewPos = prevFirstItemInView->position(); + prevFirstItemInViewIndex = prevFirstItemInView->index; } qreal prevVisibleItemsFirstPos = visibleItems.count() ? visibleItems.constFirst()->position() : 0.0; - totalInsertionResult->visiblePos = prevViewPos; - totalRemovalResult->visiblePos = prevViewPos; + totalInsertionResult->visiblePos = prevFirstItemInViewPos; + totalRemovalResult->visiblePos = prevFirstItemInViewPos; const QVector &removals = currentChanges.pendingChanges.removes(); const QVector &insertions = currentChanges.pendingChanges.inserts(); - ChangeResult insertionResult(prevViewPos); - ChangeResult removalResult(prevViewPos); + ChangeResult insertionResult(prevFirstItemInViewPos); + ChangeResult removalResult(prevFirstItemInViewPos); int removedCount = 0; for (const QQmlChangeSet::Change &r : removals) { @@ -1973,7 +1971,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult visibleAffected = true; if (!visibleAffected && needsRefillForAddedOrRemovedIndex(r.index)) visibleAffected = true; - const int correctedFirstVisibleIndex = prevFirstVisibleIndex - removalResult.countChangeBeforeVisible; + const int correctedFirstVisibleIndex = prevFirstItemInViewIndex - removalResult.countChangeBeforeVisible; if (correctedFirstVisibleIndex >= 0 && r.index < correctedFirstVisibleIndex) { if (r.index + r.count < correctedFirstVisibleIndex) removalResult.countChangeBeforeVisible += r.count; @@ -2000,7 +1998,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult // set positions correctly for the next insertion if (!insertions.isEmpty()) { - repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult); + repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstItemInView, &insertionResult, &removalResult); layoutVisibleItems(removals.first().index); } } @@ -2020,7 +2018,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult // set positions correctly for the next insertion if (i < insertions.count() - 1) { - repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult); + repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstItemInView, &insertionResult, &removalResult); layoutVisibleItems(insertions[i].index); } itemCount += insertions[i].count; @@ -2037,7 +2035,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult for (const MovedItem &m : qAsConst(movingIntoView)) { int fromIndex = findMoveKeyIndex(m.moveKey, removals); if (fromIndex >= 0) { - if (prevFirstVisibleIndex >= 0 && fromIndex < prevFirstVisibleIndex) + if (prevFirstItemInViewIndex >= 0 && fromIndex < prevFirstItemInViewIndex) repositionItemAt(m.item, fromIndex, -totalInsertionResult->sizeChangesAfterVisiblePos); else repositionItemAt(m.item, fromIndex, totalInsertionResult->sizeChangesAfterVisiblePos); @@ -2048,7 +2046,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult // reposition visibleItems.first() correctly so that the content y doesn't jump if (removedCount != prevVisibleItemsCount) - repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult); + repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstItemInView, &insertionResult, &removalResult); // Whatever removed/moved items remain are no longer visible items. prepareRemoveTransitions(¤tChanges.removedItems); diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 89c0de704b..1f42c847b3 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -158,7 +158,7 @@ public: qreal contentStartOffset() const; int findLastVisibleIndex(int defaultValue = -1) const; FxViewItem *visibleItem(int modelIndex) const; - FxViewItem *firstVisibleItem() const; + FxViewItem *firstItemInView() const; int findLastIndexInView() const; int mapFromModel(int modelIndex) const; From b6d88c73c4affec93655f97588abc7ae1d53cea0 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Wed, 23 Oct 2019 10:25:23 +0200 Subject: [PATCH 07/13] Loader: Actually clear initial properties when changing source Fixes: QTBUG-79435 Change-Id: Ic99a3b1a9d64426a64117b90a3e11fe99af0d260 Reviewed-by: Simon Hausmann --- src/quick/items/qquickloader.cpp | 3 ++- .../qquickloader/data/CacheClearTest.qml | 4 ++++ .../data/initialPropertyValues.11.qml | 20 +++++++++++++++++++ .../quick/qquickloader/tst_qquickloader.cpp | 5 +++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquickloader/data/CacheClearTest.qml create mode 100644 tests/auto/quick/qquickloader/data/initialPropertyValues.11.qml diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index d0e29c204e..b389e7a11b 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -590,8 +590,8 @@ void QQuickLoader::setSource(QQmlV4Function *args) d->clear(); QUrl sourceUrl = d->resolveSourceUrl(args); + d->disposeInitialPropertyValues(); if (!ipv->isUndefined()) { - d->disposeInitialPropertyValues(); d->initialPropertyValues.set(args->v4engine(), ipv); } d->qmlCallingContext.set(scope.engine, scope.engine->qmlContext()); @@ -601,6 +601,7 @@ void QQuickLoader::setSource(QQmlV4Function *args) void QQuickLoaderPrivate::disposeInitialPropertyValues() { + initialPropertyValues.clear(); } void QQuickLoaderPrivate::load() diff --git a/tests/auto/quick/qquickloader/data/CacheClearTest.qml b/tests/auto/quick/qquickloader/data/CacheClearTest.qml new file mode 100644 index 0000000000..acab79f96e --- /dev/null +++ b/tests/auto/quick/qquickloader/data/CacheClearTest.qml @@ -0,0 +1,4 @@ +import QtQml 2.12 +QtObject { + property int i: 42 +} diff --git a/tests/auto/quick/qquickloader/data/initialPropertyValues.11.qml b/tests/auto/quick/qquickloader/data/initialPropertyValues.11.qml new file mode 100644 index 0000000000..ddc874d14c --- /dev/null +++ b/tests/auto/quick/qquickloader/data/initialPropertyValues.11.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + id: root + property int oldi: 0 + property int i: 0 + + Loader { + id: loader + objectName: "loader" + active: true + } + + Component.onCompleted: { + loader.setSource("CacheClearTest.qml", {i: 12}) + root.oldi = loader.item.i + loader.setSource("CacheClearTest.qml") + root.i = loader.item.i // should be 42 + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index fbdd87905b..d0a1a8a45b 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -681,6 +681,11 @@ void tst_QQuickLoader::initialPropertyValues_data() << QStringList() << (QStringList() << "initialValue") << (QVariantList() << 6); + + QTest::newRow("source url changed, previously initial properties are discared") << testFileUrl("initialPropertyValues.11.qml") + << QStringList() + << (QStringList() << "oldi" << "i") + << (QVariantList() << 12 << 42); } void tst_QQuickLoader::initialPropertyValues() From 032c356ec91879599d6770bfb061a85b0f10eb34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 22 Oct 2019 13:33:59 +0200 Subject: [PATCH 08/13] Add missing emits from various property setters in {Grid,Row}Layout Change-Id: I3ac473b3d46ff1f898c1607deb6ad3d586753244 Fixes: QTBUG-79359 Reviewed-by: Mitch Curtis --- src/imports/layouts/qquicklinearlayout.cpp | 6 +++ .../qquicklayouts/data/tst_gridlayout.qml | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp index fa51ef1f2f..2e3b12064b 100644 --- a/src/imports/layouts/qquicklinearlayout.cpp +++ b/src/imports/layouts/qquicklinearlayout.cpp @@ -283,8 +283,11 @@ Qt::LayoutDirection QQuickGridLayoutBase::layoutDirection() const void QQuickGridLayoutBase::setLayoutDirection(Qt::LayoutDirection dir) { Q_D(QQuickGridLayoutBase); + if (d->m_layoutDirection == dir) + return; d->m_layoutDirection = dir; invalidate(); + emit layoutDirectionChanged(); } Qt::LayoutDirection QQuickGridLayoutBase::effectiveLayoutDirection() const @@ -524,6 +527,7 @@ void QQuickGridLayout::setColumnSpacing(qreal spacing) d->engine.setSpacing(spacing, Qt::Horizontal); invalidate(); + emit columnSpacingChanged(); } /*! @@ -546,6 +550,7 @@ void QQuickGridLayout::setRowSpacing(qreal spacing) d->engine.setSpacing(spacing, Qt::Vertical); invalidate(); + emit rowSpacingChanged(); } /*! @@ -817,6 +822,7 @@ void QQuickLinearLayout::setSpacing(qreal space) d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical); invalidate(); + emit spacingChanged(); } void QQuickLinearLayout::insertLayoutItems() diff --git a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml index 49838c4fd5..e8b3960486 100644 --- a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml +++ b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml @@ -1019,5 +1019,59 @@ Item { waitForRendering(layout); verify(layout.children[1].visible == false); } + + + + Component { + id: gridlayout_propertyChanges_Component + GridLayout { + columns: 1 + property alias spy : signalSpy + SignalSpy { + id: signalSpy + target: parent + } + } + } + + Component { + id: rowlayout_propertyChanges_Component + RowLayout { + property alias spy : signalSpy + SignalSpy { + id: signalSpy + target: parent + } + } + } + + function test_propertyChanges_data() + { + let data = [ + { tag: "columnSpacing", value: 9 }, + { tag: "rowSpacing", value: 9 }, + { tag: "columns", value: 2 }, + { tag: "rows", value: 2 }, + { tag: "flow", value: GridLayout.TopToBottom}, + { tag: "layoutDirection", value: Qt.RightToLeft }, + { tag: "spacing", value: 9 } + ] + return data + } + + function test_propertyChanges(data) + { + var propName = data.tag + var layout = createTemporaryObject(propName === "spacing" + ? rowlayout_propertyChanges_Component + : gridlayout_propertyChanges_Component + , container) + + layout.spy.signalName = propName + "Changed" + verify(layout.spy.valid) + + layout[propName] = data.value + compare(layout.spy.count, 1) + } } } From 76b86342d47df953009457a554245aace49eecf6 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 28 Oct 2019 08:35:08 +0100 Subject: [PATCH 09/13] qv4compileddata: do not use raw constexpr Necessary after change 50481fb909c2bbbc26a193e23783e5b0151168b9 in qtbase Fixes: QTBUG-79563 Change-Id: I72c94cd87b881f2fb3fee005f73583f64cbf68e4 Reviewed-by: Simon Hausmann Reviewed-by: Ulf Hermann --- src/qml/compiler/qv4compileddata_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 9050cfba94..7b26939da0 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -293,7 +293,7 @@ struct Function typedef quint16_le TraceInfoCount; TraceInfoCount nTraceInfos; - static constexpr TraceInfoCount NoTracing() { return TraceInfoCount::max(); } + static Q_DECL_CONSTEXPR TraceInfoCount NoTracing() { return TraceInfoCount::max(); } // Keep all unaligned data at the end quint8 flags; From 73ad6e87bbeceea5830ab3a6b3dc66fa99e30f45 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 28 Oct 2019 13:41:11 +0100 Subject: [PATCH 10/13] QQuickItem::setParentItem: add child earlier Calling (de)refWindow can trigger QQuickItem::windowChanged, which in turn can call a user defined windowChanged handler. If that signal handler were to call setParentItem, we would encounter an inconsistent state: The item already has its parent set, but that parent would lack the item in its children list (as we would only call refWindow at a later point). Fixes: QTBUG-79573 Fixes: QTBUG-73439 Change-Id: I46adaa54a0521b5cd7f37810b3dd1a206e6a09c6 Reviewed-by: Simon Hausmann --- src/quick/items/qquickitem.cpp | 21 +++++++++++++++---- .../data/setParentInWindowChange.qml | 12 +++++++++++ .../auto/quick/qquickitem/tst_qquickitem.cpp | 8 +++++++ 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 tests/auto/quick/qquickitem/data/setParentInWindowChange.qml diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 396012e1e6..26f02aeed7 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2748,22 +2748,35 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) } QQuickWindow *parentWindow = parentItem ? QQuickItemPrivate::get(parentItem)->window : nullptr; + bool alreadyAddedChild = false; if (d->window == parentWindow) { // Avoid freeing and reallocating resources if the window stays the same. d->parentItem = parentItem; } else { - if (d->window) - d->derefWindow(); + auto oldParentItem = d->parentItem; d->parentItem = parentItem; + if (d->parentItem) { + QQuickItemPrivate::get(d->parentItem)->addChild(this); + alreadyAddedChild = true; + } + if (d->window) { + d->derefWindow(); + // as we potentially changed d->parentWindow above + // the check in derefWindow could not work + // thus, we redo it here with the old parent + if (!oldParentItem) { + QQuickWindowPrivate::get(d->window)->parentlessItems.remove(this); + } + } if (parentWindow) d->refWindow(parentWindow); } d->dirty(QQuickItemPrivate::ParentChanged); - if (d->parentItem) + if (d->parentItem && !alreadyAddedChild) QQuickItemPrivate::get(d->parentItem)->addChild(this); - else if (d->window) + else if (d->window && !alreadyAddedChild) QQuickWindowPrivate::get(d->window)->parentlessItems.insert(this); d->setEffectiveVisibleRecur(d->calcEffectiveVisible()); diff --git a/tests/auto/quick/qquickitem/data/setParentInWindowChange.qml b/tests/auto/quick/qquickitem/data/setParentInWindowChange.qml new file mode 100644 index 0000000000..d68b7adb72 --- /dev/null +++ b/tests/auto/quick/qquickitem/data/setParentInWindowChange.qml @@ -0,0 +1,12 @@ +import QtQuick 2.12 + +Rectangle { + width: 800 + height: 600 + Item { + id: it + onWindowChanged: () => it.parent = newParent + } + + Item { id: newParent } +} diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 7e132f97b6..9ce9766c92 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -197,6 +197,8 @@ private slots: void qtBug60123(); #endif + void setParentCalledInOnWindowChanged(); + private: enum PaintOrderOp { @@ -2145,6 +2147,12 @@ void tst_qquickitem::qtBug60123() activateWindowAndTestPress(&window); } #endif +void tst_qquickitem::setParentCalledInOnWindowChanged() +{ + QQuickView view; + view.setSource(testFileUrl("setParentInWindowChange.qml")); + QVERIFY(ensureFocus(&view)); // should not crash +} QTEST_MAIN(tst_qquickitem) From 234dbbf25567ce44a8c8e099d003f04a12f2b371 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 29 Oct 2019 16:11:21 +0100 Subject: [PATCH 11/13] QML Drag: Prevent crash when using image provider url For attached property objects, qmlEngine will not return an engine. However, QQuickDragAttached's parent is the object to which it is attached, and from that one we can get the engine. Fixes: QTBUG-72045 Change-Id: I40748dd11ea3eb4604c37e932b2cfd3baad6fd1f Reviewed-by: Mitch Curtis --- src/quick/items/qquickdrag.cpp | 2 +- .../auto/quick/qquickdrag/tst_qquickdrag.cpp | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp index a900406b17..a2cb739ff2 100644 --- a/src/quick/items/qquickdrag.cpp +++ b/src/quick/items/qquickdrag.cpp @@ -442,7 +442,7 @@ void QQuickDragAttached::setImageSource(const QUrl &url) if (url.isEmpty()) { d->pixmapLoader.clear(); } else { - d->pixmapLoader.load(qmlEngine(this), url); + d->pixmapLoader.load(qmlEngine(parent()), url); } Q_EMIT imageSourceChanged(); diff --git a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp index 9d832066af..d3d3505e85 100644 --- a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp +++ b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp @@ -143,6 +143,7 @@ private slots: void source(); void recursion_data(); void recursion(); + void noCrashWithImageProvider(); private: QQmlEngine engine; @@ -1279,6 +1280,30 @@ void tst_QQuickDrag::recursion() } } +void tst_QQuickDrag::noCrashWithImageProvider() +{ + // QTBUG-72045 + QQmlComponent component(&engine); + component.setData( + R"( + import QtQuick 2.9 + Item { + Rectangle { + id: item + width: 50 + height: 50 + anchors.centerIn: parent + color: "orange" + Component.onCompleted: { + item.Drag.imageSource = "image://kill/me" + } + } + })", QUrl()); + QScopedPointer object(component.create()); + QQuickItem *item = qobject_cast(object.data()); + QVERIFY(item); +} + QTEST_MAIN(tst_QQuickDrag) From bcbc3c9cec1f7d7bb8c9d5f5ea94eb5c81ec2853 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Wed, 30 Oct 2019 10:15:23 +0100 Subject: [PATCH 12/13] QQmlProperty: handle reads of QQmlPropertyMap correctly Fixes: QTBUG-79614 Change-Id: Iaf84c0178dc88072a367da2b42b09554b85c7d57 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlproperty.cpp | 12 ++++++++--- .../qml/qqmlproperty/tst_qqmlproperty.cpp | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index c8166695ba..a394ed1ad9 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -63,6 +63,7 @@ #include #include #include +#include Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) @@ -331,10 +332,15 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) return; } else { - if (!property->isQObject()) - return; // Not an object property + if (!property->isQObject()) { + if (auto asPropertyMap = qobject_cast(currentObject)) + currentObject = asPropertyMap->value(path.at(ii).toString()).value(); + else + return; // Not an object property, and not a property map + } else { + property->readProperty(currentObject, ¤tObject); + } - property->readProperty(currentObject, ¤tObject); if (!currentObject) return; // No value } diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 27e06c6f67..ed213cd01a 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -37,6 +37,7 @@ #include #include #include "../../shared/util.h" +#include #include class MyQmlObject : public QObject @@ -149,6 +150,8 @@ private slots: void floatToStringPrecision(); void copy(); + + void nestedQQmlPropertyMap(); private: QQmlEngine engine; }; @@ -2106,6 +2109,24 @@ void tst_qqmlproperty::initTestCase() qmlRegisterType("Test",1,0,"MyContainer"); } +void tst_qqmlproperty::nestedQQmlPropertyMap() +{ + QQmlPropertyMap mainPropertyMap; + QQmlPropertyMap nestedPropertyMap; + QQmlPropertyMap deeplyNestedPropertyMap; + + mainPropertyMap.insert("nesting1", QVariant::fromValue(&nestedPropertyMap)); + nestedPropertyMap.insert("value", 42); + nestedPropertyMap.insert("nesting2", QVariant::fromValue(&deeplyNestedPropertyMap)); + deeplyNestedPropertyMap.insert("value", "success"); + + QQmlProperty value{&mainPropertyMap, "nesting1.value"}; + QCOMPARE(value.read().toInt(), 42); + + QQmlProperty success{&mainPropertyMap, "nesting1.nesting2.value"}; + QCOMPARE(success.read().toString(), QLatin1String("success")); +} + QTEST_MAIN(tst_qqmlproperty) #include "tst_qqmlproperty.moc" From 15d1b173d030f5ae5ca72f511d33c80979503268 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 31 Oct 2019 10:22:12 +0100 Subject: [PATCH 13/13] QQuickItem::setParentItem: Check for d->window after deref'ing it The window may have been deleted. In that case there is nothing to do. Amends commit 73ad6e87bbeceea5830ab3a6b3dc66fa99e30f45. Change-Id: Ib591f34b51f58d49ed0b065be7025f8e54777c10 Reviewed-by: Liang Qi --- src/quick/items/qquickitem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 26f02aeed7..d90cc71997 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2764,7 +2764,8 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) // as we potentially changed d->parentWindow above // the check in derefWindow could not work // thus, we redo it here with the old parent - if (!oldParentItem) { + // Also, the window may have been deleted by derefWindow() + if (!oldParentItem && d->window) { QQuickWindowPrivate::get(d->window)->parentlessItems.remove(this); } }