Constraint layouts

What are constraints

At its most basic, a constraint is a relation between two values. The relation
can be described as a linear equation:

target.attribute = source.attribute × multiplier + constant

For instance, this:

Can be described as:

blue.start = red.end × 1.0 + 8.0

Or:

  • the attribute, “start”, of the target, “blue”, which is going to be set by the constraint; this is the left hand side of the equation
  • the relation between the left and right hand sides of the equation, in this case equality; relations can also be greater than or equal to,
    and less than or equal to
  • the attribute, “end”, of the source, “red”, which is going to be read by the constraint; this is the right hand side of the equation
  • the multiplier, “1.0”, applied to the attribute of the source
  • the constant, “8.0”, an offset added to the attribute

A constraint layout is a series of equations like the one above, describing all the relationships between the various parts of your UI.

It’s important to note that the relation is not an assignment, but an equality (or an inequality): both sides of the equation will be solved in a way that satisfies the constraint; this means that the list of constraints can be rearranged; for instance, the example above can be rewritten as:

red.end = blue.start × 1.0 - 8.0

In general, for the sake of convenience and readability, you should arrange your constraints in reading order, from leading to trailing edge, from top to bottom. You should also favour whole numbers for multipliers, and positive numbers for constants.

Solving the layout

Systems of linear equations can have one solution, multiple solutions, or even no solution at all. Additionally, for performance reasons, you don’t really want to recompute all the solutions every time.

Back in 1998, the Cassowary algorithm for solving linear arithmetic constraints was published by Greg J. Badros and Alan Borning, alongside its implementation in C++, Smalltalk, and Java. The Cassowary algorithm tries to solve a system of linear equations by finding its optimal solution; additionally, it does so incrementally, which makes it very useful for user interfaces.

Over the past decade various platforms and toolkits started providing layout managers based on constraints, and most of them used the Cassowary algorithm. The first one was Apple’s AutoLayout, in 2011; in 2016, Google added a ConstraintLayout to the Android SDK.

In 2016, Endless implemented a constraint layout for GTK 3 in a library called Emeus. Starting from that work, GTK 4 now has a GtkConstraintLayout layout manager available for application and widget developers.

The machinery that implements the constraint solver is private to GTK, but the public API provides a layout manager that you can assign to your GtkWidget class, and an immutable GtkConstraint object that describes each constraint you wish to add to the layout, binding two widgets together.

Guiding the constraints

Constraints use widgets as sources and targets, but there are cases when you want to bind a widget attribute to a rectangular region that does not really draw anything on screen. You could add a dummy widget to the layout, and then set its opacity to 0 to avoid it being rendered, but that would add unnecessary overhead to the scene. Instead, GTK provides GtkConstraintGuide, and object whose only job is to contribute to the layout:

An example of the guide UI element

In the example above, only the widgets marked as “Child 1” and “Child 2” are going to be visible, while the guide is going to be an empty space.

Guides have a minimum, natural (or preferred), and maximum size. All of them are constraints, which means you can use guides not just as helpers for alignment, but also as flexible spaces in a layout that can grow and shrink.

Describing constraints in a layout

Constraints can be added programmatically, but like many things in GTK, they can also be described inside GtkBuilder UI files, for convenience. If you add a GtkConstraintLayout to your UI file, you can list the constraints and guides inside the special “<constraints>” element:

  <object class="GtkConstraintLayout">
    <constraints>
      <constraint target="button1" target-attribute="width"
                     relation="eq"
                     source="button2" source-attribute="width" />
      <constraint target="button2" target-attribute="start"
                     relation="eq"
                     source="button1" source-attribute="end"
                     constant="12" />
      <constraint target="button1" target-attribute="start"
                     relation="eq"
                     source="super" source-attribute="start"
                     constant="12" />
      <constraint target="button2" target-attribute="end"
                     relation="eq"
                     source="super" source-attribute="end"
                     constant="-12"/>
    </constraints>
  </object>

You can also describe a guide, using the “<guide>” custom element:

  <constraints>
    <guide min-width="100" max-width="500" />
  </constraints>

Visual Format Language

Aside from XML, constraints can also be described using a compact syntax called “Visual Format Language”. VFL descriptions are row and column oriented: you describe each row and column in the layout using a line that visually resembles the layout you’re implementing, for instance:

|-[findButton]-[findEntry(<=250)]-[findNext][findPrev]-|

Describes an horizontal layout where the findButton widget is separated from the leading edge of the layout manager by some default space, and followed by the same default amount of space; then by the findEntry widget, which is meant to be at most 250 pixels wide. After the findEntry widget we have some default space again, followed by two widgets, findNext and findPrev, flush one against the other; finally, these two widgets are separated from the trailing edge of the layout manager by the default amount of space.

Using the VFL notation, GtkConstraintLayout will create all the required constraints without necessarily having to describe them all manually.

It’s important to note that VFL cannot describe all possible constraints; in some cases you will need to create them using GtkConstraint’s API.

Limits of a constraint layout

Constraint layouts are immensely flexible because they can implement any layout policy. This flexibility comes at a cost:

  • your layout may have too many solutions, which makes it ambiguous and unstable; this can be problematic, especially if your layout is very complex
  • your layout may not have any solution. This is usually the case when you’re not using enough constraints; a rule of thumb is to use at least two constraints per target per dimension, since all widgets should have a defined position and size
  • the same layout can be described by different series of constraints; in some cases it’s virtually impossible to say which approach is better, which means you will have to experiment, especially when it comes to layouts that dynamically add or remove UI elements, or that allow user interactions like dragging UI elements around

Additionally, at larger scales, a local, ad hoc layout manager may very well be more performant than a constraint based one; if you have a list box that can grow to an unknown amount of rows you should not replace it with a constraint layout unless you measure the performance impact upfront.

Demos

Of course, since we added this new API, we also added a few demos to the GTK Demo application:

A constraints demo
The constraints demo window, as part of the GTK demo application.

As well as a full constraints editor demo:

The GTK constraints editor demo
A screenshot of the GTK constraints editor demo application, showing the list of UI elements, guides, and constraints in a side bar on the left, and the result on the right side of the window

More information

GTK 3.96.0

This week, we released GTK 3.96.0. Again, it has been a while since the last release, so it is worth summarizing whats new in this release. There is really too much here to cover it all, so this post will only highlight the most important changes.

This release is another milestone on our way towards GTK 4. And while there are still some unfinished things, this release is much closer to we hope to achieve with GTK 4.

GSK

GSK has seen a number of bug fixes and new tests that are made much easier using a new debug tool, gtk4-node-editor. It can load and display serialized render node trees, such as this one that was saved from the GTK inspector, and compare the output of different renderers.

The 3D transformation support has been brought up to the level where we can do animated transitions like the cube spin below.

GDK

The trend to move toward Wayland inspired APIs has continued, with more X11-only apis being moved to the X11 backend or just removed. Use of child surfaces and global coordinates has been greatly reduced, but this work remains incomplete.

The refactoring of Drag-and-Drop has also continued, with the introduction of GdkDrag and GdkDrop objects. The GTK part of this refactoring is still incomplete.

Events have been simplified and are now used just for input. Other event have been replaced by signals and properties on GdkSurface. In detail, expose events have been replaced by the ::render signal, configure events have been replaced by the ::size-changed signal. Map events have been replaced by the :mapped property, and gdk_event_handler_set() has been replaced by the ::event signal.

The Wayland backend has gained support for the Settings portal for GtkSettings, and uses the text-input-unstable-v3 protocol for its input method support.

GTK

Widgets

One big change for custom widgets is the introduction of GtkLayoutManager, which is a new delegate object that takes over size allocation. Layout managers can optionally use layout children for holding layout properties. This replaces the layout-related child properties in GTK containers such as GtkBox or GtkGrid.

A number of layout managers are available:

  • GtkBinLayout, for simple single-child containers
  • GtkBoxLayout, for children that are arranged linearly
  • GtkGridLayout, for children that are arranged in a grid
  • GtkFixedLayout, for freely positioned and transformed children
  • GtkCustomLayout, as a quick way to turn traditional measure and size_allocate vfuncs into a layout manager

More layout manager implementations will appear in the future. Most prominently, work is underway on a constraints-based layout manager.

GtkAssistant, GtkStack and GtkNotebook have publicly
accessible page objects for their children. The page objects
are also exposed via a list model. They non-layout related child properties of these containers have been converted into regular properties on these page objects.

Since all existing child properties have been converted to regular properties, moved to layout properties or moved to such page objects, support for child properties has been dropped from GtkContainer.

The core GtkEntry functionality has been moved into a new GtkText widget, which also implements an expanded GtkEditable interface. All existing entry subclasses in GTK have been turned into GtkEditable implementations wrapping a GtkText widget. This also includes a new GtkPasswordEntry.

Other Changes

GTK widgets can transform their children using projective linear
transformations. This functionality is available in CSS and
as a GskTransform argument to gtk_widget_allocate. GtkFixed is
the first container that exposes this functionality. For further examples,
see the swing transition of GtkRevealer, the rotate transitions
of GtkStack or the Fixed Layout example in gtk4-demo.

A number of list models have been introduced, for internal use
and as public API: GtkMapListModel, GtkSliceListModel, GtkSortListModel, GtkSelectionModel, GtkSingleSelection. These will become more widely used when we introduce a list model-based GtkListView.

GtkBuilder can specify object-valued properties inline, instead of referring to them by ID, and the simplify command of gtk4-builder-tool has gained an option to automatically convert GTK 3 UI definition files to GTK 4.

Coming soon

For more information on the things that are still still coming for GTK 4, find us on Discourse, IRC, or look here.

Layout managers in GTK 4

Containers and layout policies have been a staple of GTK’s design since the very beginning. If you wanted your widget to lay out its children according to a specific policy, you had to implement GtkContainer for handling the addition, removal, and iteration of the child widgets, and then you had to implement the size negotiation virtual functions from GtkWidget to measure, position, and size each child.

One of the major themes of the GTK 4 development cycle is to delegate more functionality to ancillary objects instead of encoding it into the base classes provided by GTK. For instance, we moved the event handling from signal handlers described by GtkWidget into event controllers, and rendering is delegated to GtkSnapshot objects. Another step in that direction is decoupling the layout mechanism from GtkWidget itself to an ancillary type, GtkLayoutManager.

Layout Managers

A layout manager is the object responsible for measuring and sizing a widget and its children. Each GtkWidget owns a GtkLayoutManager, and uses it in place of the measure() and allocate() virtual functions—which are going away. The gist of the change: instead of subclassing a GtkWidget to implement its layout policy, you subclass GtkLayoutManager, and then assign the layout manager to a widget.

Just like in the old GtkWidget code, you will need to override a virtual function to measure the layout, called measure(), which replaces the get_preferred_* family of virtual functions of GTK 3:

static void
layout_measure (GtkLayoutManager *layout_manager,
                GtkWidget        *widget,
                GtkOrientation    orientation,
                int               for_size,
                int              *minimum,
                int              *natural,
                int              *minimum_baseline,
                int              *natural_baseline)

After measuring, you need to assign the size to the layout; this happens in the allocate() virtual function, which replaces the venerable size_allocate() virtual function of previous GTK major versions:

static void
layout_allocate (GtkLayoutManager *layout_manager,
                 GtkWidget        *widget,
                 int               width,
                 int               height,
                 int               baseline)

On the more esoteric side, you can also override the get_request_mode() virtual function, which allows you to declare whether the layout manager requests a constant size, or if one of its sizes depend on the opposite one, like height-for-width or width-for-height:

static GtkSizeRequestMode
layout_get_request_mode (GtkLayoutManager *layout_manager,
                         GtkWidget        *widget)

As you may notice, each virtual function gets passed the layout manager instance, as well as the widget that is using the layout manager.

Of course, this has bigger implications on various aspects of how GTK widgets work, the most obvious being that all the complexity for the layout code can now stay confined into its own object, typically not derivable, whereas the widgets can stay derivable and become simpler.

Another feature of this work is that you can change layout managers at run time, if you want to change the layout policy of a container; you can also have a per-widget layout policy, without adding more complexity to the widget code.

Finally, layout managers allow us to get rid of one of the special cases of GTK, namely: container child properties.

Child properties

Deep in the guts of GtkContainer sits what’s essentially a copy of the GObject property-related code, and whose only job is to implement “child” properties for types deriving from GtkContainer. These container/child properties exist only as long as a child is parented to a specific class of container, and are used for a variety of reasons—but, generally, to control layout options, like the packing direction in boxes and box-like containers; the fixed positioning inside GtkFixed; or the expand/fill rules for notebook tab widgets.

Child properties are hard to use, as they require ad hoc API instead of the usual GObject one, and thus require special casing in GtkBuilder, gtk-doc, and language bindings. Child properties are also attached to the actual direct child of the container, so if a widget interposes a child—like, say, GtkScrolledWindow or GtkListBox do—then you need to keep a reference to that child around in order to change the layout that applies to your own widget.

In GTK’s master branch we got rid of most of them—either by simply removing them when there’s actual widget API that implements the same functionality, or by creating ancillary GObject types and moving child properties to those types. The end goal is to remove all of them, and the relative API from GtkContainer, by the time GTK 4 rolls out. For layout-related properties, GtkLayoutManager provides its own API so that objects are created and destroyed automatically once a child is added to, or removed from, a widget using a layout manager, respectively. The object created is introspectable, and does not require special casing when it comes to documentation or bindings.

You start from deriving your own type from the GtkLayoutChild class, and adding properties just like you would for any other GObject type. Then, you override GtkLayoutManager‘s create_layout_child() virtual function:

static GtkLayoutChild *
create_layout_child (GtkLayoutManager *manager,
                     GtkWidget *container,
                     GtkWidget *child)
{
  // The simplest implementation
  return g_object_new (your_layout_child_get_type (),
                       "layout-manager", manager,
                       "child-widget", child,
                       "some-property", some_property_initial_state,
                       NULL);
}

After that, you can access your layout child object as long as a widget is still a child of the container using the layout manager; if the child is removed from its parent, or the container changes the layout manager, the layout child is automatically collected.

New layout managers

Of course, just having the GtkLayoutManager class in GTK would not do us any good. GTK 4 introduces various layout managers for application and widget developers:

  • GtkBinLayout implements the layout policy of GtkBin, with the added twist that it supports multiple children stacked on top of each other, similarly to how GtkOverlay works. You can use each widget’s alignment and expansion properties to control their location within the allocated area, and the GtkBinLayout will always ask for as much space as it’s needed to allocate its largest child.
  • GtkBoxLayout is a straight port of the layout policy implemented by GtkBox; GtkBox itself has been ported to use GtkBoxLayout internally.
  • GtkFixedLayout is a port of the fixed layout positioning policy of GtkFixed and GtkLayout, with the added functionality of letting you define a generic transformation, instead of a pure 2D translation for each child; GtkFixed has been modified to use GtkFixedLayout and use a 2D translation—and GtkLayout has been merged into GtkFixed, as its only distinguishing feature was the implementation of the GtkScrollable interface.
  • GtkCustomLayout is a convenience layout manager that takes functions that used to be GtkWidget virtual function overrides, and it’s mostly meant to be a bridge while porting existing widgets towards the layout manager future.

We are still in the process of implementing GtkGridLayout and make GtkGrid use it internally, following the same pattern as GtkBoxLayout and GtkBox. Other widgets inside GTK will get their own layout managers along the way, but in the meantime they can use GtkCustomLayout.

The final step is to implement a constraint-based layout manager, which would let us create complex, responsive user interfaces without resorting to packing widgets into nested hierarchies. Constraint-based layouts deserve their own blog post, so stay tuned!

News from GLib 2.58

Next September, GLib will hit version 2.58. There have been a few changes during the past two development cycles, most notably the improvement of the Meson build, which in turn led to an improved portability of GLib to platforms such as Windows, macOS, and Android. It is time to take stock of the current status of GLib, and to highlight some of the changes that will impact GLib-based code.

  • Meson – Thanks to the ongoing work of Nirbheek Chauhan and Xavier Claessens, the Meson build has been constantly improving, to the point that we can start switching to it as the default build system. The plan—as outlined on the mailing list—is to release GLib 2.58 using Meson, while keeping the Autotools build in tree and available in the release archive; then, we’ll drop the Autotools build during the following development cycle, and release GLib 2.60 without Autotools support. Linux distributors are very much welcome to start testing the Meson build in their builders; we’ve been running the Meson build as part of our CI process for a while, now, but more exposure will bring out eventual regressions that we missed; additionally, it would be stellar if people with different toolchains than GCC/Clang/MSVC would start trying the Meson build and report bugs. In the meantime, if you’re using GLib on macOS and Windows, we already recommend you switch to Meson to build GLib, as it’s easier and better integrated with those platforms than Autotools
  • Reliability and portability – GLib switched to GitLab alongside the rest of GNOME, which meant being able to run continuous integration outside of the GNOME Continuous builds. Now we run CI on multiple toolchains, multiple build systems, and multiple platforms for every commit and merge request, which significantly reduces the chances of a broken build. We’ve also improved the code coverage in the test suite. Of course, we could always do better; for instance, we don’t have a CI runner for macOS and the Solaris family of OSes, and more runners for the *BSD family would be greatly appreciated. We’ve issued a call for help, if you have a spare machine and some bandwidth that you can donate
  • File monitoring on *BSD – Apropos the *BSD family, the kqueue backend for file monitoring in GIO has been completely overhauled by Martin Pieuchot and Ting-Wei Lan; the new code is simpler, more robust, and passes all the tests
  • Use posix_spawn() for efficient process launching — Thanks to Daniel Drake, GLib now can use posix_spawn() under specific circumstances, if the platform’s C library supports it; this allows hitting fast paths in the kernel, compared to manually calling fork() + exec(); those fast paths are especially beneficial when running on memory constrained platforms
  • Reference counting types and allocations — GLib uses reference counting as a memory management and garbage collection mechanism in many of its types, but lacks the public API to allow other people to implement the same semantics in their own data structures; this leads to much copy-pasting and re-implementations, and typically to things like undefined behavior when it comes to saturation and thread safety. GLib 2.58 has a grefcount and a gatomicrefcount types, alongside their API, to reduce this duplication. Additionally, taking a cue from other languages like Rust, GLib provides a way to add reference counting semantics on memory allocations, by adding a low level API that allows you to allocate structures that do not have a reference count field, and automatically add reference counting semantics to them
  • Deprecations – A few soft deprecations have become real deprecations in this last development cycle:
      • g_type_class_add_private() has finally been deprecated, five years after we introduced the instance private data macros; if you’re still using that function in your class initialization, please switch to G_DEFINE_TYPE_WITH_PRIVATE or G_ADD_PRIVATE
      • g_main_context_wait() is officially deprecated, but you should have already seen run time warnings about its use
      • gtester, the GTest harness provided by GLib, is deprecated; if you’re using Autotools, you should use the TAP harness that comes with Automake

There have been lots of contributions in GLib, in this past cycle, thanks to the tireless efforts of Philip Withnall; he’s been instrumental in reviewing patches, triaging bugs, and implementing changes in the development process of the project. The switch over to GitLab has also improved the contribution process, with many more developers opening merge requests:

  • 2.54.0..c182cd68: 968 changesets from 143 developers, up from 412 changesets and 68 developers during the 2.53 development cycle
  • A total of 31851 lines added, 27976 removed (delta: +3875)
Developers with the most changesets
Philip Withnall 303 31.3%
Xavier Claessens 79 8.2%
Emmanuele Bassi 69 7.1%
Christoph Reiter 42 4.3%
Ting-Wei Lan 21 2.2%
Chun-wei Fan 21 2.2%
Nirbheek Chauhan 21 2.2%
Ondrej Holy 20 2.1%
Руслан Ижбулатов 20 2.1%
Mikhail Zabaluev 20 2.1%
Simon McVittie 15 1.5%
Matthias Clasen 14 1.4%
Christian Hergert 13 1.3%
Iñigo Martínez 12 1.2%
Bastien Nocera 10 1.0%
Rafal Luzynski 9 0.9%
Michael Catanzaro 9 0.9%
Will Thompson 8 0.8%
Allison Lortie 8 0.8%
Daniel Boles 8 0.8%

Make sure to test your code with GLib 2.57.2, the next development snapshot towards the 2.58.0 stable release.

textures and paintables

With GTK4, we’ve been trying to find better solution for image data. In GTK3 the objects we used for this were pixbufs and Cairo surfaces. But they don’t fit the bill anymore, so now we have GdkTexture and GdkPaintable.

GdkTexture

GdkTexture is the replacement for GdkPixbuf. Why is it better?
For a start, it is a lot simpler. The API looks like this:

int gdk_texture_get_width (GdkTexture *texture);
int gdk_texture_get_height (GdkTexture *texture);

void gdk_texture_download (GdkTexture *texture,
                           guchar     *data,
                           gsize       stride);

So it is a 2D pixel array and if you want to, you can download the pixels. It is also guaranteed immutable, so the pixels will never change. Lots of constructors exist to create textures from files, resources, data or pixbufs.

But the biggest difference between textures and pixbufs is that they don’t expose the memory that they use to store the pixels. In fact, before gdk_texture_download() is called, that data doesn’t even need to exist.
And this is used in the GL texture. The GtkGLArea widget for example uses this method to pass data around. GStreamer is expected to pass video in the form of GL textures, too.

GdkPaintable

But sometimes, you have something more complex than an immutable bunch of pixels. For example you could have an animated GIF or a scalable SVG. That’s where GdkPaintable comes in.
In abstract terms, GdkPaintable is an interface for objects that know how to render themselves at any size. Inspired by CSS images, they can optionally provide intrinsic sizing information that GTK widgets can use to place them.
So the core of the GdkPaintable interface are the function make the paintable render itself and the 3 functions that provide sizing information:

void gdk_paintable_snapshot (GdkPaintable *paintable,
                             GdkSnapshot  *snapshot,
                             double        width,
                             double        height);

int gdk_paintable_get_intrinsic_width (GdkPaintable *paintable);
int gdk_paintable_get_intrinsic_height (GdkPaintable *paintable);
double gdk_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable);

On top of that, the paintable can emit the “invalidate-contents” and “invalidate-size” signals when its contents or size changes.

To make this more concrete, let’s take a scalable SVG as an example: The paintable implementation would return no intrinsic size (the return value 0 for those sizing function achieves that) and whenever it is drawn, it would draw itself pixel-exact at the given size.
Or take the example of the animated GIF: It would provide its pixel size as its intrinsic size and draw the current frame of the animation scaled to the given size. And whenever the next frame of the animation should be displayed, it would emit the “invalidate-size” signal.
And last but not least, GdkTexture implements this interface.

We’re currently in the process of changing all the code that in GTK3 accepted GdkPixbuf to now accept GdkPaintable. The GtkImage widget of course has been changed already, as have the drag’n’drop icons or GtkAboutDialog. Experimental patches exist to let applications provide paintables to the GTK CSS engine.

And if you now put all this information together about GStreamer potentially providing textures backed by GL images and creating paintables that do animations that can then be uploaded to CSS, you can maybe see where this is going

GTK+ 3.92

Yesterday, we released GTK+ 3.92.1, 重庆市. Since it has been a while since the last 3.91 release, here is a brief look at the major changes.

This release is another milestone on our way towards GTK+ 4. And while a lot still needs to be done, this release allows a first glimpse at some of the things we hope to achieve in GTK+ 4.

GSK

Much of the work since the last release has gone into GSK. The Vulkan renderer is now close to complete, as far as avoiding cairo fallbacks goes. The only missing piece are blurred shadows (admittedly, an important piece).

One major step forward since the 3.91.2 release is that we no longer use cairo fallbacks for all text. Instead, text (in labels and entries, sadly not in text views yet) gets translated into text nodes. Each text node contains a PangoGlyphString and a PangoFont. The Vulkan renderer uses a glyph cache to avoid re-rendering the glyphs for each frame.

The internal logic of the Vulkan renderer has been reworked to use textures instead of cairo surfaces for intermediate results and thus avoid more cairo fallbacks.

Other node types that have gained support in the Vulkan renderer include blurs, repeat nodes, blend modes and cross-fades. In some cases, the shaders we use are very naive implementations. Help with improving them would be more than welcome!

As a first example of what we can do with render nodes, we have implemented a blur-under feature for GtkOverlay. This works by capturing the ‘main child’ of the overlay as a render node, and then reusing it several times, with the right clipping, and sometimes with a blur node.

Inspector

To help you explore GSK, the inspector now shows Vulkan information and the recorder shows a lot more information about render nodes.

Input

On the input side, events have gained accessors, and we are no longer accessing their fields directly. This is an intermediate step, cleaning up events is still a work in progress. We have moved the traditional widget signals for events (such as ::key-press-event) to an event controller, and most widgets inside GTK+ have stopped using them altogether.

Build System

We have switched over to using Meson exclusively for GTK+, and the 3.92.1 release is the first one done using Meson’s dist support. To get the release out the door, we also had to port the documentation, the test suite and the installed tests to using Meson.

There are still some rough edges (we don’t get all dependencies 100% right), but overall, Meson worked out well for us.

The rest

Of course, everybody loves Emoji, and the same color Emoji support that has landed in GTK+ 3.22 is also available in this release. Beyond that, font support in CSS has improved a bit with support for the CSS3 font-variant property.

Of course, this relies on fonts that have the corresponding features.

Try it out

With GTK+ 3.92.1, it should be easy to try some of these things out for yourself.

And if you’ve always wanted to get into GTK+ development but never found the right opportunity, now is a great time to get involved!

Logging and more

A while ago, GLib gained a new facility for ‘structured logging’. At the same time, it also gained support for writing logs to the systemd journal. Clearly, logging in GLib got a bit more complicated, and it can be a bit confusing.

This article is an attempt to clarify things.

Structured or not

The traditional GLib logging facilities are the g_message(), g_debug(), etc macros, which eventually call the g_log() function, which then uses the log handler that has been set with g_log_set_handler() to do the actual writing. You can put any information you like into your logs, but it has to all be formatted as a single string, the message.

g_debug ("You have %d eggs", 12 + 2);

g_log (G_LOG_DOMAIN,
       G_LOG_LEVEL_DEBUG,
       "You have %d eggs", 12 + 2);

With the new structured logging facilities, you call g_log_structured(), which then uses a log writer function to do the writing. So far, this is very similar to the older logging facility. The advantage of structured logs is that you can put multiple fields into the log without resorting to formatting it all into a string. Instead, you pass an array of log fields, which are key-value pairs.

g_log_structured (G_LOG_DOMAIN,
                  G_LOG_LEVEL_DEBUG,
                  "CODE_FILE", "mysource.c",
                  "CODE_LINE", 312,
                  "MESSSAGE_ID", "06d4df59e6c24647bfe69d2c27ef0b4e",
                  "MESSAGE", "You have %d eggs", 12 + 2);

CODE_FILE, CODE_LINE and MESSAGE_ID here are just examples for “standard” fields. You can also invent your own fields. Note that you can still use printf-style formatting for the MESSAGE field.

So GLib has two separate logging facilities now. To make matters a bit more interesting, we allow you to redirect the g_message(), g_debug(), etc wrapper macros to use g_log_structured() instead of g_log() under the covers. To do so, define the G_LOG_USE_STRUCTURED macro before including glib.h.

Why is this useful? For one thing, it saves you the trouble of replacing all your g_debug() and still lets you take some advantage of the structured logging – when used in this fashion, the traditional macros use separate fields for the log domain, the code file and line and some other fields, which can be helpful for filtering and searching in the resulting logs, in particular with the systemd journal.

Another advantage is that you can use a single backend, the log writer function, to control where both old and new logging calls end up.

Where have all my logs gone ?

Structured logging is frequently associated with the systemd journal. So, it is not surprising that people expect the g_log_structured() output to go the journal. And that is a really useful thing for services, or when you are launching an application e.g. from a desktop icon. But if you run it from the terminal, you probably expect to see its output right there.

To satisfy these competing demands, the GLib default log writer function tries to be smart. If it detects that stderr is redirected to the journald socket, then it writes its structured output to the journal. Otherwise, it formats a message and writes it to stderr.

Both GNOME Shell and DBus arrange for stderr to be redirected to the journal when they start apps or services. A way to explicitly redirect stderr to the journal is to run your application under systemd-cat:

systemd-cat my-app-that-logs

If you are sure that you want your logs to always go to the journal, you can tell GLib to use a log writer that does that:

g_log_set_writer_func (g_log_writer_journald, NULL, NULL)

Beyond the default

Even though the log writer functions that GLib provides by default should serve many needs, you might need to write your own. In that case, GLib has a number of useful functions that can help you, such as g_log_writer_format_fields(), g_log_writer_is_journald() or g_log_writer_supports_color().

Happy logging!

References

Widget hierarchies in GTK+ 4.0

Today we’re going to have guest author Timm Bäder, maintainer of Corebird and a contributor of GTK+, talk about the changes in store for writing composite widgets in GTK+ 4.0.

(Note: Some of the information here is based on branches that have not been merged into master yet, but I’m confident that they will be in the near future)

In GTK+3, only GtkContainer subclasses can have child widgets. This makes a lot of sense for “public” container children like we know them, e.g. GtkBox — i.e. the developer can add, remove and reorder child widgets arbitrarily and the container just does layout.

However, there are more complicated widgets in GTK+3 which don’t inherit from GtkContainer, e.g. GtkSpinButton or GtkSwitch. These never have real GtkWidget children. Consider, for example, the two clickable areas in a GtkSpinButton. I’m not calling them “buttons” here for a reason, since in GTK+3, they are not actual GtkButton instances, as GtkSpinButton is not a GtkContainer. Instead, GtkSpinButton has to work around that fact, and create two GdkWindows for the up/down areas and then render two icons in there; care about hover and CSS states; various button up/down events; and the GdkWindow lifetime, etc. In order to work around the GtkContainer requirement, in GTK+3 we introduced gadgets (GtkCssGadget). On the styling side, a gadget corresponds to a CSS box and therefore represents one node in the CSS tree. On the widget side they were being used to have “widget-like”, CSS-stylable, children for non-container widgets.

GtkWidget Changes

Of course there were plenty of changes needed to support these use cases in GTK+4. I’m not going to list all of them here (in particular the more ugly ones like focus handling), but I think most of them are quire interesting and important for application developers and custom widget authors. Generally, we’re trying to get a away from special cases and go a more general way by re-using widgets wherever we can. So, instead of using a PangoLayout to display text, widgets should use a GtkLabel. If you have a clickable area with button-like semantics, try to use a GtkButton. If you want to lay out widgets in horizontal or vertical orientation, use a GtkBox. This way we have one widget tree that both input and rendering can operate on. In practice, this means mostly getting rid of all the gadgets used inside widgets, as well as standalone GtkCssNode instances.

Iterating over child widgets

While in GTK+3, every container had to implement GtkContainer::forall and one could easily iterate over all the child widgets using gtk_container_foreach() and gtk_container_forall(), in GTK+4, every GtkWidget can have child widgets, so every widget potentially has a list of children we need to draw, measure, size-allocate, etc. In the widget hierarchy, these children and sibling widgets can be accessed through:
  • gtk_widget_get_first_child()
  • gtk_widget_get_last_child()
  • gtk_widget_get_prev_sibling()
  • gtk_widget_get_next_sibling()
So, the easiest possible way of iterating over the child widgets of a given GtkWidget would be (in C):
GtkWidget *widget;
GtkWidget *child;
for (child = gtk_widget_get_first_child (widget);
     child != NULL;
     child = gtk_widget_get_next_sibling (child))
  {
    /* Do stuff with @child */
    g_assert (gtk_widget_get_parent (child) == widget);
  }

Adding widgets to a non-container parent

Every widget in GTK+ (both 3 and 4) saves a pointer to its parent widget. This parent can be set using gtk_widget_set_parent(), and all the GtkContainer::add implementations eventually had to use this function to set the parent of the given child widget.

In GTK+4, gtk_widget_set_parent() still works and adds the widget to the end of the child widget list of the parent. However, we clearly also want to manage the order of the child widgets, as well as where we add new children in the list, so we have:

  • gtk_widget_insert_before()
  • gtk_widget_insert_after()
to add new child widgets before or after a child widget that’s already in the parent’s list. These can also be used to reorder children child widgets by passing a child that already has the given parent set.
Since lots of widgets inside GTK+ currently use composite widget templates in XML form, GtkWidget now also has its very own GtkBuildable::add_child() implementation to support this use case. This is what e.g. GtkFileChooserWidget uses which is almost exclusively defined in XML.

Widget CSS names

Since we frequently need to use arbitrary CSS node names for arbitrary widgets, GtkWidget now has a construct-only property called GtkWidget:css-name that will be used as the css node name if specified. If not, the one passed to the widget’s gtk_widget_class_set_css_name() call will be used. If none of the 2 have been used, the CSS node will simply be called “widget”.

Examples of Converted Widgets

There are already a few widgets in current master (and side-branches) that were converted from using a variety of GtkCssGadgets, GdkWindows and PangoLayouts to using actual widgets. The end-goal being, of course, to re-use widgets as much as possible, therefore reducing code size and maintenance burden.

GtkSwitch

In GTK+3, GtkSwitch is a direct GtkWidget subclass (yay!) that uses a GdkWindow for the input (clicking on the switch will enable/disable it), one GtkCssGadget for the widget itself, two PangoLayouts for the ON/OFF text and another GtkCssGadget for the slider.
In GTK+ master, the switch still has its widget-level GtkCssGadget so it supports min-width/min-height CSS properties and CSS margins, but the slider gadget has been replaced by a GtkButton and the two PangoLayouts are replaced with GtkLabels. This way we can save roughly 300 lines in gtkswitch.c. Theoretically we also have more features and can e.g. use the limited support for the text-decoration CSS property that GtkLabel supports, but I’m just going to doubt that this is very useful.

GtkSpinButton

As noted earlier, GtkSpinButton could easily use actual GtkButtons for the up/down areas, and it does so in GTK+ master (which will become GTK+4 at some point). This gets rid of another 300 lines in gtkspinbutton.c. Through using GtkButtons, the old icon helper gadgets also become actual GtkImage instances. Unfortunately we have to implement some of the GtkGesture magic ourselves here since GtkSpinButton also supports middle and right clicks on its buttons while GtkButton::clicked only reacts to single, primary mouse button clicks.

GtkLevelBar

GtkLevelBar manages a set of blocks and assigns different style classes to them. In GTK+3, these blocks are all GtkCssGadget instances. All of them are “dumb” in the sense that they don’t do anything special — they are just CSS boxes and that’s it. That’s why converting it to use GtkWidgets for all blocks didn’t gain much of a reduction in file size.

 

GtkProgressBar

GtkProgressBar uses gadgets for the trough and the progress nodes. It also uses a PangoLayout to display the percentage or a user-given string.

In master, both trough and progress are widgets and the PangoLayout is a GtkLabel of course. Not having to listen to GtkWidget::style-changed (which gets done automatically for widgets) and not having to draw the PangoLayout ourselves (which the GtkLabel now takes care of) yields a nice code size saving of around 200 lines, however.

 

GtkExpander

GtkExpander is more complex than it looks like. In GTK+3, it consists of 2 GtkBoxGadgets (which is like a GtkBox, but not a widget…), one gadget for the arrow to the left of the title widget, the title widget and the actual content widget. In master, this is done using an actual GtkBox, and a GtkIcon (an internal widget) for the arrow. I’m not sure if this is the best way to express the GtkExpander functionality, e.g. we could also use a GtkButton for the arrow+title widget combination.
Since GtkBoxGadget is already almost a perfect GtkBox clone, the code savings here aren’t very interesting, but not having to listen to GtkWidget::direction-changed once again saves around 30 lines.

Accidental GtkBox & GtkButton subclasses

GTK+3 contains quit a lot of widgets that inherit from another widget for the sole purpose of looking and behaving like them. The problem here is that these widgets also inherit all the API of the parent class, which is only rarely wanted.
For GtkBox, almost all subclasses in GTK+3 are “accidental” in the sense that actually using them as a GtkBox doesn’t make any sense and people usually don’t do it, but they had to be GtkBox subclasses to satisfy GTK+’s GtkContainer requirement. One example of such a widget would be GtkFileChooserWidget. This is already one of the most complex widget to ever exist, but have you ever considered using gtk_container_add() or gtk_box_pack_{start,end}() to add widgets to it? It doesn’t make a lot of sense. It’s a closed entity with its own API. So, in GTK+4 it will be a direct GtkWidget subclass that contains a GtkBox. Or maybe not. That’s just an implementation detail you don’t have to care about. (Fun Fact on the side: GtkFileChooserButton is a GtkBox in GTK+3)
The same applies to GtkButton. In GTK+3, GtkButton has lots of subclasses that inherited all the GtkButton API without actually supporting it. What happens if you remove the child widget from a GtkLinkButton? What if you set the GtkButton:label property of a GtkFontButton? Again, these are closed entities that have their own API to set and get various data and change behavior and/or looks based on them, but that doesn’t mean they support all the GtkButton/GtkContainer shenanigans.

General Restructuring Rules and Future

For this refactoring work we try to keep the CSS node structure as it was in GTK+3, i.e. we try not to break the CSS node tests we currently have in testsuite/css/nodes.c.
A few of the more complex widgets inside GTK+ still heavily rely on gadgets and porting them away to use only actual widgets will be quite a lot of work. GtkRange is historically one of the most complex non-container widgets inside GTK+. It’s used both for scrollbars and scales so porting it to widgets might first need another round of refactoring.
Another interesting case is GtkNotebook, which combines gadget and widget usage. Here we could e.g. use a real GtkStack to switch between pages and effortlessly support page switching transitions.
Another exciting look into the future is of course Carlos’ wip/carlosg/event-delivery branch that gets rid of a ton of GdkWindow instances and makes widget input easier than ever before.

Versioning and long term stability promise in GTK+

The plans set out in this post supersede those that were publicised after the Toronto GTK+ hackfest in June 2016.

This month, the GTK+ team will publish the first in a series of long-term stable releases. This will make GTK+ more predictable and reliable, while not inhibiting future GTK+ improvements.

These plans are a result of discussions held with a variety of stakeholders since initial plans were made at the GTK+ hackfest in Toronto last June.

Background

GTK+ has followed a fairly straightforward versioning scheme since the 2.0 release in 2002:

  • major versions designate the general API version
  • minor versions designate development cycles (if odd) and stable cycles (if even)
  • micro versions designate bug fix updates

Any API introduced in GTK+ is guaranteed to exist until the next major version; API introduced during a development cycle is guaranteed to remain once the stable cycle begins. Stable cycles do not provide new features or new API.

This scheme served us well, but its problems have become increasingly clear during the 3.x series, especially when coupled with 6 month, time-based development cycles. During the 2.x cycle new features in GNOME applications were forced to appear in additional libraries because the toolkit was too complex or moving too slowly. Since 3.0, the development pace of GTK+ has been picking up. GTK+ has been placed front and center, with new widgets and new functionality being introduced every six months. In order to implement these new widgets and functionality, though, some of the toolkit’s internals have been in a state of flux.

From a GNOME perspective, GTK+ has been a reasonably stable, albeit moving target, because GNOME developers and GTK+ developers can share feedback and proposals and quickly keep up with internal changes. From the perspective of the community, on the other hand, following GTK+ development has been more painful. Application developers outside of the GNOME project have had a hard time finding out about what changes in the toolkit will impact their codebases. The GTK+ team has attempted to improve its communication channels, but blogging about changes during development cycles hasn’t been enough for many in the wider community of GTK+ users.

Long-term stable GTK+ releases

GTK+ has three primary stakeholders: application developers who want feature and API stable releases; desktop developers who want access to development versions of GTK+ in order to introduce new functionality at a rapid pace (this includes most of the GNOME project); and the GTK+ team itself, which needs the ability to iterate on the internals of the library during longer development cycles.

The introduction of long-term stable GTK+ releases is designed to ensure that GTK+ strikes a good balance between each of these audiences. In particular, application developers will have access to a stable platform which nonetheless provides access to new GTK+ features that have been developed during the 3.x series, such as CSS styling, touchscreen support, HiDPI displays support, Wayland support, new widgets, the GTK+ inspector, and more.

GTK+ will continue to publish major, minor and micro releases. New major versions will be released once new features have stabilised, which is expected to be roughly every 2-3 years. When bumping to a new major version deprecated API will be removed. After that, this API series will be considered stable. New minor releases may introduce new widgets, or update the implementation of windowing system protocols in the GDK backends, but no additional features or theme changes will be allowed. Whereas previously minor releases were published every six months, now they will be produced as and when necessary. We’ll also keep doing micro releases for bug fixes and security issues, for at least three years. Maintenance after this point may continue, depending on the amount of volunteer resources available. Distributors of operating systems with long term support release cycles that extend past three years may want to contact the GTK team to establish a policy for backports.

Updates within long-term stable series will be ABI stable. Alongside these stable series, GTK+ development will continue in semi-stable development series. These development releases will contain some API changes between minor versions, although changes will be limited wherever possible. This is the path that we expect GNOME applications to take, but other application developers may choose this option if they want access to the latest features, at the cost of some potential porting work for each minor release.

While the GTK+ team reserves the right to change API during development series, this does not mean that the whole GTK+ API will constantly break each release; only specific, and hopefully rarely used parts of the API may change, and if the changes are too extensive they will very likely be delayed to the next major development cycle. We’ll ensure that these changes are well-communicated in advance.

The new versioning scheme

The new GTK+ versioning scheme is a modification of the “semantic versioning” scheme that we have followed until now. Once a new major stable release has been published, the development cycle starts and we will:

  • update the pkg-config file to a new major version, to allow GNOME developers to target the new API during development
  • keep the existing major version at the same number
  • update the minor version to 90 to indicate a development release

For instance, after the 3.22.0 release and at the start of the new development cycle, the pkg-config file will be called gtk+-4.0 and the version in the configure.ac file will be set to 3.90.

Every six months a new even development version will be released, such as x.90, x.92, x.94, until the GTK+ team is confident that the new API and feature set are stable. Each of these minor versions will bump the soname of the shared library, to ensure that automated tools can pick up the eventual changes and notify distributors and maintainers. Once we reach the point where the API and feature set is stable enough for the wider community to use, we will release a new major version (x + 1).0 and declare the API stable.

Once this point-zero release has been made, a new stable branch will be created, and the master branch will be bumped to the next point-ninety release and begin the new development cycle. The point-ninenty releases will be parallel installable with the previous stable releases.

gtk-versioning-scheme

3.22 will be the last minor release of the 3.x series, with the new versioning scheme coming into effect with 3.90. The 3.22 release is irregular in the scheme, in that it is a long-term stable version but won’t receive further minor releases and doesn’t have a .0 version number. This is a necessary transition step.

What’s next

More details about these plans, including specifics for library developers and distribution packagers, will follow in subsequent blog posts. The GTK+ development blog will also continue to provide updates about technical changes in GTK+ itself, in order to provide information about which changes will arrive in each upcoming major release.

We’re excited about these plans and are hopeful that they will usher in a new era for GTK+, in which application authors can be more confident in our platform, while still allowing the rapid pace of development that we have seen during the 3.x series.

The plans set out in this post supersede those that were publicised after the Toronto GTK+ hackfest in June 2016.

Drawing in GTK+

The topic of how GTK+ draws the content of a window is a fairly complex one; it involves drilling down from GtkWidget, to GdkWindow, to Cairo, to the windowing system currently in use. This task can seem somewhat daunting, even for people that are familiar with the GTK+ API from an application development standpoint, so I decided to write down a quick introduction of how GTK+ draws, going from widgets, to windows, to surfaces, to native windowing resources.

How it starts

GTK+ always draws because something asked it to. This request may come from the windowing system — for instance, because the window manager presented your application window to the user, or because the user resized it — but more often it’ll come from a widget updating its contents. Let’s say, a progress bar going from 50% to 60%; or a label, changing its text; or a spinner, doing a new iteration. This request invalidates the backing GdkWindow of the widget — which usually it’s the GdkWindow of the top-level GtkWindow that contains the widget. Each invalidation carries with itself the region of the window to be invalidated (the “damage”), so that when we get to actually drawing, we know which parts of the window need to be updated, and we can avoid drawing outside of the damaged areas.

Race the clock

The first invalidation will start the “frame clock”; this clock is an object that keeps track of each phase inside a frame, like painting windows, laying out widgets, or processing the event queue. This allows GTK+ to be synchronized to things like the windowing system compositor, and to avoid performing unnecessary work that won’t be seen by the user — for instance, drawing something at 1000 frames per second when your display can only run at 60 Hz.

Once the clock reaches the “paint” phase, we process all the scheduled updates on a window; this will cause a GDK_EXPOSE event to be emitted. The GDK_EXPOSE event contains the GdkWindow that needs to be updated, and the union of all the invalidated areas. It’s important to note that, by and large, only top level windows will receive a GDK_EXPOSE event; for historical reasons, though, some widgets may apply a particular event mask that will cause GDK_EXPOSE events to be delivered to them as well. You should not write code that depends on that, and if you have legacy code ported from older versions of GTK+ 2.x you should really consider dropping the GDK_EXPOSURE_MASK from the event mask.

Rendering

GTK+ takes the window and invalidated region out of the GDK_EXPOSE event and figures out which top level widget they belong to. Once that’s found, GTK+ will begin the actual rendering process. First of all, GTK+ will ask the GdkWindow to create a buffer where to draw the contents of the window; the buffer is going to be clipped to the region that needs to be drawn, and will be cleared with the background color of the window. GDK will create a “drawing context” — a transient object that keeps track of things like OpenGL and Cairo drawing. Then, GTK+ will ask the widget to draw itself using a Cairo context. For leaf widgets this means drawing themeselves on that context; for container widgets, this additionally means recursing through all their children. At the end of this process, GTK+ will end the frame by telling GDK to take the buffer that contains all the rendered widgets and use it to replace the current contents of the window. GDK will then ask the windowing system to present the window to the user, whenever it’s more appropriate.

Changing History

The process outlined above has various caveats, and the code that deals with invalidation and validation of windows inside GDK is fairly complex; it also has a long history, which means that its API is littered by the headstones of ages past.

Before GTK+ 3.0, for instance, you were supposed to handle the “expose” events yourself, and create a Cairo context to draw on a widget by using gdk_cairo_create(); this has long since been unnecessary, because the GtkWidget::draw virtual function already provides us with a Cairo context with which to draw. The gdk_cairo_create() function, though, has been deprecated in GTK+ 3.22, and should not be used in newly written code; if you need a Cairo context you should create a similar Cairo surface, call cairo_create() on it, and then use the surface as the source for the Cairo context that GTK+ provides to you when drawing a widget. On the other hand, if you were using gdk_cairo_create() to draw on a top-level, native GdkWindow in response to a GDK_EXPOSE event then you should use the newly added gdk_window_begin_draw_frame(), gdk_window_end_draw_frame(), and GdkDrawingContext API instead.

Shaping Future

The internals of the drawing code in GTK+ have been progressively updated over the years, to cope with things like new windowing systems, as well as other rendering API. It’s fairly certain that they will change again, especially when it comes to improving the rendering performance. Many of the changes that may seem arbitrary are, in reality, stepping stones towards reducing the time spent inside the toolkit in each frame, and leave more time to the application logic.