last-exit installs itself as a handler for lastfm: URIs, but every click on a link launcher a new instance of the application. Such waste obviously can not be tolerated, so I figured last-exit should be single-instance. And use DBus for that, naturally.
Note: The following is not a sane way to do it. One really should be using the mono bindings. Or simple callbacks rather than GObjects.
C# and DBus the hard way
As I was told DBus C# bindings are unusable I went on about writing DBus# objects the hard way. (Last time I tried with using the DBus mono bindings it kind of worked. I had to make the method call return a value or the messages would appear to be lost most of the time, and even then every other message caused mono to segfault.)
It turns out there’s quite a few levels of code generation and necessary autotools magic involved in the whole process:
- dbus-binding-tool: takes a (hand written) XML file describing a DBus object interface and generates client and server side glue code, very similar to orbit-idl-2. Combined with the C implementation this gives you a shared library you can start wrapping for C#.
- gapi2-parser: takes a (hand written) XML file referencing source files to parse as well as some namespace annotations and generates an XML description of the GObject(s). Semantically very close to the XML file for dbus, syntactically not.
- gapi2-codegen: takes the output of gapi2-parser and generates C# source files. Logically almost identical to dbus-binding-tool. Building the sources gives you C# dll wrapping the shared library.
- gapi2-fixup: takes a bunch of extra (hand written) files and then customizes the generated code in wonderful ways I’m sure, but I didn’t want to go there.
None of which naturally had useful manpages, –help or other easily/obviously accessible documentation. Eventually Google found GAPI Overview in Mono wiki and dbus-binding-tool --mode=glib-server was mentioned somewhere else.
Well, in the end it worked nicely and I was able to use dbus-send as the URI handler:
#!/bin/sh exec dbus-send --session --type=method_call \ --dest=org.gnome.LastExit /org/gnome/LastExit \ org.gnome.LastExit.Open string:"$1"
Using dbus-send, or preferrably having gnome-vfs send the DBus message directly from the application itself, should be more efficient than loading the mono runtime just to send a few bytes down the socket.
I couldn’t be bothered to figure out the automagic needed to make the whole thing bootstrap cleanly. It was an awful hack and no one in their right mind would accept such a patch. I was happy to just get it built.
C# the high level language
I abandonded that line of development and thought about trying the very latest mono bindings from freedesktop git repository. Needed to add a little hack to make it run with the dbus version that comes with Ubuntu Dapper. The echo server example appeared to be working, but mono was segfaulting when the client was trying to handle the method call response.
After a little digging I found mono was segfaulting during finalizing an object, and the following code seemed to be responsible one way or another. At least just skipping the whole function makes the crash go away…
mono/ProxyBuilder.cs (BuildFinalizer):
[…]
//generator.EmitWriteLine("this.service.SignalCalled -= this.delegate_created"); generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldfld, serviceF); generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldfld, deleF); generator.EmitCall (OpCodes.Callvirt, Service_RemoveSignalCalledMI, null); generator.Emit (OpCodes.Ret);
There’s a lot more where that came from. I lost interest as I didn’t feel like learning assembler again. At least not this twistedly verbose dialect of it.
Last Exit “Minor Numbers are For Wusses” 2.0
Of course the whole exercise was for nothing, other than being a learning experience, as a different implementation was committed to CVSreleased shortly after. They cheated, there’s no GObject exposed to C# side but just a simple function for setting a callback function. On the plus side it causes much less headaches. I was also told there are better mono bindings around, waiting for commit approval somewhere.
At least last-exit is looking better than ever 🙂
1 comment so far ↓
Wrapping GObjects in C# by hand isn’t actually that hard, look at Player.cs and player.c