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.