Contents:
The Qt3 bindings do not support autogeneration of service objects yet. In order to provide interfaces over D-Bus, an application has to implement the QDBusObjectBase interface and register an instance of the resulting class with the QDBusConnection.
#include <dbus/qdbusconnection.h>; #include <dbus/qdbusobject.h>; class QStringList; class TestService : public QDBusObjectBase { public: TestService(const QDBusConnection& connection); virtual ~TestService(); protected: virtual bool handleMethodCall(const QDBusMessage& message); private: QDBusConnection m_connection; private: QStringList sortStrings(const QStringList& list); };
#include <qstringlist.h>; #include <dbus/qdbuserror.h>; #include <dbus/qdbusmessage.h>; TestService::TestService(const QDBusConnection& connection) : m_connection(connection) { m_connection.registerObject("/ListSorter", this); } TestService::~TestService() { m_connection.unregisterObject("/ListSorter"); } // return false to let D-Bus send a standard error message that the method is unknown bool TestService::handleMethod(const QDBusMessage& message) { if (message.interface() != "org.example.Sort") return false; if (message.member() == "Strings") { // check parameters if (message.count() != 1 || message[0].type() != QDBusData::List) { // method signature not what we expected QDBusError error = QDBusError::stdInvalidArgs( "Expected one argument of type array of string"); QDBusMessage reply = QDBusMessage::methodError(message, error); // send error m_connection.send(reply); // tell D-Bus we did handle the call return true; } // call implementation QStringList result = sortStrings(message[0].toQStringList()); // prepare reply QDBusMessage reply = QDBusMessage::methodReply(message); reply << QDBusData::fromList(result); // send reply m_connection.send(reply); // tell D-Bus we did handle the call return true; } return false; } QStringList TestService::sortStrings(const QStringList& list) { QStringList result = list; result.sort(); return result; }
int main(int argc, char** argv) { QApplication app(argc, argv, false); QDBusConnection connection = QDBusConnection::sessionBus(); if (!connection.isConnected()) qFatal("Cannot connect to session bus"); // try to get a specific service name if (!connection.requestName("org.example.SortService")) { qWarning("Requesting name 'org.example.SortService' failed. " "Will only be addressable through unique name '%s'", connection.uniqueName().local8Bit().data()); } else { qDebug("Requesting name 'org.example.SortService' successfull"); } TestService service(connection); return app.exec(); }
When an application connects to D-Bus it gets a unique name generated by the bus daemon.
However, an application providing service will often want to be reachable under a fixed name, like a webserver being reachable through a domain name independent from its actual IP address. See section Service names for details on service names.
In order to get such a specific name an application has to request it using QDBusConnection::requestName()
The example above request "org.example.SortService"
but continues with the default unique name in the case some other application is currently owning that name.
To make service objects available to other applications on the same bus the application has to register the objects instances with the connection to the bus using QDBusConnection::registerObject()
Registering means to specify an object path where the object will be located, i.e. how it can be unambiguously be addressed in method calls. See section Object paths for details on object paths.
If the applications has introspectable objects it is recommended to register an introspectable root object, i.e. using "/"
as the path, so other applications have a common place to start asking for introspection data.
In the example above a service object providing sorting services on lists is registered on the path "/ListSorter"
D-Bus methods and signals of a service object a grouped into interfaces.
See section Interface names for details on interface naming.
An object can implement any number of interfaces, for example the interface for the functionality it wants to provide and a D-Bus standard interface like "org.freedesktop.DBus.Introspectable"
for providing an XML description of all its interfaces.
The service object of the example above implements just one interface "org.example.Sort"
and its handleMethodCall() explicitly checks all received messages and rejects any messsage not sent to this particular interface by returning false
and thus telling the D-Bus layer to generate a standard error response.
Multiple interfaces can of course be directly implemented in one C++ class, however it might sometimes be wise to delegate calls for different interfaces to different implementations:
class Interface1 : public QDBusObjectBase { public: Interface1(const QDBusConnection&); protected: virtual bool handleMethodCall(const QDBusMessage&); }; class Interface2 : public QDBusObjectBase { public: Interface2(const QDBusConnection&); protected: virtual bool handleMethodCall(const QDBusMessage&); }; class MultiInterfaceService : public QDBusObjectBase { public: MultiInterfaceService(const QDBusConnection&); protected: virtual bool handleMethodCall(const QDBusMessage&); private: QMap<QString, QDBusObjectBase*> m_interfaces; }; MultiInterfaceService::MultiInterfaceService(const QDBusConnection& connection) { m_interfaces.insert("org.example.Interface1", new Interface1(connection)); m_interfaces.insert("org.example.Interface2", new Interface2(connection)); } bool MultiInterfaceService::handleMethodCall(const QDBusMessage& message) { // delegate call to its interface handler QDBusObjectBase* handler = m_interfaces[message.interface()]; if (handler != 0) return delegateMethodCall->(message, handler); else return false; // no such interface }