glib dbus bindings notes

Havoc Pennington hp at pobox.com
Tue Feb 24 16:47:22 PST 2009


Hi,

A followup on the gjs binding API, because I think it shows how a
dynamic binding is quite different from C, and also just how small the
API really needs to be.

The "dbus" js module has two items in it, the "session" and "system"
objects; these are pretty much DBusConnection wrappers.

Interface to these is:

  bus.unique_name  (attribute, bus unique name)

  bus.call_async(bus_name, obj_path, iface, method, out_sig, in_sig,
args_array, callback)

  id = bus.acquire_name(bus_name, name_type=SINGLE_INSTANCE|MANY,
on_acquired_callback, on_lost_callback)
  bus.release_name(id)

  id = bus.watch_signal(bus_name, obj_path, iface, signal, callback)
  bus.unwatch_signal(id)

  bus.emit_signal(obj_path, iface, signal, signature, args_array)

The above are not used directly, but are used to implement proxy
objects in JavaScript.

To export an object on the bus, you just do this:

  bus.exports.org.gnome.foobar = new MyObject()

So of my pieces discussed in the other mail,
1. main loop integration is from dbus-glib
2. async dbus connection is not exported to JS but is used for
acquire_name, watch_signal
3. async name ownership (acquire_name)
4. async name watching (watch_name)
5. async signal watching (watch_signal)

Then 6 is the object system mapping built on top of the above; most of
the code in the object system mapping is just converting dbus types to
JS types and vice versa, it's just a bunch of boring gunge.

Proxy objects are constructed dynamically. You need a JavaScript
object which is an interface description (either just put it inline or
generate it with a dbus-introspection-to-JS-interface-object script).
I've only used the dbus-introspection-to-JS script 1 time, for
NetworkManager, since its interface is huge; for everything else, did
not bother. In particular, extensive dbus communication happens in the
litl codebase between different JS apps, and there's no reason to ever
define the interface in anything but JSON.

Once you have an interface description, you call a function
proxifyPrototype(MyProxy.prototype) which adds each method in the
interface description to the proxy.

Given a proxy, you can just do:

  function onFooRemoteReply (result, error) {
  }

  proxy.FooRemote(arg1, arg2, onFooRemoteReply)

  id = proxy.connect("SomeRemoteSignal", onSomeSignal)

  proxy.disconnect(id)

For exporting interfaces, you only need an interface object if you
want to validate your object, otherwise it's just the 1 line to stick
the object in exports:
  DBus.session.exports.org.gnome.whatever = new MyObject();

That's pretty much it.

The big point here is that it's just a tiny API, and needs only pieces
1-5 from my earlier mail, but allows you to do everything you could
want to do with dbus from JavaScript.

I'm sure the python bindings would illustrate a pretty similar point.

Havoc


More information about the dbus mailing list