Fiddling with Gtk+ (2)

Tagged:  •    •    •    •    •  

Here come the pictures:

This is a resizer grip widget:
A resizer grip widget

This is an ellipsis widget:
An ellipsis widget

This is the stack/flow layout manager in action. The four buttons are in the same GtkHBox, but they wrap to the following line:
Stack/flow layout management

Regarding the stack/flow layout manager, I'll describe the implementation more completely in this post. After fixing a bug in a really hideous way, I decided that I was using the wrong approach, and that the switch to interfaces (see the previous post) had to happen sooner than later; luckily, however, most of the code I had written (as opposed to code I had blindly copied from Gtk+) still applies. The stack/flow layout manager is now ~1300 lines of code instead of 2800, which is actually not bad. :-) Instead of 5 classes, I have 1 class and 1 interface. In addition, there are four implementations of this interface, that are plugged into widget classes that are part of Gtk+, such as GtkLabel or GtkVBox.

The new interface, GtkLayoutable, is implemented by all widgets, and provides an additional pair of size_request/size_allocate methods. These methods have slightly different semantics than the size_request/size_allocate methods that are already part of Gtk+; basically, the allocation phase can occupy more vertical space, and less horizontal space, than it had requested.

The class is the only thing that stayed almost the same from the old implementation. It is called GtkManagedLayout (the scrollable thing in the picture above), but while the old implementation managed all the widgets in the hierarchy of stacks and flows, now it is much more coherent with the existing Gtk+ containers. GtkManagedLayout is a GtkBin (a kind of decorator widget) which wraps a widget and lays out the wrapped widget using the new pair of methods.

If a container or widget wants to support stack/flow layout, all it has to do is to implement GtkLayoutable; since this is a composite pattern, the implementation will call the GtkLayoutable methods on the subwidgets. If a widget (or even a container) does not support the new system, it does not have to do anything: GtkWidget provides a default implementation of the two methods that delegates to the old system.

It is very elegant that existing containers can be modified to support the new methods. For example in the new implementation stacks are just GtkVBoxes and flows are just GtkHBoxes. The same happens for widgets: in fact, it is also possible that a leaf of the widget tree is reached without ever reverting to the old style of layout management. For example, a GtkLabel that is placed inside a GtkManagedLayout becomes the equivalent of an HTML display: block or inline-block element.

Here is the tree of the above example:

GtkWindow
 GtkScrolledWindow
  GtkManagedLayout
   GtkVBox*
    GtkLabel*
    GtkHBox*
     GtkButton
      GtkHBox
       GtkPixmap
       GtkLabel
     GtkButton
      GtkHBox
       GtkPixmap
       GtkLabel
     GtkButton
      GtkHBox
       GtkPixmap
       GtkLabel
     GtkButton
      GtkLabel
    GtkLabel*

Widgets marked with * are the ones that are laid out using GtkLayoutable. You can see that they are reachable from a GtkManagedlayout, and you can see that once you get out of the stack/flow system (as is the case for GtkButton) there's no way back. You can also see that the GtkBin decorator pattern is used extensively in Gtk+, for instance GtkWindow, GtkScrolledWindow and GtkButton (yes, even that one!) are all decorators. This is why I considered elegant that GtkManagedLayout is a GtkBin subclass.

I liked a lot this foray into Gtk+; it is just amazing that such a complex system was programmed entirely in C. The object system is extremely powerful and customizable. While this does mean that you have to write a lot of boilerplate code, on the other hand I probably would not have done anything of this if it had been written in Java or another language that I cannot just as easily turn into a GNU Smalltalk module.

(code is available at this git repository)

For reasons I don't fully understand, git-clone http://www.inf.unisi.ch/phd/bonzini/webdav/gtk-widgets.git/ left me with only the 'origin/master' branch and no way to get the other ones. wget -r -np http://www.inf.unisi.ch/phd/bonzini/webdav/gtk-widgets.git/ and then removing all the extra index.html* files let me use git-clone directly from a local path, and that worked like I expected. Hm.

I assume the managed-layout-v2 branch is the interesting one? I checked out the code primarily to take a look at the stack layout, which should be useful for a project I'm working on (http://wiki.laptop.org/go/Journal%2C_reloaded).

User login