parent
91f02a09d7
commit
c079359845
@ -1 +1 @@
|
|||||||
SOURCES/qtdeclarative-everywhere-opensource-src-5.15.9.tar.xz
|
SOURCES/qtdeclarative-everywhere-opensource-src-5.15.15.tar.xz
|
||||||
|
@ -1 +1 @@
|
|||||||
c1230f5c709f80d5bf7e61456a7d605983201cde SOURCES/qtdeclarative-everywhere-opensource-src-5.15.9.tar.xz
|
04598aaa01a546648769e85e2e225047d153e7a8 SOURCES/qtdeclarative-everywhere-opensource-src-5.15.15.tar.xz
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
From 7be5422134167fe6d9fd44ef683f407bbda1bce7 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
|
||||||
Date: Tue, 30 Nov 2021 14:39:48 +0100
|
|
||||||
Subject: [PATCH 14/19] Qml: Don't crash when as-casting to type with errors
|
|
||||||
|
|
||||||
Such types don't have a compilation unit, but we still know their names.
|
|
||||||
|
|
||||||
Pick-to: 6.2
|
|
||||||
Fixes: QTBUG-98792
|
|
||||||
Change-Id: I2db8dea3a5a02ec1492f7f7a054fd3ad4c6ad69a
|
|
||||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
|
||||||
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
|
|
||||||
(cherry picked from commit e0cd201e91ae64b9c03e0128cd17656b00611fbb)
|
|
||||||
---
|
|
||||||
src/qml/qml/qqmltypewrapper.cpp | 6 ++++--
|
|
||||||
src/qml/types/qqmlconnections.cpp | 2 +-
|
|
||||||
tests/auto/qml/qqmllanguage/data/Broken.qml | 5 +++++
|
|
||||||
tests/auto/qml/qqmllanguage/data/asBroken.qml | 6 ++++++
|
|
||||||
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 16 ++++++++++++++++
|
|
||||||
5 files changed, 32 insertions(+), 3 deletions(-)
|
|
||||||
create mode 100644 tests/auto/qml/qqmllanguage/data/Broken.qml
|
|
||||||
create mode 100644 tests/auto/qml/qqmllanguage/data/asBroken.qml
|
|
||||||
|
|
||||||
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
|
|
||||||
index 175de8b936..a6ba4b8cb3 100644
|
|
||||||
--- a/src/qml/qml/qqmltypewrapper.cpp
|
|
||||||
+++ b/src/qml/qml/qqmltypewrapper.cpp
|
|
||||||
@@ -419,8 +419,10 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
|
|
||||||
return Encode(false);
|
|
||||||
|
|
||||||
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
|
|
||||||
- ExecutableCompilationUnit *cu = td->compilationUnit();
|
|
||||||
- myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
|
|
||||||
+ if (ExecutableCompilationUnit *cu = td->compilationUnit())
|
|
||||||
+ myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
|
|
||||||
+ else
|
|
||||||
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
|
|
||||||
} else {
|
|
||||||
myQmlType = qenginepriv->metaObjectForType(myTypeId);
|
|
||||||
}
|
|
||||||
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
|
|
||||||
index 29ed62cd39..aba930dfe1 100644
|
|
||||||
--- a/src/qml/types/qqmlconnections.cpp
|
|
||||||
+++ b/src/qml/types/qqmlconnections.cpp
|
|
||||||
@@ -338,7 +338,7 @@ void QQmlConnections::connectSignalsToMethods()
|
|
||||||
&& propName.at(2).isUpper()) {
|
|
||||||
qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
|
|
||||||
"This is probably intended to be a signal handler but no "
|
|
||||||
- "signal of the target matches the name.").arg(propName);
|
|
||||||
+ "signal of the \"%2\" target matches the name.").arg(propName).arg(target->metaObject()->className());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/tests/auto/qml/qqmllanguage/data/Broken.qml b/tests/auto/qml/qqmllanguage/data/Broken.qml
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000..e24d9112a8
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tests/auto/qml/qqmllanguage/data/Broken.qml
|
|
||||||
@@ -0,0 +1,5 @@
|
|
||||||
+import QtQml 2.15
|
|
||||||
+
|
|
||||||
+QtObject {
|
|
||||||
+ notThere: 5
|
|
||||||
+}
|
|
||||||
diff --git a/tests/auto/qml/qqmllanguage/data/asBroken.qml b/tests/auto/qml/qqmllanguage/data/asBroken.qml
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000..bd88d14c76
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tests/auto/qml/qqmllanguage/data/asBroken.qml
|
|
||||||
@@ -0,0 +1,6 @@
|
|
||||||
+import QtQml 2.15
|
|
||||||
+
|
|
||||||
+QtObject {
|
|
||||||
+ id: self
|
|
||||||
+ property var selfAsBroken: self as Broken
|
|
||||||
+}
|
|
||||||
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
|
||||||
index bffb62c59e..97cc64991f 100644
|
|
||||||
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
|
||||||
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
|
|
||||||
@@ -336,6 +336,7 @@ private slots:
|
|
||||||
void bareInlineComponent();
|
|
||||||
|
|
||||||
void hangOnWarning();
|
|
||||||
+ void objectAsBroken();
|
|
||||||
|
|
||||||
void ambiguousContainingType();
|
|
||||||
|
|
||||||
@@ -5876,6 +5877,21 @@ void tst_qqmllanguage::ambiguousContainingType()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+void tst_qqmllanguage::objectAsBroken()
|
|
||||||
+{
|
|
||||||
+ QQmlEngine engine;
|
|
||||||
+ QQmlComponent c(&engine, testFileUrl("asBroken.qml"));
|
|
||||||
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
|
||||||
+ QScopedPointer<QObject> o(c.create());
|
|
||||||
+ QVERIFY(!o.isNull());
|
|
||||||
+ QVariant selfAsBroken = o->property("selfAsBroken");
|
|
||||||
+ QVERIFY(selfAsBroken.isValid());
|
|
||||||
+ // QCOMPARE(selfAsBroken.metaType(), QMetaType::fromType<std::nullptr_t>());
|
|
||||||
+
|
|
||||||
+ QQmlComponent b(&engine, testFileUrl("Broken.qml"));
|
|
||||||
+ QVERIFY(b.isError());
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
QTEST_MAIN(tst_qqmllanguage)
|
|
||||||
|
|
||||||
#include "tst_qqmllanguage.moc"
|
|
||||||
--
|
|
||||||
2.40.0
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
|||||||
From d54b978c0cba2bf75e145c9e1b00d2a9ab495d70 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
|
||||||
Date: Mon, 19 Dec 2022 10:05:33 +0100
|
|
||||||
Subject: [PATCH 15/19] Fix missing glyphs when using NativeRendering
|
|
||||||
|
|
||||||
When we look up glyphs with subpixel positions in the glyph cache,
|
|
||||||
we use the calculated subpixel position (from a set of predefined
|
|
||||||
subpixel positions) as key. In some very rare cases, we could end
|
|
||||||
up with different subpixel positions when looking up an on-screen
|
|
||||||
position than when we entered it into the cache, due to numerical
|
|
||||||
differences when doing the calculation.
|
|
||||||
|
|
||||||
The reason for this was that when entering the glyph into the
|
|
||||||
cache, we used the 16.6 fixed point representation, whereas when
|
|
||||||
looking up, we used the unmodified float. In some cases, the
|
|
||||||
converted fixed point approximation might snap to a different
|
|
||||||
predefined subpixel position than the floating point equivalent.
|
|
||||||
|
|
||||||
To avoid this, we reuse the converted fixed point positions when
|
|
||||||
looking up the glyphs in the cache.
|
|
||||||
|
|
||||||
[ChangeLog][Text] Fixed an issue where text using NativeRendering
|
|
||||||
would sometimes be missing glyphs.
|
|
||||||
|
|
||||||
Pick-to: 5.15 6.2 6.4 6.5
|
|
||||||
Fixes: QTBUG-108713
|
|
||||||
Change-Id: Iecc264eb3d27e875c24257eaefcfb18a1a5fb5be
|
|
||||||
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
|
||||||
Reviewed-by: Lars Knoll <lars@knoll.priv.no>
|
|
||||||
(cherry picked from commit 4bad329985b75090c68a70cceee7edadc172d7ab)
|
|
||||||
---
|
|
||||||
src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 4 +++-
|
|
||||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
|
||||||
index f912da5799..fd128aa06e 100644
|
|
||||||
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
|
||||||
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
|
||||||
@@ -839,9 +839,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
|
|
||||||
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
|
|
||||||
for (int i=0; i<glyphIndexes.size(); ++i) {
|
|
||||||
QPointF glyphPosition = glyphPositions.at(i) + position;
|
|
||||||
+ QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
|
|
||||||
+
|
|
||||||
QFixed subPixelPosition;
|
|
||||||
if (supportsSubPixelPositions)
|
|
||||||
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x()));
|
|
||||||
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
|
|
||||||
|
|
||||||
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
|
|
||||||
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
|
|
||||||
--
|
|
||||||
2.40.0
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
|||||||
|
From 7882c22b04ecd7bc349d3d585b3de860b2c64781 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||||
|
Date: Wed, 29 Mar 2023 16:36:03 +0200
|
||||||
|
Subject: [PATCH 15/25] Models: Avoid crashes when deleting cache items
|
||||||
|
|
||||||
|
Pick-to: 6.5 6.2 5.15
|
||||||
|
Fixes: QTBUG-91425
|
||||||
|
Change-Id: I58cf9ee29922f83fc6621f771b80ed557b31f106
|
||||||
|
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
||||||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
(cherry picked from commit 0cfdecba54e4f40468c4c9a8a6668cc1bc0eff65)
|
||||||
|
|
||||||
|
* asturmlechner 2023-04-08: Resolve conflict with dev branch commit
|
||||||
|
c2d490a2385ea6f389340a296acaac0fa198c8b9 (qAsConst to std::as_const)
|
||||||
|
---
|
||||||
|
.../qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp | 12 ++++++++++++
|
||||||
|
1 file changed, 12 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||||
|
index e128d77c52..e5daf2d28b 100644
|
||||||
|
--- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||||
|
+++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
||||||
|
@@ -51,6 +51,7 @@ private slots:
|
||||||
|
void contextAccessedByHandler();
|
||||||
|
void deleteRace();
|
||||||
|
void redrawUponColumnChange();
|
||||||
|
+ void deleteRace();
|
||||||
|
};
|
||||||
|
|
||||||
|
class AbstractItemModel : public QAbstractItemModel
|
||||||
|
@@ -214,6 +215,17 @@ void tst_QQmlDelegateModel::redrawUponColumnChange()
|
||||||
|
QCOMPARE(item->property("text").toString(), "Coconut");
|
||||||
|
}
|
||||||
|
|
||||||
|
+void tst_QQmlDelegateModel::deleteRace()
|
||||||
|
+{
|
||||||
|
+ QQmlEngine engine;
|
||||||
|
+ QQmlComponent c(&engine, testFileUrl("deleteRace.qml"));
|
||||||
|
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
||||||
|
+ QScopedPointer<QObject> o(c.create());
|
||||||
|
+ QVERIFY(!o.isNull());
|
||||||
|
+ QTRY_COMPARE(o->property("count").toInt(), 2);
|
||||||
|
+ QTRY_COMPARE(o->property("count").toInt(), 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
QTEST_MAIN(tst_QQmlDelegateModel)
|
||||||
|
|
||||||
|
#include "tst_qqmldelegatemodel.moc"
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -1,32 +0,0 @@
|
|||||||
From 70b44dd18b9727e9aae857297265a751700a297e Mon Sep 17 00:00:00 2001
|
|
||||||
From: Fushan Wen <qydwhotmail@gmail.com>
|
|
||||||
Date: Tue, 10 Jan 2023 20:42:04 +0800
|
|
||||||
Subject: [PATCH 16/19] Revert "Fix missing glyphs when using NativeRendering"
|
|
||||||
|
|
||||||
This reverts commit da5e53b649f50cd9cdd89dadbba16f05e4070be2.
|
|
||||||
|
|
||||||
It breaks fonts on Wayland when global scale > 100%.
|
|
||||||
---
|
|
||||||
src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 4 +---
|
|
||||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
|
||||||
index fd128aa06e..f912da5799 100644
|
|
||||||
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
|
||||||
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
|
|
||||||
@@ -839,11 +839,9 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
|
|
||||||
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
|
|
||||||
for (int i=0; i<glyphIndexes.size(); ++i) {
|
|
||||||
QPointF glyphPosition = glyphPositions.at(i) + position;
|
|
||||||
- QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
|
|
||||||
-
|
|
||||||
QFixed subPixelPosition;
|
|
||||||
if (supportsSubPixelPositions)
|
|
||||||
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
|
|
||||||
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x()));
|
|
||||||
|
|
||||||
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
|
|
||||||
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
|
|
||||||
--
|
|
||||||
2.40.0
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
|||||||
|
From e2c7bdca3d1442b9e4e265378ee17b9ac347b4c3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Maximilian Goldstein <max.goldstein@qt.io>
|
||||||
|
Date: Wed, 9 Jun 2021 15:02:45 +0200
|
||||||
|
Subject: [PATCH 16/25] qv4function: Fix crash due to reference being
|
||||||
|
invalidated
|
||||||
|
|
||||||
|
Function::updateInternalClass creates a reference to a QStringList that is appended to before being used.
|
||||||
|
This is unsafe and can leads to a segfault if the append() causes a reallocation.
|
||||||
|
|
||||||
|
Fixes: QTBUG-94360
|
||||||
|
Pick-to: 5.15 6.1 6.2
|
||||||
|
Change-Id: Iac49e8d816cf440ca2b70e133c88314eb8df6b91
|
||||||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
|
||||||
|
(cherry picked from commit 7fa28f98824a94396106eadfc028b329985a0cfc)
|
||||||
|
---
|
||||||
|
src/qml/jsruntime/qv4function.cpp | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
|
||||||
|
index cf8a53cf9f..223e64271e 100644
|
||||||
|
--- a/src/qml/jsruntime/qv4function.cpp
|
||||||
|
+++ b/src/qml/jsruntime/qv4function.cpp
|
||||||
|
@@ -136,7 +136,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
|
||||||
|
if (duplicate == -1) {
|
||||||
|
parameterNames.append(QString::fromUtf8(param));
|
||||||
|
} else {
|
||||||
|
- const QString &dup = parameterNames[duplicate];
|
||||||
|
+ const QString dup = parameterNames[duplicate];
|
||||||
|
parameterNames.append(dup);
|
||||||
|
parameterNames[duplicate] =
|
||||||
|
QString(0xfffe) + QString::number(duplicate) + dup;
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,141 @@
|
|||||||
|
From 980ed9bae736634ed6edf2d2b85b91bdb90e4f19 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
Date: Tue, 29 Mar 2022 10:44:04 +0200
|
||||||
|
Subject: [PATCH 17/25] Quick Animations: Fix crash
|
||||||
|
|
||||||
|
SwipeDelegate causes the running animation job to be deleted when
|
||||||
|
calling swipe.close in swipe.completed. Employ the RETURN_IF_DELETED
|
||||||
|
check in more places to avoid crashes.
|
||||||
|
|
||||||
|
Fixes: QTBUG-100560
|
||||||
|
Task-number: QTBUG-103223
|
||||||
|
Pick-to: 6.3 6.2 5.15
|
||||||
|
Change-Id: I276eeaa9aed1bdb36449b322a24641fa02c4d5e4
|
||||||
|
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
||||||
|
(cherry picked from commit 0238af0bd48b831d72126f2228d5913eccf67bae)
|
||||||
|
|
||||||
|
* asturmlechner 2023-04-09: Resolve conflict with dev branch commit
|
||||||
|
4938984f9a779192264757a06e6ca555fc8f5e91
|
||||||
|
---
|
||||||
|
.../qcontinuinganimationgroupjob.cpp | 4 +-
|
||||||
|
.../animations/qparallelanimationgroupjob.cpp | 4 +-
|
||||||
|
.../swipedelegate/CloseOnCompletedWorks.qml | 74 +++++++++++++++++++
|
||||||
|
3 files changed, 78 insertions(+), 4 deletions(-)
|
||||||
|
create mode 100644 tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||||||
|
|
||||||
|
diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||||||
|
index 88c0e9e60e..61a9dc36f8 100644
|
||||||
|
--- a/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||||||
|
+++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp
|
||||||
|
@@ -82,9 +82,9 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
|
||||||
|
- resetUncontrolledAnimationFinishTime(animation);
|
||||||
|
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
|
||||||
|
animation->setDirection(m_direction);
|
||||||
|
- animation->start();
|
||||||
|
+ RETURN_IF_DELETED(animation->start());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
|
||||||
|
index 420a934ba2..a828d0e234 100644
|
||||||
|
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
|
||||||
|
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
|
||||||
|
@@ -144,10 +144,10 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
|
||||||
|
animation->stop();
|
||||||
|
m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
|
||||||
|
}
|
||||||
|
- resetUncontrolledAnimationFinishTime(animation);
|
||||||
|
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
|
||||||
|
animation->setDirection(m_direction);
|
||||||
|
if (shouldAnimationStart(animation, oldState == Stopped))
|
||||||
|
- animation->start();
|
||||||
|
+ RETURN_IF_DELETED(animation->start());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
diff --git a/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml b/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000..38dfde41c3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/manual/quickcontrols2/swipedelegate/CloseOnCompletedWorks.qml
|
||||||
|
@@ -0,0 +1,74 @@
|
||||||
|
+/****************************************************************************
|
||||||
|
+**
|
||||||
|
+** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
+** Contact: https://www.qt.io/licensing/
|
||||||
|
+**
|
||||||
|
+** This file is part of the test suite of the Qt Toolkit.
|
||||||
|
+**
|
||||||
|
+** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
+** Commercial License Usage
|
||||||
|
+** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
+** accordance with the commercial license agreement provided with the
|
||||||
|
+** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
+** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
+** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
+** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
+**
|
||||||
|
+** BSD License Usage
|
||||||
|
+** Alternatively, you may use this file under the terms of the BSD license
|
||||||
|
+** as follows:
|
||||||
|
+**
|
||||||
|
+** "Redistribution and use in source and binary forms, with or without
|
||||||
|
+** modification, are permitted provided that the following conditions are
|
||||||
|
+** met:
|
||||||
|
+** * Redistributions of source code must retain the above copyright
|
||||||
|
+** notice, this list of conditions and the following disclaimer.
|
||||||
|
+** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
+** notice, this list of conditions and the following disclaimer in
|
||||||
|
+** the documentation and/or other materials provided with the
|
||||||
|
+** distribution.
|
||||||
|
+** * Neither the name of The Qt Company Ltd nor the names of its
|
||||||
|
+** contributors may be used to endorse or promote products derived
|
||||||
|
+** from this software without specific prior written permission.
|
||||||
|
+**
|
||||||
|
+**
|
||||||
|
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
+**
|
||||||
|
+** $QT_END_LICENSE$
|
||||||
|
+**
|
||||||
|
+****************************************************************************/
|
||||||
|
+
|
||||||
|
+import QtQuick 2
|
||||||
|
+import QtQuick.Controls 2
|
||||||
|
+ApplicationWindow {
|
||||||
|
+ visible: true
|
||||||
|
+ width: 640
|
||||||
|
+ height: 480
|
||||||
|
+
|
||||||
|
+ ListView {
|
||||||
|
+ anchors.fill: parent
|
||||||
|
+ model: 2
|
||||||
|
+
|
||||||
|
+ delegate: SwipeDelegate {
|
||||||
|
+ text: "Swipe me left (should not crash)"
|
||||||
|
+
|
||||||
|
+ swipe.right: Label {
|
||||||
|
+ text: "Release (should not crash)"
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ swipe.onCompleted: {
|
||||||
|
+ swipe.close()
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,129 @@
|
|||||||
|
From d6d08e3bee98f150cc3182dba9b38996b1409a34 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joni Poikelin <joni.poikelin@qt.io>
|
||||||
|
Date: Thu, 3 Sep 2020 14:22:26 +0300
|
||||||
|
Subject: [PATCH 18/25] Prevent crash when destroying asynchronous Loader
|
||||||
|
|
||||||
|
Fixes: QTBUG-86255
|
||||||
|
Pick-to: 5.15
|
||||||
|
Change-Id: I30488b64d910a1409a43e2e98ee7ab084aec33d2
|
||||||
|
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
||||||
|
(cherry picked from commit 149c1dd07b54ee0c027d94a49d52160dc4f4e2ac)
|
||||||
|
|
||||||
|
* asturmlechner 2023-01-06: Resolve conflict with dev branch commits
|
||||||
|
d51c007ecc8aa6256cb95cf3992e5ac34a70fa3f and
|
||||||
|
b2a4a61e8cb0839ba293783ac03c72f35c7b1307
|
||||||
|
---
|
||||||
|
src/qml/qml/qqmlvmemetaobject.cpp | 2 +-
|
||||||
|
.../quick/qquickgridview/data/qtbug86255.qml | 55 +++++++++++++++++++
|
||||||
|
.../qquickgridview/tst_qquickgridview.cpp | 13 +++++
|
||||||
|
3 files changed, 69 insertions(+), 1 deletion(-)
|
||||||
|
create mode 100644 tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||||||
|
|
||||||
|
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
|
||||||
|
index 1e0e4e419f..a0532d1794 100644
|
||||||
|
--- a/src/qml/qml/qqmlvmemetaobject.cpp
|
||||||
|
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
|
||||||
|
@@ -251,7 +251,7 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
|
||||||
|
if (!pd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
- if (pd->notifyIndex() != -1)
|
||||||
|
+ if (pd->notifyIndex() != -1 && ctxt->engine)
|
||||||
|
connect(target, pd->notifyIndex(), ctxt->engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/tests/auto/quick/qquickgridview/data/qtbug86255.qml b/tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000..20688b1967
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/auto/quick/qquickgridview/data/qtbug86255.qml
|
||||||
|
@@ -0,0 +1,55 @@
|
||||||
|
+import QtQuick 2.15
|
||||||
|
+
|
||||||
|
+Item {
|
||||||
|
+ width: 240
|
||||||
|
+ height: 320
|
||||||
|
+
|
||||||
|
+ GridView {
|
||||||
|
+ id: grid
|
||||||
|
+ objectName: "view"
|
||||||
|
+ anchors.fill: parent
|
||||||
|
+ cellWidth: 64
|
||||||
|
+ cellHeight: 64
|
||||||
|
+ model: ListModel {
|
||||||
|
+ id: listModel
|
||||||
|
+
|
||||||
|
+ Component.onCompleted: reload()
|
||||||
|
+
|
||||||
|
+ function reload() {
|
||||||
|
+ clear();
|
||||||
|
+ for (let i = 0; i < 1000; i++) {
|
||||||
|
+ let magic = Math.random();
|
||||||
|
+ append( { magic } );
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ clip: true
|
||||||
|
+ delegate: Item {
|
||||||
|
+ id: d
|
||||||
|
+ property string val: magic
|
||||||
|
+ Loader {
|
||||||
|
+ property alias value: d.val
|
||||||
|
+ asynchronous: true
|
||||||
|
+ sourceComponent: cmp
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Timer {
|
||||||
|
+ running: true
|
||||||
|
+ interval: 1000
|
||||||
|
+ onTriggered: listModel.reload()
|
||||||
|
+ }
|
||||||
|
+ Timer {
|
||||||
|
+ running: true
|
||||||
|
+ interval: 500
|
||||||
|
+ onTriggered: grid.flick(0, -4000)
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Component {
|
||||||
|
+ id: cmp
|
||||||
|
+ Text {
|
||||||
|
+ text: value
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||||||
|
index 94ec4f44d5..7d0d9fa7a7 100644
|
||||||
|
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||||||
|
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
|
||||||
|
@@ -213,6 +213,7 @@ private slots:
|
||||||
|
void QTBUG_45640();
|
||||||
|
void QTBUG_49218();
|
||||||
|
void QTBUG_48870_fastModelUpdates();
|
||||||
|
+ void QTBUG_86255();
|
||||||
|
|
||||||
|
void keyNavigationEnabled();
|
||||||
|
void resizeDynamicCellWidthRtL();
|
||||||
|
@@ -6814,6 +6815,18 @@ void tst_QQuickGridView::resizeDynamicCellWidthRtL()
|
||||||
|
QTRY_COMPARE(gridview->contentX(), 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void tst_QQuickGridView::QTBUG_86255()
|
||||||
|
+{
|
||||||
|
+ QScopedPointer<QQuickView> window(createView());
|
||||||
|
+ window->setSource(testFileUrl("qtbug86255.qml"));
|
||||||
|
+ window->show();
|
||||||
|
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
|
||||||
|
+ QQuickGridView *view = findItem<QQuickGridView>(window->rootObject(), "view");
|
||||||
|
+ QVERIFY(view != nullptr);
|
||||||
|
+ QTRY_COMPARE(view->isFlicking(), true);
|
||||||
|
+ QTRY_COMPARE(view->isFlicking(), false);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void tst_QQuickGridView::releaseItems()
|
||||||
|
{
|
||||||
|
QScopedPointer<QQuickView> view(createView());
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -1,162 +0,0 @@
|
|||||||
From 89bf481b9b14f038c5e16421a7fce6dc6523785f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
|
||||||
Date: Wed, 29 Mar 2023 16:36:03 +0200
|
|
||||||
Subject: [PATCH 19/19] Models: Avoid crashes when deleting cache items
|
|
||||||
|
|
||||||
Pick-to: 6.5 6.2 5.15
|
|
||||||
Fixes: QTBUG-91425
|
|
||||||
Change-Id: I58cf9ee29922f83fc6621f771b80ed557b31f106
|
|
||||||
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
|
||||||
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
|
||||||
(cherry picked from commit 0cfdecba54e4f40468c4c9a8a6668cc1bc0eff65)
|
|
||||||
|
|
||||||
* asturmlechner 2023-04-08: Resolve conflict with dev branch commit
|
|
||||||
c2d490a2385ea6f389340a296acaac0fa198c8b9 (qAsConst to std::as_const)
|
|
||||||
---
|
|
||||||
src/qmlmodels/qqmldelegatemodel.cpp | 23 ++++++---
|
|
||||||
.../qml/qqmldelegatemodel/data/deleteRace.qml | 50 +++++++++++++++++++
|
|
||||||
.../tst_qqmldelegatemodel.cpp | 12 +++++
|
|
||||||
3 files changed, 78 insertions(+), 7 deletions(-)
|
|
||||||
create mode 100644 tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
|
||||||
|
|
||||||
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
|
|
||||||
index bc6b2447af..551e0ede95 100644
|
|
||||||
--- a/src/qmlmodels/qqmldelegatemodel.cpp
|
|
||||||
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
|
|
||||||
@@ -1883,10 +1883,15 @@ void QQmlDelegateModelPrivate::emitChanges()
|
|
||||||
for (int i = 1; i < m_groupCount; ++i)
|
|
||||||
QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
|
|
||||||
|
|
||||||
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
|
|
||||||
- for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) {
|
|
||||||
- if (cacheItem->attached)
|
|
||||||
- cacheItem->attached->emitChanges();
|
|
||||||
+ // emitChanges may alter m_cache and delete items
|
|
||||||
+ QVarLengthArray<QPointer<QQmlDelegateModelAttached>> attachedObjects;
|
|
||||||
+ attachedObjects.reserve(m_cache.length());
|
|
||||||
+ for (const QQmlDelegateModelItem *cacheItem : qAsConst(m_cache))
|
|
||||||
+ attachedObjects.append(cacheItem->attached);
|
|
||||||
+
|
|
||||||
+ for (const QPointer<QQmlDelegateModelAttached> &attached : qAsConst(attachedObjects)) {
|
|
||||||
+ if (attached && attached->m_cacheItem)
|
|
||||||
+ attached->emitChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2707,20 +2712,24 @@ void QQmlDelegateModelAttached::emitChanges()
|
|
||||||
m_previousGroups = m_cacheItem->groups;
|
|
||||||
|
|
||||||
int indexChanges = 0;
|
|
||||||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
|
|
||||||
+ const int groupCount = m_cacheItem->metaType->groupCount;
|
|
||||||
+ for (int i = 1; i < groupCount; ++i) {
|
|
||||||
if (m_previousIndex[i] != m_currentIndex[i]) {
|
|
||||||
m_previousIndex[i] = m_currentIndex[i];
|
|
||||||
indexChanges |= (1 << i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Don't access m_cacheItem anymore once we've started sending signals.
|
|
||||||
+ // We don't own it and someone might delete it.
|
|
||||||
+
|
|
||||||
int notifierId = 0;
|
|
||||||
const QMetaObject *meta = metaObject();
|
|
||||||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
|
|
||||||
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
|
|
||||||
if (groupChanges & (1 << i))
|
|
||||||
QMetaObject::activate(this, meta, notifierId, nullptr);
|
|
||||||
}
|
|
||||||
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
|
|
||||||
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
|
|
||||||
if (indexChanges & (1 << i))
|
|
||||||
QMetaObject::activate(this, meta, notifierId, nullptr);
|
|
||||||
}
|
|
||||||
diff --git a/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml b/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000..23874970e7
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/tests/auto/qml/qqmldelegatemodel/data/deleteRace.qml
|
|
||||||
@@ -0,0 +1,50 @@
|
|
||||||
+import QtQuick 2.15
|
|
||||||
+import QtQml.Models 2.15
|
|
||||||
+
|
|
||||||
+Item {
|
|
||||||
+ DelegateModel {
|
|
||||||
+ id: delegateModel
|
|
||||||
+ model: ListModel {
|
|
||||||
+ id: sourceModel
|
|
||||||
+
|
|
||||||
+ ListElement { title: "foo" }
|
|
||||||
+ ListElement { title: "bar" }
|
|
||||||
+
|
|
||||||
+ function clear() {
|
|
||||||
+ if (count > 0)
|
|
||||||
+ remove(0, count);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ groups: [
|
|
||||||
+ DelegateModelGroup { name: "selectedItems" }
|
|
||||||
+ ]
|
|
||||||
+
|
|
||||||
+ delegate: Text {
|
|
||||||
+ height: DelegateModel.inSelectedItems ? implicitHeight * 2 : implicitHeight
|
|
||||||
+ Component.onCompleted: {
|
|
||||||
+ if (index === 0)
|
|
||||||
+ DelegateModel.inSelectedItems = true;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ Component.onCompleted: {
|
|
||||||
+ items.create(0)
|
|
||||||
+ items.create(1)
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ListView {
|
|
||||||
+ anchors.fill: parent
|
|
||||||
+ model: delegateModel
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ Timer {
|
|
||||||
+ running: true
|
|
||||||
+ interval: 10
|
|
||||||
+ onTriggered: sourceModel.clear()
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ property int count: delegateModel.items.count
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
|
||||||
index 1722447830..f473cff75f 100644
|
|
||||||
--- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
|
||||||
+++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
|
|
||||||
@@ -50,6 +50,7 @@ private slots:
|
|
||||||
void qtbug_86017();
|
|
||||||
void contextAccessedByHandler();
|
|
||||||
void redrawUponColumnChange();
|
|
||||||
+ void deleteRace();
|
|
||||||
};
|
|
||||||
|
|
||||||
class AbstractItemModel : public QAbstractItemModel
|
|
||||||
@@ -213,6 +214,17 @@ void tst_QQmlDelegateModel::redrawUponColumnChange()
|
|
||||||
QCOMPARE(item->property("text").toString(), "Coconut");
|
|
||||||
}
|
|
||||||
|
|
||||||
+void tst_QQmlDelegateModel::deleteRace()
|
|
||||||
+{
|
|
||||||
+ QQmlEngine engine;
|
|
||||||
+ QQmlComponent c(&engine, testFileUrl("deleteRace.qml"));
|
|
||||||
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
|
|
||||||
+ QScopedPointer<QObject> o(c.create());
|
|
||||||
+ QVERIFY(!o.isNull());
|
|
||||||
+ QTRY_COMPARE(o->property("count").toInt(), 2);
|
|
||||||
+ QTRY_COMPARE(o->property("count").toInt(), 0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
QTEST_MAIN(tst_QQmlDelegateModel)
|
|
||||||
|
|
||||||
#include "tst_qqmldelegatemodel.moc"
|
|
||||||
--
|
|
||||||
2.40.0
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
|||||||
|
From 11f5bc3d80c57ad2094ab2e8010955a1a0130feb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Volker Hilsheimer <volker.hilsheimer@qt.io>
|
||||||
|
Date: Fri, 18 Nov 2022 14:20:20 +0100
|
||||||
|
Subject: [PATCH 19/25] QQuickItem: Fix effective visibility for items without
|
||||||
|
parent
|
||||||
|
|
||||||
|
Items are visible if they are children of a visible parent, and not
|
||||||
|
explicitly hidden. The effectiveVisible member stores the state and is
|
||||||
|
updated when conditions that impact the item visibility changes.
|
||||||
|
|
||||||
|
The old code returned true for items outside a visual hierarchy, which
|
||||||
|
broke signal emission when items were removed from a parent, e.g.
|
||||||
|
because the parent got destroyed. With this change, items removed from
|
||||||
|
a visual hierarchy will emit the visibleChanged signal.
|
||||||
|
|
||||||
|
Note: QQuickItem initializes the effectiveVisible member to true, even
|
||||||
|
if the item was created without parent item. Visual items are required
|
||||||
|
to be added to a visual hierarchy via setParentItem. For this reason,
|
||||||
|
newly created items never emit visibleChanged when they are added to
|
||||||
|
a parent.
|
||||||
|
|
||||||
|
Adjust the QQuickItem::visible test - it creates an item hierarchy
|
||||||
|
without window. Such items are never visible, so add a window and
|
||||||
|
parent the test item hierarchy to the window's content item.
|
||||||
|
|
||||||
|
This fixes the expected failures in the tests. It does introduce an
|
||||||
|
incompatibility with QGraphicsView and QGraphicsItem, which continue
|
||||||
|
to return true from QGraphicsItem::isVisible for items that are not
|
||||||
|
in an item hierarchy.
|
||||||
|
|
||||||
|
[ChangeLog][Qt Quick][QQuickItem] The visible property of Items without
|
||||||
|
a parent now always returns false, and the visibleChanged signal gets
|
||||||
|
emitted when the parent item of a visible item becomes null.
|
||||||
|
|
||||||
|
Fixes: QTBUG-108213
|
||||||
|
Change-Id: If4b2947cefd1407853f0f29e6c3fdbd49fc9af65
|
||||||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
|
||||||
|
(cherry picked from commit d1b9a4cacfb966cf0a37983d8f8044f3aedf5de3)
|
||||||
|
|
||||||
|
CCBUG: 467909
|
||||||
|
CCBUG: 396359
|
||||||
|
---
|
||||||
|
src/quick/items/qquickitem.cpp | 6 ++----
|
||||||
|
tests/auto/quick/qquickitem/tst_qquickitem.cpp | 2 ++
|
||||||
|
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
|
||||||
|
index 708dc5fe5e..7236973216 100644
|
||||||
|
--- a/src/quick/items/qquickitem.cpp
|
||||||
|
+++ b/src/quick/items/qquickitem.cpp
|
||||||
|
@@ -6082,10 +6082,8 @@ void QQuickItem::setEnabled(bool e)
|
||||||
|
|
||||||
|
bool QQuickItemPrivate::calcEffectiveVisible() const
|
||||||
|
{
|
||||||
|
- // XXX todo - Should the effective visible of an element with no parent just be the current
|
||||||
|
- // effective visible? This would prevent pointless re-processing in the case of an element
|
||||||
|
- // moving to/from a no-parent situation, but it is different from what graphics view does.
|
||||||
|
- return explicitVisible && (!parentItem || QQuickItemPrivate::get(parentItem)->effectiveVisible);
|
||||||
|
+ // An item is visible if it is a child of a visible parent, and not explicitly hidden.
|
||||||
|
+ return explicitVisible && parentItem && QQuickItemPrivate::get(parentItem)->effectiveVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
|
||||||
|
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||||
|
index 42348d8dd1..34eefd85e6 100644
|
||||||
|
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||||
|
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||||
|
@@ -989,7 +989,9 @@ void tst_qquickitem::setParentItem()
|
||||||
|
|
||||||
|
void tst_qquickitem::visible()
|
||||||
|
{
|
||||||
|
+ QQuickWindow window;
|
||||||
|
QQuickItem *root = new QQuickItem;
|
||||||
|
+ root->setParentItem(window.contentItem());
|
||||||
|
|
||||||
|
QQuickItem *child1 = new QQuickItem;
|
||||||
|
child1->setParentItem(root);
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,51 @@
|
|||||||
|
From 9c27fd5c02dd4314192d142a9f2120be45748414 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Fushan Wen <qydwhotmail@gmail.com>
|
||||||
|
Date: Fri, 21 Apr 2023 23:38:04 +0800
|
||||||
|
Subject: [PATCH 20/25] Revert "QQuickItem: Fix effective visibility for items
|
||||||
|
without parent"
|
||||||
|
|
||||||
|
This breaks applications that use QQmlPropertyList to store QQuickItem
|
||||||
|
and don't set a parentItem for them.
|
||||||
|
|
||||||
|
Ref: https://github.com/musescore/MuseScore/issues/17276
|
||||||
|
|
||||||
|
This reverts commit 45c22a0221937682f4496801a495458a00f76d3a.
|
||||||
|
---
|
||||||
|
src/quick/items/qquickitem.cpp | 6 ++++--
|
||||||
|
tests/auto/quick/qquickitem/tst_qquickitem.cpp | 2 --
|
||||||
|
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
|
||||||
|
index 7236973216..708dc5fe5e 100644
|
||||||
|
--- a/src/quick/items/qquickitem.cpp
|
||||||
|
+++ b/src/quick/items/qquickitem.cpp
|
||||||
|
@@ -6082,8 +6082,10 @@ void QQuickItem::setEnabled(bool e)
|
||||||
|
|
||||||
|
bool QQuickItemPrivate::calcEffectiveVisible() const
|
||||||
|
{
|
||||||
|
- // An item is visible if it is a child of a visible parent, and not explicitly hidden.
|
||||||
|
- return explicitVisible && parentItem && QQuickItemPrivate::get(parentItem)->effectiveVisible;
|
||||||
|
+ // XXX todo - Should the effective visible of an element with no parent just be the current
|
||||||
|
+ // effective visible? This would prevent pointless re-processing in the case of an element
|
||||||
|
+ // moving to/from a no-parent situation, but it is different from what graphics view does.
|
||||||
|
+ return explicitVisible && (!parentItem || QQuickItemPrivate::get(parentItem)->effectiveVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
|
||||||
|
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||||
|
index 34eefd85e6..42348d8dd1 100644
|
||||||
|
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||||
|
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
|
||||||
|
@@ -989,9 +989,7 @@ void tst_qquickitem::setParentItem()
|
||||||
|
|
||||||
|
void tst_qquickitem::visible()
|
||||||
|
{
|
||||||
|
- QQuickWindow window;
|
||||||
|
QQuickItem *root = new QQuickItem;
|
||||||
|
- root->setParentItem(window.contentItem());
|
||||||
|
|
||||||
|
QQuickItem *child1 = new QQuickItem;
|
||||||
|
child1->setParentItem(root);
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,111 @@
|
|||||||
|
From 9a1488c33d888e8d22905373599219b1d716aa8a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Volker Hilsheimer <volker.hilsheimer@qt.io>
|
||||||
|
Date: Tue, 18 Apr 2023 22:05:36 +0200
|
||||||
|
Subject: [PATCH 21/25] Accessibility: respect value in attached Accessible in
|
||||||
|
controls
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
QQuickItemPrivate::accessibleRole is virtual and called by the framework
|
||||||
|
to determine the role of an item. The default implementation checks and
|
||||||
|
respects a possible Accessible attached object. However, subclasses that
|
||||||
|
override the virtual don't, so the attached properties are ignored, and
|
||||||
|
the class-specific implementation wins. This makes it impossible to
|
||||||
|
change the role of e.g. a checkable button.
|
||||||
|
|
||||||
|
To fix that, move the code respecting the attached object into a non-
|
||||||
|
virtual function that the framework calls instead, and only call the
|
||||||
|
virtual member if there is no attached object, or if that object is not
|
||||||
|
initialized with a role. Replace calls to the virtual from the
|
||||||
|
framework with calls to the non-virtual wrapper.
|
||||||
|
|
||||||
|
Do this for both QQuickItem and for QQuickPopup, and adjust the logic
|
||||||
|
in QQuickControl types that create an attached object and initialize
|
||||||
|
it's role when accessibility becomes active. Use the non-overridable
|
||||||
|
effective role value for that as well.
|
||||||
|
|
||||||
|
Add a test case, and to avoid any new framework calls to the virtual,
|
||||||
|
make it private.
|
||||||
|
|
||||||
|
Fixes: QTBUG-110114
|
||||||
|
Pick-to: 6.5 6.2
|
||||||
|
Change-Id: Ia709cecbd181b6d8ee3297a4af60c1e7db9a2c51
|
||||||
|
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
||||||
|
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
|
||||||
|
(cherry picked from commit 3c08d08ae2bbd449cc0579a1b3cb499383c7a60c)
|
||||||
|
---
|
||||||
|
src/quick/accessible/qaccessiblequickitem.cpp | 2 +-
|
||||||
|
src/quick/items/qquickitem.cpp | 17 ++++++++++++-----
|
||||||
|
src/quick/items/qquickitem_p.h | 3 +++
|
||||||
|
3 files changed, 16 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
|
||||||
|
index a8df58d450..99e6eff7c3 100644
|
||||||
|
--- a/src/quick/accessible/qaccessiblequickitem.cpp
|
||||||
|
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
|
||||||
|
@@ -230,7 +230,7 @@ QAccessible::Role QAccessibleQuickItem::role() const
|
||||||
|
|
||||||
|
QAccessible::Role role = QAccessible::NoRole;
|
||||||
|
if (item())
|
||||||
|
- role = QQuickItemPrivate::get(item())->accessibleRole();
|
||||||
|
+ role = QQuickItemPrivate::get(item())->effectiveAccessibleRole();
|
||||||
|
if (role == QAccessible::NoRole) {
|
||||||
|
if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item())))
|
||||||
|
role = QAccessible::StaticText;
|
||||||
|
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
|
||||||
|
index 708dc5fe5e..8b139cb539 100644
|
||||||
|
--- a/src/quick/items/qquickitem.cpp
|
||||||
|
+++ b/src/quick/items/qquickitem.cpp
|
||||||
|
@@ -2401,7 +2401,7 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#if QT_CONFIG(accessibility)
|
||||||
|
- QAccessible::Role role = QQuickItemPrivate::get(item)->accessibleRole();
|
||||||
|
+ QAccessible::Role role = QQuickItemPrivate::get(item)->effectiveAccessibleRole();
|
||||||
|
if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) {
|
||||||
|
return true;
|
||||||
|
} else if (role == QAccessible::ComboBox || role == QAccessible::SpinBox) {
|
||||||
|
@@ -9010,13 +9010,20 @@ QQuickItemPrivate::ExtraData::ExtraData()
|
||||||
|
|
||||||
|
|
||||||
|
#if QT_CONFIG(accessibility)
|
||||||
|
-QAccessible::Role QQuickItemPrivate::accessibleRole() const
|
||||||
|
+QAccessible::Role QQuickItemPrivate::effectiveAccessibleRole() const
|
||||||
|
{
|
||||||
|
Q_Q(const QQuickItem);
|
||||||
|
- QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false));
|
||||||
|
- if (accessibleAttached)
|
||||||
|
- return accessibleAttached->role();
|
||||||
|
+ auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false);
|
||||||
|
+ auto role = QAccessible::NoRole;
|
||||||
|
+ if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(attached))
|
||||||
|
+ role = accessibleAttached->role();
|
||||||
|
+ if (role == QAccessible::NoRole)
|
||||||
|
+ role = accessibleRole();
|
||||||
|
+ return role;
|
||||||
|
+}
|
||||||
|
|
||||||
|
+QAccessible::Role QQuickItemPrivate::accessibleRole() const
|
||||||
|
+{
|
||||||
|
return QAccessible::NoRole;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
|
||||||
|
index ade8fb61f2..6f329bd119 100644
|
||||||
|
--- a/src/quick/items/qquickitem_p.h
|
||||||
|
+++ b/src/quick/items/qquickitem_p.h
|
||||||
|
@@ -575,7 +575,10 @@ public:
|
||||||
|
virtual void implicitHeightChanged();
|
||||||
|
|
||||||
|
#if QT_CONFIG(accessibility)
|
||||||
|
+ QAccessible::Role effectiveAccessibleRole() const;
|
||||||
|
+private:
|
||||||
|
virtual QAccessible::Role accessibleRole() const;
|
||||||
|
+public:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setImplicitAntialiasing(bool antialiasing);
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,111 @@
|
|||||||
|
From 788c7ea1500dd6e82dd602fc51e5aa6f639bcf5e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||||
|
Date: Mon, 10 Jul 2023 07:43:28 +0200
|
||||||
|
Subject: [PATCH 22/25] QtQml: Clean up QQmlData ctor
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Initialize the "dummy" member even though we never use it. Static
|
||||||
|
analyzers complain about it and we may appreciate it having a defined
|
||||||
|
value in the future. Also, initialize other members inline where
|
||||||
|
possible.
|
||||||
|
|
||||||
|
Coverity-Id: 415867
|
||||||
|
Change-Id: Ie428eb3294d6363afe9d7ab2d2bed6e52df0b304
|
||||||
|
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
|
||||||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
(cherry picked from commit 10985a568db8cfb4140140967f7d247627ec4350)
|
||||||
|
|
||||||
|
* asturmlechner 2023-08-12: Resolve conflicts with dev branch commits
|
||||||
|
10985a568db8cfb4140140967f7d247627ec4350 and
|
||||||
|
e5246cafffb93f69a49c133210390c253fcb71f2 and
|
||||||
|
d3b3fef5a878d7fd53de6a9f9fff196a273930e3
|
||||||
|
---
|
||||||
|
src/qml/qml/qqmldata_p.h | 20 ++++++++++----------
|
||||||
|
src/qml/qml/qqmlengine.cpp | 7 ++-----
|
||||||
|
2 files changed, 12 insertions(+), 15 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
|
||||||
|
index ee31cb38d9..bb0adf9dfa 100644
|
||||||
|
--- a/src/qml/qml/qqmldata_p.h
|
||||||
|
+++ b/src/qml/qml/qqmldata_p.h
|
||||||
|
@@ -187,7 +187,7 @@ public:
|
||||||
|
private:
|
||||||
|
void layout(QQmlNotifierEndpoint*);
|
||||||
|
};
|
||||||
|
- NotifyList *notifyList;
|
||||||
|
+ NotifyList *notifyList = nullptr;
|
||||||
|
|
||||||
|
inline QQmlNotifierEndpoint *notify(int index);
|
||||||
|
void addNotify(int index, QQmlNotifierEndpoint *);
|
||||||
|
@@ -201,12 +201,12 @@ public:
|
||||||
|
QQmlContextData *outerContext = nullptr;
|
||||||
|
QQmlContextDataRef ownContext;
|
||||||
|
|
||||||
|
- QQmlAbstractBinding *bindings;
|
||||||
|
- QQmlBoundSignal *signalHandlers;
|
||||||
|
+ QQmlAbstractBinding *bindings = nullptr;
|
||||||
|
+ QQmlBoundSignal *signalHandlers = nullptr;
|
||||||
|
|
||||||
|
// Linked list for QQmlContext::contextObjects
|
||||||
|
- QQmlData *nextContextObject;
|
||||||
|
- QQmlData**prevContextObject;
|
||||||
|
+ QQmlData *nextContextObject = nullptr;
|
||||||
|
+ QQmlData**prevContextObject = nullptr;
|
||||||
|
|
||||||
|
inline bool hasBindingBit(int) const;
|
||||||
|
inline void setBindingBit(QObject *obj, int);
|
||||||
|
@@ -216,10 +216,10 @@ public:
|
||||||
|
inline void setPendingBindingBit(QObject *obj, int);
|
||||||
|
inline void clearPendingBindingBit(int);
|
||||||
|
|
||||||
|
- quint16 lineNumber;
|
||||||
|
- quint16 columnNumber;
|
||||||
|
+ quint16 lineNumber = 0;
|
||||||
|
+ quint16 columnNumber = 0;
|
||||||
|
|
||||||
|
- quint32 jsEngineId; // id of the engine that created the jsWrapper
|
||||||
|
+ quint32 jsEngineId = 0; // id of the engine that created the jsWrapper
|
||||||
|
|
||||||
|
struct DeferredData {
|
||||||
|
DeferredData();
|
||||||
|
@@ -240,7 +240,7 @@ public:
|
||||||
|
|
||||||
|
QQmlPropertyCache *propertyCache;
|
||||||
|
|
||||||
|
- QQmlGuardImpl *guards;
|
||||||
|
+ QQmlGuardImpl *guards = 0;
|
||||||
|
|
||||||
|
static QQmlData *get(const QObject *object, bool create = false) {
|
||||||
|
QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
|
||||||
|
@@ -289,7 +289,7 @@ public:
|
||||||
|
|
||||||
|
private:
|
||||||
|
// For attachedProperties
|
||||||
|
- mutable QQmlDataExtended *extendedData;
|
||||||
|
+ mutable QQmlDataExtended *extendedData = nullptr;
|
||||||
|
|
||||||
|
Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv);
|
||||||
|
Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object);
|
||||||
|
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
|
||||||
|
index 852a673ebd..86a2d2b45a 100644
|
||||||
|
--- a/src/qml/qml/qqmlengine.cpp
|
||||||
|
+++ b/src/qml/qml/qqmlengine.cpp
|
||||||
|
@@ -725,11 +725,8 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
|
||||||
|
QQmlData::QQmlData()
|
||||||
|
: ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
|
||||||
|
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
|
||||||
|
- hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
|
||||||
|
- bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
|
||||||
|
- bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
|
||||||
|
- lineNumber(0), columnNumber(0), jsEngineId(0),
|
||||||
|
- propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
|
||||||
|
+ hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), dummy(0),
|
||||||
|
+ bindingBitsArraySize(InlineBindingArraySize), propertyCache(nullptr)
|
||||||
|
{
|
||||||
|
memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
|
||||||
|
init();
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,277 @@
|
|||||||
|
From d15877e074b5e7c0e61589168b5eaaced7e55bf4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||||
|
Date: Tue, 8 Aug 2023 14:54:01 +0200
|
||||||
|
Subject: [PATCH 23/25] QML: Make notify list thread safe
|
||||||
|
|
||||||
|
We keep the notifyList itself alive until the QQmlData itself is
|
||||||
|
deleted. This way any isSignalConnected() called while an
|
||||||
|
intermediate dtor runs can safely access it. We use atomics to make the
|
||||||
|
concurrent access to the pointer and the connection mask defined
|
||||||
|
behavior. However, we never need anything but relaxed semantics when
|
||||||
|
accessing it.
|
||||||
|
|
||||||
|
Pick-to: 5.15 6.2 6.5 6.6
|
||||||
|
Fixes: QTBUG-105090
|
||||||
|
Change-Id: I82537be86e5cc33c2a3d76ec639fcbac87eb45ad
|
||||||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
||||||
|
(cherry picked from commit 691956654c1acab356ce704c58602cc3a99fabc3)
|
||||||
|
|
||||||
|
* asturmlechner 2023-08-12: Resolve conflict with dev branch commit
|
||||||
|
c249edb83fa67b3e5f711b28923397e66876182d which introduces a behavior
|
||||||
|
change, so cannot be backported. Applied changes logically as if that
|
||||||
|
commit never happened.
|
||||||
|
---
|
||||||
|
src/qml/qml/qqmldata_p.h | 66 ++++++++++++++++++-----------
|
||||||
|
src/qml/qml/qqmlengine.cpp | 85 +++++++++++++++++++++++++-------------
|
||||||
|
2 files changed, 99 insertions(+), 52 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
|
||||||
|
index bb0adf9dfa..187339169b 100644
|
||||||
|
--- a/src/qml/qml/qqmldata_p.h
|
||||||
|
+++ b/src/qml/qml/qqmldata_p.h
|
||||||
|
@@ -176,24 +176,24 @@ public:
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NotifyList {
|
||||||
|
- quint64 connectionMask;
|
||||||
|
-
|
||||||
|
- quint16 maximumTodoIndex;
|
||||||
|
- quint16 notifiesSize;
|
||||||
|
-
|
||||||
|
- QQmlNotifierEndpoint *todo;
|
||||||
|
- QQmlNotifierEndpoint**notifies;
|
||||||
|
+ QAtomicInteger<quint64> connectionMask;
|
||||||
|
+ QQmlNotifierEndpoint *todo = nullptr;
|
||||||
|
+ QQmlNotifierEndpoint**notifies = nullptr;
|
||||||
|
+ quint16 maximumTodoIndex = 0;
|
||||||
|
+ quint16 notifiesSize = 0;
|
||||||
|
void layout();
|
||||||
|
private:
|
||||||
|
void layout(QQmlNotifierEndpoint*);
|
||||||
|
};
|
||||||
|
- NotifyList *notifyList = nullptr;
|
||||||
|
+ QAtomicPointer<NotifyList> notifyList;
|
||||||
|
|
||||||
|
- inline QQmlNotifierEndpoint *notify(int index);
|
||||||
|
+ inline QQmlNotifierEndpoint *notify(int index) const;
|
||||||
|
void addNotify(int index, QQmlNotifierEndpoint *);
|
||||||
|
int endpointCount(int index);
|
||||||
|
bool signalHasEndpoint(int index) const;
|
||||||
|
- void disconnectNotifiers();
|
||||||
|
+
|
||||||
|
+ enum class DeleteNotifyList { Yes, No };
|
||||||
|
+ void disconnectNotifiers(DeleteNotifyList doDelete);
|
||||||
|
|
||||||
|
// The context that created the C++ object
|
||||||
|
QQmlContextData *context = nullptr;
|
||||||
|
@@ -240,7 +240,7 @@ public:
|
||||||
|
|
||||||
|
QQmlPropertyCache *propertyCache;
|
||||||
|
|
||||||
|
- QQmlGuardImpl *guards = 0;
|
||||||
|
+ QQmlGuardImpl *guards = nullptr;
|
||||||
|
|
||||||
|
static QQmlData *get(const QObject *object, bool create = false) {
|
||||||
|
QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
|
||||||
|
@@ -342,23 +342,31 @@ bool QQmlData::wasDeleted(const QObject *object)
|
||||||
|
return ddata && ddata->isQueuedForDeletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
-QQmlNotifierEndpoint *QQmlData::notify(int index)
|
||||||
|
+inline bool isIndexInConnectionMask(quint64 connectionMask, int index)
|
||||||
|
+{
|
||||||
|
+ return connectionMask & (1ULL << quint64(index % 64));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+QQmlNotifierEndpoint *QQmlData::notify(int index) const
|
||||||
|
{
|
||||||
|
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||||||
|
+
|
||||||
|
Q_ASSERT(index <= 0xFFFF);
|
||||||
|
|
||||||
|
- if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) {
|
||||||
|
+ NotifyList *list = notifyList.loadRelaxed();
|
||||||
|
+ if (!list || !isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index))
|
||||||
|
return nullptr;
|
||||||
|
- } else if (index < notifyList->notifiesSize) {
|
||||||
|
- return notifyList->notifies[index];
|
||||||
|
- } else if (index <= notifyList->maximumTodoIndex) {
|
||||||
|
- notifyList->layout();
|
||||||
|
- }
|
||||||
|
|
||||||
|
- if (index < notifyList->notifiesSize) {
|
||||||
|
- return notifyList->notifies[index];
|
||||||
|
- } else {
|
||||||
|
- return nullptr;
|
||||||
|
+ if (index < list->notifiesSize)
|
||||||
|
+ return list->notifies[index];
|
||||||
|
+
|
||||||
|
+ if (index <= list->maximumTodoIndex) {
|
||||||
|
+ list->layout();
|
||||||
|
+ if (index < list->notifiesSize)
|
||||||
|
+ return list->notifies[index];
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -367,7 +375,19 @@ QQmlNotifierEndpoint *QQmlData::notify(int index)
|
||||||
|
*/
|
||||||
|
inline bool QQmlData::signalHasEndpoint(int index) const
|
||||||
|
{
|
||||||
|
- return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
|
||||||
|
+ // This can be called from any thread.
|
||||||
|
+ // We still use relaxed semantics. If we're on a thread different from the "home" thread
|
||||||
|
+ // of the QQmlData, two interesting things might happen:
|
||||||
|
+ //
|
||||||
|
+ // 1. The list might go away while we hold it. In that case we are dealing with an object whose
|
||||||
|
+ // QObject dtor is being executed concurrently. This is UB already without the notify lists.
|
||||||
|
+ // Therefore, we don't need to consider it.
|
||||||
|
+ // 2. The connectionMask may be amended or zeroed while we are looking at it. In that case
|
||||||
|
+ // we "misreport" the endpoint. Since ordering of events across threads is inherently
|
||||||
|
+ // nondeterministic, either result is correct in that case. We can accept it.
|
||||||
|
+
|
||||||
|
+ NotifyList *list = notifyList.loadRelaxed();
|
||||||
|
+ return list && isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQmlData::hasBindingBit(int coreIndex) const
|
||||||
|
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
|
||||||
|
index 86a2d2b45a..d6b2711c2d 100644
|
||||||
|
--- a/src/qml/qml/qqmlengine.cpp
|
||||||
|
+++ b/src/qml/qml/qqmlengine.cpp
|
||||||
|
@@ -718,7 +718,7 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
|
||||||
|
// Disconnect the notifiers now - during object destruction this would be too late, since
|
||||||
|
// the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
|
||||||
|
// get the metaobject anymore.
|
||||||
|
- d->disconnectNotifiers();
|
||||||
|
+ d->disconnectNotifiers(QQmlData::DeleteNotifyList::No);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -786,7 +786,10 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
|
||||||
|
// QQmlEngine to emit signals from a different thread. These signals are then automatically
|
||||||
|
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
|
||||||
|
// by the qqmlecmascript::threadSignal() autotest.
|
||||||
|
- if (!ddata->notifyList)
|
||||||
|
+
|
||||||
|
+ // Relaxed semantics here. If we're on a different thread we might schedule a useless event,
|
||||||
|
+ // but that should be rare.
|
||||||
|
+ if (!ddata->notifyList.loadRelaxed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
|
||||||
|
@@ -1832,49 +1835,73 @@ void QQmlData::releaseDeferredData()
|
||||||
|
|
||||||
|
void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
|
||||||
|
{
|
||||||
|
- if (!notifyList) {
|
||||||
|
- notifyList = (NotifyList *)malloc(sizeof(NotifyList));
|
||||||
|
- notifyList->connectionMask = 0;
|
||||||
|
- notifyList->maximumTodoIndex = 0;
|
||||||
|
- notifyList->notifiesSize = 0;
|
||||||
|
- notifyList->todo = nullptr;
|
||||||
|
- notifyList->notifies = nullptr;
|
||||||
|
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||||||
|
+
|
||||||
|
+ NotifyList *list = notifyList.loadRelaxed();
|
||||||
|
+
|
||||||
|
+ if (!list) {
|
||||||
|
+ list = new NotifyList;
|
||||||
|
+ // We don't really care when this change takes effect on other threads. The notifyList can
|
||||||
|
+ // only become non-null once in the life time of a QQmlData. It becomes null again when the
|
||||||
|
+ // underlying QObject is deleted. At that point any interaction with the QQmlData is UB
|
||||||
|
+ // anyway. So, for all intents and purposese, the list becomes non-null once and then stays
|
||||||
|
+ // non-null "forever". We can apply relaxed semantics.
|
||||||
|
+ notifyList.storeRelaxed(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!endpoint->isConnected());
|
||||||
|
|
||||||
|
index = qMin(index, 0xFFFF - 1);
|
||||||
|
- notifyList->connectionMask |= (1ULL << quint64(index % 64));
|
||||||
|
|
||||||
|
- if (index < notifyList->notifiesSize) {
|
||||||
|
+ // Likewise, we don't really care _when_ the change in the connectionMask is propagated to other
|
||||||
|
+ // threads. Cross-thread event ordering is inherently nondeterministic. Therefore, when querying
|
||||||
|
+ // the conenctionMask in the presence of concurrent modification, any result is correct.
|
||||||
|
+ list->connectionMask.storeRelaxed(
|
||||||
|
+ list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64)));
|
||||||
|
|
||||||
|
- endpoint->next = notifyList->notifies[index];
|
||||||
|
+ if (index < list->notifiesSize) {
|
||||||
|
+ endpoint->next = list->notifies[index];
|
||||||
|
if (endpoint->next) endpoint->next->prev = &endpoint->next;
|
||||||
|
- endpoint->prev = ¬ifyList->notifies[index];
|
||||||
|
- notifyList->notifies[index] = endpoint;
|
||||||
|
-
|
||||||
|
+ endpoint->prev = &list->notifies[index];
|
||||||
|
+ list->notifies[index] = endpoint;
|
||||||
|
} else {
|
||||||
|
- notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
|
||||||
|
+ list->maximumTodoIndex = qMax(int(list->maximumTodoIndex), index);
|
||||||
|
|
||||||
|
- endpoint->next = notifyList->todo;
|
||||||
|
+ endpoint->next = list->todo;
|
||||||
|
if (endpoint->next) endpoint->next->prev = &endpoint->next;
|
||||||
|
- endpoint->prev = ¬ifyList->todo;
|
||||||
|
- notifyList->todo = endpoint;
|
||||||
|
+ endpoint->prev = &list->todo;
|
||||||
|
+ list->todo = endpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-void QQmlData::disconnectNotifiers()
|
||||||
|
+void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete)
|
||||||
|
{
|
||||||
|
- if (notifyList) {
|
||||||
|
- while (notifyList->todo)
|
||||||
|
- notifyList->todo->disconnect();
|
||||||
|
- for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
|
||||||
|
- while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
|
||||||
|
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
|
||||||
|
+ if (NotifyList *list = notifyList.loadRelaxed()) {
|
||||||
|
+ while (QQmlNotifierEndpoint *todo = list->todo)
|
||||||
|
+ todo->disconnect();
|
||||||
|
+ for (int ii = 0; ii < list->notifiesSize; ++ii) {
|
||||||
|
+ while (QQmlNotifierEndpoint *ep = list->notifies[ii])
|
||||||
|
ep->disconnect();
|
||||||
|
}
|
||||||
|
- free(notifyList->notifies);
|
||||||
|
- free(notifyList);
|
||||||
|
- notifyList = nullptr;
|
||||||
|
+ free(list->notifies);
|
||||||
|
+
|
||||||
|
+ if (doDelete == DeleteNotifyList::Yes) {
|
||||||
|
+ // We can only get here from QQmlData::destroyed(), and that can only come from the
|
||||||
|
+ // the QObject dtor. If you're still sending signals at that point you have UB already
|
||||||
|
+ // without any threads. Therefore, it's enough to apply relaxed semantics.
|
||||||
|
+ notifyList.storeRelaxed(nullptr);
|
||||||
|
+ delete list;
|
||||||
|
+ } else {
|
||||||
|
+ // We can use relaxed semantics here. The worst thing that can happen is that some
|
||||||
|
+ // signal is falsely reported as connected. Signal connectedness across threads
|
||||||
|
+ // is not quite deterministic anyway.
|
||||||
|
+ list->connectionMask.storeRelaxed(0);
|
||||||
|
+ list->maximumTodoIndex = 0;
|
||||||
|
+ list->notifiesSize = 0;
|
||||||
|
+ list->notifies = nullptr;
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1958,7 +1985,7 @@ void QQmlData::destroyed(QObject *object)
|
||||||
|
guard->objectDestroyed(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
- disconnectNotifiers();
|
||||||
|
+ disconnectNotifiers(DeleteNotifyList::Yes);
|
||||||
|
|
||||||
|
if (extendedData)
|
||||||
|
delete extendedData;
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
From 83cac09d86872edaa6fd4779597d6ba0bc4d2a8e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ulf Hermann <ulf.hermann@qt.io>
|
||||||
|
Date: Wed, 8 Feb 2023 12:14:21 +0100
|
||||||
|
Subject: [PATCH 24/25] QML: Fortify qmlExecuteDeferred some more
|
||||||
|
|
||||||
|
I don't know how to trigger this, but a recent crash report from the CI
|
||||||
|
shows that we can get there without a valid engine.
|
||||||
|
|
||||||
|
Pick-to: 6.5
|
||||||
|
Change-Id: I9f17894da82b8e7eab88181c96dfa8eaf7795523
|
||||||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
(cherry picked from commit f69b6f0940b178b46ecbaa5f0b4956ac44e8379e)
|
||||||
|
---
|
||||||
|
src/qml/qml/qqmlengine.cpp | 21 +++++++++++++--------
|
||||||
|
1 file changed, 13 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
|
||||||
|
index d6b2711c2d..5f3367e4d2 100644
|
||||||
|
--- a/src/qml/qml/qqmlengine.cpp
|
||||||
|
+++ b/src/qml/qml/qqmlengine.cpp
|
||||||
|
@@ -1588,17 +1588,22 @@ void qmlExecuteDeferred(QObject *object)
|
||||||
|
{
|
||||||
|
QQmlData *data = QQmlData::get(object);
|
||||||
|
|
||||||
|
- if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
|
||||||
|
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
|
||||||
|
+ if (!data
|
||||||
|
+ || !data->context
|
||||||
|
+ || !data->context->engine
|
||||||
|
+ || data->deferredData.isEmpty()
|
||||||
|
+ || data->wasDeleted(object)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- QQmlComponentPrivate::DeferredState state;
|
||||||
|
- QQmlComponentPrivate::beginDeferred(ep, object, &state);
|
||||||
|
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
|
||||||
|
+ QQmlComponentPrivate::DeferredState state;
|
||||||
|
+ QQmlComponentPrivate::beginDeferred(ep, object, &state);
|
||||||
|
|
||||||
|
- // Release the reference for the deferral action (we still have one from construction)
|
||||||
|
- data->releaseDeferredData();
|
||||||
|
+ // Release the reference for the deferral action (we still have one from construction)
|
||||||
|
+ data->releaseDeferredData();
|
||||||
|
|
||||||
|
- QQmlComponentPrivate::completeDeferred(ep, &state);
|
||||||
|
- }
|
||||||
|
+ QQmlComponentPrivate::completeDeferred(ep, &state);
|
||||||
|
}
|
||||||
|
|
||||||
|
QQmlContext *qmlContext(const QObject *obj)
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,52 @@
|
|||||||
|
From 310c124dac82d711ab15309a9cb0b9d95db9ea8f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Antonio Napolitano <anton@polit.no>
|
||||||
|
Date: Sat, 30 Dec 2023 19:11:32 +0100
|
||||||
|
Subject: [PATCH 25/25] masm: Don't crash on failed MADV_DONTNEED on Linux
|
||||||
|
|
||||||
|
The application could call mlockall(MCL_CURRENT|MCL_FUTURE) to lock all
|
||||||
|
its memory for performance reasons, causing the madvise call to fail.
|
||||||
|
There's no need to crash. Instead, manually zero-out the memory when
|
||||||
|
decommitting.
|
||||||
|
|
||||||
|
Fixes: QTBUG-120450
|
||||||
|
Pick-to: 5.15 6.2 6.5 6.6 6.7
|
||||||
|
Change-Id: I6f1a8968853cc5e61561371bd2a435a686eaf0e4
|
||||||
|
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
||||||
|
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
|
||||||
|
(cherry picked from commit 524d260c5c135d193e06350e48357444ddb13ddb)
|
||||||
|
---
|
||||||
|
src/3rdparty/masm/wtf/OSAllocatorPosix.cpp | 11 +++++------
|
||||||
|
1 file changed, 5 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
|
||||||
|
index b5c5f6a2b0..1a3d3cdf97 100644
|
||||||
|
--- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
|
||||||
|
+++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
|
||||||
|
@@ -112,10 +112,7 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable,
|
||||||
|
if (result == MAP_FAILED)
|
||||||
|
CRASH();
|
||||||
|
|
||||||
|
- while (madvise(result, bytes, MADV_DONTNEED)) {
|
||||||
|
- if (errno != EAGAIN)
|
||||||
|
- CRASH();
|
||||||
|
- }
|
||||||
|
+ while (madvise(result, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
|
||||||
|
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
@@ -248,8 +245,10 @@ void OSAllocator::decommit(void* address, size_t bytes)
|
||||||
|
mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
|
#elif OS(LINUX)
|
||||||
|
while (madvise(address, bytes, MADV_DONTNEED)) {
|
||||||
|
- if (errno != EAGAIN)
|
||||||
|
- CRASH();
|
||||||
|
+ if (errno != EAGAIN) {
|
||||||
|
+ memset(address, 0, bytes); // We rely on madvise to zero-out the memory
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
if (mprotect(address, bytes, PROT_NONE))
|
||||||
|
CRASH();
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -1,44 +0,0 @@
|
|||||||
From e2bdde18d9758efdc6a0d7d106aad56995df1271 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ulf Hermann <ulf.hermann@qt.io>
|
|
||||||
Date: Wed, 15 Mar 2023 08:59:43 +0100
|
|
||||||
Subject: [PATCH] JIT: Add missing {STORE|LOAD}_ACC() to CreateCallContext
|
|
||||||
|
|
||||||
We cannot assume anything about the accumulator register after calling
|
|
||||||
PushCallContext::call(). Also add a note about not needing to re-load
|
|
||||||
the accumulator on ThrowException.
|
|
||||||
|
|
||||||
Pick-to: 6.5 6.2 5.15
|
|
||||||
Fixes: QTBUG-111935
|
|
||||||
Change-Id: I7196585e1d2697c215f4fe87d8d7ac9b98b622a3
|
|
||||||
---
|
|
||||||
src/qml/jit/qv4baselinejit.cpp | 4 ++++
|
|
||||||
1 file changed, 4 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
|
|
||||||
index 14e183adb8..1d65169dce 100644
|
|
||||||
--- a/src/qml/jit/qv4baselinejit.cpp
|
|
||||||
+++ b/src/qml/jit/qv4baselinejit.cpp
|
|
||||||
@@ -506,6 +506,8 @@ void BaselineJIT::generate_ThrowException()
|
|
||||||
as->passEngineAsArg(0);
|
|
||||||
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
|
|
||||||
as->gotoCatchException();
|
|
||||||
+
|
|
||||||
+ // LOAD_ACC(); <- not needed here since it would be unreachable.
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaselineJIT::generate_GetException() { as->getException(); }
|
|
||||||
@@ -513,9 +515,11 @@ void BaselineJIT::generate_SetException() { as->setException(); }
|
|
||||||
|
|
||||||
void BaselineJIT::generate_CreateCallContext()
|
|
||||||
{
|
|
||||||
+ STORE_ACC();
|
|
||||||
as->prepareCallWithArgCount(1);
|
|
||||||
as->passCppFrameAsArg(0);
|
|
||||||
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
|
|
||||||
+ LOAD_ACC();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
|
|
||||||
--
|
|
||||||
2.39.2
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
|
|
||||||
index 621e8bb4..24ea2201 100644
|
|
||||||
--- a/tests/auto/qml/qml.pro
|
|
||||||
+++ b/tests/auto/qml/qml.pro
|
|
||||||
@@ -25,7 +25,6 @@ PUBLICTESTS += \
|
|
||||||
qqmlmoduleplugin \
|
|
||||||
qqmlnotifier \
|
|
||||||
qqmlqt \
|
|
||||||
- qqmlxmlhttprequest \
|
|
||||||
qqmlpromise \
|
|
||||||
qtqmlmodules \
|
|
||||||
qquickfolderlistmodel \
|
|
Loading…
Reference in new issue