thoughts on summer of code

there are two or three things about summer of code that are really awesome.

number one is that you’re given a mentor who you can harass. this is fantastic. this person can function both as a helper in terms of “how do i do this in gtk?” and also in terms of “i have a tough decision to make; what do you think?”

number two is probably the most important. it’s that you’re given a mandate. i’ve written a lot of code before that i’d have hoped would make it into gnome but hasn’t. with summer of code, you’re told by the community that you’re doing something that they want done. there is a very high probability of your code appearing in a future gnome release. this is very exciting and motivating.

you’re also (or at least it feels like it) given help from the community to a level that you’re not normally given it. this could be caused by any number of factors. the people in the community might be kinder to you because you’re a summer of code student. you also may feel some solidarity with other summer of code students and discuss things with them. it might also just be that because you’re motivated by the programme in general (see point two) you’re more interested in figuring out all sorts of intricate details of how things work and therefore ask more questions.

i’m always tinkering to a certain extent and learning about gnome and gtk and gobject. i can say without a shadow of a doubt, though, that participating in summer of code has accelerated this process for me. the past little while i’ve learned an awful lot. compared to my state before the summer i feel like an elite gtk hacker.

this is important. having people in the community who understand how things work is important.

notice that in this entire post (so far) i haven’t said anything about money. i think all of the effects listed above are independent of money.

it would be really cool if we could continue to use the sort of power created by the summer of code. what follows is a sort of idea how that could possibly happen.

gnome love, bugdays, etc are all very nice, but they lack structure.

what would be really nice is a structured mentorship program. there could be some token amount of cash reward (certainly no more than $500). there could be a loose community voting process on what makes a worthwhile project. involved, knowledgeable and influential hackers in the community (like my mentor, vincent, for example) could propose to mentor projects that they feel are worthwhile. if the community approves their proposal then applications are accepted for work on this project.

it seems like a good idea to solicit applications for a few projects at the same time. having a few students hacking at the same time is important (for solidarity reasons). for a given set of applications a specific area should be targetted in such a way that the students are working on a similar area but won’t step on each others’ toes. applications in general are good because they avoid work duplication. the token prize amount would serve to offset the hassle of going through an application process and motivate people to do so.

having everyone working on a similar area is also good in terms of the next release of gnome coming out and users being able to say things like “wow! a lot of great work has been done on nautilus this release!”.

the primary goal of the program would be not to get lots of cool stuff done on gnome (although that’s nice) but rather to get people involved in the community. once you’ve done a nice chunk of work that’s released as part of gnome you feel a greater involvement in and attachment to the community. as such, the programme would not be open to people who had been involved in the programme in the past or in summer of code or wsop.

end braindump. for now.

fontcrime – less is more

in two ways, really.

i had a talk with clare the other day during the lunch break of dave parnas‘s talk at formal methods 2006.

apparently rendering of kanji on ubuntu is really awful. each character looks different from the next. a dirty secret of pango comes out.

i attended behdad’s talk about how all of this works at guadec and pango decides what glyph will be used for a specific character on a character-at-a-time basis. this means that you can easily have different fonts chosen for different characters in the same string. what’s more — pango seems to like to pick from fonts with fewer glyphs (thinking that they’re more specific and therefore better) — “less is more”.

the problem is that this is often an evil policy.

these fonts look quite different from each other. if you look at the screenshot, the right radical (“bird”) in each shot should look identical. they are very different.

sure enough, if you put these characters side by side in a string, you get one drawn in each font.

in this case, arial unicode (which i installed myself) has complete coverage of (at least nearly all) kanji. however, on a default ubuntu install you have kochi gothic which is used by preference. remove kochi gothic and you have baekmuk dotum.

if you remove both of these fonts, however, you’re left with just arial unicode (if you’re blessed enough to have this font). now things are beautiful. less is more.

i’m not up on all of this font stuff but why is it that we don’t have a big free font with all of the glyphs for every language in it? if it does exist then why isn’t ubuntu shipping it?

also — why can’t pango do a sort of prescan on the string to look at all of the characters in the string and do its hardest to try to pick a font in which all of the characters exist and use that for every character? even if there are higher quality glyphs for some of the characters in one font, it sort of seems more important that the string is displayed in a consistent font. would this be entirely too expensive?

of course, on the other side of this argument, you have the case of a single (for example) kanji character appearing inside a huge block of latin text and causing the latin to be rendered in a lower quality junk font that just happened to be inclded in the same file as the kanji…

oi.

your domain, "lowercase.ca" is expiring

excuse my caps…

Today is August 21st — the Summer of Code deadline.

It’s been a pretty fun ride. I’ve been getting up close and personal with the gnome-panel code in ways that I wouldn’t previously have imagined to be possible.

I’ve been working on an API for applets. In addition to this API, I’ve written an implementation of a client-side library for this API and in-panel code for this library to communicate with.

The communication is done by way of DBUS and XEmbed. The API has been constructed in such a way, however, that other than GTK itself, all underlying implementation detail is invisible. If DBUS should fall out of fashion, it will be possible to replace the back-end implementation without an API shift. This is not the case for the current applet system which is very much tied to Bonobo.

Note: the API is UNSTABLE. It will change. I promise.

From the standpoint of the user (applet writer) a class is provided named GnomeApplet. You subclass this class to create your own types of applets. To give a feel for this API, I will present an example of a very simple applet.

The applet in question is a simple clock. An icon has been added for demonstration purposes.

I’ll assume for the sake of simplicity that the following function has been provided:

const char *format_current_time (gboolean seconds, gboolean _24hour);

This function returns a string representing the current time either in 24 or 12 hour format and with or without seconds.

The code of the applet is included here:

#include <libgnome-applet.h>

GNOME_APPLET_DEFINE (ClockApplet, clock_applet,
  gboolean _24hour;
  gboolean show_seconds;
);

static gboolean
update_time (ClockApplet *clock)
{
  gnome_applet_set_text (GNOME_APPLET (clock),
    format_current_time (clock->show_seconds, clock->_24hour));
  return TRUE;
}

static void
update_boolean (GnomeApplet *applet, const char *key,
                gboolean value, gpointer user_data)
{
  *(gboolean *) user_data = value;
  update_time ((ClockApplet *) applet);
}

static void
clock_applet_initialise (ClockApplet *clock)
{
  GnomeApplet *applet = GNOME_APPLET (clock);

  gnome_applet_set_name (applet, "Clock Applet");
  gnome_applet_set_persist (applet, TRUE);

  gnome_applet_add_dropdown_widget (applet, gtk_calendar_new ());
  gnome_applet_set_image_from_stock (applet, GTK_STOCK_YES);

  gtk_timeout_add (1000, (GtkFunction) update_time, clock);
  gnome_applet_config_watch_boolean (applet, "24hour", update_boolean,
                                     &clock->_24hour, NULL);
  gnome_applet_config_watch_boolean (applet, "24hour", update_boolean,
                                     &clock->show_seconds, NULL);
}

The first thing to notice is the GNOME_APPLET_DEFINE line. In its simple form, this line is like a G_DEFINE_TYPE instantiation minus the parent class (since the parent class is always GnomeApplet).

For example:

GNOME_APPLET_DEFINE (ClockApplet, clock_applet);

However, this macro aims to reduce your typing for you. As such, you do not need to define structures for your class. If you want additional items in these structures (other than the parent class) then you give them using the syntax seen in the example code.

The update_time function is uninteresting. It shows that the fields defined in the extended syntax of GNOME_APPLET_DEFINE are accessed as you’d expect them to be. It also shows use of the gnome_applet_set_text function.

The new applet API is a hybrid API. As a subclass of GtkContainer, you can gtk_container_add a widget to the applet and it will be displayed on the panel. You are much more likely, however, to want to use the set_text and set_image functions.

The first time you use a set_text or set_image function the applet will internally create a GnomeAppletLayoutBox and add it to itself. It will then request the creation of the image or label inside of this box.

The GnomeAppletLayoutBox system allows you to easily create applets that feature 0 or 1 icons and 0 or 1 text labels. In addition, it gracefully handles horizontal and vertical panels and drawers of varying thickness.




The label that is created is not a GtkLabel, but rather a GnomeAppletLabel. GnomeAppletLabel has some functions that make it easier to use than a simple GtkLabel for purposes of putting in a GnomeAppletLayoutBox. The most noticeable feature of a GnomeAppletLabel, however, is that when placed on a coloured, pixmap or transparent panel, it shows a drop shadow like Nautilus shows on its desktop contents.

update_boolean is not a very interesting function either. It simply updates a boolean value pointed at by the user_data parameter and calls update_clock. The need for functions like this may disappear as the API becomes more developed.

clock_applet_initialise is the most important function here. When you use GNOME_APPLET_DEFINE the 2nd parameter has _initialise added to it and this is the name of the only function that you must implement.

This function is NOT a normal GObject init function. It would be called clock_applet_init if that were the case. This function is, rather, called after the object has been entirely constructed and connected to the panel. This means that you can perform function calls from it which query the state of the panel.

We perform a number of calls here:

gnome_applet_set_name tells the panel the name of the applet. This is used in UI that the user sees concerning the applet. For example, of the applet were to unexpectedly exit, the message dialog shown would be customised with the applet’s name.

gnome_applet_set_persist registers the applet as a persistent applet. When an applet is first created it is non-persistent. This means that the applet can come and go as it pleases. The panel will make no attempt to start the applet on login and won’t complain if the applet just vanishes. This behaviour is useful for programs like Gossip or Muine, where the life of the applet is tied to the life of the application, rather than the life of the session. It is also useful for applets that wish to come and go as hardware is added or removed.

If an applet is marked persistent then its current path is noted down in the panel’s GConf tree. On login the applet will be invoked and asked to join the panel at its previous location.

gnome_applet_add_dropdown_widget is a new feature. When passed a GtkWidget, this function will add the widget to a dropdown display. Many applets would or currently do benefit from this functionality. For the clock, it makes sense to have a dropdown calendar. For the weather applet you could have a dropdown detailed forecast. For the mixer, a dropdown slider. If a dropdown is registered then it is displayed when the left mouse button is clicked. If the user moves their mouse from applet to applet while a dropdown is displayed then the dropdowns of the different applets are displayed.

gnome_applet_set_image_from_stock sets the image shown with an applet. There are functions for setting from stock, from file, from icon theme, from pixmaps and from pixbufs. See the discussion above about GnomeAppletLayoutBox.

gtk_timeout_add is gtk_timeout_add.

gnome_applet_config_watch_boolean is showing a very small part of the configuration system that exists. It was decided, for a number of reasons, that applets would not link against GConf. It is still possible to do this for yourself and use GConf functions with your applet, but this behaviour is not recommended. All configuration requests are, instead, sent to the panel via DBUS.

There are a number of reasons for this:

  1. The configuration information associated with an applet should be tied to the panel (as it is now). The panel might be using a different configuration system then the applet. (think: mixing KDE, xfce, GNOME).
  2. If GNOME itself shifts configuration systems, the GConf API is completely hidden. (think: you won’t need to rewrite your applet).
  3. There is a memory savings associated with not linking to GConf in every applet, not firing up the machinery in every applet and not having a server-side connection for every applet.
  4. There is an additional benefit interms of load time. Since the panel can preload all of the information for all of the applets in a single roundtrip to the GConf daemon, the number of roundtrips is reduced. This means less contention for a heavily contended resource.

There are a few unfortunate effects:

  1. You can not store pairs or lists. Only values which fit in a GValue are supported. I could add more API, but the point is to not expose GConf-specifics.
  2. I had to do a lot more typing. More typing introduces the possibility of more bugs and certainly, the interface won’t share the exact semantics of GConf.

In general, there are 5 flavours of each function. One for each of GValue, string, int, boolean, double. I’ll introduce the integer variants:

  • gnome_applet_config_get_int – gets a key of a given name and returns it in a pass-by-reference variable. This function returns TRUE if the key existed or FALSE if it did not.
  • gnome_applet_config_get_int_default – gets a key of a given name and returns it. If the key did not exist then a user-provided default value is returned.
  • gnome_applet_config_set_int – sets a key of a given name to a given value. Returns TRUE if successful.
  • gnome_applet_config_watch_int – registers a watch function on a given key. A user_data (with corresponding destroy notify) field is also given. When this function is first called, a synthetic notify event is immediately generated. You can, therefore, use this function to initialise variables without having to manually call one of the ‘get’ functions.

There is more API than shown here, but this should give a good overview of the general flavour. This project is not yet done! The following features are planned to be completed before GNOME 2.18 when, if all goes well, this code will ship as part of gnome-panel.

Immediate TODOs:

  • gtk-doc for the client-side API with the documentation posted on developer.gnome.org
  • integration of Vytautas’ work to make multiple instances of the same applet use the same process
  • support for dynamic loading of applets into the panel to further reduce memory use
  • improved support for finding and loading persistent applets (the path for invoking applets on startup is currently hard-coded to my working directory)

Other TODOs:

  • gather feedback from early adopters of the API. What needs to change? Can there be some more convenience functions?
  • look into language bindings (python and C# are likely early candidates)
  • bug fixes! I can’t even imagine how many bugs are in the code. It will take time to reveal them all and get the code to be stable enough for general use.

A recent version of the code is usually available at http://desrt.mcmaster.ca/random/applets.tar.gz. I’m going to wait until after the GNOME CVS branches 2.16 stable until I commit the code to CVS HEAD.