From ed5fed36f38b9de0452cc427db679266d249f216 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 19 Jan 2010 11:16:36 +0100 Subject: Remove QtScript connection when receiver QObject has been deleted We don't want to have to listen to the destroyed() signal for every receiver object of a connection, and likewise we don't want to create a QObject to handle each connection; instead, remove the connection lazily at signal emission time after we've detected that the receiver has been deleted. Task-number: QTBUG-7313 Reviewed-by: Simon Hausmann --- src/script/bridge/qscriptqobject.cpp | 9 ++++++++- .../qscriptextqobject/tst_qscriptextqobject.cpp | 23 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index 3f4f6bb..db312bc 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -2220,7 +2220,14 @@ void QObjectConnectionManager::execute(int slotIndex, void **argv) JSC::call(exec, slot, callType, callData, thisObject, jscArgs); if (exec->hadException()) { - engine->emitSignalHandlerException(); + if (slot.inherits(&QtFunction::info) && !static_cast(JSC::asObject(slot))->qobject()) { + // The function threw an error because the target QObject has been deleted. + // The connections list is stale; remove the signal handler and ignore the exception. + removeSignalHandler(sender(), signalIndex, receiver, slot); + exec->clearException(); + } else { + engine->emitSignalHandlerException(); + } } } diff --git a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp index de9d37e..b4ce561 100644 --- a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp +++ b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp @@ -532,6 +532,7 @@ private slots: void prototypes(); void objectDeleted(); void connectToDestroyedSignal(); + void emitAfterReceiverDeleted(); private: QScriptEngine *m_engine; @@ -3020,5 +3021,27 @@ void tst_QScriptExtQObject::connectToDestroyedSignal() #endif } +void tst_QScriptExtQObject::emitAfterReceiverDeleted() +{ + for (int x = 0; x < 2; ++x) { + MyQObject *obj = new MyQObject; + QScriptValue scriptObj = m_engine->newQObject(obj); + if (x == 0) { + // Connecting from JS + m_engine->globalObject().setProperty("obj", scriptObj); + QVERIFY(m_engine->evaluate("myObject.mySignal.connect(obj, 'mySlot()')").isUndefined()); + } else { + // Connecting from C++ + qScriptConnect(m_myObject, SIGNAL(mySignal()), scriptObj, scriptObj.property("mySlot")); + } + delete obj; + QSignalSpy signalHandlerExceptionSpy(m_engine, SIGNAL(signalHandlerException(QScriptValue))); + QVERIFY(!m_engine->hasUncaughtException()); + m_myObject->emitMySignal(); + QCOMPARE(signalHandlerExceptionSpy.count(), 0); + QVERIFY(!m_engine->hasUncaughtException()); + } +} + QTEST_MAIN(tst_QScriptExtQObject) #include "tst_qscriptextqobject.moc" -- cgit v0.12