Thursday, 17 April 2008

simple qdbus tutorial (part one)

If you are a reasonably seasoned user of kde, the chances are you will have encountered the Desktop COmmunications Protocol, or DCOP. Now, DCOP has many uses, it is useful for apps to communicate with each other, it is certainly handy when scripting for a GUI app. Personally I find the most useful aspect of DCOP is the ability to control GUI apps remotely, and to see what they are up to. For example, if I wish to find out what song amarok is playing on a remote machine, I can execute the following on the command line (as root):
dcop --user fred amarok player nowPlaying
Pretty nifty. But DCOP is now being phased out, and is being replaced by D-Bus. D-Bus is heavily influenced by DCOP and the basics are fairly easily learned.

This post will attempt to show how to communicate with D-Bus, specifically using qdbus. (qdbusviewer may be a topic for another time, but do have a look at it - it may be a whole lot more self-explanatory).

First off, let's see what happens when we run qdbus on its own:
cm@fool:~> qdbus
:1.0
org.kde.KResourcesManager
org.kde.kopete
:1.2
org.kde.klauncher
:1.23
:1.3
org.kde.kded
org.kde.kwalletd
:1.30
org.ktorrent.ktorrent
:1.37
:1.38
:1.6
org.kde.kwalletmanager
:1.8
org.kde.knotify
org.freedesktop.DBus
That give us a list of all the applications we can manipulate using qdbus. In this instance we'll focus on ktorrent. First I want to see what objects are available in the application:
cm@fool:~> qdbus org.ktorrent.ktorrent
/
/KDebug
/KIO
/KIO/Scheduler
/KTorrent
/MainApplication
/ktorrent
/ktorrent/MainWindow_1
/ktorrent/MainWindow_1/actions
/ktorrent/MainWindow_1/actions/file_new
/ktorrent/MainWindow_1/actions/file_open
/ktorrent/MainWindow_1/actions/file_quit
/ktorrent/MainWindow_1/actions/options_show_statusbar
/ktorrent/MainWindow_1/actions/options_show_menubar
/ktorrent/MainWindow_1/actions/options_configure
/ktorrent/MainWindow_1/actions/options_configure_keybinding
/ktorrent/MainWindow_1/actions/options_configure_toolbars
/ktorrent/MainWindow_1/actions/help_contents
/ktorrent/MainWindow_1/actions/help_whats_this
/ktorrent/MainWindow_1/actions/help_report_bug
/ktorrent/MainWindow_1/actions/switch_application_language
/ktorrent/MainWindow_1/actions/help_about_app
/ktorrent/MainWindow_1/actions/help_about_kde
Each of these objects will have methods (functions) and variables, with which we can manipulate the program, and learn about the current status of the program.
cm@fool:~> qdbus org.ktorrent.ktorrent /KTorrent
method int org.ktorrent.KTorrent.downloadSpeed(QString torrent)
method void org.ktorrent.KTorrent.start(QString torrent)
method void org.ktorrent.KTorrent.startAll()
method void org.ktorrent.KTorrent.stop(QString torrent)
method void org.ktorrent.KTorrent.stopAll()
signal void org.ktorrent.KTorrent.torrentAdded(QString tor)
signal void org.ktorrent.KTorrent.torrentRemoved(QString tor)
method QStringList org.ktorrent.KTorrent.torrents()
method int org.ktorrent.KTorrent.uploadSpeed(QString torrent)
method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface_name, QString property_name)
method void org.freedesktop.DBus.Properties.Set(QString interface_name, QString property_name, QDBusVariant value)
method QString org.freedesktop.DBus.Introspectable.Introspect()
This gives me a list of available methods with any required arguments in brackets. The names of many of these functions makes their use obvious, for example the org.ktorrent.KTorrent.stopAll() function will stop all active torrents. If we try it, we find out that that is indeed what happens. Similarly, qdbus org.ktorrent.ktorrent /KTorrent org.ktorrent.KTorrent.torrents will list the torrents currently being downloaded:
cm@fool:~> qdbus org.ktorrent.ktorrent /KTorrent org.ktorrent.KTorrent.torrents
drivexv_drivexv.zip
As we can see, one torrent is currently being downloaded, a zip file from stereogum. A couple of things to note. Although the function description will contain brackets, the command itself must not. Arguments must be placed sequentially after the function, again without brackets.

And that's the basic usage of qdbus. Next time we'll look at doing this remotely, as the above will not work on a remote machine without tinkering a little. The reason being that you will most likely be querying a different bus to the one that is running your app.

5 comments:

kwilliam said...

Thank you so much for this tutorial! I'd been struggling to write shell scripts using dbus-send, which involves huge convoluted commands, like:

dbus-send \
--session \
--dest=org.kde.kmix \
--type=method_call \
--print-reply \
--reply-timeout=2000 \
/Mixer0 \
org.kde.KMix.setMasterVolume int32:$1

Also, I'd been using kdbus to investigate what methods existed, and for some reason kdbus is incredibly slow and unresponsive. Your tutorial introduced me to qdbus, which is so much faster! I'd never heard of it before, but is SO much easier:

qdbus org.kde.kmix /Mixer0 org.kde.KMix.setMasterVolume $1

cm said...

Glad to have helped. Still to figure out a decent way to script qdbus for remote services, but it's been low on the list of priorites. :)

Nate said...

Thank you so much for this post. I just upgraded my system which upgraded my trusty Amarok 1.4 to 2. I actually like amarok 2, but suddenly discovered my dcop scripts to control it were broken. After some fruitless googling, I found your post and now I understand qdbus. So thank you! Now, I just need to figure out how to use it remotely...

coordinatezero said...

Great tutorial!!! Saved my butt at work.

Question: under what object would I find the windows that KDE has opened as a result of "wall" messages?

KNCH said...

Thanks a lot!