Extending the layout for GTK+

These weeks, on the generous behalf of Openismus; I’ve been spending my full attentions on teaching GTK+ some new tricks where resizing the interface is involved.

It was a rocky ride of detective work at first; picking up the bit’s and pieces of Mathias Hasselmann’s original work, various other patches from the old branch and reading dozens of email threads and bug reports; all of which make up a web of information that spans over the last 5 years.

This was followed by a session of regression testing; I wanted to have a good grasp of what was working and what was broken in the branch (I also hoped I could kill all the regressions before introducing any features). That went quite well as I have a good grasp on what’s still broken and what features are still missing.

After all that hacking it was about time I owed you all a blog so lets take a look at what the features are and where we stand with them.

What is the Extended/Natural Layout ?

The Extended Layout has been defined as a few things in the past which covered different feature sets. For the purpose of this writeup we intend to achieve the 2 main goals which are:

  • Smartly distributing space to child widgets to display the maximum content of children before adding any extra space.
  • Allowing height-for-width/width-for-height contextual resizing

Some key points about what these features introduce are:

  • In addition to the concept of a widget having a minimum size; a widget can also use up extra space by declaring a “natural size”, this aspect allows for the first feature.
  • Sizes are only ever computed in one dimension at a time, either for the default widths/heights or in context of the size in the opposing dimension. This means a minimum “size” no longer exists as we know it; although it can be emulated by getting the minimum width for the natural height of a widget. This change is also what allows us to negotiate size properly with wrapping labels.

So, people may remember Havoc Pennington’s blog post on text that resizes properly (it was years ago), anyhow; here are some similar visuals on how GTK+ widgets are resizing in the native-layout branch:

Here is a horizontal box with some basic display widgets inside; at the natural size:

And here at a smaller size, note that the larger button and label will ellipsize before the small combo box:

But all the children do ellipsize:

When the layout is larger; the button in the center is sized to its natural size before allocating extra size to the children which asked to “expand”:

Well that’s an idea of what the natural sizes bring to the GTK+ interface, there are of course other widgets that are not yet working with the new layout; I gave cell renderers some attention for combo boxes but they still need work to be usable in treeviews (that’s one of the current regressions actually…).

Height-for-Width

The height for width feature basically allows for the above feature to work the same for container widgets who are interested in allocating decent sizes for children, but allow for more flexible display widgets found deep in the roots of GTK+ widget hierarchies.

Here is a quick example of what wrapping labels can do with height-for-width support, here is a vertical box with some height-for-width aware widgets packed in; along with a static Label widget to fill the extra space:

Here is the same interface slightly wider:

Note how the wrapping labels request less height for every line they unwrap:

Extended Layout features allow labels to unwrap automatically; relinquishing valuable screen realestate to parent containers in the interface. These are the effects of "height-for-width".

Currently I’m also experiencing some difficulty getting height-for-width information to cascade correctly through the ancestry of boxes in GTK+, I tried my best to outline the details in a post I wrote to gtk-devel-list yesterday, of course all feedback welcome there.

For those who will checkout the branch; I will be adding some more test cases next week (in a few days), currently sizegroups are broken after a mega API change; although they we’re broken in some ways to begin with and now I have a good idea of how to fix them; any feedback on the new GtkExtendedLayout/GtkExtendedCell apis would be great if you have time to stop by gtk-devel-list.

Well so far it’s been an honor and pleasure to do this work for Openismus, on a project I already like to participate in (GTK+). The project is an ambitious one surely, lets go do it justice ;-)

Update:

Murray suggested I should post some comparison shots; Good idea.

All the previously shown screen shots were taken using the new GTK+ native-layout features.

Here are some comparisons of how the interface reacts with and without the added features. In this first example you can see that with current GTK+; Combo Boxes request widths for ellipsizing Cell Renderers which it shouldn’t. Also you can see that Buttons/Labels will not know how to request more than: “…”:

A Combo Box, Button and Label with Current GTK+

Here we can see that without any explicit width requests, GTK+ with Extended Layout features can spread the ellipsizing Labels properly:

A Combo Box, Button and Label with the Extended Layout

when stretched out, the exact same interface will comparatively look like this:

Stretched Combo Box, Button and Label with Current GTK+

In the case of normal GTK+ the Button in the center never requests a “Natural” size. As it is also not set to expand inside the Horizontal Box; the button stays very small in the center.

Here we can see that even though we never told the button to expand, Extended Layout will help it at least request a “Natural” size:

Natural Size Combo Box, Button and Label with Extended Layout

In the height-for-width case, this is what the stretched UI would look like without the Extended Layout features:

GTK+ does not unwrap the Label naturally to fit the width. With the Extended Layout the Labels will unwrap and relinquish vertical space to its parents.

In this final case its clear that GTK+ doesn’t know how to rewrap the label on its own, some applications these days implement hacks to get this to work by riding the “size-request” and “size-allocate” signals.

13 Responses to “Extending the layout for GTK+”

  1. This is really valuable work! Thank you for continuing with what Matthias started.

  2. Matt says:

    Nice work!!! Much appreciated!

  3. I think this would be easier for people to understand if they could see a before and after, like in Mathias’s original wiki page that you linked to:
    http://live.gnome.org/MathiasHasselmann/NewLayoutManager
    But you could show the before and after with real working code.

    There are real noticeable bugs that this can solve. See the list of blocked bugs at the bottom of this:
    https://bugzilla.gnome.org/show_bug.cgi?id=101968

    For instance,
    multiline label text gets wrapped stupidly (and that’s even worse on an embedded device where the text should fill almost the whole screen):
    https://bugzilla.gnome.org/show_bug.cgi?id=369602
    and label ellipsising just doesn’t work in multiline lables:
    https://bugzilla.gnome.org/show_bug.cgi?id=406528
    and the file-types drop-down in the file chooser can become insanely long:
    https://bugzilla.gnome.org/show_bug.cgi?id=527499

    And my personal interest is to implement a generic flowing columned container for Glom’s details view that really allows the window to be resized for both width and height:
    http://www.glom.org/
    That seems to be a general wish:
    https://bugzilla.gnome.org/show_bug.cgi?id=135287 (wrapping in GtkToolbar instead of overflow)
    https://bugzilla.gnome.org/show_bug.cgi?id=77669 (a wrapping widgets container used in GIMP, that presumably doesn’t quite work properly)

  4. tvb says:

    Thanks for pointing that out Murray, good point.

    I just updated the above post right away by throwing together some screen shots of the same UI while running against GTK+ master.

  5. mpt says:

    Thank you, thank you, thank you. Many programs will look better because of this work.

  6. Tristan, thanks but that last screenshot looks totally unrelated. I think you made a typo.

  7. Tristan, or I’m just confused. I think you need to more clearly label the screenshots as being with current GTK+ or extended-layout GTK+, with before and after in both cases. Please don’t overestimate my intelligence.

  8. tvb says:

    Murray, I sat down and revised the post a bit more (and added some captions).

    I hope things are clearer now.

  9. Rui says:

    Fantastic work Tristan!

    But I wonder. Can this work go into GTK+ 2.x? I mean, isn’t this a change which could change the behaviour of applications an thus be an ABI break?

    If the target is GTK+ 3 then it should be there from the beggining , right? Else the problem would be the same, i.e. ABI break in 3.x series.

  10. tvb says:

    Rui,
    This work is targeting 3.0 technically but I’ve been writing it to
    be fully compatible with the 2.0 series.

    Strictly speaking its an api break because it changes the expected behavior for widgets, except its not that bad since it only augments undefined behavior from GTK+.

    For instance, this code has to keep honoring gtk_widget_set_size_requst()
    and it has to honor size groups and it also has to honor packing properties
    in container widgets, actually it also honors “size-request” signals for the sake of compatibility with existing applications.

    With all of those considerations, the extended layout features should only
    augment the behavior of widgets inside boxes that have no explicitly
    defined sizes.

    Currently this is working well for Glade running against the branch, I’ll want to make tests with the Gimp and some other programs running in the branch as soon as I get a little further…

  11. anon says:

    how about doing something like that but for gtktables?

    for example, open gnome-control-center. note the number of columns on the table on the right. now resize the window to make it wider. the number of columns grows! naturally, if you make the window narrower, the number of columns shrinks, until there is only 1 column left.

    can something like that be implemented at the gtk level, so people don’t have to duplicate code to get this functionality?

  12. tvb says:

    Anon, it is definitely planned for GtkTable to take advantage of the new
    geometry management system.

    What Extended Layout brings to GtkTable is the capability to query children
    for minimum and natural sizes in context with the other dimension
    (i.e. height-for-width), the current patch unfortunately does not take it that
    far yet.

  13. [...] GtkSizeRequest interface allows widgets to trade height for width when negotiating their geometry, read this informative post for more details on how this [...]