DBusGLibRoadmap

dbus-glib Roadmap

This is an area to collect various thoughts on the future of using dbus from glib/gobject code. Please feel free to add any thoughts at all here for now. We will try to generate a consensus!

Interoperability

These need sorting out first, really...

GObject introspection

One option that's been discussed a lot is to use gobject-introspection to allow a programer to directly attach an object to the bus.

Work needed:

  1. Add in/out/ownership to Gobject-introspection genintrospect.
  2. Write layer for mapping dbus messages to invocation on introspectable methods
    • - This would take two sets of xml, the dbus intropspection xml to specify the expected wire format and the gobject-introspection xml of the interface to which to map the dbus method calls
  3. gobject signal to dbus signals (again using the gi and dbus xml to generate the marshallers to map gobject signals to dbus signals)
  4. Gobject Introspection to D-Bus introspection conversion tool.
  5. D-Bus introspection conversion to Gobject Introspection tool.
  6. Dbus gobject proxy generation from gobject-introspection
    • - this would take two sets of xml, the gobject-introspection specifying the c interface to generate and the dbus introspection specifying the wire protocol to map to.

Hippo D-Bus helper - a lower-level binding

Other discussed possibilities is the extension of Havoc's hippo-dbus-helper.

RobTaylor: IMHO, both modes of directly marshalling messages and component object bindings should be useable by an applictation, different situations call for different approaches.

TpProxy from telepathy-glib >= 0.7.1

SimonMcVittie considers TpProxy and TpDBusDaemon in telepathy-glib darcs (note: UNRELEASED, API may change) to be a reasonable prototype for next-generation D-Bus bindings in GLib.

The naming is only for namespace reasons - they're designed to be generic (wrappers to avoid the deficiencies of the current) D-Bus GObject bindings, and could reasonably be renamed and moved into dbus-glib. They don't use any undocumented or internal API from dbus-glib, except for the format of the "glue" in dbus-binding-tool (which ought to be documented anyway).

How it works: TpProxy is a proxy for a remote object (unlike DBusGProxy, which is a proxy for one interface of a remote object).

There are two levels of API, proxy.h (for general client use) and proxy-subclass.h (for subclasses and mixins only - may change drastically as we improve dbus-glib).

For each interface, we generate (from augmented introspect XML) some "mixin" functions which use the proxy-subclass.h API; they take a TpProxy (or subclass) as first argument. For each method, there's a function to set up an async call, and a function to make a call that recurses the mainloop (much like gtk_dialog_run). We don't use libdbus' "blocking" methods that make method replies jump the queue, because the Grand Unified GInterfaces proposal (to be documented later) will probably not support those.

Grand Unified GInterfaces

SimonMcVittie and RobertMcQueen have vague plans for the generation-after-next D-Bus GLib bindings:

... better description to be written ...

  1. common GInterface on client and service side
  2. API designed around async calls, with a gtk_dialog_run-style convenience API (doesn't pretend to be normal local C code, because it isn't and we should admit that):

/* THIS IS JUST A SKETCH - precise API not even planned yet
 *
 * assume foo is the dbus-glib-ng namespace, bar is something
 * like telepathy-glib that uses it, BarWidgetIface is a GInterface,
 * and Bar widgets have a method GetBadgers(b: recursive) -> as
 */

/* the generated header would say something like:
 * typedef void (*BarWidgetIfaceGetBadgersResultCb) (BarWidgetIface *self,
 *     const GError *error, const gchar * const *badger_list,
 *         gpointer user_data); */

static void
got_badgers_cb (BarWidgetIface *self,
                const GError *error,
                const gchar * const *badger_list,
                gpointer user_data)
{
}

call = foo_call_new (proxy, 5000 /* timeout */);
bar_widget_iface_start_get_badgers (proxy, call, TRUE,
    got_badgers_cb, some_user_data_or_other);
foo_call_run_until_completed (call);
  1. ???
  2. Profit!

Ideally, the GInterfaces would be such that a service and a client in the same process could just call each other's callbacks directly.

This is partly why we don't want to spin in libdbus (e.g. dbus_connection_send_with_reply_and_block) - that fundamentally fails if the D-Bus part of the call is actually going to be optimized away.

Also, the deadlocks that result from blocking without re-entering the main loop have plagued e.g. Sugar Activity writers on the OLPC, which has convinced me that this mode of operation is fundamentally a bad idea.

Instead, we can recurse the main loop like gtk_dialog_run() does, to achieve a friendlier blocking call. We just need to remind authors that their code will be reentrant, e.g. with a _run_ method naming convention.


Design considerations

The world according to SMcV

Here are the things SimonMcVittie considers to be axiomatic: