diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 69e246ff28..6e7eb0c9d4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2674,8 +2674,7 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() { EntityItemProperties entityProperties = entity->getProperties(desiredProperties); { std::lock_guard guard(_scriptEngineLock); - ScriptValuePointer scriptProperties; - scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); + ScriptValuePointer scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties); avatarEntityData["properties"] = scriptProperties->toVariant(); } avatarEntitiesData.append(QVariant(avatarEntityData)); diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 2f49bc9615..e86b667696 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -102,8 +102,10 @@ ScriptValuePointer interactiveWindowPointerToScriptValue(ScriptEngine* engine, c } void interactiveWindowPointerFromScriptValue(const ScriptValuePointer& object, InteractiveWindowPointer& out) { - if (const auto interactiveWindow = qobject_cast(object->toQObject())) { - out = interactiveWindow; + if (!object) { + if (const auto interactiveWindow = qobject_cast(object->toQObject())) { + out = interactiveWindow; + } } } diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index cdb819ecb7..de35259816 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -375,10 +375,10 @@ void JSConsole::commandFinished() { _ui->promptTextEdit->setFocus(); } - bool error = (_scriptManager->engine()->hasUncaughtException() || result->isError()); + bool error = (_scriptManager->engine()->hasUncaughtException() || (result && result->isError())); QString gutter = error ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND; QString resultColor = error ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE; - QString resultStr = "" + result->toString().toHtmlEscaped() + ""; + QString resultStr = result ? "" + result->toString().toHtmlEscaped() + "" : ""; appendMessage(gutter, resultStr); resetCurrentCommandHistory(); diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index 9b596b2356..db877bf91a 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -89,11 +89,11 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou while (property->hasNext()) { property->next(); ScriptValuePointer value = property->value(); - if (value->isBool()) { + if (value && value->isBool()) { set(property->name(), value->toBool()); - } else if (value->isString()) { + } else if (value && value->isString()) { set(property->name(), value->toString()); - } else if (value->isNumber()) { + } else if (value && value->isNumber()) { int asInteger = value->toInt32(); float asFloat = value->toNumber(); if (asInteger == asFloat) { @@ -102,15 +102,15 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou set(property->name(), asFloat); } } else { // Try to get x,y,z and possibly w - if (value->isObject()) { + if (value && value->isObject()) { ScriptValuePointer x = value->property("x"); - if (x->isNumber()) { + if (x && x->isNumber()) { ScriptValuePointer y = value->property("y"); - if (y->isNumber()) { + if (y && y->isNumber()) { ScriptValuePointer z = value->property("z"); - if (z->isNumber()) { + if (z && z->isNumber()) { ScriptValuePointer w = value->property("w"); - if (w->isNumber()) { + if (w && w->isNumber()) { set(property->name(), glm::quat(w->toNumber(), x->toNumber(), y->toNumber(), z->toNumber())); } else { set(property->name(), glm::vec3(x->toNumber(), y->toNumber(), z->toNumber())); @@ -120,7 +120,7 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou } } } - qCWarning(animation) << "Ignoring unrecognized data" << value->toString() << "for animation property" << property->name(); + qCWarning(animation) << "Ignoring unrecognized data " << (value ? value->toString() : "(undefined)") << " for animation property " << property->name(); Q_ASSERT(false); } } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 6edda21992..935efd3030 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1589,7 +1589,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList) { // called in script thread // validate argument types - if (handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) { + if (handler && handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) { QMutexLocker locker(&_stateMutex); // Find a safe id, even if there are lots of many scripts add and remove handlers repeatedly. while (!_nextStateHandlerId || _stateHandlers.contains(_nextStateHandlerId)) { // 0 is unused, and don't reuse existing after wrap. @@ -1610,7 +1610,7 @@ ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, Scr void Rig::removeAnimationStateHandler(ScriptValuePointer identifier) { // called in script thread // validate arguments - if (identifier->isNumber()) { + if (identifier && identifier->isNumber()) { QMutexLocker locker(&_stateMutex); _stateHandlers.remove(identifier->toInt32()); // silently continues if handler not present. 0 is unused } else { diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index dc7dd38b23..4fb7d93983 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -67,7 +67,7 @@ static const float LATE_MIX_RIGHT_DEFAULT = 90.0f; static const float WET_DRY_MIX_DEFAULT = 50.0f; static void setOption(ScriptValuePointer arguments, const QString name, float defaultValue, float& variable) { - variable = arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue; + variable = arguments && arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue; } /*@jsdoc diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index b49adf6963..27ca80687f 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -67,7 +67,7 @@ ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const Audi * removed.

*/ void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjectorOptions& injectorOptions) { - if (!object->isObject()) { + if (!object || !object->isObject()) { qWarning() << "Audio injector options is not an object."; return; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 106eb53f15..df95f3de52 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -3184,11 +3184,11 @@ void RayToAvatarIntersectionResultFromScriptValue(const ScriptValuePointer& obje value.face = boxFaceFromString(object->property("face")->toVariant().toString()); ScriptValuePointer intersection = object->property("intersection"); - if (intersection->isValid()) { + if (intersection && intersection->isValid()) { vec3FromScriptValue(intersection, value.intersection); } ScriptValuePointer surfaceNormal = object->property("surfaceNormal"); - if (surfaceNormal->isValid()) { + if (surfaceNormal && surfaceNormal->isValid()) { vec3FromScriptValue(surfaceNormal, value.surfaceNormal); } value.jointIndex = object->property("jointIndex")->toInt32(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8488873680..34b1846d7e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -103,6 +103,7 @@ public: virtual bool setProperty(const char* name, const QVariant& value) = 0; virtual void setProcessEventsInterval(int interval) = 0; virtual QThread* thread() const = 0; + virtual void setThread(QThread* thread) = 0; virtual ScriptValuePointer undefinedValue() = 0; virtual ScriptValuePointer uncaughtException() const = 0; virtual QStringList uncaughtExceptionBacktrace() const = 0; diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h index 22221e74a4..d597efc780 100644 --- a/libraries/script-engine/src/ScriptEngineCast.h +++ b/libraries/script-engine/src/ScriptEngineCast.h @@ -65,7 +65,8 @@ int scriptRegisterMetaType(ScriptEngine* eng, ScriptValuePointer (*toScriptValue)(ScriptEngine*, const T& t), void (*fromScriptValue)(const ScriptValuePointer&, T& t), const ScriptValuePointer& prototype = ScriptValuePointer(), - T* = 0) { + T* = 0) +{ const int id = qRegisterMetaType(); // make sure it's registered eng->registerCustomType(id, reinterpret_cast(toScriptValue), reinterpret_cast(fromScriptValue), prototype); diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index b6886eaeb0..7ebd41ec9d 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -87,6 +87,8 @@ int scriptManagerPointerMetaID = qRegisterMetaType(); Q_DECLARE_METATYPE(ExternalResource::Bucket); +Q_DECLARE_METATYPE(ScriptValuePointer); + // --- Static script initialization registry static ScriptManager::StaticInitializerNode* rootInitializer = nullptr; @@ -325,6 +327,7 @@ void ScriptManager::runInThread() { QThread* workerThread = new QThread(); QString name = QString("js:") + getFilename().replace("about:",""); workerThread->setObjectName(name); + _engine->setThread(workerThread); moveToThread(workerThread); // NOTE: If you connect any essential signals for proper shutdown or cleanup of @@ -1256,13 +1259,13 @@ ScriptValuePointer ScriptManager::currentModule() { } auto jsRequire = _engine->globalObject()->property("Script")->property("require"); auto cache = jsRequire->property("cache"); - auto candidate = ScriptValuePointer(); + ScriptValuePointer candidate; ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan - for (auto context = _engine->currentContext(); context && !candidate->isObject(); parentContext = context->parentContext(), context = parentContext.data()) { + for (auto context = _engine->currentContext(); context && (!candidate || !candidate->isObject()); parentContext = context->parentContext(), context = parentContext.data()) { auto contextInfo = context->functionContext(); candidate = cache->property(contextInfo->fileName()); } - if (!candidate->isObject()) { + if (!candidate || !candidate->isObject()) { return ScriptValuePointer(); } return candidate; @@ -1589,8 +1592,8 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer } _parentURL = parentURL; - if (callback->isFunction()) { - callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, ScriptValuePointer(callback), ScriptValuePointer(), ScriptValueList()); + if (callback && callback->isFunction()) { + callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, callback, ScriptValuePointer(), ScriptValueList()); } loader->deleteLater(); @@ -1603,7 +1606,7 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer loader->start(processLevelMaxRetries); - if (!callback->isFunction() && !loader->isFinished()) { + if ((!callback || !callback->isFunction()) && !loader->isFinished()) { QEventLoop loop; QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit); loop.exec(); @@ -1963,7 +1966,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c if (sandbox->hasUncaughtException()) { exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); sandbox->clearExceptions(); - } else if (testConstructor->isError()) { + } else if (testConstructor && testConstructor->isError()) { exception = testConstructor; } } else { @@ -2038,7 +2041,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c if (sandbox->hasUncaughtException()) { exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString())); sandbox->clearExceptions(); - } else if (testConstructor->isError()) { + } else if (testConstructor && testConstructor->isError()) { exception = testConstructor; } } @@ -2048,7 +2051,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c // exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0"); } - if (exception->isError()) { + if (exception && exception->isError()) { // create a local copy using makeError to decouple from the sandbox engine exception = _engine->makeError(exception); setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); @@ -2057,7 +2060,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c } // CONSTRUCTOR VIABILITY - if (!testConstructor->isFunction()) { + if (!testConstructor || !testConstructor->isFunction()) { QString testConstructorType = QString(testConstructor->toVariant().typeName()); if (testConstructorType == "") { testConstructorType = "empty"; @@ -2100,7 +2103,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c doWithEnvironment(entityID, sandboxURL, initialization); - if (entityScriptObject->isError()) { + if (entityScriptObject && entityScriptObject->isError()) { auto exception = entityScriptObject; setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT); emit unhandledException(exception); diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp index 41cd945ca2..798d93a0ea 100644 --- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp +++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp @@ -52,7 +52,7 @@ ScriptFunctionContextPointer ScriptContextQtWrapper::functionContext() const { ScriptContextPointer ScriptContextQtWrapper::parentContext() const { QScriptContext* result = _context->parentContext(); - return ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)); + return result ? ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)) : ScriptContextPointer(); } ScriptValuePointer ScriptContextQtWrapper::thisObject() const { diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp index fe3cc76c88..7700d778d2 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp @@ -62,13 +62,16 @@ static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_P static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true }; +Q_DECLARE_METATYPE(ScriptValuePointer); + Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) int qfunctionSignatureMetaID = qRegisterMetaType(); int scriptEnginePointerMetaID = qRegisterMetaType(); bool ScriptEngineQtScript::IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method) { - if (QThread::currentThread() == thread) { + const QThread* currentThread = QThread::currentThread(); + if (currentThread == thread) { return true; } qCCritical(scriptengine) << QString("Scripting::%1 @ %2 -- ignoring thread-unsafe call from %3") @@ -380,11 +383,22 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { return QScriptValue(); } +static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValuePointer& src) { + return ScriptValueQtWrapper::fullUnwrap(static_cast(engine), src); +} + +static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValuePointer& dest) { + ScriptEngineQtScript* engine = static_cast(src.engine()); + dest = ScriptValuePointer(new ScriptValueQtWrapper(engine, src)); +} + ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : QScriptEngine(), _manager(scriptManager), _arrayBufferClass(new ArrayBufferClass(this)) { + qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue); + if (_manager) { connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { if (hasUncaughtException()) { @@ -397,6 +411,7 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) : emit _manager->unhandledException(ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(thrown)))); } }, Qt::DirectConnection); + moveToThread(scriptManager->thread()); } QScriptValue null = QScriptEngine::nullValue(); @@ -993,6 +1008,10 @@ QThread* ScriptEngineQtScript::thread() const { return QScriptEngine::thread(); } +void ScriptEngineQtScript::setThread(QThread* thread) { + moveToThread(thread); +} + ScriptValuePointer ScriptEngineQtScript::uncaughtException() const { QScriptValue result = QScriptEngine::uncaughtException(); return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); @@ -1013,47 +1032,11 @@ bool ScriptEngineQtScript::raiseException(const ScriptValuePointer& exception) { } ScriptValuePointer ScriptEngineQtScript::create(int type, const void* ptr) { - // first we'll try custom types registered with us - ScriptEngine::MarshalFunction marshalFunc = nullptr; - ScriptValuePointer prototype; - { - std::lock_guard guard(_customTypeProtect); - TCustomTypeMap::const_iterator loc = _customTypes.find(type); - if (loc != _customTypes.end()) { - const CustomTypeInfo& typeInfo = loc->second; - marshalFunc = typeInfo.marshalFunc; - prototype = typeInfo.prototype; - } - } - if (marshalFunc) { - ScriptValuePointer result = marshalFunc(this, ptr); - if (result && prototype) { - result->setPrototype(prototype); - } - return result; - } - - // falling back to having QtScript handle it QScriptValue result = qScriptValueFromValue_helper(this, type, ptr); return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result))); } bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, void* ptr) { - // first we'll try custom types registered with us - ScriptEngine::DemarshalFunction demarshalFunc = nullptr; - { - std::lock_guard guard(_customTypeProtect); - TCustomTypeMap::const_iterator loc = _customTypes.find(type); - if (loc != _customTypes.end()) { - demarshalFunc = loc->second.demarshalFunc; - } - } - if (demarshalFunc) { - demarshalFunc(value, ptr); - return true; - } - - // falling back to having QtScript handle it ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value); if (unwrapped == nullptr) { return false; @@ -1061,22 +1044,100 @@ bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, vo return qscriptvalue_cast_helper(unwrapped->toQtValue(), type, ptr); } +template +class CustomTypeInstance { +public: + static ScriptEngine::MarshalFunction marshalFunc; + static ScriptEngine::DemarshalFunction demarshalFunc; + + static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) { + ScriptEngineQtScript* unwrappedEngine = static_cast(engine); + ScriptValuePointer dest = marshalFunc(unwrappedEngine, src); + return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest); + } + + static void internalDemarshalFunc(const QScriptValue& src, void* dest) { + ScriptEngineQtScript* unwrappedEngine = static_cast(src.engine()); + ScriptValuePointer wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src)); + demarshalFunc(wrappedSrc, dest); + } +}; +template +ScriptEngine::MarshalFunction CustomTypeInstance::marshalFunc; +template +ScriptEngine::DemarshalFunction CustomTypeInstance::demarshalFunc; + +// I would *LOVE* it if there was a different way to do this, jeez! +// Qt requires two functions that have no parameters that give any context, +// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates). +// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of +// the system that would require anyone other than us to have a dependency on QtScript +#define CUSTOM_TYPE_ENTRY(idx) \ + case idx: \ + CustomTypeInstance::marshalFunc = marshalFunc; \ + CustomTypeInstance::demarshalFunc = demarshalFunc; \ + internalMarshalFunc = CustomTypeInstance::internalMarshalFunc; \ + internalDemarshalFunc = CustomTypeInstance::internalDemarshalFunc; \ + break; +#define CUSTOM_TYPE_ENTRY_10(idx) \ + CUSTOM_TYPE_ENTRY((idx * 10)); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 1); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 2); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 3); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 4); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 5); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 6); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 7); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 8); \ + CUSTOM_TYPE_ENTRY((idx * 10) + 9); + void ScriptEngineQtScript::registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc, ScriptEngine::DemarshalFunction demarshalFunc, const ScriptValuePointer& prototype) { - ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(prototype); - if (unwrapped == nullptr) { + QScriptValue unwrapped = ScriptValueQtWrapper::fullUnwrap(this, prototype); + QScriptEngine::MarshalFunction internalMarshalFunc; + QScriptEngine::DemarshalFunction internalDemarshalFunc; + + if (_nextCustomType >= 300) { // have we ran out of translators? + Q_ASSERT(false); return; } - std::lock_guard guard(_customTypeProtect); - TCustomTypeMap::iterator loc = _customTypes.find(type); - if(loc == _customTypes.end()) { - _customTypes.insert(TCustomTypeMap::value_type(type, CustomTypeInfo())).first; + switch (_nextCustomType++) { + CUSTOM_TYPE_ENTRY_10(0); + CUSTOM_TYPE_ENTRY_10(1); + CUSTOM_TYPE_ENTRY_10(2); + CUSTOM_TYPE_ENTRY_10(3); + CUSTOM_TYPE_ENTRY_10(4); + CUSTOM_TYPE_ENTRY_10(5); + CUSTOM_TYPE_ENTRY_10(6); + CUSTOM_TYPE_ENTRY_10(7); + CUSTOM_TYPE_ENTRY_10(8); + CUSTOM_TYPE_ENTRY_10(9); + CUSTOM_TYPE_ENTRY_10(10); + CUSTOM_TYPE_ENTRY_10(11); + CUSTOM_TYPE_ENTRY_10(12); + CUSTOM_TYPE_ENTRY_10(13); + CUSTOM_TYPE_ENTRY_10(14); + CUSTOM_TYPE_ENTRY_10(15); + CUSTOM_TYPE_ENTRY_10(16); + CUSTOM_TYPE_ENTRY_10(17); + CUSTOM_TYPE_ENTRY_10(18); + CUSTOM_TYPE_ENTRY_10(19); + CUSTOM_TYPE_ENTRY_10(20); + CUSTOM_TYPE_ENTRY_10(21); + CUSTOM_TYPE_ENTRY_10(22); + CUSTOM_TYPE_ENTRY_10(23); + CUSTOM_TYPE_ENTRY_10(24); + CUSTOM_TYPE_ENTRY_10(25); + CUSTOM_TYPE_ENTRY_10(26); + CUSTOM_TYPE_ENTRY_10(27); + CUSTOM_TYPE_ENTRY_10(28); + CUSTOM_TYPE_ENTRY_10(29); + CUSTOM_TYPE_ENTRY_10(30); } - CustomTypeInfo& typeInfo = loc->second; - typeInfo.marshalFunc = marshalFunc; - typeInfo.demarshalFunc = demarshalFunc; + + qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, unwrapped); } diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h index 78b71e37b4..1c8d9ce781 100644 --- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h +++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h @@ -89,6 +89,7 @@ public: // ScriptEngine implementation virtual bool setProperty(const char* name, const QVariant& value); virtual void setProcessEventsInterval(int interval); virtual QThread* thread() const; + virtual void setThread(QThread* thread); virtual ScriptValuePointer undefinedValue(); virtual ScriptValuePointer uncaughtException() const; virtual QStringList uncaughtExceptionBacktrace() const; @@ -404,18 +405,9 @@ protected: */ Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection ); - // store for handling custom type marshaling/demarshaling - struct CustomTypeInfo { - ScriptEngine::MarshalFunction marshalFunc; - ScriptEngine::DemarshalFunction demarshalFunc; - ScriptValuePointer prototype; - }; - typedef std::map TCustomTypeMap; - TCustomTypeMap _customTypes; - std::mutex _customTypeProtect; - QPointer _manager; + int _nextCustomType = 0; ScriptValuePointer _nullValue; ScriptValuePointer _undefinedValue; mutable ScriptContextQtPointer _currContext;