Jump on the D-Bus

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
Image:qt-logo_new.png Image:qq-title-article.png
Qt Quarterly | Выпуск 20 | Документация


by Harald Fernengel

If you are running a GNU/Linux system, chances are high that there's a livelyconversation happening on your desktop. D-Bus, the freedesktop.org messagebus system is currently the standard for desktop communication. It offers aneasy way for applications to talk to one another, and integrates well withvarious frameworks, toolkits and languages.

Содержание

Qt has had built-in D-Bus support via the QtDBuslibrary since version 4.2.Here is a simple "Hello world" example that connects to your desktop'ssession bus and lists all registered service names:

#include <QtCore>
#include <QtDBus>
 
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
 
    QDBusConnection bus = QDBusConnection::sessionBus();
    QStringList serviceNames = bus.interface()->
                               registeredServiceNames();
    qDebug() << serviceNames;
 
    return 0;
}

The static function QDBusConnection::sessionBus() returns a handle to thesession bus. The bus itself implements an interface which lets you query theexisting services. Under the hood, a message will be sent to the bus, askingfor all registered service names. The results are printed via qDebug().

Sending and Receiving

Let's send something to the bus. First, we create a new message &emdash; in our case,a signal.

QDBusMessage message = QDBusMessage::createSignal("/",
                           "com.mycompany.ping", "ping");

The first argument to createSignal() is the object path,describing where the sender object is located; in our case, we passa single slash to refer to the root path. The second argument is the objectinterface; we choose com.mycompany.ping. In the third argument, we passthe name of the signal: ping.

We can add an arbitrary amount of arguments toour signals &emdash; in our case, we add one string containing a nice hello message.

message << "Hello, just wanted to say that I'm here.";

Finally, we send the message via the session bus.

bus.send(message);

Now that we know how to send signals to the bus, we also want to receive something. D-Bus and Qtconnections are similar. Here is how we do connections within Qt code:

QObject::connect(<sender>, <signal>, <receiver>, <slot>);

And here is the syntax for D-Bus connections:

QDBusConnection::connect(<service name>, <object path>,
                         <interface name>, <signal name>, <receiver>, <slot>);
  • <service name> is the name of the application. There is no equivalentin Qt since all signals and slots are connected within the same application.
  • <object path> is the object we want to invoke. For Qt connections,this would be equivalent to the <sender> in the Qt connection code.)
  • <interface name> describes the interface that implements thesignal or slot, in the case where the object on the given path implementsmore than one interface. There is no equivalent to this in Qt.
  • <signal name> is purely the name of the signal, rather than thefull signature that Qt uses to resolve connections.
  • <receiver> is specified in the same way as for standard Qtconnections.

Connecting to our ping signal is therefore quite simple:

bus.connect("", "", "com.mycompany.ping", "ping",
            myObject, SLOT(pingReceived(QString)));

The line above connects signals originating from any connectedapplication on any object path that are named "ping" to the pingReceived()slot. Any time we emit the "ping" signal on the bus, this slot will be invoked.

In order to provide a service on the Bus, we can register a nice name for it:

bus.interface()->registerService("MyHome");

Talking to the Animals

Let's assume we want to make the mood of our household pets available on thebus for other interested parties:

class Animal : public QObject
{
    Q_OBJECT
 
public:
    Animal() { mood = 0; }
 
public slots:
    void feed() { ++mood; }
    void shoutAt() { --mood; }
 
    int currentMood() const { return mood; }
 
private:
    int mood;
};

Now we can create two animals and connect them to the bus:

Animal myCat, myDog;
 
bus.registerObject("/pets/snowflake", &amp;myCat,
                   QDBusConnection::ExportAllSlots);
bus.registerObject("/pets/waldi", &amp;myDog,
                   QDBusConnection::ExportAllSlots);

Each animal gets a unique object path so they can be referenced unambiguously.Anyone can now inquire about our dog's mood:

QDBusMessage msg = QDBusMessage::createMethodCall(
             "MyHome", "/pets/waldi", "", "currentMood");
 
QDBusMessage reply = bus.call(msg);
qDebug() << reply;

In the example above, call() will block until the answer arrives. To makethe call asynchronous, we can use callWithCallback() instead:

bus.callWithCallback(msg, this,
                     SLOT(answerReceived(QDBusMessage)));

The callWithCallback() function additionally takes a QObject and a slotas arguments. Once the reply arrives, Qt will invoke the answerReceived()slot, passing the reply as the slot's argument.

Summary

The QtDBus module integrates D-Bus nicely into the world of Qt'ssignals and slots. Similarly, other bindings solutions integrateD-Bus into other programming languages and toolkits, making D-Bus avery popular technology for exchanging messages.


Copyright © 2007 Trolltech Trademarks