https://bugs.kde.org/show_bug.cgi?id=509192 https://bugreports.qt.io/browse/QTBUG-140018 https://codereview.qt-project.org/c/qt/qtdeclarative/+/681080 --- a/src/quicktemplates/qquickstackelement.cpp +++ b/src/quicktemplates/qquickstackelement.cpp @@ -41,3 +41,5 @@ auto privIncubator = QQmlIncubatorPrivate::get(this); - element->incubate(object, privIncubator->requiredProperties()); + if (QQmlEnginePrivate *enginePriv = privIncubator->enginePriv) { + element->incubate(enginePriv->v4engine(), object, privIncubator->requiredProperties()); + } } @@ -92,3 +94,4 @@ -QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickStackView *view, QString *error) +QQuickStackElement *QQuickStackElement::fromString( + QQmlEngine *engine, const QString &str, QQuickStackView *view, QString *error) { @@ -104,3 +107,3 @@ QQuickStackElement *element = new QQuickStackElement; - element->component = new QQmlComponent(qmlEngine(view), url, view); + element->component = new QQmlComponent(engine, url, view); element->ownComponent = true; @@ -129,3 +132,4 @@ -QQuickStackElement *QQuickStackElement::fromStackViewArg(QQuickStackView *view, QQuickStackViewArg arg) +QQuickStackElement *QQuickStackElement::fromStackViewArg( + QQmlEngine *engine, QQuickStackView *view, QQuickStackViewArg arg) { @@ -146,3 +150,3 @@ } 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; @@ -154,3 +158,3 @@ -bool QQuickStackElement::load(QQuickStackView *parent) +bool QQuickStackElement::load(QV4::ExecutionEngine *v4, QQuickStackView *parent) { @@ -163,3 +167,3 @@ if (status == QQmlComponent::Ready) - load(view); + load(component->engine()->handle(), view); else if (status == QQmlComponent::Error) @@ -179,3 +183,3 @@ } else { - initialize(/*required properties=*/nullptr); + initialize(v4, /*required properties=*/nullptr); } @@ -184,3 +188,4 @@ -void QQuickStackElement::incubate(QObject *object, RequiredProperties *requiredProperties) +void QQuickStackElement::incubate( + QV4::ExecutionEngine *v4, QObject *object, RequiredProperties *requiredProperties) { @@ -190,3 +195,3 @@ item->setParent(view); - initialize(requiredProperties); + initialize(v4, requiredProperties); } @@ -194,3 +199,4 @@ -void QQuickStackElement::initialize(RequiredProperties *requiredProperties) +void QQuickStackElement::initialize( + QV4::ExecutionEngine *v4, RequiredProperties *requiredProperties) { @@ -207,7 +213,4 @@ if (!properties.isUndefined()) { - QQmlEngine *engine = qmlEngine(view); - Q_ASSERT(engine); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine); - Q_ASSERT(v4); QV4::Scope scope(v4); + Q_ASSERT(scope.engine); QV4::ScopedValue ipv(scope, properties.value()); --- a/src/quicktemplates/qquickstackelement_p_p.h +++ b/src/quicktemplates/qquickstackelement_p_p.h @@ -45,9 +45,10 @@ - static QQuickStackElement *fromString(const QString &str, QQuickStackView *view, QString *error); + static QQuickStackElement *fromString(QQmlEngine *engine, const QString &str, QQuickStackView *view, QString *error); static QQuickStackElement *fromObject(QObject *object, QQuickStackView *view, QString *error); - static QQuickStackElement *fromStackViewArg(QQuickStackView *view, QQuickStackViewArg arg); + static QQuickStackElement *fromStackViewArg(QQmlEngine *engine, QQuickStackView *view, QQuickStackViewArg arg); - bool load(QQuickStackView *parent); - void incubate(QObject *object, RequiredProperties *requiredProperties); - void initialize(RequiredProperties *requiredProperties); + bool load(QV4::ExecutionEngine *v4, QQuickStackView *parent); + void incubate( + QV4::ExecutionEngine *v4, QObject *object, RequiredProperties *requiredProperties); + void initialize(QV4::ExecutionEngine *v4, RequiredProperties *requiredProperties); --- a/src/quicktemplates/qquickstackview.cpp +++ b/src/quicktemplates/qquickstackview.cpp @@ -459,4 +459,8 @@ if (element) { - if (behavior == ForceLoad) - element->load(this); + if (behavior == ForceLoad) { + // It's possible for a slot to still be connected during destruction of the receiver's + // parent (QTBUG-140018), so only try to load new things if our engine is alive. + if (QQmlEngine *engine = qmlEngine(this)) + element->load(engine->handle(), this); + } return element->item; @@ -494,3 +498,3 @@ if (behavior == ForceLoad) - element->load(this); + element->load(engine->handle(), this); if (element->item) { @@ -626,3 +630,3 @@ int oldDepth = d->elements.size(); - if (d->pushElements(elements)) { + if (d->pushElements(v4, elements)) { d->depthChange(d->elements.size(), oldDepth); @@ -739,3 +743,3 @@ - if (d->popElements(enter)) { + if (d->popElements(v4, enter)) { if (exit) { @@ -909,3 +913,3 @@ - if (exit != target ? d->replaceElements(target, elements) : d->pushElements(elements)) { + if (exit != target ? d->replaceElements(v4, target, elements) : d->pushElements(v4, elements)) { d->depthChange(d->elements.size(), oldDepth); @@ -993,2 +997,6 @@ + QQmlEngine *engine = qmlEngine(this); + if (!engine) + return nullptr; + QScopedValueRollback modifyingElements(d->modifyingElements, true); @@ -996,3 +1004,3 @@ - const QList stackElements = d->parseElements(args); + const QList stackElements = d->parseElements(engine, args); @@ -1005,3 +1013,3 @@ const int oldDepth = d->elements.size(); - if (d->pushElements(stackElements)) { + if (d->pushElements(engine->handle(), stackElements)) { d->depthChange(d->elements.size(), oldDepth); @@ -1111,3 +1119,7 @@ Q_D(QQuickStackView); - return d->popToItem(item, operation, QQuickStackViewPrivate::CurrentItemPolicy::DoNotPop); + QQmlEngine *engine = qmlEngine(this); + if (!engine) + return nullptr; + return d->popToItem( + engine->handle(), item, operation, QQuickStackViewPrivate::CurrentItemPolicy::DoNotPop); } @@ -1151,4 +1163,9 @@ QQuickStackElement *element = d->elements.at(index); - element->load(this); - return d->popToItem(element->item, operation, QQuickStackViewPrivate::CurrentItemPolicy::Pop); + QQmlEngine *engine = qmlEngine(this); + if (!engine) + return nullptr; + QV4::ExecutionEngine *v4 = engine->handle(); + element->load(v4, this); + return d->popToItem( + v4, element->item, operation, QQuickStackViewPrivate::CurrentItemPolicy::Pop); } @@ -1180,3 +1197,9 @@ } - return d->popToItem(d->currentItem, operation, QQuickStackViewPrivate::CurrentItemPolicy::Pop); + + QQmlEngine *engine = qmlEngine(this); + if (!engine) + return nullptr; + return d->popToItem( + engine->handle(), d->currentItem, operation, + QQuickStackViewPrivate::CurrentItemPolicy::Pop); } @@ -1234,2 +1257,6 @@ + QQmlEngine *engine = qmlEngine(this); + if (!engine) + return nullptr; + QScopedValueRollback modifyingElements(d->modifyingElements, true); @@ -1239,3 +1266,3 @@ - const QList stackElements = d->parseElements(args); + const QList stackElements = d->parseElements(engine, args); @@ -1247,4 +1274,4 @@ const bool successfullyReplaced = exit != currentElement - ? d->replaceElements(currentElement, stackElements) - : d->pushElements(stackElements); + ? d->replaceElements(engine->handle(), currentElement, stackElements) + : d->pushElements(engine->handle(), stackElements); if (successfullyReplaced) { @@ -1609,2 +1636,7 @@ int oldDepth = d->elements.size(); + + QQmlEngine *engine = qmlEngine(this); + if (!engine) + return; + if (QObject *o = d->initialItem.toQObject()) @@ -1612,3 +1644,3 @@ else if (d->initialItem.isString()) - element = QQuickStackElement::fromString(d->initialItem.toString(), this, &error); + element = QQuickStackElement::fromString(engine, d->initialItem.toString(), this, &error); if (!error.isEmpty()) { @@ -1616,3 +1648,3 @@ delete element; - } else if (d->pushElement(element)) { + } else if (d->pushElement(engine->handle(), element)) { d->depthChange(d->elements.size(), oldDepth); --- a/src/quicktemplates/qquickstackview_p.cpp +++ b/src/quicktemplates/qquickstackview_p.cpp @@ -111,3 +111,4 @@ -QList QQuickStackViewPrivate::parseElements(const QList &args) +QList QQuickStackViewPrivate::parseElements( + QQmlEngine *engine, const QList &args) { @@ -143,4 +144,4 @@ - QQuickStackElement *element = QQuickStackElement::fromStackViewArg(q, arg); - QV4::ExecutionEngine *v4Engine = qmlEngine(q)->handle(); + QQuickStackElement *element = QQuickStackElement::fromStackViewArg(engine, q, arg); + QV4::ExecutionEngine *v4Engine = engine->handle(); element->properties.set(v4Engine, v4Engine->fromVariant(properties)); @@ -185,3 +186,4 @@ -QQuickStackElement *QQuickStackViewPrivate::createElement(const QV4::Value &value, const QQmlRefPointer &context, QString *error) +QQuickStackElement *QQuickStackViewPrivate::createElement( + const QV4::Value &value, const QQmlRefPointer &context, QString *error) { @@ -189,3 +191,4 @@ if (const QV4::String *s = value.as()) - return QQuickStackElement::fromString(resolvedUrl(s->toQString(), context), q, error); + return QQuickStackElement::fromString( + s->engine()->qmlEngine(), resolvedUrl(s->toQString(), context), q, error); if (const QV4::QObjectWrapper *o = value.as()) @@ -193,9 +196,11 @@ if (const QV4::UrlObject *u = value.as()) - return QQuickStackElement::fromString(resolvedUrl(u->href(), context), q, error); + return QQuickStackElement::fromString( + u->engine()->qmlEngine(), resolvedUrl(u->href(), context), q, error); - if (value.as()) { + if (const QV4::Object *o = value.as()) { const QVariant data = QV4::ExecutionEngine::toVariant(value, QMetaType::fromType()); if (data.typeId() == QMetaType::QUrl) { - return QQuickStackElement::fromString(resolvedUrl(data.toUrl(), context).toString(), q, - error); + return QQuickStackElement::fromString( + o->engine()->qmlEngine(), resolvedUrl(data.toUrl(), context).toString(), q, + error); } @@ -206,3 +211,4 @@ -bool QQuickStackViewPrivate::pushElements(const QList &elems) +bool QQuickStackViewPrivate::pushElements( + QV4::ExecutionEngine *v4, const QList &elems) { @@ -214,3 +220,3 @@ } - return elements.top()->load(q); + return elements.top()->load(v4, q); } @@ -219,6 +225,6 @@ -bool QQuickStackViewPrivate::pushElement(QQuickStackElement *element) +bool QQuickStackViewPrivate::pushElement(QV4::ExecutionEngine *v4, QQuickStackElement *element) { if (element) - return pushElements(QList() << element); + return pushElements(v4, QList() << element); return false; @@ -226,3 +232,3 @@ -bool QQuickStackViewPrivate::popElements(QQuickStackElement *element) +bool QQuickStackViewPrivate::popElements(QV4::ExecutionEngine *v4, QQuickStackElement *element) { @@ -234,6 +240,8 @@ } - return elements.top()->load(q); + return elements.top()->load(v4, q); } -bool QQuickStackViewPrivate::replaceElements(QQuickStackElement *target, const QList &elems) +bool QQuickStackViewPrivate::replaceElements( + QV4::ExecutionEngine *v4, QQuickStackElement *target, + const QList &elems) { @@ -247,6 +255,8 @@ } - return pushElements(elems); + return pushElements(v4, elems); } -QQuickItem *QQuickStackViewPrivate::popToItem(QQuickItem *item, QQuickStackView::Operation operation, CurrentItemPolicy currentItemPolicy) +QQuickItem *QQuickStackViewPrivate::popToItem( + QV4::ExecutionEngine *v4, QQuickItem *item, QQuickStackView::Operation operation, + CurrentItemPolicy currentItemPolicy) { @@ -303,3 +313,3 @@ QQuickItem *previousItem = nullptr; - if (popElements(enter)) { + if (popElements(v4, enter)) { if (exit) { --- a/src/quicktemplates/qquickstackview_p_p.h +++ b/src/quicktemplates/qquickstackview_p_p.h @@ -52,3 +52,3 @@ QList parseElements(int from, QQmlV4FunctionPtr args, QStringList *errors); - QList parseElements(const QList &args); + QList parseElements(QQmlEngine *engine, const QList &args); QQuickStackElement *findElement(QQuickItem *item) const; @@ -56,6 +56,6 @@ QQuickStackElement *createElement(const QV4::Value &value, const QQmlRefPointer &context, QString *error); - bool pushElements(const QList &elements); - bool pushElement(QQuickStackElement *element); - bool popElements(QQuickStackElement *element); - bool replaceElements(QQuickStackElement *element, const QList &elements); + bool pushElements(QV4::ExecutionEngine *v4, const QList &elements); + bool pushElement(QV4::ExecutionEngine *v4, QQuickStackElement *element); + bool popElements(QV4::ExecutionEngine *v4, QQuickStackElement *element); + bool replaceElements(QV4::ExecutionEngine *v4, QQuickStackElement *element, const QList &elements); @@ -65,3 +65,3 @@ }; - QQuickItem *popToItem(QQuickItem *item, QQuickStackView::Operation operation, CurrentItemPolicy currentItemPolicy); + QQuickItem *popToItem(QV4::ExecutionEngine *v4, QQuickItem *item, QQuickStackView::Operation operation, CurrentItemPolicy currentItemPolicy);