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.

4 October 2004

Icon Theme APIs (continued)

Of course, after recommending that people use gtk_icon_theme_load_icon() to perform the icon load and scale the icon for you, Ross manages to find a bug in that function.

If the icon is not found in the icon theme, but instead in the legacy $prefix/share/pixmaps directory, then gtk_icon_theme_load_icon() will not scale the image down (it will scale them up if necessary though).

jhbuild

Jhbuild now includes a notification icon when running in the default terminal mode. The code is loosely based on Davyd’s patch, but instead uses Zenity’s notification icon support. If you have the HEAD branch of Zenity installed, it should display without any further configuration. Some of the icons are a little difficult to tell apart at notification icon sizes, so it would be good to update some of them.

DVDs

The Double the Fist DVD is great. I hope they do another season, and release the second half of the first season on DVD. It is a satire on extreme sports and reality TV shows among other things, and is worth watching. Apparently it was originally shown on ABC digital, so not many people saw it during its original screening (digital television is fairly new in Australia, and equipment is still fairly expensive).

29 September 2004

Ubuntu

Ubuntu seems to have taken off very quickly since the preview release came out a few weeks ago. In general, people seem to like the small tweaks we’ve made to the default Gnome install. Of course, after the preview came out people found bugs in some of my Gnome patches …

One of the things we added was the trash applet on the panel. I made a fair number of fixes that make the applet fit in with the desktop a bit better and handle error conditions a bit better.

Probably the biggest fix was adding support for multiple trash directories. Originally the applet would move files to ~/.Trash and didn’t monitor any other trash directories, which meant that moving to the trash took longer than necessary on slow volumes and the applet didn’t correctly reflect the trash’s empty state if you used the “move to trash” context menu item in Nautilus.

One of the problems implementing this was that the trash handling in Gnome is pretty much entirely private to Nautilus. I managed to adapt the Nautilus code into a small class (about 500 lines) that could provide an item count for the trash, notification of changes to the item count, and the ability to empty the trash. A lot of the complexity in this code is to handle plugging and and unplugging of removable volumes. It’d be nice if this kind of code was available in gnome-vfs or something though.

Icon Theme APIs

While working on various Ubuntu fixes, I found an error that seems to be quite common in various bits of the desktop. It goes something like this:

  1. Find the image file for an icon at size n using gnome_icon_theme_lookup_icon() or gtk_icon_theme_lookup_icon().
  2. Create a GdkPixbuf from the image file using gdk_pixbuf_new_from_file().
  3. Use the pixbuf as an nxn icon.

The first problem with this is that gtk_icon_theme_lookup_icon() is not guaranteed to return an image at the desired size. This is quite obvious when you consider that you can pass in an arbitrary size to the lookup function, but the icon theme will only contain a finite number of sizes. However, if you ask for a common sized icon and the icon theme contains that size image, it might appear that the function will always return an image file of the requested size. The fix is to check the size of the loaded pixbuf and scale it if it is of the wrong dimensions.

The second problem is to do with SVG image files. They can be rendered at arbitrary sizes, but gdk_pixbuf_new_from_file() doesn’t tell the loader backend what size is actually wanted. This means that the SVG will be rendered at whatever size is listed in the file itself, which could be very large or very small. To avoid having to resize the SVG image after rendering it (which could be slow), you can use the gdk_pixbuf_new_from_file_at_size() routine (new in GTK 2.4) which passes the desired size to the backend so that ones like the SVG backend can render at an appropriate size. This function will return a pixbuf that fits into the bounding height/width you pass to it, and will perform scaling if the backend can’t load the image at the requested size.

If this sounds complicated, there is an easier way. You can just use gtk_icon_theme_load_icon(), which will lookup the image, and load it at the desired size all in one go. I guess there aren’t many people using it because there wasn’t an equivalent in the older GnomeIconTheme API.

Applets vs. Notification Icons

It seems that a lot of people get confused by what things on the panel should be applets and what should be notification icons. Originally, the main difference between the two was this:

  • The lifecycle of an applet is managed by the panel, which in turn is tied to the lifecycle of the session. So applets generally live for the length of the session (unless they are added/removed part way through a session).
  • Notification icons are more transient. Their lifecycle is linked to whatever app they were created by. Once the app exits the notification icon goes away too.

There are some other differences though:

  • Applets can be moved around on the panel while notification icons are constrained to the system tray. If you accept that notification icons are transient then it isn’t that big a deal.
  • KDE also implements the system tray spec, so a notification icon can be used on both desktops (plus any other desktop that implements the spec). In contrast, Gnome applets are Bonobo controls which makes them a bit difficult to use on other desktops.
  • The panel can merge menu items into the context menu of applets, and supports middle click drag to move applets.
  • The system tray is supposed to be able to display “message balloons” for the notification icons. This doesn’t seem to work properly though. The reason for getting the system tray to show the balloons is so you don’t get multiple applets popping up such notices on top of each other, and to make it easier for the user to manage such notifications.

Due to these differences there are a number of notification icons such as Novell’s netapplet which more closely follow the lifecycle of an applet but are notification icons for cross desktop compatibility.

While talking with Mark on IRC, it became apparent that a number of the applets included with Gnome aren’t strictly linked to the session’s lifetime. For example, my laptop has a PCMCIA wireless adapter, so I put the wireless applet on my panel to show the signal strength. However, it doesn’t really make sense to display the applet when the card is unplugged.

Similarly, if I share my home directory between a number of computers, it doesn’t make sense to show the volume control applet on systems without a sound card or the battery status applet on systems without a battery. So perhaps these applets shouldn’t really be tied to the panel’s life cycle.

With infrastructure like NetworkManager where there is a user-level daemon used to communicate with the user when necessary, it would make sense for that daemon to provide network status as notification icons. This way the icons would only appear when the associated device was attached. Something similar could be done for the volume control and battery status applets — query HAL to see if they need to be loaded.

However, with such long lasting notification icons you probably want some of the features of applets such as being able to move them round a bit. This indicates that it might not make so much sense to make such a big distinction between applets and notification applets.

I wonder how difficult it would be to extend the system tray/notification icon spec to handle the features applets currently have?. From a quick look, the additional features include:

  1. Some way for icons to cooperate with the panel to handle moving icons around.
  2. Some way to uniquely identify applets so that the panel can place them in the same location next time the icon is created.
  3. Provide some standard context menu items. The standard ones that applets have merged in are “Move”, “Lock” and “Remove from panel”. Only the first two would need additions to handle.
  4. Better size negotiation. An applet can query the width and orientation of a panel when deciding what its size should be. I don’t think a notification icon can do so.
  5. Figure out a good way to start notification icons on session startup.
  6. If notifcation icons can be moved to anywhere on the panel, where should truely transient icons be placed the first time? Currently they are placed in the system tray, which provides a convenient place for the user to expect to see such notifications.

This should also make it easier to provide more full featured panel widgets that work cross desktop. I wonder how feasible it is?

Notification Icons

I decided to go ahead and write the code to allow Zenity to listen for commands on stdin. It was pretty easy to add, and Glynn accepted the patch so it is in the latest CVS version. The main difference between the implementation and what I described earlier is that you need to pass the --listen argument to Zenity to activate this mode (without it, it acts as a one-shot notification icon where it exits when the icon is clicked on). The easiest way to use it from a bash script is to tie Zenity to a file descriptor like this:

exec 3> >(zenity --notification --listen)

You can then feed commands to the notification icon by echoing things to that file descriptor. For example:

echo "tooltip: a new tooltip" >&3

The available commands are icon, tooltip and visible. When you’ve finished and want to kill off the icon, you can simply close the file descriptor:

exec 3>&-

Some things that would be good to add are message balloon support (although the Gnome system tray doesn’t seem to support them right now) and support for animated images (useful to get the user’s attention while message balloons don’t work).

One of the reasons for adding this functionality to Zenity was for use in jhbuild. Davyd did the initial prototype for this, but the idea for the notification icon seemed fairly generic and useful outside of jhbuild. Also, by putting it in Zenity there is less to maintain in jhbuild itself :)

14 September 2004

Foundation Elections (continued)

bolsh: as I said, many real elections make modifications to an idealised STV system to simplify vote counting. The counting for the .au senate elections sounds like it takes a random sample of votes when transfering preferences too.

Also, in my description a candidate needed to get more votes than the quota and the quota could be fractional. In contrast, the Australian senate elections say candidates must reach the Droop Quota, which is the smallest integer greater than the quota formula I used. If you are using random sampling for preference transfers so that each ballot has a weight of either 0 or 1, then this is equivalent. However, if you count fractional votes, then it does make a difference.

Since the votes are all collected electionically for the foundation elections, it shouldn’t be any more difficult to count the votes exactly (which the pSTV software you pointed out trivial).

I agree that it would be interesting to get people to list preferences on the ballot even if we don’t switch to STV for the election (I mentioned this in one of my foundation-list emails). The top 11 preferences could be used to perform the existing vote counting algorithm.

Work

The preview release of Ubuntu will be coming out later today. While most of the work I’ve been doing is in some of the backend infrastructure rather than packaging, for the past half week I’ve been helping out with some of the Gnome modifications. I doubt all of the changes will be accepted up stream, but I think a number of them would be welcome changes for Gnome 2.10.

I also now realise how bad the battstat_applet code is, and can understand why Glynn started from scratch. It seems like a good thing to improve for 2.10. Davyd mentioned on IRC that it would be nice if it could work with UPSs as well as laptop batteries. NUT can easily provide all the info that the applet gets from the APM or ACPI code, so this shouldn’t be too difficult. I wonder how useful sysadmins would find such a feature?

Thunderbird

The new version of thunderbird looks quite nice. As well as the usual incremental improvements, this release can also act as an RSS reader. It converts items from the feeds into email messages and puts them in the chosen folder. You can then manage them as you would your mail. It’s an interesting way of reading sites like planet gnome. If the feeds provide full content like the PG does, then you probably want to turn on the “Show the article summary instead of loading the web page” option. For feeds without much content you can leave that option off and it will load the linked web page instead.

13 September 2004

Foundation Elections

There has been talk on the foundation list about changing the vote counting procedure to something more fair. The method being proposed is Single Transferable Vote, which is the same system used within a single electorate for the senate vote in the Australian Federal Election. As with the Australian elections, some people have some trouble understanding exactly how it works, so here is a description.

  1. Each voter orders every candidate on their ballot in order of preference. Each ballot is assigned a weight of 1.
  2. The ballots are grouped by the first preference.
  3. If any candidate’s total reaches the quota, then they get in. The quota is chosen such that if there are s seats, then at most s candidates can reach the quota. So a candidate must get more than n/(s + 1) first preference votes in order to reach the quota.
  4. If any candidate gets over the quota, then the highest vote getter is elected, and their votes are redistributed at a reduced strength. If x people voted for the candidate, then the weighting of each of the votes is scaled by (xq)/x where q is the quota (xq is the number of votes over the quota). The winning candidate’s name is removed from all ballots and we go back to step 2 and repeat to find the next winner.
  5. If no candidate reaches the quota, then the candidate with the least first preference votes is removed from the election. Their name is removed from all ballots, and we go back to step 2. The votes for the removed candidate are redistributed at the same strength, since they didn’t help elect a candidate.

Note that this vote counting system is identical to Instant-runoff voting when there is only a single seat. The quota calculation shows that the winning candidate needs to get more than 50% of the votes to win, as expected.

Some of the nice properties of this system include:

  • If you vote for a losing candidate, your vote is transfered at the same strength, so is not wasted. This reduces the risk of voting for a candidate that is unlikely to win.
  • Voting for a popular candidate doesn’t waste your vote. The portion of your vote that wasn’t needed to elect the candidate is redistributed to the next preference. For example, if 50% of people vote for dcamp, but the quota is 10% of the votes, then all his votes will be redistributed to second preference at 80% strength.
  • If there are two similar candidates, they shouldn’t split the vote in such a way that neither wins. If one candidate gets knocked out, their votes will transfer to the other.

There are some differences between what I described and what is used in the Australian elections. This seems to be to make the process more discrete and easier to count (mostly rounding the various quotas and transfer values). For the foundation election though, I can’t see any reason not to use a more exact version.

Zenity Notification Icon

Yesterday Glynn posted about notification icon support in Zenity. His current implementation really only handles one-shot notifications, since the icon disappears and zenity exits when you click the icon.

I talked with him on IRC about adding support for a different mode where you send commands to zenity via stdin, similar to the jhbuild notification icon prototype Davyd did. This would allow you to write bash scripts like this:

exec 3> >(zenity --notification)
echo "icon: someicon" >&3
echo "tooltip: doing some important work" >&3
# do stuff
echo "icon: someothericon" >&3
# do some more stuff
exec 3>&-

This could be very useful for many scripts in addition to jhbuild, which is why I suggested adding it to zenity. Now it just needs implementing …

20 May 2004

Mail Viruses

The barrage of mail viruses and their side effects is getting quite annoying. In the past week, I’ve had a gnome.org mailing list subscriptions disabled twice. After looking at the mailing list archive, it was pretty obvious why.

The mail server that serves my account is set up to reject windows executables a few other viruses at SMTP delivery time (so it isn’t responsible for generating bounces). Unfortunately, a number of viruses got through to the mailing lists and were subsequently rejected before reaching my account. After a certain number of bounces of this type, mailman helpfully disables delivery.

It’d be nice if mail.gnome.org was set up to reject these sort of messages too (in the case of gnome.org it’d probably be safe to block zip files as well, which would cut out virtually all the viruses).

It also seems that the email viruses don’t pick the sender and recipient completely at random. Apparently a number of infected machines keep on mailing the XML mailing list with my address as the sender. It got so bad that the list admin put me in the “always moderate” list. Of course, this meant that I ended up receiving many messages telling me my message awaits moderation (which are pretty easy to filter). Luckily the new version of Mailman limits itself to 10 of these messages a day.

jhbuild

I’ve merged in some of Thomas Fitzsimmons’ jhbuild patches. It isn’t yet at a stage where you can build GCJ using an unmodified jhbuild, but we’ve got some of the basics in there. A big part of the changes involve adding support for srcdir != builddir builds, which is apparently the preferred way of compiling GCJ. This is accomplished by setting the buildroot config key to the directory where you want builds to be performed. Things aren’t fully working yet, but at least some modules build in this mode. We’ll probably need to add support for marking some modules as not supporting srcdir != builddir builds, since some modules will most likely never support it.

gnome-common

I’ve been doing some work to simplify the gnome-common autogen script. A lot of the infrastructure dates back to the early 2.0 days where it was important to make sure developers could hack on 1.x apps and 2.0 stuff at the same time, which involved complicated infrastructure to make sure 2.0 packages didn’t see the Gnome 1.x autoconf macros and vice versa.

Since then things have changed. Developing Gnome 1.x apps isn’t really a priority any more (and no one was using the stuff installed by gnome-common for 1.x work anyway). We also have far fewer autoconf macros in gnome-common, and they aren’t particularly Gnome 2 specific. This is partly because I killed a lot of them last year, and deprecated most of the rest. While looking through the macros this time, it turned out I could remove another one, and get rid of the deprecated macros altogether. This just leaves some macros for setting compiler warning flags, one for adding a --enable-debug configure option.

The patch moves the remaining autoconf macros to the normal $(datadir)/aclocal directory so that aclocal can find it easily, and install the common autogen script as $(bindir)/bin/gnome-autogen.sh (which was previously a small script that would choose which set of macros and autogen script to call based on an environment variable).

Hopefully these simplifications will make it easier to debug autotool failures in the various Gnome packages. Many people seem to find autoconf hard enough to understand as is without us making things more complicated and adding extra ways that things could fail.

28 April 2003

Red Hat 9

Installed it on a few boxes, and I like what I see so far. The Bluecurve mouse cursors look really nice. It is also good to see some more of my packages included in the distro (fontilus and pyorbit).

Spam

Some spammer has been sending mail with random @daa.com.au addresses in the From: field. So far, I have received lots of double bounces, a few messages asking if we know about the spam, and many automated responses (some saying the message came from a blocked domain!). The Received headers indicate that the mail comes from somewhere else, so there isn’t much I can do. I hate spammers.

I put up a bit of documentation on the SpamAssassin/Mailman setup I developed on my website. It would be good to get mail.gnome.org switched over to the new setup (they are using an older version of my filter), as it has greatly reduced the amount of moderation required.

jhbuild

Did a bit more hacking on jhbuild. It now builds fontconfig and Xft from CVS, which should give Keith a few more testers. I had to update jhbuild to use libtool-1.5 as it was required to build them. This has uncovered a few bugs in various autogen.sh scripts that still need to be fixed. I also added the ability to override the cvsroots used to check things out (so if you have an account capable of writing to gstreamer from cvs, you can use it), and change the branches for individual modules which should be useful for module maintainers.

libglade

I am about half way through modifying libglade to construct arbitrary GObjects, rather than just widgets. When this is finished, it will allow eg. setting up tree view columns in the .glade file, size groups and a few other things. The change will break compatibility for backend modules, but should keep binary compatibility for apps. This seems okay given that there are only about 3-4 backend modules in existance (which add support for libgnomeui widgets, gnome-canvas and libbonoboui widgets).