15 December 2004

Mataró

The conference has been great so far. The PyGTK BoF on the weekend was very productive, and I got to meet Anthony Baxter (who as well as being the Python release manager, wrote a cool VoiP application called Shtoom). There was an announcement of some of the other things Canonical have been working on, which has been reported on in LWN (currently subscriber only) among other places.

Over the weekend, I had a little time to do some tourist-type things in Barcelona. I went to La Sagrada Família. It was a great place to visit, and there was an amazing level of detail in the architecture. You can walk almost to the very top of the cathedral, and see out over the Barcelona skyline (and see various bits of the cathedral not visible from the ground). I’ll have to put my photos up online.

Bazaar

I’ve been using using Bazaar a bit more at work, and it is becoming quite usable, compared to tla. It is a little interesting using daily builds of baz from the 1.1 development branch, where some features appear, get renamed or removed as they get developped, but it has a few more useful features not found in the 1.0 release. From a user point of view, it feels like the command line interface for baz is being designed to be easy to use, while tla‘s feels like they made choices based on what was easy to implement.

I built some Fedora Core 2 i386 builds of the 1.0.1 release, and some 1.1 snapshots that are now up on the Bazaar website in case anyone wants to try them. When I get back home and install FC3 onto my AMD64 box (it only has Ubuntu on at the moment), I’ll do some FC3 x86-64 and i386 builds too.

8 December 2004

Mataró

I’ve been in Mataró (about an hour from Barcelona) now since Sunday, and it’s quite a nice place. It is a bit cooler than Perth due to it being the middle of Winter here, but the way most of the locals are rugged up you’d think it was a lot colder. It’s great to catch up with everyone, and a number of pygtk developers will be turning up over the next few days for the BOF on the weekend.

Gnome Foundation Elections

Congratulations to the new board members. It is a little disappointing that only about 56% of members voted though. Once the membership committee has the anonymous voting stuff set up, it might be worth doing the preferential voting referrendum.

jhbuild

I’ve been working on some preliminary documentation for JHBuild, which is available here. It should be useful for new users and people looking at writing new module sets for it. It has a fairly complete command reference and config file reference, so it is probably useful for current users too. It would be good to add some information about setting up a tinderbox like the one Luis set up for Gnome.

Nautilus Extensions

One of the changes in the Gnome 2.9 development series is the removal of most of the Bonobo code from Nautilus, which results in a speed boost due to lower complexity and less IPC overhead. This had the effect of breaking existing bonobo based context menus, property pages and views. The first two can be converted to the Nautilus extension interface, but the second has no equivalent in the new code (partly because Nautilus is concentrating on being a file manager these days rather than a universal component shell like it was in the early days).

Two of the casualties of the change were gnome-control-center‘s font and theme code, and nautilus-media. Since I wrote the font browser code in gnome-control-center, I updated it to work again. It isn’t clear whether nautilus-media will be updated, since the view was a major component of it, and most of the remaining functionality is provided by totem.

Context Menus

If you are looking at updating a Nautilus context menu to use the new extension interface, fontilus-context-menu.c is a pretty good example to model your code on.

One of the big differences is the way Nautilus extensions are loaded compared to the old context menu API. With the old API, you would provide a Bonobo component and set a number of properties in the bonobo-activation server file listing a menu label, the list of mime types the context menu applies to, what URI schemes it supports and whether it supports multiple files. Nautilus could then do a single bonobo-activation query to find out what context menu items correspond to the current selection, and add them to the menu. If the user selected one of the items, the corresponding component would be activated, and an event sent to its Bonobo::EventListener interface.

In contrast, Nautilus extensions are initialised on Nautilus startup. They indicate that they provide context menu items by implementing the NautilusMenuProvider interface. When the user brings up the context menu, the get_file_items method will be called on all extensions that implement that interface. A list of NautilusFileInfo objects is passed in, and the method returns a list of NautilusMenuItem objects. Also, Nautilus extensions are run in-process while Bonobo components could be written for in-process or out of process use.

One of the benefits of this system is the added control of when to display a menu item, and what to use as the label. If you want to only display your context menu item when 42 text/html files and one image/png file are selected you can. However it does mean that each new extension causes some code to be run before popping up a context menu. I have no idea how this compares time wise to the time taken for the previous bonobo-activation query though.

Property Pages

The interface for property pages is quite similar to the context menu interface. As with context menus, you have an imperative NautilusPropertyPageProvider::get_pages interface rather than a declaritive interface based on activation properties. This has the benefit that you can simply not provide the page when the properties in question are not available for the file (with the old setup, you’d end up providing a properties page stating that there is nothing to display).

The other interesting parts of the extension interface is the NautilusInfoProvider interface that lets you attach extra information to files, such as extra emblems or custom attributes, and NautilusColumnProvider, which lets you provide additional columns for the list view that map to custom file attributes. One example of this is nautilus-vcs, which can show revision numbers for files in CVS working copies and adds emblems indicating the file state.

Of course, there are downsides to the extension interface too — since extensions are always in process, they can crash Nautilus or leak memory. However, it was already possible for Bonobo based extensions to do this if they were designed as in-process components and badly written …

Another issue is that language bindings might find it more difficult to support the extension interface where the language runtime would have to cooperate with Nautilus, compared to out of process Bonobo components where they have more control. I guess we’ll see what happens.

1 November 2004

Libtool

When looking into the libtool problem I mentioned earlier, I decided to take a look at the libtool-2.0 betas. Overall, it looks pretty good. I’ve updated the gnome-common autogen.sh script to support it. So if a package uses the LT_INIT macro, it will call libtoolize for you.

One of the new features in these versions of libtool is that if you have a AC_CONFIG_MACRO_DIR(directory) call in your configure.ac file, it will copy the libtool M4 macros to that directory. If you then call aclocal with the correct -I flag, autoconf will use that version of the macro.

This means that you will get consistent versions of ltmain.sh and libtool.m4, which is a lot more reliable. With the old setup, the version of ltmain.sh you got would depend on $PATH while the version of libtool.m4 would depend on the aclocal search path. With the new setup, it just depends on $PATH.

The only problem is that aclocal doesn’t automatically check the macro dir for macros. This is pretty easy to work around. Just pass the appropriate -I flag to aclocal in autogen.sh, and make sure ACLOCAL_AMFLAGS gets set appropriately in your Makefile.am‘s. This second part can be done from the configure.in file like so:

AC_CONFIG_MACRO_DIR([m4])
...
# make sure $ACLOCAL_FLAGS are used during a rebuild.
AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_macro_dir \${ACLOCAL_FLAGS}"])

(the above will also pass $ACLOCAL_FLAGS to aclocal on a rebuild, which is expected when building most Gnome packages).

I also updated the gnome-common autogen.sh script to check for AC_CONFIG_MACRO_DIR, and call aclocal correctly, so a package maintainer doesn’t need to do anything special.

This system could benefit some of the other Gnome related build tools like intltool and gtk-doc — I recently got CC’d on an intltool bug that seemed to be caused by mismatched macros and support files, so people are tripping over the problem. It should be pretty trivial to modify intltoolize to check for AC_CONFIG_MACRO_DIR, and copy over the macro file if it finds it. This wouldn’t affect its behaviour on existing packages, but would be more reliable on packages that have been updated to use the macro.

Bazaar

I did some initial Fedora Core 2 packages for Bazaar (a new GNU Arch command line tool sponsored by Canonical). It is only an i386 build, but I’ll add an x86-64 build once I have FC2 or FC3 set up on my desktop (so far I’ve only got round to installing Ubuntu/AMD64 on it).

At the moment baz is quite similar to tla, but there are some promising interface ideas that should make it a lot nicer to use. If you’ve avoided Arch due to tla‘s complexity, baz might be worth trying when it develops further.

Libtool Problem (continued)

Shortly after posting the last entry about the libtool problem I sent a message to the bug-libtool list, Scott helped to track down the problem.

With the help of the test script I wrote, he managed to track down the change on the libtool-2.0 branch that fixed the problem. Applying this same change to a 1.5.x release fixed the problem. He has uploaded a new Debian package with the change, and I’ve altered the jhbuild bootstrap module set to include the patch too. The copy of the patch included with JHBuild can be found here. Hopefully it will also be in a future 1.5.x release (assuming that there are any more).

Scott pointed out another case where people might run into the problem is when building binary packages for software. A packager usually builds the new version of the software into a temporary prefix (often by setting the $DESTDIR environment variable when calling make install). If the package includes a library with some applications that link to the library and there is an old version of the package installed on the system, libtool could end up linking with the library in /usr/lib, which could result in a build failure if some new APIs were added. The patch should fix this particular case too.

So if you release tarballs that make use of libtool, applying this patch may help out the people maintaining binary packages of the software for a distro too (assuming that they haven’t gone the scorched earth route and deleted all the .la files …).

25 October 2004

Drive Mount Applet

The new drive mount applet is now checked into the HEAD branch of gnome-applets, so will be in Gnome 2.10. There are a few things left to do, such as making it possible to open the file manager as well as unmounting/ejecting it. I did up a screenshot showing what it looks like as an applet.

Libtool

Finally managed to reproduce a particular libtool bug that people have reported on and off. It does show why some people decide that .la files are evil, since it doesn’t occur when people delete those files …

A reduced test case can be found here. The problem occurs when you have multiple copies of a library in your linker library search path with associated .la files. In the test case, there are the following libraries:

  • libfoo.so and libfoo.la in the directory /A. This is the library we want to link to.
  • libfoo.so and libfoo.la in the directory /B. We don’t want to link to this one, because it is old.
  • libbar.so and libbar.la in the directory /B.

Let’s say I then try to link an app that needs libbar and the new version of libfoo, and happen to use the following link line:

libtool --mode=link gcc -o main main.c -lbar -L/A -L/B -lfoo

In the absense of libtool, this would result in us linking against /B/libbar.so and /A/libfoo.so (since /A comes before /B in the search path).

However, libtool ends up doing something quite different. When it sees -lbar, it notices that there is a libbar.la in /B, expands that argument to the full path name of the actual library (/B/libbar.so), and prepends /B to the library search path. This means that when it gets round to processing -lfoo, it finds /B/libfoo.la instead of /A/libfoo.la, and links to the wrong library.

If this sounds like an obscure bug, note that it also happens if we replace /B with /usr/lib. In this case, we don’t even need the -L/usr/lib argument. So the following command results in linking with /usr/lib/libfoo.so instead of /A/libfoo.so:

libtool --mode=link gcc -o main main.c -lbar -L/A -lfoo

This sort of situation is quite common when trying to build some software into a separate prefix that is also provided by the OS, when you are relying on a few libraries installed in /usr/lib with .la files.

After putting together the test case I tested it out in the latest development release (1.9f), and it appears that the problem has been fixed. Given that the libtool developers are so close to a 2.0 release, I don’t know whether they would bother putting out another 1.5.x release to fix the problem.

So if you do run into the problem, some possible solutions are:

  1. Upgrade to libtool-1.9f. I’m not sure how good an idea this is if you are producing tarballs, since they will be packaged with the development release too.
  2. Remove all the .la files in /usr/lib. Some distributors seem to take this route (eg. Ximian/Novell and Red Hat).

20 October 2004

Even More Icon Theme Stuff

To make it a bit easier to correctly display themed icons, I added support to GtkImage, so that it is as easy as calling gtk_image_new_from_icon_name() or gtk_image_set_from_icon_name(). The patch is attached to bug #155688.

This code takes care of theme changes so the application developer doesn’t need to. Once this is in, it should be trivial to add themed icon support to various other widgets that use GtkImage (such as GtkAbout and GtkToolItem).

JHBuild

I started work on some extended documentation for JHBuild. At the moment, this just includes some information on setting it up and basic use. I’ll extend it to hold a reference to all JHBuild commands, some documentation on the module set file format and some frequently asked questions.

It would be good to include some information on setting up JHBuild’s tinderbox mode (like Luis has). Getting a few more tinderboxes running for Gnome on other platforms such Solaris/SPARC would be really useful — Luis’s build logs have already helped track down a few build failures, so having build information for a few more platforms would be very useful.

New Computer

I just got the last components for my new computer (an Athlon 64 system). It is a fair bit faster than the laptop I’ve been doing most of the development on, so should be quite nice once it is all set up.

It is amazing how much hardware has improved and gone down in price. The motherboard alone is packed with features I wouldn’t have expected for something costing AU$220:

  • Gigabit ethernet
  • An 802.11g wireless card (PCI)
  • An extra Promise SATA chip, bringing the number of SATA connectors up to 4, and the IDE connectors to 3.
  • Firewire
  • SPDIF output (both electrical and optical).
  • 6 headphone-style jacks on the back, so you can get 6 channel audio output without losing your line in and microphone jacks.

I also got a Raptor hard drive for the system. These drives seem to have up to twice the performance of most 7200rpm desktop drives, and make a big difference to the overall performance of the system.

It should be a nice system once I finish building it. Also, since it is an x86-64 system, it effectively provides two architectures to test stuff on.

Drive Mount Applet

I started to look at bringing the drive mount applet from gnome-applts up to scratch, since it hasn’t really had much work done on it other than porting to the 2.x development platform.

The applet is a classic example of Gnome 1.x user interface complexity. The applet shows a button that can be clicked to mount or unmount a particular mount point. For this simple functionality, it provides the following preferences:

  • The mount directory
  • The interval at which to check the mounted state
  • Which of a set of custom images to use to show the mounted state (eg. floppy drive, cdrom drive, etc).
  • The ability to specify custom mounted/unmounted images.
  • Whether to eject the disk after unmounting.
  • Whether to use a second method for checking the mounted state which might work better with automounters.

The applet also had a few problems, such as not being able to unmount a disk if there was a trash directory on it (since fam would have a dnotify watch active on that directory).

By using some of the newer gnome-vfs APIs, I think it should be possible to remove all the preferences:

  1. The GnomeVFSVolumeManager API can be used to get a list of attached drives and volumes, and receive notification when volumes are mounted or new drives are connected or disconnected. This allows one applet to display the status of all user (un)mountable drives/volumes in one applet.
  2. By using the gnome-vfs APIs to unmount or eject a volume, a volume_pre_unmount signal to interested applications before attempting to unmount it. When Nautilus receives this signal, it drops its FAM watches on the trash directory for that volume, and closes all associated windows. This means that Nautilus/FAM won’t cause a “volume is busy” error (although some other apps might hold files opne on the volume).
  3. The gnome-vfs APIs tell us what the volume type is. This way we can automatically do an unmount+eject for cdrom, zip and jaz drives like Nautilus does rather than having to provide a preference.
  4. Gnome-vfs also tells us what icon name should be used for a particular drive or volume. This way the applet can just pull the icons from the current icon theme rather than having to maintain separate ones.

My code is at the point where it produces nice screenshots, and has the above features. The screenshot shows it as a separate window, but adding the applet wrapper stuff isn’t too difficult (it is easier to test as a standalone app). It is less than half the size of the old applet too, which is promising.

11 October 2004

Federal Election

Looks like we are going to have at least another three years with The Rodent. It also looks like they will have a majority in the senate, which will reduce the senate’s effectiveness as a house of review.

We might not have John Howard for the entire term though, since he is of retirement age. NineMSN seems to think that Peter Costello is already the leader.

It also looks like The Democrats senators up for reelection got completely wiped out, with much of their support going to The Greens.

Gnome-VFS

Robert Collins wrote an interesting critique on the gnome-vfs API. I don’t agree with all the points, and there are some reasons why the API isn’t as elegant as it could be. Below are some responses.

Initialisation

One thing that gnome_vfs_init() does is to call g_thread_init(). Before this function is called, the locking APIs in glib are no-ops. You really want this function called early on if the app is going to use threads, otherwise you will end up with inconsistencies (eg. a lock() call might be a no-op, but the unlock() call might not be if g_thread_init() is called in between).

The other issue is that gnome_vfs_init() can fail. If it is called automatically, then any function that might invoke the initialisation routine now has a new failure mode. I don’t know whether this is a real problem or not though.

Calling Style – Inconsistent Ordering

One big difference between the out parameters in gnome_vfs_open() and gnome_vfs_read() is that the first function is essentially a constructor for a file handle, while the second is a method for a file handle that fills in a provided buffer.

I’ll agree that the calling conventions are not as nice as they could be though. If they were being designed today, I suspect that they would look more like this:

GnomeVFSHandle  *gnome_vfs_open (const gchar     *text_uri,
                                 GnomeVFSOpenMode open_mode,
                                 GError         **error);
GnomeVFSFileSize gnome_vfs_read (GnomeVFSHandle  *handle,
                                 gpointer         buffer,
                                 GnomeVFSFileSize bytes,
                                 GError         **error);

Unfortunately, the GError API was not developped til the 2.0 series, while these parts of the gnome-vfs API persist from the 1.x days.

Calling Style – Inconsistent Method Naming

I agree that the gnome_vfs_truncate() function name is inconsistent. My guess as to why they chose gnome_vfs_truncate and gnome_vfs_truncate_handle() was to match the underlying truncate() and ftruncate() C library calls. This was probably a case of balancing consistent APIs with ease of transition from libc APIs to gnome-vfs APIs.

Returning data to pointers

I agree that the existing calling convention is not as nice as it could be. As I said earlier, it would probably have been designed to use GError if it was being developed today.

The GError API has a number of benefits over errno style ones, including:

  1. Automatically threadsafe. The place where the error is reported is on the stack. A global variable is a problem for multi threaded apps on systems without Linux 2.6 style thread local storage (you need to do tricks like making errno into a function that returns the appropriate variable for the current thread).
  2. In Robert’s example, the actual error information is looked up from a file handle. What do you do if there is no file handle involved in the function call? Also, wouldn’t gnome_vfs_open() return a NULL file handle on error?
  3. For the cases where there is a file handle to look up the error info on, what happens if two threads are working with the file handle at the same time?
  4. GError is consistent with other Gnome APIs :)

The GError API also makes it easy to pass error data up a number of call frames similar to exceptions. If your function has a GError argument, you can simply pass that same error object to other functions when you call them. If those functions fail on an error, simply return immediately, and the caller can handle the error.

Streams Interface

There actually is a stream interface available in one of the libraries both GTK and gnome-vfs depend on: GIOChannel. I guess it would be nice if gnome-vfs provided a GIOChannel implementation for VFS file handles. The main thing that would be needed here would be the io_create_watch() implementation, which would probably require exposing a file descriptor to poll on (this could probably be implemented using a pipe pretty easily).

Doing this as GObject interfaces isn’t really an option, since GIOChannel is implemented in libglib which is below libgobject, and gnome-vfs file handles aren’t GObjects. I know that at one point Ian was planning to change the various handles to GObjects, but this didn’t happen. It would probably be possible to do this kind of change while only requiring changes to VFS methods, so it can’t be completely ruled out.

Directory Interface

You can asynchronously load a directory listing using gnome_vfs_async_load_directory(). I don’t blame you for missing it — the organisation of the APIs in the various headers is a bit confusing.

Language Bindings

There are a lot of things a language binding can do to make gnome-vfs nicer to use. Some of these things include:

  • If the language provides exceptions, convert error GnomeVFSResult‘s to exceptions and change the calling conventions to something more sane.
  • If the language allows for runtime type checking or multiple dispatch, don’t wrap the gnome_vfs_foo() and gnome_vfs_foo_uri() functions separately. Instead, just check if a string or a GnomeVFSURI was passed in and do the right thing.
  • If the language has a standard file handle interface or convention, try to implement it in the binding.

The Python bindings do some of these things, and definitely make things easier to use.