Ride on a White Horse

Filed under the category: “useful programming tips for problems that bit my ass”

The wise men from old said: Thou shalt not check if a directory or file existeth before creating it.

Well, or something like that.

I often see code that looks like this:

if (!g_file_test (some_directory, G_FILE_TEST_EXISTS))
  {
    if (g_mkdir (some_directory, 0700) != 0)
      {
        g_warning ("Unable to create `%s'", some_directory);
        return;
      }
  }
else
  do_something_with_some_directory (some_directory);

or, worse, code that looks like this:

if (!g_file_test (some_file, G_FILE_TEST_EXISTS))
  {
    symlink (some_other_file, some_file);
  }

Despite a BFW on the g_file_test() API reference page.

These code snippes are wrong, because they contains an implicit race: what if the directory/file you are checking suddenly disappears (or is created)? Also, blindly invoking functions like g_mkdir() or symlink without checking the returned value (“hey, I just checked so how can it fail?”) is looking for troubles; finally: when a system call fails, you should always report the error message the OS sets: too many things can go wrong, and if you can get a meaningful message then you’ll be able to debug faster.

The solution for these problems is: shoot first, then ask the questions. Or, in other words, execute the function inside the if block and act according to the results. For this to happen, you’ll often need to rely on errno.h and g_strerror():

#include <errno.h>

...

if (g_mkdir (some_directory, 0700) == -1)
  {
    if (errno != EEXIST)
      {
        g_warning ("Unable to create `%s': %s",
                   some_directory,
                   g_strerror (errno));
        return;
      }
  }

do_something_with_some_directory (some_directory);

and:

#include <errno.h>

...

if (symlink (some_other_file, some_file) == -1)
  {
    if (errno != EEXIST)
      {
        g_warning ("Unable to create a link from`%s' to `%s': %s",
                   some_other_file,
                   some_file,
                   g_strerror (errno));
        return;
      }
  }

At the end of the if block we are guaranteed that the file or the directory does indeed exist either because we successfully created it or because the system call failed and errno was set to EEXIST; inside the if, instead, we can deal with failures, using various error trapping branches based on the value of errno (just remember to store it if you’re going to use it multiple times).

Rainbows and Pots of Gold

Of docked windows, bugs and the Dictionary applet

One of the two major UI issues for the new Dictionary was the absence of the speller. Since that has been somewhat fixed, even if it still lacks some polish, I decided to address the other, that is the fact that the Dictionary applet uses a docked window instead of a full window.

The rationale for having a docked window instead of a floating one was that a docked window is alwas at the same place, linked to the applet, so if you want to check a word you can’t possibily “lose” the Dictionary and have to cycle through the window or workspaces list – which is the whole point of having the applet on a panel. If you want a “fire and forget” Dictionary you can always create a launcher on you panel and click on it.

One problem with this rationale is that the dictionaries usually return preformatted text, which is understandable – they should work on ANSI terminals too; but this creates a dilemma: should we remove the formatting from the text, allowing the text view widget to reflow its content without changing the size of the window? Or should we keep the formatting and resize the window?

Docked window should not be resized by the user; I don’t resize the clock applet’s drop-down, or the drawer applet, or any menu: I expect them to change their size according to their content. So, if we want to avoid what could be perceived as a regression by some users and keep the formatting of the dictionary entries, we must resize the window according to its content whenever is possible.

Here comes the bug:

Neat Bug

I haven’t been able to hit, let alone reproduce, this bug until a couple of days ago. Actually, I tried again with 2.14.0 and I could not hit it, so I think the issue is much more weird that I’ve thought :-P. Anyway: if you exposed the definition window before searching something, the window would not be resized. The actual fix took less than ten minutes (writing, compiling, adding the stock applet to the panel, killing the applet, launching the newly compiled applet from terminal and hijacking the factory included) and consisted in a couple of lines.

I’ve closed both reports, essentially because inside all code paths that lead to the visualization of the window now take care of checking its size against its content. If you hit this weird bug again with HEAD file a bug about it, but please, please avoid asking that the window should be resizable. The definition window should just work; if it does require the user to change it, it’s a bug.

Of side bars, widgets and UI changes

In related news, I’ve finally been able to spend some time updating Dictionary’s UI; the Speller widget is now embedded into a real side bar (like the one Evince and Totem use, albeit I used my own code), and there’s also a list showing the databases available on the dictionary source used; if you double click on a database, the following queries will be made against that database only (the setting is not permanent: you’ll have to update the source definition for this to happen).

Available databases

Still, the time I planned to spend and the features I intended to add to the Dictionary (and the rest of gnome-utils) are way below par, as you can see on gnome-utils roadmap. I can mostly blame moving to London and the wedding, but the thruth is that after the feat of rewriting the entire Dictionary (backend, main frontend and applet) in three months I felt a little bit burned out. The real upside, though, is that I can still hack new features like these without spending too much time (the sidebar and the database chooser are the result of 12 hours of hacking, after two months of not touching the code base except for the occasional bug fixing) thinking: “what was I thinking when I wrote this code” (except for the occasional: “hrm, what was I drinking before writing this code”); this means that the rewrite turned out pretty good: compare to adding the docked window inside the applet, a minor feature that required rewriting the entire thing.

Documentation

Davyd, the GTK+ Perl bindings come with documentation in the perldoc format (which works upon man); each object has its unique perldoc page, so if you need to know all the methods of the Gtk2::TreeView widget, all you have to do is open a terminal and type:


$ perldoc Gtk2::TreeView

And you’ll be greeted by a screenful like this:

TREEVIEW(1)         User Contributed Perl Documentation        TREEVIEW(1)

NAME
       Gtk2::TreeView

HIERARCHY
         Glib::Object
         +----Glib::InitiallyUnowned
              +----Gtk2::Object
                   +----Gtk2::Widget
                        +----Gtk2::Container
                             +----Gtk2::TreeView

INTERFACES
         Glib::Object::_Unregistered::AtkImplementorIface

METHODS
       widget = Gtk2::TreeView->new ($model=undef)

           * $model (Gtk2::TreeModel)
...

Support of man pages, by the way, is sorely missed inside GTK+ itself: instead, you’ll have to use devhelp or point your browser to a long URI; I love devhelp, but I’m usually coding (with) development releases of many libraries, all installed inside a jhbuild sandbox so in order to make it find the autogenerated API documentation you’ll have to build devhelp inside the sandbox too – which is unnecessary pain I’d like to avoid inflicting upon myself.

Anyway, perldoc to the rescue: at the end of the object page you’ll find the SIGNALS section – if the object’s class exports signals, that is – which looks like this:

SIGNALS
       set-scroll-adjustments (Gtk2::TreeView, Gtk2::Adjustment, Gtk2::Adjustment)
       row-activated (Gtk2::TreeView, Gtk2::TreePath, Gtk2::TreeViewColumn)
       boolean = test-expand-row (Gtk2::TreeView, Gtk2::TreeIter, Gtk2::TreePath)
       boolean = test-collapse-row (Gtk2::TreeView, Gtk2::TreeIter, Gtk2::TreePath)
       row-expanded (Gtk2::TreeView, Gtk2::TreeIter, Gtk2::TreePath)
       row-collapsed (Gtk2::TreeView, Gtk2::TreeIter, Gtk2::TreePath)
...

As you can see, you have the signal name, the arguments of the callback and the eventual return value. The “gotcha” is that there are no named arguments, so you’ll have to know the C counterpart of the signal; this might be a worthy addition to the API documentation generation module.

Another dirty trick is to use the Data::Dumper module inside a callback you don’t know which arguments passes:


sub my_unknown_callback {
    use Data::Dumper;

    print STDERR Dumper(@_);
}

Which will print whatever the callback gives you – even descending into hashes and arrays if it knows how to print their contents.

If you don’t want to use a terminal and the perldoc command, there’s the Gtk2::Ex::PodViewer widget on CPAN, which comes with a podviewer application which you can use to browse the entire Perl documentation available on the system,or you can download PodBrowser which does a bazillion things more.

Tides that I tried to swim against

gtk-recent: For those who missed the mail on gtk-devel-list, language-bindings and desktop-devel:

Unfortunately, when importing the GtkRecent API in GTK+ I made a mistake and these two functions have been erroneously left inside the GtkRecentChooser interface API:


  gtk_recent_chooser_set_show_numbers()
  gtk_recent_chooser_get_show_numbers()

These two functions try to set the “show-numbers” property, which is installed only by GtkRecentChooserMenu and it’s not one of the properties defined by the GtkRecentChooser interface. Using these functions on a GtkRecentChooserMenu (or any other custom GtkRecentChooser implementation which defines a boolean “show-numbers” property) will yield the expected results, while using them on a GtkRecentChooser implementation that does not support the “show-numbers” property will result in a warning.

Since we are in a stable release we can’t mark those functions as deprecated, and we cannot remove them without breaking the API. You are advised not to use these functions: use the GtkRecentChooserMenu functions instead:


  gtk_recent_chooser_menu_set_show_numbers()
  gtk_recent_chooser_menu_get_show_numbers()

Language binding authors should not bind those functions, but bind the GtkRecentChooserMenu functions instead.

These functions will be marked as deprecated as soon as GTK+ will branch off for the 2.11/2.12 cycle, so you’ll have to bear with this inconsistency for a short period of time.

language-bindings/1: By the way, gtk2-perl now supports the GtkRecent code in HEAD, thanks to the hard work of Torsten kaffee Schoenfeld who fixed most of my first iteration binding code and wrote the tests for it.

language-bindings/2: I also finished the Perl bindings for Clutter, as well as the Python ones. As I changed Clutter to behave like GTK, with the ClutterActor objects being created with a “floating” reference count, you’ll have to update Clutter to HEAD if you want to test the bindings. Beware that Clutter’s API is still a bit fuzzy at the moment. Of course, if you find bugs in the library or in the bindings, be sure to report them.

Now Listening: Last-exit, Neighbour radio

Shake Your Groove Thing

Still in Italy, for the next 48 hours at least

_DSC1728.JPG

The wedding went incredibly well: the ceremony itself was so short (twenty minutes) that I don’t remember much of it.

185646708_0508f28c8e.jpg

We were married in a beautiful building in Milan, with frescoes made by Tiepolo, by a city hall official.

185646833_f702dae4e4.jpg

The lunch was much more fun, even though it proved to be really tiresome: we went to sleep at 18:00 and woke up at 9 the day after.

_DSC1782.JPG

We were cheered by (many) relatives and (many) friends – surely one of the best days in my entire life, and an awesome way to begin a new life as well.

More photos: here