Dbus

QtDBus and the Silent Reply

I wrote a tiny QtDBus client to ask a desktop service for its current state. The call returned immediately with an empty string, so I spent an hour changing service names and object paths. They were correct.

My naive mistake was treating an asynchronous call as a strangely fast synchronous one. I sent the message and read my result before the reply had travelled back through the bus. Adding a sleep appeared to fix it, which is how bad ideas acquire supporters.

QtDBus offers both blocking calls and asynchronous replies. A blocking call is simple, but doing it from the graphical thread can freeze the interface while another process is slow or absent. An asynchronous call returns a pending reply; completion must be observed later, after the event loop receives it. Errors are replies too, and ignoring them turns a useful complaint into an empty value.

I changed the client to watch the pending call and handle success and error explicitly. The window remains responsive, and stopping the service now produces an intelligible message instead of mysterious silence. I also registered the one custom type crossing the boundary rather than hoping QVariant would develop telepathy.

The bus is attractive because applications can expose small interfaces without linking directly to each other. That boundary is also real: names may be unavailable, processes may exit, and types must have a declared wire representation.

My conclusion is to use asynchronous calls for desktop interactions unless startup absolutely depends on the answer. Never repair an event-driven mistake with a delay. Sleeping makes the race less visible, not less present, rather like closing one’s eyes during a compiler warning.

D-Bus 1.0 and Boring Interfaces

D-Bus 1.0 arrived last week, so I replaced a small experimental IPC call today and discovered that my “simple” interface exposed an internal class name, an internal enum, and optimism about call order.

The wire has four names worth keeping straight: a bus name identifies the service, an object path identifies an object, an interface groups methods and signals, and a member names the operation. Treating all four as one application string works until the service grows a second object.

For a thumbnail service I settled on deliberately plain values:

service:   org.kde.Thumbnailer
path:      /Thumbnailer
interface: org.kde.Thumbnailer
method:    Queue(string url, int width, int height)
signal:    Ready(string url, string file)

The exact names may change; the useful constraint is that callers do not need my C++ headers or object layout. Strings and integers cross the process boundary predictably. Errors should cross as named errors, not magic negative dimensions.

A method call can be synchronous, but that does not make blocking the GUI wise. Thumbnail generation may involve disk access or a broken file. The caller should queue work and react to completion, while also handling service disappearance. Processes are allowed to crash independently; that is among their principal features.

I prefer small, boring bus interfaces with operations phrased in domain terms. They are easier to inspect and less likely to preserve an accidental implementation forever. The caveat is round-trip cost and versioning. Turning every getter into a remote call creates slow, chatty code, and changing a published signature later can break clients I do not control.

Introspection is useful during development, but readable metadata does not replace a written contract. Callers still need to know whether requests are idempotent, which errors are expected, and how long returned object paths remain valid.

For KDE 4 porting, D-Bus 1.0 gives us a stable point to build against, not permission to export every object. I am writing the interface first, testing it from a separate process, and only then attaching the current implementation. If the test needs a private header, the boundary has failed.

Today’s service returns one error instead of hanging when the source file vanishes. This is less exciting than transparent desktop integration, but substantially more useful when transparent desktop integration loses a file.