summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp24
-rw-r--r--src/webchannel/signalhandler_p.h2
-rw-r--r--tests/auto/webchannel/tst_webchannel.cpp77
-rw-r--r--tests/auto/webchannel/tst_webchannel.h13
4 files changed, 105 insertions, 11 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index d796d1e..b4747d4 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -374,22 +374,26 @@ QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const int met
for (int i = 0; i < qMin(args.size(), method.parameterCount()); ++i) {
arguments[i].value = toVariant(args.at(i), method.parameterType(i));
}
-
// construct QGenericReturnArgument
QVariant returnValue;
- if (method.returnType() != qMetaTypeId<QVariant>() && method.returnType() != qMetaTypeId<void>()) {
+ if (method.returnType() == QMetaType::Void) {
+ // Skip return for void methods (prevents runtime warnings inside Qt), and allows
+ // QMetaMethod to invoke void-returning methods on QObjects in a different thread.
+ method.invoke(object,
+ arguments[0], arguments[1], arguments[2], arguments[3], arguments[4],
+ arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]);
+ } else {
+ QGenericReturnArgument returnArgument(method.typeName(), returnValue.data());
+
// Only init variant with return type if its not a variant itself, which would
// lead to nested variants which is not what we want.
- // Also, skip void-return types for obvious reasons (and to prevent a runtime warning inside Qt).
- returnValue = QVariant(method.returnType(), 0);
- }
- QGenericReturnArgument returnArgument(method.typeName(), returnValue.data());
-
- // now we can call the method
- method.invoke(object, returnArgument,
+ if (method.returnType() != QMetaType::QVariant)
+ returnValue = QVariant(method.returnType(), 0);
+ method.invoke(object, returnArgument,
arguments[0], arguments[1], arguments[2], arguments[3], arguments[4],
arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]);
-
+ }
+ // now we can call the method
return returnValue;
}
diff --git a/src/webchannel/signalhandler_p.h b/src/webchannel/signalhandler_p.h
index b6c316b..9bcb071 100644
--- a/src/webchannel/signalhandler_p.h
+++ b/src/webchannel/signalhandler_p.h
@@ -184,7 +184,7 @@ void SignalHandler<Receiver>::connectTo(const QObject *object, const int signalI
} // otherwise not yet connected, do so now
static const int memberOffset = QObject::staticMetaObject.methodCount();
- QMetaObject::Connection connection = QMetaObject::connect(object, signal.methodIndex(), this, memberOffset + signalIndex, Qt::DirectConnection, 0);
+ QMetaObject::Connection connection = QMetaObject::connect(object, signal.methodIndex(), this, memberOffset + signalIndex, Qt::AutoConnection, 0);
if (!connection) {
qWarning() << "SignalHandler: QMetaObject::connect returned false. Unable to connect to" << object << signal.name() << signal.methodSignature();
return;
diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp
index dd2059e..0f050a7 100644
--- a/tests/auto/webchannel/tst_webchannel.cpp
+++ b/tests/auto/webchannel/tst_webchannel.cpp
@@ -365,6 +365,18 @@ void TestWebChannel::testInfoForObject()
}
{
QJsonArray method;
+ method.append(QStringLiteral("setProp"));
+ method.append(obj.metaObject()->indexOfMethod("setProp(QString)"));
+ expected.append(method);
+ }
+ {
+ QJsonArray method;
+ method.append(QStringLiteral("fire"));
+ method.append(obj.metaObject()->indexOfMethod("fire()"));
+ expected.append(method);
+ }
+ {
+ QJsonArray method;
method.append(QStringLiteral("method1"));
method.append(obj.metaObject()->indexOfMethod("method1()"));
expected.append(method);
@@ -392,6 +404,12 @@ void TestWebChannel::testInfoForObject()
signal.append(obj.metaObject()->indexOfMethod("sig2(QString)"));
expected.append(signal);
}
+ {
+ QJsonArray signal;
+ signal.append(QStringLiteral("replay"));
+ signal.append(obj.metaObject()->indexOfMethod("replay()"));
+ expected.append(signal);
+ }
QCOMPARE(info["signals"].toArray(), expected);
}
@@ -473,6 +491,19 @@ void TestWebChannel::testInfoForObject()
property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.returnedObject())));
expected.append(property);
}
+ {
+ QJsonArray property;
+ property.append(obj.metaObject()->indexOfProperty("prop"));
+ property.append(QStringLiteral("prop"));
+ {
+ QJsonArray signal;
+ signal.append(1);
+ signal.append(obj.metaObject()->indexOfMethod("propChanged(QString)"));
+ property.append(signal);
+ }
+ property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.prop())));
+ expected.append(property);
+ }
QCOMPARE(info["properties"].toArray(), expected);
}
}
@@ -694,6 +725,52 @@ void TestWebChannel::testInfiniteRecursion()
QJsonObject objectInfo = channel.d_func()->publisher->wrapResult(QVariant::fromValue(&obj), m_dummyTransport).toObject();
}
+void TestWebChannel::testAsyncObject()
+{
+ QWebChannel channel;
+ channel.connectTo(m_dummyTransport);
+
+ QThread thread;
+ thread.start();
+
+ TestObject obj;
+ obj.moveToThread(&thread);
+
+ QJsonArray args;
+ args.append(QJsonValue("message"));
+
+ int method = obj.metaObject()->indexOfMethod("setProp(QString)");
+ QVERIFY(method != -1);
+
+ {
+ QSignalSpy spy(&obj, &TestObject::propChanged);
+ channel.d_func()->publisher->invokeMethod(&obj, method, args);
+ QVERIFY(spy.wait());
+ QCOMPARE(spy.at(0).at(0).toString(), args.at(0).toString());
+ }
+
+ channel.registerObject("myObj", &obj);
+ channel.d_func()->publisher->initializeClient(m_dummyTransport);
+
+ QJsonObject connectMessage;
+ connectMessage["type"] = 7;
+ connectMessage["object"] = "myObj";
+ connectMessage["signal"] = obj.metaObject()->indexOfSignal("replay()");
+ channel.d_func()->publisher->handleMessage(connectMessage, m_dummyTransport);
+
+ {
+ QSignalSpy spy(&obj, &TestObject::replay);
+ QMetaObject::invokeMethod(&obj, "fire");
+ QVERIFY(spy.wait());
+ channel.deregisterObject(&obj);
+ QMetaObject::invokeMethod(&obj, "fire");
+ QVERIFY(spy.wait());
+ }
+
+ thread.quit();
+ thread.wait();
+}
+
static QHash<QString, QObject*> createObjects(QObject *parent)
{
const int num = 100;
diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h
index 11786b4..5e832c9 100644
--- a/tests/auto/webchannel/tst_webchannel.h
+++ b/tests/auto/webchannel/tst_webchannel.h
@@ -69,6 +69,7 @@ class TestObject : public QObject
Q_PROPERTY(QString bar READ bar NOTIFY theBarHasChanged)
Q_PROPERTY(QObject * objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectPropertyChanged)
Q_PROPERTY(TestObject * returnedObject READ returnedObject WRITE setReturnedObject NOTIFY returnedObjectChanged)
+ Q_PROPERTY(QString prop READ prop WRITE setProp NOTIFY propChanged)
public:
explicit TestObject(QObject *parent = 0)
@@ -96,6 +97,11 @@ public:
return mReturnedObject;
}
+ QString prop() const
+ {
+ return mProp;
+ }
+
Q_INVOKABLE void method1() {}
protected:
@@ -111,6 +117,8 @@ signals:
void theBarHasChanged();
void objectPropertyChanged();
void returnedObjectChanged();
+ void propChanged(const QString&);
+ void replay();
public slots:
void slot1() {}
@@ -128,6 +136,9 @@ public slots:
emit objectPropertyChanged();
}
+ void setProp(const QString&prop) {emit propChanged(mProp=prop);}
+ void fire() {emit replay();}
+
protected slots:
void slot3() {}
@@ -137,6 +148,7 @@ private slots:
public:
QObject *mObjectProperty;
TestObject *mReturnedObject;
+ QString mProp;
};
class BenchObject : public QObject
@@ -281,6 +293,7 @@ private slots:
void testRemoveUnusedTransports();
void testPassWrappedObjectBack();
void testInfiniteRecursion();
+ void testAsyncObject();
void benchClassInfo();
void benchInitializeClients();