Using D-Bus as a client

Contents:

Introduction

While it is of course possible to just exchange D-Bus messages with a D-Bus service, it is a lot more comfortable to use QDBusProxy.

With QDBusProxy you only need to specify the service object once, i.e. its D-Bus name, path and interface, and just provide the method and its parameters when initiating an invokation.

Additionally the proxy transforms D-Bus signals from the proxy's peer (the D-Bus service object's interface it is associated with) to QObject signal carrying the original signal's content.

A simple D-Bus client example

   #include <dbus/qdbusconnection.h>
   #include <dbus/qdbusmessage.h>
   #include <dbus/qdbusproxy.h>

   int main()
   {
       // establish a connection to the session bus

       QDBusConnection connection = QDBusConnection::sessionBus();
       if (!connection.isConnected())
           qFatal("Failed to connect to session bus");

       // create a proxy object for method calls

       QDBusProxy proxy(connection);
       proxy.setService("org.freedesktop.DBus");   // who we work with
       proxy.setPath("/org/freedesktop/DBus");     // which object inside the peer work with
       proxy.setInterface("org.freedesktop.DBus"); // which of its interfaces we will use

       // call the "ListNames" method. It returns an array of string, in Qt3 terms
       // a QStringList, it expects no parameters

       QValueList<QDBusData> params;
       QDBusMessage reply = proxy.sendWithReply("ListNames", params);

       if (reply.type() != QDBusMessage::ReplyMessage)
           qFatal("Call failed");

       if (reply.count() != 1 || reply[0].type() != QDBusData::List)
           qFatal("Unexpected reply");

       bool ok = false;
       QStringList names = reply[0].toQStringList(&ok);

       if (!ok) qFatal("Unexpected reply");

       for (QStringList::iterator it = names.begin(); it != names.end(); ++it)
       {
           qDebug("%s", (*it).local8Bit().data());
       }

       return 0;
   }

Program initialization

A connection to the bus is acquired using QDBusConnection::sessionBus()

Next, a proxy is created for the object "/org/freedesktop/DBus" with interface "org.freedesktop.DBus" on the service "org.freedesktop.DBus"

This is a proxy for the message bus itself.

Method invocation

There are two choices for method invocation:

Synchronous method calls

As seen in the example code above, a synchronous method call can be achieved by QDBusProxy::sendWithReply(). It sends a method call to the remote object, and blocks until reply is received. The outgoing arguments are specified as a list of QDBusData.

Asynchronous method calls

To invoke a method asynchronously, connect the proxy's signal QDBusProxy::asyncReply(int, const QDBusMessage&) to a suitable slot like with any other Qt Signal-Slot connection.

Then call QDBusProxy::sendWithAsyncReply() It returns a numerical identifier of the call, so it can be related in the slot once the result is available.

The slot's first argument is the reveived reply's call identifier as returned by the method call. The second parameter is the reply message similar to the one in the synchronous call.

Note:
For asynchronous calls you'll need a running event loop, i.e. a QApplication object and its exec() having been invoked.

Connecting to D-Bus signals

To receive D-BUS signals just connect to the QDBusProxy's signal QDBusProxy::dbusSignal(const QDBusMessage&)

It will be emitted whenever a D-Bus signal message is received from the peer object. Filtering of signals is based on the value set for service, path and interface

Note:
Filtering for service will only happen if service is a unique D-Bus name, i.e. if it starts with a colon ":" since D-Bus signals carry the sender's unique name and filtering by a requested name would reject all signals

Usually a proxy will be also be used to send to the peer object, thus having them all set. However if a proxy is only needed for signals, any of the three properties can be omitted (e.g. set to QString::null ), in which case only the available properties will be checked against the respective message field when deciding about dropping or emitting the message. See QDBusProxy::handleDBusSignal()

If you want all signal travelling on the bus, or apply filtering for different criteria, e.g. get all signals coming from interfaces starting with "org.", use QDBusConnection::connect() instead. The signature of the slot stays the same.

Signal example

First declare a receiver class:

   class MyReceiver : public QObject
   {
       Q_OBJECT
   public slots:
       void handleDBusSignal(const QDBusMessage&);
   };

Then somewhere else in a source file:

   QDBusConnection connection = QDBusConnection::sessionBus();

   MyReceiver* receiver1 = new MyReceiver();

   connection.connect(receiver1, SLOT(handleDBusSignal(const QDBusMessage&)));

receiver1 will get all signals on this connection

   QDBusProxy* proxy = new QDBusProxy(connection);
   proxy->setService("org.freedesktop.DBus");   // who we work with
   proxy->setPath("/org/freedesktop/DBus");     // which object inside the peer work with
   proxy->setInterface("org.freedesktop.DBus"); // which of its interfaces we will use

   MyReceiver* receiver2 = new MyReceiver();

   QObject::connect(proxy,     SIGNAL(dbusSignal(const QDBusMessage&)),
                    receiver2, SLOT(handleDBusSignal(const QDBusMessage&)));

receiver2 will only get signals coming from the proxy's peer interface


Generated by  doxygen 1.6.2