Steve Frécinaux

A quick look at Mathusalem’s young boy body

Sorry for the lack of news about Mathusalem these times, I’ve been busy on something else that had to be done quicky (crappy PHP).

But, despite quite a lot of people seem to be interested in Mathusalem, I have had no feedback at all after the first release. I know it came at a wrong time during Gnome’s release cycle, and I guess depending on a patch on latest D-Bus doesn’t help.

So what am I going to do now is explain how the interaction between Mathusalem and an hypothetical client (owner or third party) goes currently. It’s not settled in stone yet, and is not normative in anyway. Hey, it’s just for feedback from possible users, isn’t it ;-).

Thus I’m talking about both clients, first I’ll register a task, and then I’ll set up a third party client interested in that kind of tasks. The example will be a file download. So the owner of the task will be Epiphany, and the third party client, Nautilus.

Registering a task

The user clicks on a link with his right mouse button, and selects the right menu entry to actually download the linked file. He enters a file name and hits the “Save” button.

Epiphany sends a org.gnome.Mathusalem.RegisterTask request on the daemon, providing a set of interfaces to implement, in this case org.gnome.Mathusalem.FileTransfer only, a title for the task (“Downloading foobar.tar.gz”), a length (foobar.tar.gz size) and the owner name (his own).

The server returns the new task object path, for instance /org/gnome/Mathusalem/Tasks/00000001, and fires the TaskRegistered signal.

Now Epiphany finishes configuring the task, by sending additional information needed by the FileTransfer interface, like the files involved, etc. When it is done, it triggers the Start signal.

Periodically, Epiphany can update the progress using the SetProgress method, and can cancel a task using provided methods. As well, the daemon can ask for cancellation or custom actions if they have been registered by the owner, in a way similar to what the notification daemon does.

When the progress status reaches 100% (ie when Epiphany calls the SetProgress task method using the task length as the argument), a Completed signal is fired and the task object disappears from the bus. The task also supports cancellation and pause in a similar fashion.

I only covered here what’s available from the stock Task interface, but third party clients can of course use the extra functionnalities provided by the additional interface if they need to.

Being a third party client

Nautilus is interrested in epiphany’s download progression to show feedback and avoid people trying to delete files being worked on. In a more general fashion it cares about all tasks implementing the FileTransfer interface, since, eh, file transfers are the main Nautilus job.

So what Nautilus does on startup is getting a list of the tasks (currently, you can only do that using introspection), then check the ones that correspond to what you’re interested in. In our case, we check if the task implements the FileTransfer interface, using the ImplementsInterface task method. Then it connects itself on the TaskRegistered signal so that it is aware of what tasks are registered later.

When showing a directory, Nautilus looks in the task set if there are files in the current directory that are involved in a file transfer. If so, they are showed in a particular fashion, for example with a small progress bar as an emblem. When the ProgressChanged signal is caught, the progress emblem is updated. When the task is completed the emblem is removed, if the task is cancelled the file is removed. That’s it.

Design quirks

Current implementation has a few issues that need to be addressed.

First, it does not handle tasks with unknown lenght at all. This will require some D-Bus API adaptation, I fear…

Listing running tasks is currently only possible using D-Bus introspection. I plan to add two methods to the main object: ListTasks and ListTasksWithInterface, whose behaviour seems obvious to me.

Another possible issue is the quick succession of the TaskRegistered and the Started signals (the first is emitted on registration, the second one on actual start), on different objects (so the client has to connect to the object to catch the second one). This could be problematic, because the Started signal could be emitted before the client connects on it… I don’t really know how to avoid that, especially since mergeing the two brings other issues (for instance, the Started signal is also emitted when a task is unpaused). Maybe I could emit both of them when the task actually starts, so that a registered task is always started when the third party client is made aware of it.

Latest one is playing nice with D-Bus activation. I don’t know the subject well now, but if Nautilus connects to a signal, would it allow the daemon to be shut down when no task is registered? (especially since Nautilus is always present.)

I only exposed the use of the daemon in a general fashion. If you want to see the whole API available currently, I enjoin you to have a look at the XML files in the tarball.