Boogie Woogie Bugle Boy

Lately there has been some activity in projects moving from EggRecent to GtkRecent. Obviously, this led to questions and bugs opened about the API.

One of the questions is: if I had a EggRecentModel singleton what should I use now?. Since EggRecent needed a EggRecentModel around for the entire lifetime of the recently used files list, you had to keep at least a singleton around; you also had to pass it to the objects (not widgets) displaying the list, because each istance of the objects would modify the list itself. GtkRecentManager does not need that, since the widgets usually use their own internal instance of the manager and they don’t change the list in any way. So you can create a new GtkRecentManager and keep it around as a singleton (remember to call g_object_unref() on it when finished, otherwise you’ll leak it):

GtkRecentManager *manager_singleton = gtk_recent_manager_new ();

and then pass it to the widgets:

GtkWidget *dialog =
  gtk_recent_chooser_dialog_new_with_manager ("Recent Documents"
                                              parent,
                                              manager_singleton,
                                              GTK_STOCK_CLOSE,  GTK_RESPONSE_CLOSE,
                                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                              NULL);

Nevertheless, you should really use gtk_recent_manager_get_default() which will do the right thing, and pass you a per-process instance and you won’t have to care about its memory management (no g_object_unref() when quitting). Also, using gtk_recent_manager_get_default() means that you don’t have to use the _with_manager variant of the widgets constructor, as they will use the per-process GtkRecentManager by default. Using your own GtkRecentManager makes sense only if you want to use the “filename” constructor-only property to specify your own storage file (and you should do that only if you know what you are doing):

GtkRecentManager *manager = gtk_recent_manager_get_default ();

  ...

GtkWidget *dialog =
  gtk_recent_chooser_dialog_new ("Recent Documents"
                                 parent,
                                 GTK_STOCK_CLOSE,  GTK_RESPONSE_CLOSE,
                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                 NULL);

Another question is the dreaded I want an inline list of recent files in the File menu; I’ll redirect you to the bug report linked for the rationales about why I think the inline list sucks, and should be removed from the UIs of GNOME applications in favour of the sub-menu. Anyhow, for those Unbelievers still using this Windows-cloned relic of the past, here’s a simple function for adding an inline list to an existing GtkUIManager instance; it’s part of a example of integration between GtkRecent and the UI manager I sent to the gtk-devel mailing list before GUADEC.

static void
add_inline_recent_items (guint         merge_id,
                         GtkUIManager *ui_manager)
{
  GtkActionGroup *action_group;
  GtkRecentManager *manager;
  GList *items, *l;
  guint i;

  action_group = gtk_action_group_new ("recent-info");
  gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);

  manager = gtk_recent_manager_get_default ();

  /* we don't care about sorting and filtering, but it can
   * be done using g_list_sort_with_data() and clamping the
   * resulting list to the desired length
   */
  gtk_recent_manager_set_limit (manager, 4);
  items = gtk_recent_manager_get_items (manager);

  /* no items: attach an insensitive place holder */
  if (!items)
    {
      GtkAction *action;

      action = g_object_new (GTK_TYPE_ACTION,
      			     "name", "recent-info-empty",
			     "label", "No recently used files",
			     "sensitive", FALSE,
			     NULL);
      gtk_action_group_add_action (action_group, action);
      g_object_unref (action);

      gtk_ui_manager_add_ui (ui_manager, merge_id,
  			     "/MenuBar/FileMenu/RecentFiles",
			     "recent-info-empty",
			     "recent-info-empty",
			     GTK_UI_MANAGER_MENUITEM,
			     FALSE);

      return;
    }

  for (i = 0, l = items;
       l != NULL;
       i += 1, l = l->next)
    {
      GtkRecentInfo *info = l->data;
      gchar *name = g_strdup_printf ("recent-info-%d-%lu",
      				     i,
				     (gulong) time (NULL));
      gchar *action_name = g_strdup (name);
      GtkAction *action;

      action = g_object_new (GTK_TYPE_ACTION,
      			     "name", action_name,
			     "label", gtk_recent_info_get_display_name (info),
			     "stock_id", NULL,
			     NULL);
      g_object_set_data_full (G_OBJECT (action), "gtk-recent-info",
                              gtk_recent_info_ref (info),
			      (GDestroyNotify) gtk_recent_info_unref);
      g_signal_connect (action, "activate",
                        G_CALLBACK (recent_activate_cb), NULL);
      gtk_action_group_add_action (action_group, action);
      g_object_unref (action);

      /* all you need is a UI definition with a "placeholder" element called
       * "RecentFiles" under a "menu" element called "FileMenu".
       */
      gtk_ui_manager_add_ui (ui_manager, merge_id,
  			     "/MenuBar/FileMenu/RecentFiles",
			     name,
			     action_name,
			     GTK_UI_MANAGER_MENUITEM,
			     FALSE);

      g_print ("* adding action `%s'\n", action_name);

      g_free (action_name);
      g_free (name);
    }

  /* unref the info objects so that they will be destroyed when
   * the actions to which they are bound are destroyed with the
   * UIManager instance
   */
  g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
  g_list_free (items);
}

This code should give you an idea on how to implement your own version. Making the menu reloading the inline list means removing the UI definitions using the merge_id integer and calling this function again inside a callback attached to the “changed” signal of a GtkRecentManager instance, and it is left as an exercise for the reader. ;-)

GtkRecent and GtkUIManager

I’m really sorry that the UIManager integration did not happen in time for 2.10; it means that some applications will have to implement it by themselves until GTK+ 2.12 is out with a common implementation. In the meantime, continue asking me or opening bugs in Bugzilla.

Update@2006-08-02T09:51+0100: the complete code now has the “reload-when-list-change” feature. Remember: you may cut and paste this code for a basic support of recent files inside an inline menu; there are at least another couple of ways to implement the same level of support, and mostly it depends on how you handle your own documents. I’d like for GTK+ or libgnome or GLib to have a “document” class abstracting most of this and other stuff, like Cocoa on OSX has the NSDocument class.

Update@2006-08-02T16:05+0100: another update – I’ve fixed a couple of leaks (a GtkAction is a GObject and not a GtkObject) and added the sorting function for the inlined list.

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

GUADEC/Back

I’m back to London after the really amazing days in Vilanova. This year’s GUADEC has been really amazing: lots of interesting talks and great people to meet; there definitely was a great energy in the air. Kudos to everyone involved in the creation and management of this great event: you really rock the world of GNOME.

I’ve put online the slides from my talk, if anyone wants to check them out: just PNGs, so you loose all the Clutter sexyness. I’ve also put on flickr the photos I took with my really crappy mobile phone.

GUADEC/Request

If there are any liferea developers at GUADEC, I’d like to have a few words about the key bindings used in your application – specifically why did you choose Ctrl+N for “go to new item” and why Ctrl+W doesn’t close the window.

Please, don’t let me patch your application in order to behave sanely.

You can easily recognise me: I’m the one hopelessly trying to read new items using Ctrl+] and trying to close the window using Ctrl+W.

GUADEC/Day 1

The OH Gang arrived yesterday at GUADEC – just in time for my talk. I think that the tutorial went well – Clutter worked out of the box on the VGA port, which was quite a surprise. About Clutter: it was fun to see Jeff use it for his presenytation too. I’ve met with many interesting people – just hope to remember their names, though: I’m terrible with name memory; so, if OI see you and I’ll look desperatly at your name tag even if we already introduced ourselves, please bear with me.

GUADEC this year is awesome, and kudos goes to Quim and all the wonderful staff that made this magic possible.

Clutter

Behold the power of Clutter!

Clutter is a pretty raw user interface toolkit for building heavily visually applications for platforms such as media boxes and kiosks. It’s built on various GNOME libraries such as Pango and GObject, uses Gstreamer for media playback, and all this sits upon OpenGL for fast graphics rendering.

Yes, it’ll soon have bindings for Perl (like it already has bindings for another high-level language with funny syntax that begins with P).