From 33f3d70c74564fb1e296537e14d1e0bddb4bb944 Mon Sep 17 00:00:00 2001 From: Maximilian Goldstein Date: Fri, 5 Feb 2021 15:14:42 +0100 Subject: qqmlproxymetaobject: Support invoking methods and slots Previously this just failed silently and returned garbage data. Change-Id: Ia8b72836aa0ccfd50fd18b0f813c2bf3a00801c5 Reviewed-by: Ulf Hermann --- src/qml/qml/qqmlproxymetaobject.cpp | 84 ++++++++++++++-------- src/qml/qml/qqmlproxymetaobject_p.h | 2 + .../auto/qml/qqmllanguage/data/foreignExtended.qml | 3 + tests/auto/qml/qqmllanguage/testtypes.h | 3 + tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 2 + 5 files changed, 63 insertions(+), 31 deletions(-) diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp index c5cb2ec059..21d3c7ed05 100644 --- a/src/qml/qml/qqmlproxymetaobject.cpp +++ b/src/qml/qml/qqmlproxymetaobject.cpp @@ -65,6 +65,41 @@ QQmlProxyMetaObject::~QQmlProxyMetaObject() proxies = nullptr; } +QObject *QQmlProxyMetaObject::getProxy(int index) +{ + if (!proxies) { + if (!proxies) { + proxies = new QObject*[metaObjects->count()]; + ::memset(proxies, 0, + sizeof(QObject *) * metaObjects->count()); + } + } + + if (!proxies[index]) { + const ProxyData &data = metaObjects->at(index); + if (!data.createFunc) + return nullptr; + + QObject *proxy = data.createFunc(object); + const QMetaObject *metaObject = proxy->metaObject(); + proxies[index] = proxy; + + int localOffset = data.metaObject->methodOffset(); + int methodOffset = metaObject->methodOffset(); + int methods = metaObject->methodCount() - methodOffset; + + // ### - Can this be done more optimally? + for (int jj = 0; jj < methods; ++jj) { + QMetaMethod method = + metaObject->method(jj + methodOffset); + if (method.methodType() == QMetaMethod::Signal) + QQmlPropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj); + } + } + + return proxies[index]; +} + int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a) { Q_ASSERT(object == o); @@ -74,38 +109,13 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void id >= metaObjects->constLast().propertyOffset) { for (int ii = 0; ii < metaObjects->count(); ++ii) { - const ProxyData &data = metaObjects->at(ii); - if (id >= data.propertyOffset) { - if (!proxies) { - proxies = new QObject*[metaObjects->count()]; - ::memset(proxies, 0, - sizeof(QObject *) * metaObjects->count()); - } - - if (!proxies[ii]) { - if (!data.createFunc) - continue; - QObject *proxy = data.createFunc(object); - const QMetaObject *metaObject = proxy->metaObject(); - proxies[ii] = proxy; - - int localOffset = data.metaObject->methodOffset(); - int methodOffset = metaObject->methodOffset(); - int methods = metaObject->methodCount() - methodOffset; - - // ### - Can this be done more optimally? - for (int jj = 0; jj < methods; ++jj) { - QMetaMethod method = - metaObject->method(jj + methodOffset); - if (method.methodType() == QMetaMethod::Signal) - QQmlPropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj); - } - } - - int proxyOffset = proxies[ii]->metaObject()->propertyOffset(); - int proxyId = id - data.propertyOffset + proxyOffset; + const int globalPropertyOffset = metaObjects->at(ii).propertyOffset; + if (id >= globalPropertyOffset) { + QObject *proxy = getProxy(ii); + const int localProxyOffset = proxy->metaObject()->propertyOffset(); + const int localProxyId = id - globalPropertyOffset + localProxyOffset; - return proxies[ii]->qt_metacall(c, proxyId, a); + return proxy->qt_metacall(c, localProxyId, a); } } } else if (c == QMetaObject::InvokeMetaMethod && @@ -114,6 +124,18 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void if (m.methodType() == QMetaMethod::Signal) { QMetaObject::activate(object, id, a); return -1; + } else { + for (int ii = 0; ii < metaObjects->count(); ++ii) { + const int globalMethodOffset = metaObjects->at(ii).methodOffset; + if (id >= globalMethodOffset) { + QObject *proxy = getProxy(ii); + + const int localMethodOffset = proxy->metaObject()->methodOffset(); + const int localMethodId = id - globalMethodOffset + localMethodOffset; + + return proxy->qt_metacall(c, localMethodId, a); + } + } } } diff --git a/src/qml/qml/qqmlproxymetaobject_p.h b/src/qml/qml/qqmlproxymetaobject_p.h index 2b7a980361..dfa5d44059 100644 --- a/src/qml/qml/qqmlproxymetaobject_p.h +++ b/src/qml/qml/qqmlproxymetaobject_p.h @@ -80,6 +80,8 @@ protected: int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override; private: + QObject *getProxy(int index); + QList *metaObjects; QObject **proxies; diff --git a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml index 182d60fd02..4863e0d567 100644 --- a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml +++ b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml @@ -12,6 +12,9 @@ QtObject { property int extendedBase: extended.base + property int extendedInvokable: extended.invokable() + property int extendedSlot: extended.slot() + property int extendedExtension: extended.extension property int foreignExtendedExtension: foreignExtended.extension diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 77f09a232c..74cd608471 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1468,6 +1468,9 @@ class Extension : public QObject public: Extension(QObject *parent = nullptr) : QObject(parent) {} int extension() const { return 42; } + Q_INVOKABLE int invokable() { return 123; } +public slots: + int slot() { return 456; } }; class Extended : public QObject diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 5e40387ceb..ff76e4510e 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -5497,6 +5497,8 @@ void tst_qqmllanguage::extendedForeignTypes() QCOMPARE(o->property("foreignExtendedExtension").toInt(), 42); QCOMPARE(o->property("foreignObjectName").toString(), QLatin1String("foreign")); QCOMPARE(o->property("foreignExtendedObjectName").toString(), QLatin1String("foreignExtended")); + QCOMPARE(o->property("extendedInvokable").toInt(), 123); + QCOMPARE(o->property("extendedSlot").toInt(), 456); } void tst_qqmllanguage::foreignTypeSingletons() { -- cgit v1.2.3