aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates/qquickstackelement.cpp
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2025-09-19 09:48:16 +0800
committerMitch Curtis <mitch.curtis@qt.io>2025-10-01 12:07:32 +0800
commitb1ee7061ba77a7f5dc4148129bb2083f5c28e039 (patch)
tree1034050ab3342a7f0b76f98f0b5414d7c1c11631 /src/quicktemplates/qquickstackelement.cpp
parent8a7973f6f58c8e8df926b879147d854b9d0f666f (diff)
StackView: don't load new items if QML engine is null
In the linked bug report, a Loader is deactivated after an Image within it has started loading. A slot was connected to the statusChanged signal of the Image, which calls replace(). This caused an assertion failure because the StackView's QML engine was null. Note that it's not enough to check if the QML context is non-null, because it still is at that point. There isn't an easy way to check for this in one place in QQuickStackView, let alone in user code, so we need a lot of engine checks. Add a C++ test for StackView, as I wasn't able to get it to crash with a QML-only test. For now we only need to test the Basic style, since most styles don't provide anything too interesting or complex for StackView. Fixes: QTBUG-140018 Pick-to: 6.8 6.10 Change-Id: I53ba016bf44c46b7734b0b2daeeb62177f9067db Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/quicktemplates/qquickstackelement.cpp')
-rw-r--r--src/quicktemplates/qquickstackelement.cpp33
1 files changed, 19 insertions, 14 deletions
diff --git a/src/quicktemplates/qquickstackelement.cpp b/src/quicktemplates/qquickstackelement.cpp
index 032596d53d..f8039f3bde 100644
--- a/src/quicktemplates/qquickstackelement.cpp
+++ b/src/quicktemplates/qquickstackelement.cpp
@@ -40,7 +40,10 @@ protected:
void setInitialState(QObject *object) override
{
auto privIncubator = QQmlIncubatorPrivate::get(this);
- element->incubate(object, privIncubator->requiredProperties());
+ if (QQmlEnginePrivate *enginePriv = privIncubator->enginePriv) {
+ element->incubate(enginePriv->v4Engine.get(), object,
+ privIncubator->requiredProperties());
+ }
}
private:
@@ -91,7 +94,8 @@ QQuickStackElement::~QQuickStackElement()
#endif
}
-QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickStackView *view, QString *error)
+QQuickStackElement *QQuickStackElement::fromString(
+ QQmlEngine *engine, const QString &str, QQuickStackView *view, QString *error)
{
QUrl url(str);
if (!url.isValid()) {
@@ -103,7 +107,7 @@ QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickSta
url = qmlContext(view)->resolvedUrl(url);
QQuickStackElement *element = new QQuickStackElement;
- element->component = new QQmlComponent(qmlEngine(view), url, view);
+ element->component = new QQmlComponent(engine, url, view);
element->ownComponent = true;
return element;
}
@@ -128,7 +132,8 @@ QQuickStackElement *QQuickStackElement::fromObject(QObject *object, QQuickStackV
return element;
}
-QQuickStackElement *QQuickStackElement::fromStackViewArg(QQuickStackView *view, QQuickStackViewArg arg)
+QQuickStackElement *QQuickStackElement::fromStackViewArg(
+ QQmlEngine *engine, QQuickStackView *view, QQuickStackViewArg arg)
{
QQuickStackElement *element = new QQuickStackElement;
#if QT_CONFIG(quick_viewtransitions)
@@ -145,7 +150,7 @@ QQuickStackElement *QQuickStackElement::fromStackViewArg(QQuickStackView *view,
Q_ASSERT(!arg.mUrl.isValid());
} else if (arg.mUrl.isValid()) {
- element->component = new QQmlComponent(qmlEngine(view), arg.mUrl, view);
+ element->component = new QQmlComponent(engine, arg.mUrl, view);
element->ownComponent = true;
} else {
qFatal("No Item, Component or URL set on arg passed to fromStrictArg");
@@ -153,7 +158,7 @@ QQuickStackElement *QQuickStackElement::fromStackViewArg(QQuickStackView *view,
return element;
}
-bool QQuickStackElement::load(QQuickStackView *parent)
+bool QQuickStackElement::load(QV4::ExecutionEngine *v4, QQuickStackView *parent)
{
setView(parent);
if (!item) {
@@ -162,7 +167,7 @@ bool QQuickStackElement::load(QQuickStackView *parent)
if (component->isLoading()) {
QObject::connect(component, &QQmlComponent::statusChanged, [this](QQmlComponent::Status status) {
if (status == QQmlComponent::Ready)
- load(view);
+ load(component->engine()->handle(), view);
else if (status == QQmlComponent::Error)
QQuickStackViewPrivate::get(view)->warn(component->errorString().trimmed());
});
@@ -178,22 +183,24 @@ bool QQuickStackElement::load(QQuickStackView *parent)
if (component->isError())
QQuickStackViewPrivate::get(parent)->warn(component->errorString().trimmed());
} else {
- initialize(/*required properties=*/nullptr);
+ initialize(v4, /*required properties=*/nullptr);
}
return item;
}
-void QQuickStackElement::incubate(QObject *object, RequiredProperties *requiredProperties)
+void QQuickStackElement::incubate(
+ QV4::ExecutionEngine *v4, QObject *object, RequiredProperties *requiredProperties)
{
item = qmlobject_cast<QQuickItem *>(object);
if (item) {
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
item->setParent(view);
- initialize(requiredProperties);
+ initialize(v4, requiredProperties);
}
}
-void QQuickStackElement::initialize(RequiredProperties *requiredProperties)
+void QQuickStackElement::initialize(
+ QV4::ExecutionEngine *v4, RequiredProperties *requiredProperties)
{
if (!item || init)
return;
@@ -206,9 +213,7 @@ void QQuickStackElement::initialize(RequiredProperties *requiredProperties)
item->setParentItem(view);
if (!properties.isUndefined()) {
- QQmlEngine *engine = qmlEngine(view);
- Q_ASSERT(engine);
- QV4::Scope scope(engine->handle());
+ QV4::Scope scope(v4);
Q_ASSERT(scope.engine);
QV4::ScopedValue ipv(scope, properties.value());
QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value());