// untangle the arguments V8ScriptValue callback(_engine, v8::Null(isolate)); V8ScriptValue callbackThis(_engine, v8::Null(isolate)); if (arg1.isFunction()) { auto unwrappedArg0 = ScriptValueV8Wrapper::unwrap(arg0); auto unwrappedArg1 = ScriptValueV8Wrapper::unwrap(arg1); if (!unwrappedArg0 || !unwrappedArg1) { Q_ASSERT(false); return; } callbackThis = unwrappedArg0->toV8Value(); callback = unwrappedArg1->toV8Value(); } else { auto unwrappedArg0 = ScriptValueV8Wrapper::unwrap(arg0); if (!unwrappedArg0) { Q_ASSERT(false); return; } callback = unwrappedArg0->toV8Value(); } if (!callback.get()->IsFunction()) { isolate->ThrowError("Function expected as argument to 'disconnect'"); return; } // locate this connection in our list of connections { ConnectionList::iterator lookup = findConnection(callbackThis, callback); if (lookup == _connections.end()) { return; // not here } // remove it from our internal list of connections withWriteLock([&]{ _connections.erase(lookup); }); } // remove a reference to ourselves from the destination callback v8::Local<v8::Function> destFunction = v8::Local<v8::Function>::Cast(callback.get()); v8::Local<v8::String> destDataName = v8::String::NewFromUtf8(isolate, "__data__").ToLocalChecked(); v8::Local<v8::Value> destData; auto destFunctionContext = context; ScriptEngine::QObjectWrapOptions options = ScriptEngine::ExcludeSuperClassContents | ScriptEngine::PreferExistingWrapperObject; // It's not necessarily new, newQObject looks for it first in object wrapper map, and for already existing signal it should be found there V8ScriptValue v8ThisObject = ScriptObjectV8Proxy::newQObject(_engine, this, ScriptEngine::ScriptOwnership, options); if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) { Q_ASSERT(false); } if (destData->IsArray()) { v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData); int length = destArray->Length(); v8::Local<v8::Array> newArray = v8::Array::New(isolate, length - 1); int findCounter = 0; int newIndex = 0; for (int idx = 0; idx < length; ++idx) { v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked(); // For debugging: { Q_ASSERT(entry->IsObject()); V8ScriptValue v8EntryObject(_engine, entry); Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)); } if (entry->StrictEquals(v8ThisObject.get())) { findCounter++; } else { if (!newArray->Set(destFunctionContext, newIndex, entry).FromMaybe(false)) { Q_ASSERT(false); } newIndex++; } } Q_ASSERT(findCounter == 1); if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) { Q_ASSERT(false); } } else { Q_ASSERT(false); } // inform Qt that we're no longer connected to this signal if (_connections.empty()) { Q_ASSERT(_isConnected); // During cleanup qobject might be null since it might have been already deleted if (!_cleanup || (_cleanup && qobject)) { Q_ASSERT(qobject); bool result = QMetaObject::disconnect(qobject, _meta.methodIndex(), this, _metaCallId); Q_ASSERT(result); } _isConnected = false; }} void ScriptSignalV8Proxy::disconnectAllScriptSignalProxies() { _cleanup = true; QList<Connection> connections; withReadLock([&]{ connections = _connections; }); for (auto &connection : connections) { ScriptValue thisValue(new ScriptValueV8Wrapper(_engine, connection.thisValue)); ScriptValue callback(new ScriptValueV8Wrapper(_engine, connection.callback)); disconnect(thisValue, callback); }} void ScriptSignalV8Proxy::disconnectAll() { QObject::disconnect(this, nullptr, nullptr, nullptr);}Lines 1501–1613 of 1613. Previous lines
// untangle the arguments V8ScriptValue callback(_engine, v8::Null(isolate)); V8ScriptValue callbackThis(_engine, v8::Null(isolate)); if (arg1.isFunction()) { auto unwrappedArg0 = ScriptValueV8Wrapper::unwrap(arg0); auto unwrappedArg1 = ScriptValueV8Wrapper::unwrap(arg1); if (!unwrappedArg0 || !unwrappedArg1) { Q_ASSERT(false); return; } callbackThis = unwrappedArg0->toV8Value(); callback = unwrappedArg1->toV8Value(); } else { auto unwrappedArg0 = ScriptValueV8Wrapper::unwrap(arg0); if (!unwrappedArg0) { Q_ASSERT(false); return; } callback = unwrappedArg0->toV8Value(); } if (!callback.get()->IsFunction()) { isolate->ThrowError("Function expected as argument to 'disconnect'"); return; } // locate this connection in our list of connections { ConnectionList::iterator lookup = findConnection(callbackThis, callback); if (lookup == _connections.end()) { return; // not here } // remove it from our internal list of connections withWriteLock([&]{ _connections.erase(lookup); }); } // remove a reference to ourselves from the destination callback v8::Local<v8::Function> destFunction = v8::Local<v8::Function>::Cast(callback.get()); v8::Local<v8::String> destDataName = v8::String::NewFromUtf8(isolate, "__data__").ToLocalChecked(); v8::Local<v8::Value> destData; auto destFunctionContext = context; ScriptEngine::QObjectWrapOptions options = ScriptEngine::ExcludeSuperClassContents | ScriptEngine::PreferExistingWrapperObject; // It's not necessarily new, newQObject looks for it first in object wrapper map, and for already existing signal it should be found there V8ScriptValue v8ThisObject = ScriptObjectV8Proxy::newQObject(_engine, this, ScriptEngine::ScriptOwnership, options); if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) { Q_ASSERT(false); } if (destData->IsArray()) { v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData); int length = destArray->Length(); v8::Local<v8::Array> newArray = v8::Array::New(isolate, length - 1); int findCounter = 0; int newIndex = 0; for (int idx = 0; idx < length; ++idx) { v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked(); // For debugging: { Q_ASSERT(entry->IsObject()); V8ScriptValue v8EntryObject(_engine, entry); Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)); } if (entry->StrictEquals(v8ThisObject.get())) { findCounter++; } else { if (!newArray->Set(destFunctionContext, newIndex, entry).FromMaybe(false)) { Q_ASSERT(false); } newIndex++; } } Q_ASSERT(findCounter == 1); if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) { Q_ASSERT(false); } } else { Q_ASSERT(false); } // inform Qt that we're no longer connected to this signal if (_connections.empty()) { Q_ASSERT(_isConnected); // During cleanup qobject might be null since it might have been already deleted if (!_cleanup || (_cleanup && qobject)) { Q_ASSERT(qobject); bool result = QMetaObject::disconnect(qobject, _meta.methodIndex(), this, _metaCallId); Q_ASSERT(result); } _isConnected = false; } } void ScriptSignalV8Proxy::disconnectAllScriptSignalProxies() { _cleanup = true; QList<Connection> connections; withReadLock([&]{ connections = _connections; }); for (auto &connection : connections) { ScriptValue thisValue(new ScriptValueV8Wrapper(_engine, connection.thisValue)); ScriptValue callback(new ScriptValueV8Wrapper(_engine, connection.callback)); disconnect(thisValue, callback); } } void ScriptSignalV8Proxy::disconnectAll() { QObject::disconnect(this, nullptr, nullptr, nullptr); }