Category Archives: maemo

Using Tumbler in Client Applications

Yesterday, Philip briefly wrote about Tumbler, the new D-Bus thumbnailing service that is going to be used on Xfce 4.8 and Maemo 6. Today, I'd like to explain how to use this service in client applications. Depending on the application type, the usage varies a little, so I'll focus on the basics here. I'll discuss some tricks at the end of this post though. What I'm not going to do is to talk about how to connect to D-Bus, how to call methods on D-Bus objects and so on. See the D-Bus tutorial or toolkit-specific documentation for more information about that.

A separate post with information on how to extend the thumbnail service will hopefull follow soon.

The Service Architecture

The thumbnailer specification defines four D-Bus service APIs. For most client applications only two of these are interesting: org.freedesktop.thumbnails.Thumbnailer1 (the thumbnailing service) and org.freedesktop.thumbnails.Cache1 (the thumbnail cache manager). The thumbnailing service can be used to request thumbnails and get feedback on the progress of requests. The cache manager can be used to keep the cache synchronized with the hard drive contents by notifying it when files are deleted, copied or renamed.

Thumbnail Request Workflow

Thumbnail requests include the following information:

  1. An array of URIs for which thumbnails should be generated
  2. An array of MIME types for these URIs (each element corresponding to the URI with the same index in the URI array)
  3. The thumbnail flavor to generate for the URIs (normal is 128x128px, large is 256x256px, ...)
  4. The scheduling mechanism to be used for the request (foreground, background, ...)
  5. An optional handle of a previous request that should now be cancelled

Because the service implementation might vary depending on the system (right now there's only Tumbler, but who knows about the future...) there is no fixed set of thumbnail flavors and schedulers. The specification is supposed to define a standard set of flavors and schedulers that all implementations have to support (like a normal flavor and the scheduler default). The URI schemes and MIME types supported by the thumbnailing service also depend on the implementation and the availability of thumbnailer plugins and applications extendending the thumbnailing service via D-Bus. So, the first thing an application should do is to to determine which flavors, schedulers, URI schemes and MIME types are supported.

Determine flavors, schedulers, URI schemes and MIME types supported by the service

The thumbnailer service provides the methods GetFlavors, GetSchedulers and GetSupported for this. They all return string arrays with supported flavors, schedulers and URI scheme and MIME type pairs. GetSupported is a bit special, as it returns two arrays (one with URI schemes, the other with MIME types). These are to be interpreted as arrays of scheme/type pairs, each pair of which means that files with both the scheme and the MIME type at a certain index are supported. Applications can use this information to avoid requests for unsupported files. Once all this information is collected, we can continue with...

Requesting Thumbnails

Let us assume for a moment that only one thumbnail is needed and that the flavor we want is normal, the scheduler is foreground, the URI is file:///tmp/foo.png and the MIME type obviously is image/png. We can request a thumbnail to be created for this URI by calling the Queue method of ...thumbnails.Thumbnailer1 like this (written in some kind of fantasy language with dynamic D-Bus bindings ;)):

 handle = service.Queue ("file:///tmp/foo.png", "image/png", "normal", "foreground", 0)

As you can see here, requesting thumbnails for more than this one URI is simple: just append one more URI to the first array and one more MIME type to the second array.

If you perhaps need to cancel the request later, remember the handle returned by the service. In complex applications with asynchronous APIs you'll sometimes need to link internal request handle to thumbnailer service handles, so the handle returned by the service is not only useful for canceling requests.

Being Notified About the Progress of a Thumbnail Request

Once you have requested one or more thumbnails, you'll probably want to be notified about the progress of your request. Tumbler will emit D-Bus signals for the following status updates:

  1. Started is emitted together with the request handle as soon as the service starts processing the URIs of the request.
  2. Ready is emitted together with the request handle and an array of URIs whenever the thumbnail for one or more of the URIs of the request were generated and can now be used. The array passed to you contains the source URIs, not the URIs of the thumbnail files.
  3. Error is emitted together with the request handle, an array of URIs, an error message and an error code whenever the generation of a thumbnail for one or more URIs of the request failed.
  4. Finished is emitted together with the request handle once the thumbnail service has finished processing the request. This can happen when all URIs have been looked at or when the request was cancelled.

Please note that there is no guarantee for the Ready and Error signal to be emitted for all URIs of the request if the request is cancelled. So, if you maintain an internal thumbnail state for URIs depending on the thumbnail progress, you'll have to remember which URIs were queued. In any case you're advised to make sure to free up your own resources in case the service dies or D-Bus crashes. This can be achieved using a timeout (which will also be helpful if the service hangs) or by connecting to the destroy signal of the DBusGProxy (or whatever equivalent D-Bus API is used in your application).

Cancelling Requests

If you want to cancel certain requests, all you need to do is to call the Dequeue method of the service and pass the correct request handle to it.

Loading the Thumbnails

Where to look for the actual thumbnail files after they have been generated depends on the platform. If Tumbler is built with the default cache backend (which should be built on normal desktop systems), files are stored according to the thumbnail managing standard. On Maemo, files are stored as JPEGs. Philip might be able to give a more detailed description about how to access them.

Thumbnail Cache Synchronization and Cleanup

Some applications like file managers or image viewers allow users to rename, copy, move or delete files on the disk. Since renaming, copying and moving doesn't affect the contents of a file, you can avoid to regenerate its thumbnail by notifying the thumbnail cache of this change. When a file is deleted the thumbnail is no longer needed, so in order to prevent the cache from being polluted with dead thumbnails, you can notify it as well.

This is what the ...thumbnails.Cache1 service interface is for. It provides the following D-Bus methods for the above scenarios:

  • Copy (string array from_uris, string array to_uris)
  • Move (string array from_uris, string array to_uris) (this one is useful for both moving and renaming)
  • Delete (string array uris)

If you want to clean up the cache in a more general sense by deleting very old thumbnails you can do this via the following method which deletes all thumbnail whose original files have not been modified in a long time and have a certain URI prefix (which may be empty):

  • Cleanup (string uri_prefix, uint64 original_mtime_threshold)

The above should give you an insight into how the thumbnail service can be used in applications. If you have any questions about this, please let me know. Ok, now let's reveal some tricks to perform optimization on the client side.

Tips and Tricks

  • Use asynchronous D-Bus calls in your application to avoid your application to block. A separate worker thread might also be useful.
  • It's wise to cache the arrays returned from GetSupported, GetFlavors and GetSchedulers. A SupportedChanged signal is planned to allow applications to update their cached information when the thumbnailer is extended by additional URI schemes or MIME types at runtime.
  • If your application generates a lot of thumbnail requests, as file managers and picture viewers with gallery support usually do, you'll probably want to reduce the amount of messages being sent over D-Bus. You can do this by grouping individual requests. Often when you use a GtkTreeView or something similar involving stateless cell renderers, the easiest way to generate thumbnail requests is when the cell renderer renders a file icon. If you don't group these individual requests, the system might go nuts. So, to group these requests you could use a worker thread with a wait queue that is flushed (URIs in it are sent to the thumbnail service as a single request) at most every X milliseconds. When the first thumbnail is needed, you start a one-shot timeout handler that is executed after X milliseconds, grouping all URIs added to the wait queue in the meantime. I do this in Thunar and it has proven to work well. It also scales nicely by grouping more efficiently the more thumbnails are needed in the time slot. Heavier user scrolling won't make things worse.

I guess that's it for now. I hope you enjoyed reading this first real post about Tumbler coming from me (which is also pushed to Planet Maemo by the way). Again, if you have any questions, please let me know.

News Update

A lot of things are going on lately and it turns out I'm way to busy to update my weblog on a regular basis. So, this is just a short post to keep you all updated.

Last two weeks

  • I took a new student job at the university, at the Institute of Theoretical Computer Science, which I love most. I'll be working on haplotyping algorithms.
  • I went to Barcelona and had a great time at the Ubuntu Developer Summit overall. Stephan and I were very productive. One evening during dinner we discussed our development and release process and later started writing it down. The result is a beautiful document that still needs a bit of polishing. I hope it'll serve as a good foundation for the development and release process of Xfce in the future. Several others commented on it and it looks like we'll give the proposed concept a shot after we've switched to git and all that.
  • Even though the week in Barcelona was great for Xfce, I was disappointed with how it went with regards to the cooperation between Xubuntu and Xfce. I talked it through with Stephan and after I got back, I resigned from my position as the Xubuntu Xfce4 Liaison.

At the moment

  • I've started to implement the so-called thumbnail management D-Bus specification. My implementation is called Tumbler and it will hopefully start serving thumbnails for other apps soon. I'm planning to use it in Thunar, Stephan has expressed interest in using it in Ristretto and when discussing the specification and the existing hildon-thumbnail implementation, Philip van Hoof told me that Hildon/Nokia might be interested in dropping hildon-thumbnail in favor of Tumbler if it's flexible enough. I'm working on it as much as I can and I'm hoping to do a release within the next few weeks.
  • I'm still working on the Transifex installation for Xfce. It's already running but I still need to import all the projects, releases and of course create accounts for maintainers automatically.
  • The migration of Xfce to Git is still work in progress. Brian has most of the repository issues sorted out and is now waiting for me to finish the commit mail script. I have two or three possible implementations lying around but I need to have a look at that again.
  • Jim needs the documentation repository next week, so I'm about to set it up.
  • Our Buildbot server has arrived in Sweden. Today I set up the firewall. Samual is taking care of setting up the Buildbot host VM and other things. We're considering to move a lot of the services not related to development (like the Xfce websites) into separate VMs on that server too, in order to make the current server a development-only machine.

Besides that I'm trying to catch up with the work and personal stuff that piled up while I was away last week. And I really should go and sleep.