aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-06-06 14:18:11 +0200
committerLars Knoll <lars.knoll@digia.com>2013-06-07 18:32:50 +0200
commite058cc234c7bb3065b092bed304b7da9f3f98bed (patch)
treec3abd2bff819235847d341e3ae402c9d841ab3d9
parent4cde67a00201e3351d7ee6cc3021a4331e7f00a6 (diff)
Remove signal & slot related code from QV8QObjectWrapper
The code isn't needed anymore. Also moved ExtractQtSignal/QtMethod out, too. Change-Id: I8d7a0ef89ad5ea1ca102a416b70e27597c0279b7 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/qml/v8/qv8engine.cpp1
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp447
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper_p.h12
3 files changed, 228 insertions, 232 deletions
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index f37006bfcc..4a25ddb5cb 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -100,6 +100,7 @@ QV8Engine::QV8Engine(QJSEngine* qq)
v8::Isolate::SetEngine(m_v4Engine);
m_v4Engine->v8Engine = this;
+ QV4::QObjectWrapper::initializeBindings(m_v4Engine);
m_qobjectWrapper.init(this);
}
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index 4a48ef2910..32d08c3024 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -84,6 +84,27 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
+static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function)
+{
+ if (function && function->subtype == QV4::FunctionObject::WrappedQtMethod) {
+ QObjectMethod *method = static_cast<QObjectMethod*>(function);
+ return qMakePair(method->object(), method->methodIndex());
+ }
+
+ return qMakePair((QObject *)0, -1);
+}
+
+static QPair<QObject *, int> extractQtSignal(const Value &value)
+{
+ if (QV4::FunctionObject *function = value.asFunctionObject())
+ return extractQtMethod(function);
+
+ if (QV4::QmlSignalHandler *handler = value.as<QV4::QmlSignalHandler>())
+ return qMakePair(handler->object(), handler->signalIndex());
+
+ return qMakePair((QObject *)0, -1);
+}
+
QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object)
: Object(engine)
, m_object(object)
@@ -100,6 +121,12 @@ QObjectWrapper::~QObjectWrapper()
deleteQObject();
}
+void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
+{
+ engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("connect"), method_connect);
+ engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("disconnect"), method_disconnect);
+}
+
void QObjectWrapper::deleteQObject(bool deleteInstantly)
{
if (!m_object)
@@ -303,6 +330,201 @@ QV4::Value QObjectWrapper::enumerateProperties(Object *object)
return QV4::Value::fromObject(that->engine()->newArrayObject(result));
}
+namespace QV4 {
+
+struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
+{
+ QV4::PersistentValue function;
+ QV4::PersistentValue thisObject;
+ int signalIndex;
+
+ QObjectSlotDispatcher()
+ : QtPrivate::QSlotObjectBase(&impl)
+ , signalIndex(-1)
+ {}
+
+ static void impl(int which, QSlotObjectBase *this_, QObject *r, void **metaArgs, bool *ret)
+ {
+ switch (which) {
+ case Destroy: {
+ delete static_cast<QObjectSlotDispatcher*>(this_);
+ }
+ break;
+ case Call: {
+ QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
+ QVarLengthArray<int, 9> dummy;
+ int *argsTypes = QQmlPropertyCache::methodParameterTypes(r, This->signalIndex, dummy, 0);
+
+ int argCount = argsTypes ? argsTypes[0]:0;
+
+ QV4::FunctionObject *f = This->function.value().asFunctionObject();
+ QV4::ExecutionEngine *v4 = f->internalClass->engine;
+ QV4::ExecutionContext *ctx = v4->current;
+
+ QVarLengthArray<QV4::Value, 9> args(argCount);
+ for (int ii = 0; ii < argCount; ++ii) {
+ int type = argsTypes[ii + 1];
+ if (type == qMetaTypeId<QVariant>()) {
+ args[ii] = v4->v8Engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
+ } else {
+ args[ii] = v4->v8Engine->fromVariant(QVariant(type, metaArgs[ii + 1]));
+ }
+ }
+
+ try {
+ f->call(v4->current, This->thisObject.isEmpty() ? Value::fromObject(v4->globalObject) : This->thisObject.value(), args.data(), argCount);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(e, error);
+ if (error.description().isEmpty())
+ error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString()));
+ QQmlEnginePrivate::get(v4->v8Engine->engine())->warning(error);
+ }
+ }
+ break;
+ case Compare: {
+ QObjectSlotDispatcher *connection = static_cast<QObjectSlotDispatcher*>(this_);
+ if (connection->function.isEmpty()) {
+ *ret = false;
+ return;
+ }
+
+ // This is tricky. Normally the metaArgs[0] pointer is a pointer to the _function_
+ // for the new-style QObject::connect. Here we use the engine pointer as sentinel
+ // to distinguish those type of QSlotObjectBase connections from our QML connections.
+ QV4::ExecutionEngine *v4 = reinterpret_cast<QV4::ExecutionEngine*>(metaArgs[0]);
+ if (v4 != connection->function.engine()) {
+ *ret = false;
+ return;
+ }
+
+ QV4::Value function = *reinterpret_cast<QV4::Value*>(metaArgs[1]);
+ QV4::Value thisObject = *reinterpret_cast<QV4::Value*>(metaArgs[2]);
+ QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]);
+ int slotIndexToDisconnect = *reinterpret_cast<int*>(metaArgs[4]);
+
+ if (slotIndexToDisconnect != -1) {
+ // This is a QObject function wrapper
+ if (connection->thisObject.isEmpty() == thisObject.isEmpty() &&
+ (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) {
+
+ QPair<QObject *, int> connectedFunctionData = extractQtMethod(connection->function.value().asFunctionObject());
+ if (connectedFunctionData.first == receiverToDisconnect &&
+ connectedFunctionData.second == slotIndexToDisconnect) {
+ *ret = true;
+ return;
+ }
+ }
+ } else {
+ // This is a normal JS function
+ if (__qmljs_strict_equal(connection->function, function) &&
+ connection->thisObject.isEmpty() == thisObject.isEmpty() &&
+ (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) {
+ *ret = true;
+ return;
+ }
+ }
+
+ *ret = false;
+ }
+ break;
+ case NumOperations:
+ break;
+ }
+ };
+};
+
+} // namespace QV4
+
+Value QObjectWrapper::method_connect(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount == 0)
+ V4THROW_ERROR("Function.prototype.connect: no arguments given");
+
+ QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject);
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex < 0)
+ V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ if (!signalObject)
+ V4THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
+
+ if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher;
+ slot->signalIndex = signalIndex;
+
+ if (ctx->argumentCount == 1) {
+ slot->function = ctx->arguments[0];
+ } else if (ctx->argumentCount >= 2) {
+ slot->thisObject = ctx->arguments[0];
+ slot->function = ctx->arguments[1];
+ }
+
+ if (!slot->function.value().asFunctionObject())
+ V4THROW_ERROR("Function.prototype.connect: target is not a function");
+
+ if (!slot->thisObject.isEmpty() && !slot->thisObject.value().isObject())
+ V4THROW_ERROR("Function.prototype.connect: target this is not an object");
+
+ QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection);
+
+ return QV4::Value::undefinedValue();
+}
+
+Value QObjectWrapper::method_disconnect(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount == 0)
+ V4THROW_ERROR("Function.prototype.disconnect: no arguments given");
+
+ QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject);
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ if (!signalObject)
+ V4THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
+
+ if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ QV4::Value functionValue = QV4::Value::emptyValue();
+ QV4::Value functionThisValue = QV4::Value::emptyValue();
+
+ if (ctx->argumentCount == 1) {
+ functionValue = ctx->arguments[0];
+ } else if (ctx->argumentCount >= 2) {
+ functionThisValue = ctx->arguments[0];
+ functionValue = ctx->arguments[1];
+ }
+
+ if (!functionValue.asFunctionObject())
+ V4THROW_ERROR("Function.prototype.disconnect: target is not a function");
+
+ if (!functionThisValue.isEmpty() && !functionThisValue.isObject())
+ V4THROW_ERROR("Function.prototype.disconnect: target this is not an object");
+
+ QPair<QObject *, int> functionData = extractQtMethod(functionValue.asFunctionObject());
+
+ void *a[] = {
+ ctx->engine,
+ &functionValue,
+ &functionThisValue,
+ functionData.first,
+ &functionData.second
+ };
+
+ QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
+
+ return QV4::Value::undefinedValue();
+}
+
void QObjectWrapper::markObjects(Managed *that)
{
QObjectWrapper *This = static_cast<QObjectWrapper*>(that);
@@ -442,11 +664,6 @@ static inline QV4::Value valueToHandle(QV8Engine *e, QObject *v)
void QV8QObjectWrapper::init(QV8Engine *engine)
{
m_engine = engine;
-
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
-
- v4->functionPrototype->defineDefaultProperty(v4, QStringLiteral("connect"), Connect);
- v4->functionPrototype->defineDefaultProperty(v4, QStringLiteral("disconnect"), Disconnect);
}
// Load value properties
@@ -812,226 +1029,6 @@ static void FastValueSetterReadOnly(v8::Handle<v8::String> property, v8::Handle<
v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
}
-QPair<QObject *, int> QV8QObjectWrapper::ExtractQtSignal(QV8Engine *engine, const Value &value)
-{
- if (QV4::FunctionObject *function = value.asFunctionObject())
- return ExtractQtMethod(engine, function);
-
- if (QV4::QmlSignalHandler *handler = value.as<QV4::QmlSignalHandler>())
- return qMakePair(handler->object(), handler->signalIndex());
-
- return qMakePair((QObject *)0, -1);
-}
-
-QPair<QObject *, int> QV8QObjectWrapper::ExtractQtMethod(QV8Engine *engine, QV4::FunctionObject *function)
-{
- if (function && function->subtype == QV4::FunctionObject::WrappedQtMethod) {
- QObjectMethod *method = static_cast<QObjectMethod*>(function);
- return qMakePair(method->object(), method->methodIndex());
- }
-
- return qMakePair((QObject *)0, -1);
-}
-
-namespace QV4 {
-
-struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
-{
- QV4::PersistentValue function;
- QV4::PersistentValue thisObject;
- int signalIndex;
-
- QObjectSlotDispatcher()
- : QtPrivate::QSlotObjectBase(&impl)
- , signalIndex(-1)
- {}
-
- static void impl(int which, QSlotObjectBase *this_, QObject *r, void **metaArgs, bool *ret)
- {
- switch (which) {
- case Destroy: {
- delete static_cast<QObjectSlotDispatcher*>(this_);
- }
- break;
- case Call: {
- QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
- QVarLengthArray<int, 9> dummy;
- int *argsTypes = QQmlPropertyCache::methodParameterTypes(r, This->signalIndex, dummy, 0);
-
- int argCount = argsTypes ? argsTypes[0]:0;
-
- QV4::FunctionObject *f = This->function.value().asFunctionObject();
- QV4::ExecutionEngine *v4 = f->internalClass->engine;
- QV4::ExecutionContext *ctx = v4->current;
-
- QVarLengthArray<QV4::Value, 9> args(argCount);
- for (int ii = 0; ii < argCount; ++ii) {
- int type = argsTypes[ii + 1];
- if (type == qMetaTypeId<QVariant>()) {
- args[ii] = v4->v8Engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
- } else {
- args[ii] = v4->v8Engine->fromVariant(QVariant(type, metaArgs[ii + 1]));
- }
- }
-
- try {
- f->call(v4->current, This->thisObject.isEmpty() ? Value::fromObject(v4->globalObject) : This->thisObject.value(), args.data(), argCount);
- } catch (QV4::Exception &e) {
- e.accept(ctx);
- QQmlError error;
- QQmlExpressionPrivate::exceptionToError(e, error);
- if (error.description().isEmpty())
- error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString()));
- QQmlEnginePrivate::get(v4->v8Engine->engine())->warning(error);
- }
- }
- break;
- case Compare: {
- QObjectSlotDispatcher *connection = static_cast<QObjectSlotDispatcher*>(this_);
- if (connection->function.isEmpty()) {
- *ret = false;
- return;
- }
-
- // This is tricky. Normally the metaArgs[0] pointer is a pointer to the _function_
- // for the new-style QObject::connect. Here we use the engine pointer as sentinel
- // to distinguish those type of QSlotObjectBase connections from our QML connections.
- QV4::ExecutionEngine *v4 = reinterpret_cast<QV4::ExecutionEngine*>(metaArgs[0]);
- if (v4 != connection->function.engine()) {
- *ret = false;
- return;
- }
-
- QV4::Value function = *reinterpret_cast<QV4::Value*>(metaArgs[1]);
- QV4::Value thisObject = *reinterpret_cast<QV4::Value*>(metaArgs[2]);
- QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]);
- int slotIndexToDisconnect = *reinterpret_cast<int*>(metaArgs[4]);
-
- if (slotIndexToDisconnect != -1) {
- // This is a QObject function wrapper
- if (connection->thisObject.isEmpty() == thisObject.isEmpty() &&
- (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) {
-
- QPair<QObject *, int> connectedFunctionData = QV8QObjectWrapper::ExtractQtMethod(v4->v8Engine, connection->function.value().asFunctionObject());
- if (connectedFunctionData.first == receiverToDisconnect &&
- connectedFunctionData.second == slotIndexToDisconnect) {
- *ret = true;
- return;
- }
- }
- } else {
- // This is a normal JS function
- if (__qmljs_strict_equal(connection->function, function) &&
- connection->thisObject.isEmpty() == thisObject.isEmpty() &&
- (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) {
- *ret = true;
- return;
- }
- }
-
- *ret = false;
- }
- break;
- case NumOperations:
- break;
- }
- };
-};
-
-}
-
-QV4::Value QV8QObjectWrapper::Connect(SimpleCallContext *ctx)
-{
- if (ctx->argumentCount == 0)
- V4THROW_ERROR("Function.prototype.connect: no arguments given");
-
- QV8Engine *engine = ctx->engine->v8Engine;
-
- QPair<QObject *, int> signalInfo = ExtractQtSignal(engine, ctx->thisObject);
- QObject *signalObject = signalInfo.first;
- int signalIndex = signalInfo.second;
-
- if (signalIndex < 0)
- V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
-
- if (!signalObject)
- V4THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
-
- if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
-
- QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher;
- slot->signalIndex = signalIndex;
-
- if (ctx->argumentCount == 1) {
- slot->function = ctx->arguments[0];
- } else if (ctx->argumentCount >= 2) {
- slot->thisObject = ctx->arguments[0];
- slot->function = ctx->arguments[1];
- }
-
- if (!slot->function.value().asFunctionObject())
- V4THROW_ERROR("Function.prototype.connect: target is not a function");
-
- if (!slot->thisObject.isEmpty() && !slot->thisObject.value().isObject())
- V4THROW_ERROR("Function.prototype.connect: target this is not an object");
-
- QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection);
-
- return QV4::Value::undefinedValue();
-}
-
-QV4::Value QV8QObjectWrapper::Disconnect(SimpleCallContext *ctx)
-{
- if (ctx->argumentCount == 0)
- V4THROW_ERROR("Function.prototype.disconnect: no arguments given");
-
- QV8Engine *engine = ctx->engine->v8Engine;
-
- QPair<QObject *, int> signalInfo = ExtractQtSignal(engine, ctx->thisObject);
- QObject *signalObject = signalInfo.first;
- int signalIndex = signalInfo.second;
-
- if (signalIndex == -1)
- V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
-
- if (!signalObject)
- V4THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
-
- if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
-
- QV4::Value functionValue = QV4::Value::emptyValue();
- QV4::Value functionThisValue = QV4::Value::emptyValue();
-
- if (ctx->argumentCount == 1) {
- functionValue = ctx->arguments[0];
- } else if (ctx->argumentCount >= 2) {
- functionThisValue = ctx->arguments[0];
- functionValue = ctx->arguments[1];
- }
-
- if (!functionValue.asFunctionObject())
- V4THROW_ERROR("Function.prototype.disconnect: target is not a function");
-
- if (!functionThisValue.isEmpty() && !functionThisValue.isObject())
- V4THROW_ERROR("Function.prototype.disconnect: target this is not an object");
-
- QPair<QObject *, int> functionData = ExtractQtMethod(engine, functionValue.asFunctionObject());
-
- void *a[] = {
- ctx->engine,
- &functionValue,
- &functionThisValue,
- functionData.first,
- &functionData.second
- };
-
- QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
-
- return QV4::Value::undefinedValue();
-}
-
/*!
\fn v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &property, QV8QObjectWrapper::RevisionMode revisionMode)
diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h
index 18c0c26ca1..e06ce4980a 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper_p.h
+++ b/src/qml/qml/v8/qv8qobjectwrapper_p.h
@@ -73,7 +73,6 @@ class QObject;
class QV8Engine;
class QQmlData;
class QV8ObjectResource;
-class QV8QObjectConnectionList;
class QQmlPropertyCache;
namespace QV4 {
@@ -87,6 +86,8 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object
~QObjectWrapper();
+ static void initializeBindings(ExecutionEngine *engine);
+
QObject *object() const { return m_object.data(); }
void deleteQObject(bool deleteInstantly = false);
@@ -114,6 +115,9 @@ private:
{
static_cast<QObjectWrapper *>(that)->~QObjectWrapper();
}
+
+ static Value method_connect(SimpleCallContext *ctx);
+ static Value method_disconnect(SimpleCallContext *ctx);
};
struct QObjectMethod : public QV4::FunctionObject
@@ -204,7 +208,6 @@ public:
private:
friend class QQmlPropertyCache;
- friend class QV8QObjectConnectionList;
friend struct QV4::QObjectWrapper;
friend struct QV4::QObjectSlotDispatcher;
@@ -212,13 +215,8 @@ private:
const QHashedV4String &, QQmlContextData *, QV4::QObjectWrapper::RevisionMode);
static bool SetProperty(QV8Engine *, QObject *, const QHashedV4String &, QQmlContextData *,
v8::Handle<v8::Value>, QV4::QObjectWrapper::RevisionMode);
- static QV4::Value Connect(QV4::SimpleCallContext *ctx);
- static QV4::Value Disconnect(QV4::SimpleCallContext *ctx);
- static QPair<QObject *, int> ExtractQtMethod(QV8Engine *, QV4::FunctionObject *);
- static QPair<QObject *, int> ExtractQtSignal(QV8Engine *, const QV4::Value &value);
QV8Engine *m_engine;
- QHash<QObject *, QV8QObjectConnectionList *> m_connections;
};
v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV4String &string,