forked from qt-creator/qt-creator
QmlPuppet: Fix crash at puppet reset
Puppet cleanup was not handled properly, so derefFromEffectItem() was not called for all objects that needed it, causing puppet to crash at shutdown. Fixes: QDS-3461 Change-Id: I22c0552fe1223789fa42b276ab377d4a9e929955 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -771,25 +771,18 @@ QList<QObject*> NodeInstanceServer::allSubObjectsForObject(QObject *object)
|
|||||||
|
|
||||||
void NodeInstanceServer::removeAllInstanceRelationships()
|
void NodeInstanceServer::removeAllInstanceRelationships()
|
||||||
{
|
{
|
||||||
// prevent destroyed() signals calling back
|
for (ServerNodeInstance &instance : m_objectInstanceHash) {
|
||||||
|
|
||||||
foreach (ServerNodeInstance instance, m_objectInstanceHash) {
|
|
||||||
if (instance.isValid())
|
if (instance.isValid())
|
||||||
instance.setId(QString());
|
instance.setId({});
|
||||||
}
|
}
|
||||||
|
|
||||||
//first the root object
|
// First the root object
|
||||||
if (rootNodeInstance().internalObject())
|
// This also cleans up all objects that have root object as ancestor
|
||||||
rootNodeInstance().internalObject()->disconnect();
|
|
||||||
|
|
||||||
rootNodeInstance().makeInvalid();
|
rootNodeInstance().makeInvalid();
|
||||||
|
|
||||||
|
// Invalidate any remaining objects
|
||||||
foreach (ServerNodeInstance instance, m_objectInstanceHash) {
|
for (ServerNodeInstance &instance : m_objectInstanceHash)
|
||||||
if (instance.internalObject())
|
|
||||||
instance.internalObject()->disconnect();
|
|
||||||
instance.makeInvalid();
|
instance.makeInvalid();
|
||||||
}
|
|
||||||
|
|
||||||
m_idInstances.clear();
|
m_idInstances.clear();
|
||||||
m_objectInstanceHash.clear();
|
m_objectInstanceHash.clear();
|
||||||
@@ -1388,14 +1381,14 @@ void NodeInstanceServer::sendDebugOutput(DebugOutputCommand::Type type, const QS
|
|||||||
nodeInstanceClient()->debugOutput(command);
|
nodeInstanceClient()->debugOutput(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeInstanceServer::removeInstanceRelationsipForDeletedObject(QObject *object)
|
void NodeInstanceServer::removeInstanceRelationsipForDeletedObject(QObject *object, qint32 instanceId)
|
||||||
{
|
{
|
||||||
if (m_objectInstanceHash.contains(object)) {
|
if (m_objectInstanceHash.contains(object)) {
|
||||||
ServerNodeInstance instance = instanceForObject(object);
|
ServerNodeInstance instance = instanceForObject(object);
|
||||||
m_objectInstanceHash.remove(object);
|
m_objectInstanceHash.remove(object);
|
||||||
|
|
||||||
if (instance.instanceId() >= 0 && m_idInstances.size() > instance.instanceId())
|
if (instanceId >= 0 && m_idInstances.size() > instanceId)
|
||||||
m_idInstances[instance.instanceId()] = ServerNodeInstance{};
|
m_idInstances[instanceId] = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -204,7 +204,7 @@ public:
|
|||||||
const QString &message,
|
const QString &message,
|
||||||
const QVector<qint32> &instanceIds);
|
const QVector<qint32> &instanceIds);
|
||||||
|
|
||||||
void removeInstanceRelationsipForDeletedObject(QObject *object);
|
void removeInstanceRelationsipForDeletedObject(QObject *object, qint32 instanceId);
|
||||||
|
|
||||||
void incrementNeedsExtraRender();
|
void incrementNeedsExtraRender();
|
||||||
void decrementNeedsExtraRender();
|
void decrementNeedsExtraRender();
|
||||||
|
@@ -65,12 +65,7 @@ ObjectNodeInstance::ObjectNodeInstance(QObject *object)
|
|||||||
{
|
{
|
||||||
if (object)
|
if (object)
|
||||||
QObject::connect(m_object.data(), &QObject::destroyed, [=] {
|
QObject::connect(m_object.data(), &QObject::destroyed, [=] {
|
||||||
|
handleObjectDeletion(object);
|
||||||
/*This lambda is save because m_nodeInstanceServer
|
|
||||||
is a smartpointer and object is a dangling pointer anyway.*/
|
|
||||||
|
|
||||||
if (m_nodeInstanceServer)
|
|
||||||
m_nodeInstanceServer->removeInstanceRelationsipForDeletedObject(object);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +95,14 @@ void ObjectNodeInstance::destroy()
|
|||||||
m_instanceId = -1;
|
m_instanceId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectNodeInstance::handleObjectDeletion(QObject *object)
|
||||||
|
{
|
||||||
|
// We must pass the m_instanceId here, because this instance is no longer
|
||||||
|
// valid, so the wrapper ServerNodeInstance will report -1 for id.
|
||||||
|
if (m_nodeInstanceServer)
|
||||||
|
m_nodeInstanceServer->removeInstanceRelationsipForDeletedObject(object, m_instanceId);
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectNodeInstance::setInstanceId(qint32 id)
|
void ObjectNodeInstance::setInstanceId(qint32 id)
|
||||||
{
|
{
|
||||||
m_instanceId = id;
|
m_instanceId = id;
|
||||||
|
@@ -65,7 +65,7 @@ public:
|
|||||||
|
|
||||||
virtual ~ObjectNodeInstance();
|
virtual ~ObjectNodeInstance();
|
||||||
void destroy();
|
void destroy();
|
||||||
//void setModelNode(const ModelNode &node);
|
virtual void handleObjectDeletion(QObject *object);
|
||||||
|
|
||||||
static Pointer create(QObject *objectToBeWrapped);
|
static Pointer create(QObject *objectToBeWrapped);
|
||||||
static QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context);
|
static QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context);
|
||||||
|
@@ -915,6 +915,9 @@ Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer()
|
|||||||
m_render3DEditViewTimer.stop();
|
m_render3DEditViewTimer.stop();
|
||||||
m_inputEventTimer.stop();
|
m_inputEventTimer.stop();
|
||||||
|
|
||||||
|
if (m_editView3DData.rootItem)
|
||||||
|
m_editView3DData.rootItem->disconnect(this);
|
||||||
|
|
||||||
for (auto view : qAsConst(m_view3Ds))
|
for (auto view : qAsConst(m_view3Ds))
|
||||||
view->disconnect();
|
view->disconnect();
|
||||||
for (auto node : qAsConst(m_3DSceneMap))
|
for (auto node : qAsConst(m_3DSceneMap))
|
||||||
@@ -922,6 +925,15 @@ Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer()
|
|||||||
|
|
||||||
if (m_editView3DData.rootItem)
|
if (m_editView3DData.rootItem)
|
||||||
QMetaObject::invokeMethod(m_editView3DData.rootItem, "aboutToShutDown", Qt::DirectConnection);
|
QMetaObject::invokeMethod(m_editView3DData.rootItem, "aboutToShutDown", Qt::DirectConnection);
|
||||||
|
|
||||||
|
if (!Internal::QuickItemNodeInstance::unifiedRenderPath()) {
|
||||||
|
if (m_editView3DData.contentItem)
|
||||||
|
designerSupport()->derefFromEffectItem(m_editView3DData.contentItem);
|
||||||
|
if (m_modelNode3DImageViewData.contentItem)
|
||||||
|
designerSupport()->derefFromEffectItem(m_modelNode3DImageViewData.contentItem);
|
||||||
|
if (m_modelNode2DImageViewData.contentItem)
|
||||||
|
designerSupport()->derefFromEffectItem(m_modelNode2DImageViewData.contentItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::sendTokenBack()
|
void Qt5InformationNodeInstanceServer::sendTokenBack()
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#include <addimportcontainer.h>
|
#include <addimportcontainer.h>
|
||||||
#include <createscenecommand.h>
|
#include <createscenecommand.h>
|
||||||
#include <reparentinstancescommand.h>
|
#include <reparentinstancescommand.h>
|
||||||
|
#include <clearscenecommand.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
@@ -59,7 +60,8 @@ Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeIn
|
|||||||
|
|
||||||
Qt5NodeInstanceServer::~Qt5NodeInstanceServer()
|
Qt5NodeInstanceServer::~Qt5NodeInstanceServer()
|
||||||
{
|
{
|
||||||
delete quickWindow();
|
NodeInstanceServer::clearScene({});
|
||||||
|
delete m_viewData.window.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickView *Qt5NodeInstanceServer::quickView() const
|
QQuickView *Qt5NodeInstanceServer::quickView() const
|
||||||
|
@@ -59,8 +59,15 @@ QuickItemNodeInstance::QuickItemNodeInstance(QQuickItem *item)
|
|||||||
|
|
||||||
QuickItemNodeInstance::~QuickItemNodeInstance()
|
QuickItemNodeInstance::~QuickItemNodeInstance()
|
||||||
{
|
{
|
||||||
if (quickItem() && checkIfRefFromEffect(instanceId()))
|
}
|
||||||
designerSupport()->derefFromEffectItem(quickItem());
|
|
||||||
|
void QuickItemNodeInstance::handleObjectDeletion(QObject *object)
|
||||||
|
{
|
||||||
|
auto item = qobject_cast<QQuickItem *>(object);
|
||||||
|
if (item && checkIfRefFromEffect(instanceId()))
|
||||||
|
designerSupport()->derefFromEffectItem(item);
|
||||||
|
|
||||||
|
ObjectNodeInstance::handleObjectDeletion(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isContentItem(QQuickItem *item, NodeInstanceServer *nodeInstanceServer)
|
static bool isContentItem(QQuickItem *item, NodeInstanceServer *nodeInstanceServer)
|
||||||
|
@@ -42,6 +42,7 @@ public:
|
|||||||
using WeakPointer = QWeakPointer<QuickItemNodeInstance>;
|
using WeakPointer = QWeakPointer<QuickItemNodeInstance>;
|
||||||
|
|
||||||
~QuickItemNodeInstance() override;
|
~QuickItemNodeInstance() override;
|
||||||
|
void handleObjectDeletion(QObject *object) override;
|
||||||
|
|
||||||
static Pointer create(QObject *objectToBeWrapped);
|
static Pointer create(QObject *objectToBeWrapped);
|
||||||
static void createEffectItem(bool createEffectItem);
|
static void createEffectItem(bool createEffectItem);
|
||||||
|
Reference in New Issue
Block a user