Hello Dbus:
Everyone starts with "Hello World." I did too. Little is gained by repeating it. So here is something different. Here is my first dbus introspection in vala:
// This vala file is named dbus-introspection.vala [DBus (name = "org.freedesktop.DBus.Introspectable")] // Dbus interface interface Introspectable : Object { [DBus (name = "Introspect")] // Dbus method public abstract string introspect() throws IOError; } void main () { Introspectable conn = null; // If inside the try, causes fail try { conn = Bus.get_proxy_sync (BusType.SESSION, // Dbus session "org.freedesktop.Notifications", // Dbus destination "/org/freedesktop/Notifications"); // Dbus path string reply = conn.introspect(); // the actual event stdout.printf ("%s\n", reply); // print response } catch (IOError response) { // print error stderr.printf ("IO Error: %s\n", response.message); } }
Compile using
$ valac --pkg gio-2.0 dbus-introspect.vala
Run using
$ ./ dbus-introspect
The vala file is 19 lines.
The vala-generated C file is 300 lines, and about 15 times the size of the vala file.
The compiled binary is 19.4K, 130% the size of the C file.
But 19.4K is still pretty small, and it does run really fast!
For my own reference:
- The dbus server information we need to connect. This is a common service that has Introspection:
bus = session bus destination = org.freedesktop.Notifications path = /org/freedesktop/Notifications interface = org.freedesktop.DBus.Introspectable method = Introspect message = (none)
main () { }
is where the program starts.
Equivalent to python'sif "__name__" == "__main__":
.
Since it's the main, it returns either a return code (int
) or nothing (void
), and nothing else. The example above returns nothing.
To add a return code, addreturn 0;
to the end of thetry { }
block, and addreturn 1;
to the end of thecatch { }
block- Michael Brown pointed out a very useful tidbit to avoid a lot of confusion:
- Vala class = DBus interface
- Vala interface = DBus proxy
Building the dbus connection (proxy) means we call that variable an interface in vala.
And each dbus interface must be defined as a separate class in vala.
To that, I will add that each class must be a GLib.Object.
So a connection must start by opening an instance of the class, then adding the proxy information. Interface first, then proxy. That's backwards from the way dbus-send or python do it.
For example:
The dbus interfaceorg.freedesktop.DBus.Introspectable
gets defined as a vala class:interface Introspectable : Object { }
Next, let's add the method and the labels to this class:
[DBus (name = "org.freedesktop.DBus.Introspectable")] // Dbus interface interface Introspectable : Object { [DBus (name = "Introspect")] // Dbus method public abstract string introspect() throws IOError; }
- Methods must be public and abstract. We expect it to return a string (introspection returns a string of XML). As far as I can tell, methods should throw IOError in case the dbus message is malformed, the receiving service does not exist or has no such message, etc. The method is part of the interface's Object.
- Main uses the
try { } catch { }
blocks to locate those IOErrors.
Initial creation of the interface must be outside the try block, or the program won't be listening for the dbus response. Adding the bus and proxy information within the try block is not required...if you never make spelling mistakes.
No comments:
Post a Comment