QDBusConnection::registorObject with interface

Currently QDBus relies on a key in QMetaClassInfo to understand the DBus interface name.
This patch allows QDBus to also use a specified interface name in the registerObject call
instead of relying on QMetaClassInfo that might not be there (if the QObject was created
in QML or Javascript for example).

Change-Id: Ie02b2c67e7deb07f43e35eb166c11833fcbf38f3
Task-number: QTBUG-44074
Reviewed-by: Kevron Rees <kevron.m.rees@intel.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Kevron Rees 2015-01-22 15:00:36 -08:00 committed by Thiago Macieira
parent 06ecd74db1
commit 0eec8c86b6
6 changed files with 101 additions and 3 deletions

View File

@ -761,6 +761,26 @@ bool QDBusConnection::disconnect(const QString &service, const QString &path, co
was registered with QDBusConnection::ExportChildObjects.
*/
bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
{
return registerObject(path, QString(), object, options);
}
/*!
\overload
\since 5.5
Registers the object \a object at path \a path with interface name \a interface
and returns \c true if the registration was successful. The \a options parameter
specifies how much of the object \a object will be exposed through
D-Bus.
This function does not replace existing objects: if there is already an object registered at
path \a path, this function will return false. Use unregisterObject() to unregister it first.
You cannot register an object as a child object of an object that
was registered with QDBusConnection::ExportChildObjects.
*/
bool QDBusConnection::registerObject(const QString &path, const QString &interface, QObject *object, RegisterOptions options)
{
Q_ASSERT_X(QDBusUtil::isValidObjectPath(path), "QDBusConnection::registerObject",
"Invalid object path given");
@ -793,6 +813,7 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
// we can add the object here
node->obj = object;
node->flags = options;
node->interfaceName = interface;
d->registerObject(node);
//qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());

View File

@ -161,6 +161,8 @@ public:
bool registerObject(const QString &path, QObject *object,
RegisterOptions options = ExportAdaptors);
bool registerObject(const QString &path, const QString &interface, QObject *object,
RegisterOptions options = ExportAdaptors);
void unregisterObject(const QString &path, UnregisterMode mode = UnregisterNode);
QObject *objectRegisteredAt(const QString &path) const;

View File

@ -152,6 +152,7 @@ public:
{ return obj || !children.isEmpty(); }
QString name;
QString interfaceName;
union {
QObject *obj;
QDBusVirtualObject *treeNode;

View File

@ -1481,8 +1481,12 @@ void QDBusConnectionPrivate::activateObject(ObjectTreeNode &node, const QDBusMes
if (node.flags & (QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportNonScriptableSlots) ||
node.flags & (QDBusConnection::ExportScriptableInvokables|QDBusConnection::ExportNonScriptableInvokables)) {
bool interfaceFound = true;
if (!msg.interface().isEmpty())
interfaceFound = qDBusInterfaceInObject(node.obj, msg.interface());
if (!msg.interface().isEmpty()) {
if (!node.interfaceName.isEmpty())
interfaceFound = msg.interface() == node.interfaceName;
else
interfaceFound = qDBusInterfaceInObject(node.obj, msg.interface());
}
if (interfaceFound) {
if (!activateCall(node.obj, node.flags, msg))

View File

@ -134,7 +134,7 @@ QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node
// create XML for the object itself
const QMetaObject *mo = node.obj->metaObject();
for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
xml_data += qDBusGenerateMetaObjectXml(QString(), mo, mo->superClass(),
xml_data += qDBusGenerateMetaObjectXml(node.interfaceName, mo, mo->superClass(),
node.flags);
}

View File

@ -65,6 +65,27 @@ void MyObject::method(const QDBusMessage &msg)
//qDebug() << msg;
}
class MyObjectWithoutInterface: public QObject
{
Q_OBJECT
public slots:
void method(const QDBusMessage &msg);
public:
static QString path;
static QString interface;
int callCount;
MyObjectWithoutInterface(QObject *parent = 0) : QObject(parent), callCount(0) {}
};
void MyObjectWithoutInterface::method(const QDBusMessage &msg)
{
path = msg.path();
interface = msg.interface();
++callCount;
//qDebug() << msg;
}
class tst_QDBusConnection: public QObject
{
Q_OBJECT
@ -87,6 +108,8 @@ private slots:
void registerObject_data();
void registerObject();
void registerObjectWithInterface_data();
void registerObjectWithInterface();
void registerObjectPeer_data();
void registerObjectPeer();
void registerObject2();
@ -112,6 +135,7 @@ private slots:
public:
QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; }
bool callMethod(const QDBusConnection &conn, const QString &path);
bool callMethod(const QDBusConnection &conn, const QString &path, const QString &interface);
bool callMethodPeer(const QDBusConnection &conn, const QString &path);
};
@ -379,6 +403,40 @@ void tst_QDBusConnection::registerObject()
QVERIFY(!callMethod(con, path));
}
void tst_QDBusConnection::registerObjectWithInterface_data()
{
QTest::addColumn<QString>("path");
QTest::addColumn<QString>("interface");
QTest::newRow("/") << "/" << "org.foo";
QTest::newRow("/p1") << "/p1" << "org.foo";
QTest::newRow("/p2") << "/p2" << "org.foo";
QTest::newRow("/p1/q") << "/p1/q" << "org.foo";
QTest::newRow("/p1/q/r") << "/p1/q/r" << "org.foo";
}
void tst_QDBusConnection::registerObjectWithInterface()
{
QFETCH(QString, path);
QFETCH(QString, interface);
QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected());
{
// register one object at root:
MyObjectWithoutInterface obj;
QVERIFY(con.registerObject(path, interface, &obj, QDBusConnection::ExportAllSlots));
QCOMPARE(con.objectRegisteredAt(path), static_cast<QObject *>(&obj));
QVERIFY(callMethod(con, path, interface));
QCOMPARE(obj.path, path);
QCOMPARE(obj.interface, interface);
}
// make sure it's gone
QVERIFY(!callMethod(con, path, interface));
}
class MyServer : public QDBusServer
{
Q_OBJECT
@ -844,6 +902,16 @@ bool tst_QDBusConnection::callMethod(const QDBusConnection &conn, const QString
return (MyObject::path == path);
}
bool tst_QDBusConnection::callMethod(const QDBusConnection &conn, const QString &path, const QString &interface)
{
QDBusMessage msg = QDBusMessage::createMethodCall(conn.baseService(), path, interface, "method");
QDBusMessage reply = conn.call(msg, QDBus::Block/*WithGui*/);
if (reply.type() != QDBusMessage::ReplyMessage)
return false;
QTest::qCompare(MyObjectWithoutInterface::path, path, "MyObjectWithoutInterface::path", "path", __FILE__, __LINE__);
return (MyObjectWithoutInterface::path == path) && MyObjectWithoutInterface::interface == interface;
}
bool tst_QDBusConnection::callMethodPeer(const QDBusConnection &conn, const QString &path)
{
QDBusMessage msg = QDBusMessage::createMethodCall("", path, "", "method");
@ -1307,6 +1375,8 @@ void tst_QDBusConnection::callVirtualObjectLocal()
}
QString MyObject::path;
QString MyObjectWithoutInterface::path;
QString MyObjectWithoutInterface::interface;
QTEST_MAIN(tst_QDBusConnection)
#include "tst_qdbusconnection.moc"