Merger

Seems that I’m being syndacated… aggregated… whatever… on a Planet, so hi!

I’m starting merging the GBookmarkFile parser into my local copy of GLib’s HEAD branch (the tracker bug is #327662). I’ve created a testb suite and a bunch of invalid and valid bookmark files, in order to test it – and they actually helped me find a couple of stupid regressions that I had introduced.

Pending review of the patch by Matthias, the code should go in GLib first thing next week; once GBookmarkFile is in, the recent manager and the related widgets are due to go in the following days. Right now, I’m writing a patch for GTK’s HEAD branch – stay tuned for a tracker bug about it. Update 2006-03-27@00:31: bug #336121.

Whoa, just a couple weeks shy on a year since I began writing the Perl bindings for the egg-recent code – which is the reason that forced me to open that can of worms and where all the recent files rewrite really began. Never thought that it would take this long, or that it would take me this far. Well, actually I never really thought I had some chances of actually contributing something to the platform libraries at all.

Now listening: Burning down the house, Talking Heads

ChangeLog

Long time, no blog.

Here’s a brief recap of what happened in the last three weeks:

  • Matthias Clasen has began reviewing the Recent Documents code, and we are planning to get it merged beginning next week; I sent a recap to the gtk-devel mailing list, and I’ll send the draft for the Desktop Bookmark specification on the xdg mailing list at fd.o (like I did a year ago, but now I have a working implementation);
  • GNOME 2.14 is out!
  • gnome-utils 2.14.0 is out too!
  • Me and Marta went to London, last week: she went to look the premises of the London School of Economics, as she’ll be taking a MSc there starting from September; me, I met with Matthew Allum, and following the arrengements we made at FOSDEM last Februrary, I signed a contract for working with the great guys at OpenedHand.
  • And last, but not least (or I would be in trouble), I’m getting married!

Porting

I’ve just updated the Recent Files and Bookmarks page on Gnome’s wiki: some (long due) clean ups and typo checking, but I’ve also added a porting guide, showing how to use the RecentManager and RecentChooser objects: addition, look up, display, sorting and filtering. If you are using the EggRecent code in your applications, go check it out.

As soon as Gnome 2.14 hits the mirrors, I’ll finally deprecate the EggRecent code – and won’t have to deal with the horrible EggRecentViewGtk widget anymore. Really, if there is a reason I wanted to implement the recenly used documents stuff, it surely must be to get rid of that code.

Developement Trunk

Shamed by kris’ post about the state of Project Ridley stuff, I resumed the recent-files hacking after the gnome-utils/gnome-dictionary crazy run that occupied my nights in the last three months or so.

RecentManager and RecentChooser

I already did a review of the documentation and the code last month, but I stopped before committing because I wanted to make a major overhauling of the sorting and filtering stuff – namely, the removal of the sorting and filtering functions from the RecentManager class and the implementation of custom sorting inside the RecentChooser class.

At first, I designed the RecentManager object as the only proxy for every operation on the list of recently used resources; then I designed the RecentChooser interface, in order to create a uniform API to display and access the data provided by the RecentManager. It all worked without much pain: you would instantiate a RecentChooser implementation and it would create its own manager. This, though, led to an unclean separation between model and viewer in an otherwise MVC approach. I went back to the design table, and severed each direct usage of the RecentManager API that would affect the list displayed by the RecentChooser from within the various implementations. This approach allowed the usage of the same RecentManager instance inside N RecentChooser implementations – allowing, also, to have a single, session-based, RecentManager instance shared between various processes (not coded, until we can integrate all the stuff inside GTK). The only downside in this operation was due to code replication between the RecentChooser and the RecentManager; thus, like I already did move the filtering stuff out inside the RecentFilter object, I moved the sorting stuff inside the RecentChooser API (and its implementations) and out of the RecentManager – which now just manages the list, and it’s used just to add, look up and remove resources from the list it holds.

More informations on the wiki: here and here.

LinkButton

I also did some work on the LinkButton, the widget that should supercede GnomeHref from libgnomeui. Attached to bug #314808 there’s the current implementation.

More informations on the wiki: here.

Icon

I’ve just committed my development trunk of the BookmarkFile and RecentManager objects. The former now supports custom icons for every bookmark inside the file, using the icon element; the latter, finally, supports group names for every recently used item.

I’m writing a small page for documenting how to port an application from the old EggRecent code to the new RecentManager, and also how to use the new RecentChooser widgets.

On a related note, I’ve been contacted by other developers interested about the RecentManager/RecentChooser code; expect more news soon.

Leaking/2

After some six hours, a chinese dinner, two large glasses of earl grey tea, and a coffee, I’m finally able to declare that, according to Valgrind, both the libegg/recent-files and libegg/recentchooser code are leak-free.

Okay, take this with a grain of salt, as I’m not that good with Valgrind, and some of the logic of my widgets might lead to leaks; as far as my mallocs are concerned, my code is leak-free

[]
[]
[]

Leaking

Yesterday, while I was at university waiting for a seminar about network security, I was on -it, and pbor asked me to look at a leak in EggRecentModel. I began wading through the code, but I didn’t found the leakage in time before having to leave.

In the evening, after I got back home, Marta went to her church choir practice, and I looked at recent-files/egg-recent-model.c using Valgrind (and practicing with it, since I’m not that good with this tool); using the function chain reported by valgrind, I noticed that the leak was inside the logic used by egg_recent_model_filter. This function scans the list of EggRecentItem objects built from the on-disk storage and filter out using the three pre-defined filter functions (while my RecentManager object supports only custom filtering function, and the RecentChooser implementations might filter the recently used resources list using a more complex RecentFilter object). The problem is that it used the infamous GList scan using while():

  while (list) {
    SomeData *obj = l->data;

    do something with the object

    list = list->next;
  }

This code is perfectly valid: it walks the list by exhausting it; that is: the list pointer reaches the end of the list once it reaches the end of the while. Valid code does not mean right code, though. Suppose you want to move the items of a list inside another list. By using the code above, you would have:

  GList *newlist;

  /* init the target list */
  newlist = NULL;
  while (list) {
    SomeData *obj = l->data;

    if (some_condition)
      newlist = g_list_append (newlist, obj);

    list = list->next;
  }

This code is also perfectly valid for filtering a list. Suppose, now, that you want to destroy the original list and return the filtered copy; you’ll have to free the GList using g_list_free() at the end of the while cycle:

  GList *newlist;

  /* init the target list */
  newlist = NULL;
  while (list) {
    SomeData *obj = l->data;

    if (some_condition)
      newlist = g_list_append (newlist, obj);

    list = list->next;
  }

  g_list_free (list);

  return newlist;

But we said above that the list is walked by exhausting it; hence, the list pointer is now NULL (the exit condition checked by the while cycle). Thus you are leaking the old list; to avoid this leakage, you must walk the list keeping a pointer to the list start. In order to do so, the right thing to do is to use an iterator pointer, and a for() cycle to keep the cycle compact and avoid messing up with the list = list->next assignments on every cycle break condition:

  GList *newlist, *l;

  for (l = list, newlist = NULL; l; l = l->next) {
    SomeData *obj = l->data;

    if (some_condition)
      newlist = g_list_append (newlist, obj);
  }

  g_list_free (list);
  return newlist;

This code does not leak the old list, but it leaks the data that was not moved to the new list; if the function to free the data is called some_list_free, the code above becomes:

  GList *newlist, *l;

  for (l = list, newlist = NULL; l; l = l->next) {
    SomeData *obj = l->data;

    if (some_condition)
      newlist = g_list_append (newlist, obj);
    else
      some_data_free (obj);
  }

  g_list_free (list);
  return newlist;

As a performance sidenote: if the list is long, you might consider using g_list_prepend, since it’s a constant time operation, while g_list_append walks the list; just remember to return the reversed new list:

  GList *newlist, *l;

  for (l = list, newlist = NULL; l; l = l->next) {
    SomeData *obj = l->data;

    if (some_condition)
      newlist = g_list_prepend (newlist, obj);
    else
      some_data_free (obj);
  }

  g_list_free (list);
  return g_list_reverse (newlist);

I had noticed the leak around 10:30pm and began fixing it, but I had to pick up Marta and both returned home at 11:30pm, when we went straight to bed and fell asleep almost immediately. This morning, I found bug #323002 awaiting, with a fix for the first part of the leak (thanks to Paolo). Now, libegg/recent-files HEAD has the leak fully plugged. Subsequent runs of valgrind showed no mor leaks related to the recent-files.

Now, I’m going to check my libegg/recentchooser and my libegg/bookmarkfile code for leaks.

[]
[]
[]

Long-standing

I’ve just committed some code that should hopefully fix bug #172587 of the old recent-files code.

The bug was hard to track down – and for it I do own a beer to Sebastien Bacher: it appears that older versions of OpenOffice creeped unescaped & into the dot-recently-used file we use to store the recent documents. The parser code inside EggRecentModel has always been a little too fragile (a mistake I tried to avoid since the beginning of my BookmarkFile parser code, by feeding it invalid XML/XBEL streams and trying to get errors instead of crashers), and thus gnome-panel had the tendency to crash until the dot-recently-used file was deleted or corrected.

I hope to close #172587 for good before marking the whole code as deprecated: it’s personal, now.