diff options
| author | Mitch Curtis <mitch.curtis@qt.io> | 2025-09-19 09:48:16 +0800 |
|---|---|---|
| committer | Mitch Curtis <mitch.curtis@qt.io> | 2025-10-01 12:07:32 +0800 |
| commit | b1ee7061ba77a7f5dc4148129bb2083f5c28e039 (patch) | |
| tree | 1034050ab3342a7f0b76f98f0b5414d7c1c11631 /src/quicktemplates/qquickstackelement.cpp | |
| parent | 8a7973f6f58c8e8df926b879147d854b9d0f666f (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.cpp | 33 |
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()); |
