halting problem :: Episode 2.1: On Brand

:: ~10 min read

A wild GTK major API change appears! It uses better text and icon rendering. It’s super effective! GNOME dons flame retardant pants. It’s not very effective!

In the beginning of the year 2000, with the 1.2 release nearly out of the door, the GNOME project was beginning to lay down the groundwork for the design and development of the 2.0 release cycle. The platform had approached a good level of stability for the basic, day to day use; whatever rough edges were present, they could be polished in minor releases, while the core components of the platform were updated and transitioned incrementally towards the next major version. Before mid-2000, we already started seeing a 1.3 branch for GTK, and new libraries like Pango and GdkPixbuf were in development to provide advanced text rendering and replace the old and limited imlib image loading library, respectively. Of course, once you get the ball rolling it’s easy to start piling features, refactorings, and world breaking fixes on top of each other.

If X11 finally got support for loading True Type fonts, then we would need a better API to render text. If we got a better API to render text, we would need a better API to compose Unicode glyphs coming from different writing systems, outside of the plain Latin set.

If we had a better image loading library, we could use better icons. We could even use SVG icons all over the platform, instead of using the aging XPM format.

By May 2000, what was supposed to be GTK 1.4 turned into the development cycle for the first major API break since the release of GTK 1.0, which happened just the year before. Of course, the 1.2 cycle would continue, and would now cover not just GNOME 1.2, but the 1.4 release as well.

It wasn’t GTK itself that led the charge, though. In a way, breaking GTK’s API was the side effect of a much deeper change.

As we’ve seen in the first chapter’s side episode on GTK, GLib was a simple C utility library for the benefit of GTK itself; the type system for writing widgets and other toolkit-related data using object orientation was part of GTK, and required depending on GTK for writing any type of object oriented C. It turns out that various C projects in the GNOME ecosystem—projects like GdkPixbuf and Pango—liked the idea of having a type system written in C and, more importantly, the ability to easily build language bindings for any API based on that type system. Those projects didn’t really need, or want, a dependency on a GUI toolkit, with its own dependency on image loading libraries, or windowing systems. Moving the type system to a lower level library, and then reusing it in GTK would have neatly solved the problem, and made it possible to create a semi-standard C library shared across various projects.

Of course, since no solution survives contact with software developers, people depending on GLib for basic data structures, like a hash table, didn’t want to suddenly have a type system as well. For that reason, GLib acquired a second shared library containing the GTK type system, upgraded and on steroid; the “signal” mechanism to invoke a named list of functions, used by GTK to deliver windowing system events; and a base object class, called GObject, to replace GTK’s own GtkObject. On top of that, GObject provided properties associated to object instances; interface types; dynamic types for loadable modules; type wrappers for plain old data types; generic function wrappers for language bindings; and a richer set of memory management semantics.

Another important set of changes finding their way down to GLib was the portability layer needed to make sure that GTK applications could run on both Unix-like, and non-Unix-like operating systems. Namely, Windows, for which GTK was getting a backend, alongside additional backends for BeOS, macOS, and direct framebuffer rendering. The Windows backend for GTK was introduced to make GIMP build and work on that platform, and increase its visibility, and possibly the amount of contributions—something that free and open source software communities always strive towards, even if it does increase the amount of feature request, bug reports, and general work for the maintainers. It’s important to note that GTK wasn’t suddenly becoming a cross-platform toolkit, meant to be used to write applications targeting multiple platforms; the main goal was always to allow extant Linux applications to be easily ported to other operating systems first, and write native, non-Linux applications as a distant second.

With a common, low level API provided by GLib and GObject, we start to see the beginning of a more comprehensive software development platform for GNOME; if all the parts of the platform, even the ones that are not directly tied to the windowing system, follow the same semantics when it comes to memory management, type inheritance, properties, signals, and coding practices, then writing documentation becomes easier; developing bindings for various programming languages becomes a much more tractable problem; creating new, low level libraries for, say, sending and receiving data from a web server, and leveraging the existing community becomes possible. With the release of GLib and GTK 2.0, the GNOME software development platform moves from a collection of libraries with a bunch of utilities built on top of GTK to a comprehensive set of functionality centered on GLib and GObject, with GTK as the GUI toolkit, and a collection of libraries fullfilling specific tasks to complement it.

Of course, that still means having libraries like libgnome and libgnomeui lying around, as a way to create GNOME applications that integrate with the GNOME ecosystem, instead of just GTK applications. GTK gaining more GNOME-related features, or more GNOME-related integration points, was a source of contention inside the community. GTK was considered by some GNOME contributors to be a “second party” project; it had its own release schedule, and its own release manager; it incorporated feedback from GNOME application and library developers, but it was also trying to serve non-GNOME communities, by providing a useful generic GUI toolkit out of the box. On the other side of the spectrum, some GNOME developers wanted to keep the core as lean as possible, and accrue functionality inside the GNOME libraries, like libgnome and libgnomeui, even if those libraries were messier and didn’t receive as much scrutiny as GLib and GTK.

Most of 2001 was spent developing GObject and Pango, with the latter proving to be one of the lynchpins of the whole platform release. As we’ve seen in episode 1.5, Pango provided support for complex, non-latin text, a basic requirement for creating GUI applications that could be used outside of the US and Europe; in order to get there, though, various pieces of the puzzle had to come together first.

The first, big piece, was adding the ability for applications to render TrueType fonts on X11, using fontconfig to configure, enumerate, and load the fonts installed in a system, and the Xft library, for rendering glyphs. Before Xft, X applications only had access to core bitmap fonts, which may look impressive if all you have a is thin terminal in 1987, but compared to the font rendering available on Windows and macOS they were already painfully out of date by about 10 years. During the GNOME 1.x cycle some components with custom rendering code already started using Xft directly, instead of going through GTK’s text rendering wrappers around X11’s core API; this led to the interesting result of, for instance, the text rendering in Nautilus pre-1.0 looking miles better than every other GTK 1 application, including the rest of the desktop components.

The other big piece of the puzzle was Unicode. Up until GTK 2.0, all text inside GTK applications was pretty much passed as it was to the underlying windowing system text rendering primitives; that mostly meant either ASCII, or one of the then common ISO encodings; this not only imposed restrictions on what kind of text could be rendered, but it also introduced additional hilarity when it came to running applications localized by somebody in Europe on a computer in the US, or in Russia, or in Japan.

Taking advantage of Unicode to present text meant adding various pieces of API to GLib, mostly around the Unicode tables, text measurement, and iteration. More importantly, though, it meant changing all text used inside GTK and GNOME applications to UTF-8. It meant that file system paths, translations, and data stored on non-Unicode systems had to be converted—if the original encoding was available—or entirely rewritten, if you didn’t want your GUI to be a tragedy of unintelligible text.

If the written word was in the process of being transformed to another format, pictures were not in a better position. The state of the art for raster images in a GTK application was still XPM, a bitmap format that was optimised for storage inside C sources, and compiled with the rest of the application. Sadly, the results were less than stellar, compared to more common formats like JPEG and PNG; additionally, the main library used to read image assets, imlib, was very much outdated, and mostly geared towards loading image data into X11 pixmaps. Imlib provided entry points for integrating with the GTK drawing API, but it was a separate project, part of the Enlightenment window manager—which was already moving to its replacement, imlib2. The work to replace imlib with a new GNOME-driven library, called GdkPixbf, began in 1999, and was merged into the GTK repository as a way to provide API to load images in various formats like PNG, GIF, JPEG, and Windows BMP and ICO files directly into GTK widgets. As an additional feature, GdkPixbuf had an extensible plugin system which allowed writing out of tree modules for loading image formats without necessarily adding new dependencies to GTK. Another feature of GdkPixbuf was a transformation and compositing API, something that imlib did not provide.

All in all, it took almost 2 years of development for GTK 1.3 to turn into GTK 2.0, with the first stable releases of GLib, Pango, and GTK cut in March 2002, after a few months of feature freeze needed to let GNOME and application developers catch up with the changes, and port their projects to the new API. The process of porting went without a hitch, with everyone agreeing that the new functionality was incredibly easy to use, and much better than what came before. Developers were so eager to move to the new libraries that they started doing so during the development cycle, and constantly kept up with the changes so that every source code change was just a few lines of code.

Yes, of course I’m lying.

Porting proceeded in fits and jumps, and it was either done at the very beginning, when the difference between major versions of the libraries were minimal and gave a false impression of what the job entailed; or it happened at the very end of the cycle, with constant renegotiation of every single change in the platform, a constant barrage of questions of why platform developers were trying to impose misery on the poor application developers, why won’t you think of the application developers…

Essentially, like every single major version change in every project, ever.

On top of the usual woes of porting, we have to remember that GNOME 1.4 started introducing technology previews for GNOME 2.0, like GConf, the new configuration storage. While Havoc Pennington had written GConf between 2000 and 2001, and concentrated mostly on the development of GTK 2 after that, it was now time to start using GConf as part of the desktop itself, as a replacement for the configuration storage used by components by the Panel, and by applications using libgnome, which is when things got heated.

Ximian developer Dieter Maurer thought that some of the trade-offs of the GConf implementation, mostly related to its use of CORBA’s type system, were enough of a road block that they decided to write their own configuration client API, called bonobo-config, which re-implemented the GConf design with a more pervasive use of CORBA types and interfaces, thanks to the libbonobo work that was pursued as part of the GNOME componentisation effort. Bonoboc-config had multiple backends, one of which would wrap GConf, as, you might have guessed it already, a way to route around a strongly opinionated maintainer, working for a different company.

The last bit is probably the first real instance of a massive flame war caused by strife between commercial entities vying for the direction of the project.

The flames started off as a disagreement in design and technical direction between GConf and bonobo-config maintainers, confined to the GConf development mailing list, but soon spiralled out of control once libgnome was changed to use bonobo-config, engulfing multiple mailing list in fires that burned brighter than a thousand suns. Accusations of attempting to destroy the GNOME projects flew through the air, followed by rehashing of every single small roadblock ever put in the way of each interested party. The newly appointed release manager for GNOME 2.0 and committer of the dependency on bonobo-config inside libgnome, Martin Baulig, dramatically quit his role and left the community (only to come back a bit later), leaving Anders Carlsson to revert the controversial change—followed by a new round of accusations.

Totally normal community interactions in a free software project.

In the end, concessions were made, hatred simmered, and bonobo-config was left behind, to be used only be applications that decided to opt into its usage, and even then it was mostly used as a wrapper around GConf.


Fonts, Unicode, and icons” seems like a small set of user-visibile features for a whole new major version of a toolkit, and desktop environment. Of course, that byline kind of ignores all the work laid down behind the scenes, but end users don’t care about that, right? We’ll see what happens when a major refactoring to pay down the technical debt accrued over the first 5 years of GNOME, and clear the rubble to build something that didn’t make designers, documentation writers, and QA testers cry tears of blood, in the next episode, “Release Day”, which will be out in two weeks time, as next week I’m going to be at the GTK hackfest, trying to pay down the technical debt accrued over the 3.0 development cycle of the toolkit. I’m sure it’ll be fine, this time. It’s fine. We’re going to be fine. It’s fine. We’re fine.

References

history of gnome gnome podcast

Follow me on Mastodon