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.