Playing with DBus in qt

Printer-friendly versionSend to friendPDF version
When users are right

A few days ago I received an email from a user of Kdropbox saying the behaviour of the application when clicking on the the system tray icon was not the usual in KDE. As he said, if a window is opened when you click on the icon a second click should close it. It's funny but so many years using this desktop environment and I had not noticed. I checked and, it is true that not all programs fulfill it, but those that ship with KDE do it.

Kdropbox opened (and even the stable version opens at the time of writing this) a window of a file browser (konqueror or dolphin) every time you click the icon, so it was a good way to quickly launch 377 file browsers, depending on the speed of our hand :D

In any case, finally this is usability and the user was right so I had to change it. However, there was a very important problem in all this: to do such control in a window of the application itself is relatively simple, but what if what we have launched is a separate process? Well, one solution might be the first that occurred to me: start the process, save the pid and kill it with the second click. Error, Dolphin doesn't launch a new instance if it is already running, so if there is already a Dolphin window opened, when you click on the icon, it will not have a separate pid and what is worse, kill the process would terminate with all file manager windows opened by the user.

 DBus and qdbusviewer

A good solution for these cases is to use DBus which is the Linux standard for communication between applications. If we have no previous experience it is best to play a bit with qdbusviewer which will allow us to seek through all the applications that use this protocol and even call their methods.

For example we can open a new window in Dolphin showing a URL. But first it is necessary to have Dolphin already running otherwise it will not appear in the list of services in qdbusviewer (left panel)

As we give OK on the window in which the parameters are requested we will see the lower panel shows the response to the method or any errors that might occur.

Typing the code to make calls
But how do we do this from our application? There are many examples on the web to answer this question, a quick example using QT for the previous case would be this ... well, not so fast. A little bit of theory before.

We always need to know:

1. The service name of the process in DBus, in practice seems a URL
2. The path to the object you want to call
3. The interface declared by the application for the method that we want to use
4. The method and its parameters

It is obvious that we can
obtain all this easily using qdbusviewer. In our case:

1. Service Name: org.kde.dolphin
2. Path: /MainApplication
3. Interface: org.kde.dolphin.Aplication
4. Method: openWindow

Taking all the necessary, QT makes it very easy with QDBusInterface class. We just have to include the classes we need and a few lines of code to make the call.

In this example you need the following classes for DBus:

 

#include <QDBusInterface>

#include <QDBusReply>

 

The code necessary to open our Dolphin window is as follows, bearing in mind that path should contain a valid address:

QDBusInterface remoteApp("org.kde.dolphin","/MainApplication","org.kde.dolphin.Application",QDBusConnection::sessionBus());

if (remoteApp.isValid()){

QDBusReply<int> reply =remoteApp.call("openWindow",path);

int winid=(reply.value());

}

We tried to connect to the application interface and path we wanted, then we found that we really contacted it and so we called the method openWindow with the desired address as parameter. Finally we saved the response returned by the method that is the identifier of the new window.

A final example, let's see how to close that same window as the way forward is slightly different. To understand this we must see how the Dolphin tree is transformed into DBus, the next screen shot shows a new node which appeared identifying the new window, so if the identifier given to us in the above method call is 3 the path we need is

/dolphin/MainWindow3

This is important when closing the window because it is the path to use:

QDBusInterface remoteApp("org.kde.dolphin","/dolphin/MainWindow"+QString::number(getWindowId()), "org.kde.dolphin.MainWindow", QDBusConnection::sessionBus());

if (remoteApp.connection().isConnected())

QDBusReply<int> reply =remoteApp.call("quit");

We concatenated the string /dolphin/MainWindow with the ID of the window that we had saved. In this case the method have no parameters and returns no value.
This was nothing
This has been a couple of basic examples, as each application is a different world and has to be investigated a bit to see the methods it contains and what we can do with them. Of course not all applications are ready to be used by DBus.
Well, all this is just the tip of the iceberg and, in example, we can use signals and slots between different applications in a similar way as it does QT. In my case this is all I needed so far.

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.