The Engine Driver

Here we are again with the Dictionary hacking; I left my development trunk with barely enough time to close crashers and brown paper bags patchs, and now I’m finally able to return working on it.

Here’s an interesting bug, about the poor discoverability of the look up process. First of all: discoverability? Is that even a word? Who the hell filed that bug? Opened by Emmanue… ehr… looks uncomfortably away.

Anyway, linguistic issues aside, the issue is interesting: some complained that the old Dictionary had a BFB and the new Dictionary has, well, nothing – the word is searched by activating the entry. This makes sense if you are typing the word, but it breaks down if you are pasting a word into the entry as you have to reach out for the keyboard and press enter. The idea was adding a “Go” button, removable by turning off a knob inside GConf. Then I realised that the label bound to the entry could be removed in favour of a button with no relief; it would keep the current appearance of the Dictionary while adding the “mouse-only” interaction requested (and by having a mnemonic, you can also activate the entry using the button’s mnemonic tag). It’s an experiment: the bug I linked has a full patch for the button+GConf knob (courtesy of Stephen Cook, kudos to him), so if people are going to throw themselves out of the window, I’ll gladly forget my solution and apply the patch.

Another couple of squashed bugs: you cannot edit a dictionary source and even if you could, the advanced settings do not work anyway. Both these bugs are really missing implementations of existing features: the source editing was mostly in place before the code freeze of GNOME 2.16, while the advanced settings required two widgets (the database chooser and the strategy chooser) that weren’t ready in time for the UI freeze of last January. Now that I have written both widgets and that I have time to finish what I started, the source dialog has been overhauled, and it allows choosing the database and the matching strategy for the chosen source, both when adding and when editing it.

strategy chooser

Speaking of the strategy chooser, I’ve added it to the sidebar, and like the database chooser allows you to set a matching strategy for the session, so you can use the default strategy (the same set for the source) or whatever strategies the source supports; I’ll add a “reset and use the default” button, which is also currently missing from the database chooser.

Here’s the real tricky bug: adding the speller widget to the dictionary applet. I thought about it, and how integrating the speller inside the applet, now that we have that widget. While inside the application having a sidebar makes sense, the same doesn’t not hold for the applet, as it would make it really big. For this reason, I added the speller widget (and every other page inside the sidebar) as pages of a notebook; you can switch between each of them using a drop-down menu – effectively making the whole applet work like the application’s sidebar.

As for the new features: four months ago I began hacking on a parser for the DICT file format, which is used to store a database (a single “dictionary” in a dictionary source) for dictd to use. It took a bit to get ahold of the actual format, but once found I wrote a small parser object, modelled on the GKeyFile object used to parse the desktop entry files. You can use it to load the dictionary and the index from data, or from file; you can just preload the index or load everything; you can even begin with an empty object, fill stuff and write it down. Unfortunately, it doesn’t support compressed files – but it should be enough for closing this bug, and work as a base for the StarDict dictionary parser (this I’ll have to write really from scratch, as the C++ parser code sucks horribly).

dictionary with syntax highlighting

Finally, from the old-dictionary-feature-ported-to-the-new-dictionary department, the syntax highlighting has come back! Well, not entirely: just the links and the phonetics have been reinstated, and links still don’t work. Links are colored using the gtk-link-color style property, which is also used by link buttons and the like (if your application renders hyperlinks or something like them, please use that style property!). The reason why I disabled the syntax highlighting was that there’s no formal definition for the dictionary syntax: it really can break at any given time – as you’ll see when using it; also, the highlighting code was really messy, so I had to rewrite it and that took time.

All of this is going to hit HEAD this week or so.

There are plenty of other bugs lying around in Bugzilla, though; I hope to have more time during December to look at them and squash some more; but you know the drill: if you have your own pet bug scratch an itch and provide a patch. ;-)

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.

All You Want

this week end I decided to work full time on the dictionary; I ended up fixing a bunch of bugs and RFEs, namely

  • no more dialogs in case of word not found
  • a visual indicator of progress inside the main window
  • the re-addition of the “speller” widget
  • themed icons and bugzilla version inside the launcher

the error dialogs have been switched to an inline error message inside the defbox; I’d like to add an icon too, but there’s no direct placement of a pixbuf inside a GtkTextView: if you want pixel-positioning you must use a GtkImage widget.

I’ve added a throbber widget, using the same code nautilus and epiphany use. while I’d like for the “spinner” widget to get into gtk+, I don’t really like the idea of having it on the dictionary UI: it makes the dictionary look like a browser or something, which is not. on the other hand, I don’t know what to use to visually indicate that the dictionary is working and it’s not blocked; if you have an idea (even though code would be better) please let me know.

and, finally, I’ve re-done the infamous speller widget, the list of similar words that comes up when no words have been found. it’s like the old widget, for the time being, but I intend to twist it a little bit more. it remebers its state across sessions (like the whole dictionary does), and I’ll add a knob for disabling it in case you want your own personal grammar nazi on the desktop. <sarcasm>thanks to all the people that bitched about it on bugzilla and never felt the urge to move their collective asses and help instead</sarcasm>. really – if half of the energy some people spend bitching on Bugzilla about missing features could be transformed in electricity we wouldn’t need to make wars for oil anymore.

anyway, here’s the obligatory screenshot:

GdictSpeller

the code needs to be cleaned up a little bit, and some cvs surgery is needed as I changed some of the layout of the files; I expect to land my development trunk on cvs.gnome.org this weekend.

Broken

The next release of gnome-utils, 2.13.90, will make libgdict adhere to the API/ABI freeze, even if it’s not part of the Gnome Developer Platform but only of the Desktop.

The freeze had been in effect since the last release (January 18th), and I planned not to change libgdict API; unfortunately, when writing the support for the document_font_name GConf key, which was introduced in Gnome 2.12 and that should be honoured by any application showing arbitrarily long texts to the user, I noticed that a call to gtk_widget_modify_font to a GtkContainer does not propagate to the containers’s children. The widget the Dictionary uses to display the text of the definitions is, in fact, a composite widget (a GtkVBox) as it needs to hold the text display and the find bar; the inner widgets are held inside a private structure, and are not visible to the outside.

If I wanted to work around this, I would have written something like this function inside the code of the libgdict users:

static void
gtk_container_modify_font_children (GtkContainer *container,
				    const gchar  *font_name)
{
  GList *children, *l;
  PangoFontDescription *font_desc;

  g_return_if_fail (GTK_IS_CONTAINER (container));

  font_desc = NULL;
  if (font_name)
    {
      font_desc = pango_font_description_from_string (font_name);
      g_return_if_fail (font_desc != NULL);
    }

  children = gtk_container_get_children (container);
  for (l = children; l != NULL; l = l->next)
     {
        GtkWidget *widget = GTK_WIDGET (l->data);

	gtk_widget_modify_font (widget, font_desc);
     }

  g_list_free (children);

  if (font_desc)
    pango_font_description_free (font_desc);
}

But it would not have worked; I wanted to change the font of the GtkTextView widget inside the GdictDefbox, while the function above would have changed font for all internal widgets – including the find pane.

Assigning a name to the GtkTextView widget, say “text-display”, by using the gtk_widget_set_name function, and changing the code of the inner loop to something like this:

...
  for (l = children; l != NULL; l = l->next)
     {
        GtkWidget *widget = GTK_WIDGET (l->data);
	const gchar *name = gtk_widget_get_name (widget);

	if (strcmp (name, "text-display") == 0)
          gtk_widget_modify_font (widget, font_desc);
     }
...

I would have avoided the API breakage inside libgdict – but I would also have created a performance bottleneck, since I transformed a constant time operation into a linear time one (from an assignment to a list walk) – plus, I don’t know what happens into gtk_widget_modify_font; also, I would have created a documentation issue, since I now would have to document the widget’s name and hope that nobody would ever have the urge to change the GdictDefbox font – at least, not after having had lunch.

Giving a name to the inner children of a composite widget is always a good practice – it makes handling these kind of situations easier; but between an hackish approach and a breakage of an API freeze, I would rather choose the latter. Hacks tend to get sticky, and you get a design by accretion if you let them stick around enough.

So, I opten for adding a new property to the GdictDefbox widget, called font-name, and its two accessor functions:

G_CONST_RETURN gchar *gdict_defbox_get_font_name (GdictDefbox *defbox);
void                  gdict_defbox_set_font_name (GdictDefbox *defbox,
						  const gchar *font_name);

Which are just proxies for the gtk_widget_modify_font function. Since nobody uses libgdict (it’s been out there only for the folks using Ubuntu or jhbuild), the breakage is really minimal; nevertheless, I feel a bit guilty for not having tested this stuff before, in time for the freeze.

Source

Feeling a little better, today: temperature steadily under 37°C, little to no headaches.

I’ve hacked the last bits of the Add Source dialog of Dictionary, and committed away a bunch of other fixes, including one for a crasher spotted by Paolo Borelli, a bunch of UI fixes by Dennis Cranston and corrections for my bad english by Clytie Siddall. Thanks to all of them: with their help, the next release of Dictionary will suck a lot less.

The Add Source dialog makes me feel a little proud:

gnome-dictionary-source-add-1

Here you can see the dialog when you click the “Add” button; you can set the description of the source and its transport. Choosing a transport will automagically show the preferences bound to that transport:

gnome-dictionary-source-add-2

Obviously, since libgdict supports only the Dictionary Protocol transport, you have only one choice, but expect other transports to be available from the next release of GNOME. The “Advanced Settings” pane will expose the Database and Strategy settings:

gnome-dictionary-source-add-3

Those two combo boxes should automagically query the dictionary source using the GdictContext bound to the transport the user has chosen; unfortunately, they don’t – yet. I hope to get around this issue before the code freeze, but I really don’t know if I’m going to make it in time.

If you want to have a look at how it all works, I’ve prepared a little screencast (courtesy of Istanbul).

[]
[]
[]

Inkscape

On a IRC conversation, I was told that the Dictionary icon sucked. Thus, after having a look at the Tango Project and their beatiful icons, I fired up Inkscape and worked on another version of the icon:

Dictionary

It still sucks, but now it sucks in 3D!

I’ll file a bug report to remove the old “gdict” icon from the theme, and ask the GNOME artists to do a new version, with more than one size.

Spawn of hell

auto-tools: from the same people that brought you EMACS.

After two hours of struggling with that damned make distcheck, in order to smoke test the merge of the new-dictionary branch of gnome-utils, I’ve finally been greeted by:

===================================================
gnome-utils-2.13.4.tar.gz is ready for distribution
===================================================

After a bit of clean up, I’m going to commit it to HEAD.

Update 20051216@19:18 The new GNOME Dictionary is in gnome-utils HEAD; the old Dictionary is gone into the Attic. I for one welcome our new dictionary overlords.

[]
[]
[]

Dictionary Applet/10

The merge of the new-dictionary branch into gnome-utils HEAD is fast approaching: I’ve set the deadline to the end of the week – in time to write off the last bits of the preferences dialog:

gdict-pref-dialog
the sources tab of the preferences dialog

Right now, you can’t add or activate a new dictionary source, unless you write the .desktop file and drop it into $HOME/.gnome2/gnome-dictionary, and then change the /apps/gnome-dictionary/source key inside GConf – but I plan to have this nailed down in the next couple of days (the UI for both display and edit has already been designed using Glade).

gdict-pref-dialog
the printing tab of the preferences dialog

The font selection thingy for the printed output is, instead, already working.

Known regressions: the text highlighting is still missing, and I don’t know if it’s going to make it not only before the merge deadline, but also before UI freeze.

[]
[]
[]

Dictionary Applet/9

I’ve added printing support – after a bit of struggle with GnomePrint:

The output format is stolen^Winspired by Gedit, and the font is hardcoded as Serif, 12; I’ve already added a GConf key to the shipped schema – GConf integration, as well as preferences are still in a state of flux. Now that the printing is mostly nailed down, I’ll resume work on the UI side, by adding a status bar and the preferences dialog. Also, work on the applet will begin as soon as these issues are solved; the applet should be, in fact, very easy to code.

Note: It seems that a critical warning is issued each time a print dialog is destroyed and then recreated – like some signals handlers that aren’t correctely disconnected; I’ll have a look at it, but it seems a bug of libgnomeprint as far as I can tell. Update 20051212@02:53: it is now bug #323836 of libgnomeprintui

Also, judging from the memory consumption, I’m afraid of some leakage inside libgdict (mostly). I’ll have a run with Valgrind, and see what’s going on under the hood. Update 20051210@16:33: it seems that I was fooled by the system monitor memory usage graph, as I found two simple leaks (due to me being a sloppy coder), accountable of just 6kB lost – and just once per process, since one was inside the singleton init, and the other inside the GdictSourceLoader directory walking. Both are now fixed inside my development trunk. I’m positive that, if the trend continues, the new code might land inside HEAD the next two weeks – given that the preferences dialog and the dictionary source creation code are pretty much done, and that the applet will be easy to code. Once we reach feature freeze time (in January), I’ll devote myself in writing a good user’s manual. Some might think that the next release will be a regression, but believe me: the trade-off of a few features for code readability, maintainability and overall performance is well worth it; features will be re-implemented in no time.

[]
[]
[]