Various people are working on porting desktop virtualization UIs to GTK4. This typically involves virgl, and the GTK3 solution was to use GtkGLArea.
With GTK4, rendering is happening in GL anyway, so it should be enough to just wrap your content in a GdkTexture and hand it to GTK, either by using it as a paintable with GtkPicture, or with a GskTextureNode in your own snapshot() implementation.
This is a nice theory, but the practice is more complicated – the content is typically available as a dmabuf object, and with 4k rendering, you really want to avoid extra copies if you can help it. So we had to look at the available solutions for importing dmabufs as textures into GL without copies.
This turned into a quick tour through the maze of graphics APIs: OpenGL, EGL, GL ES, GLX, DRI, … the list goes on. In the end, it turns out that you can use EGL to wrap a dmabuf into an EGLImage, and use the GL_OES_EGL_image extension to create a GL texture from it.
GLX to EGL
This works fine with our Wayland backend, which uses EGL. Unfortunately, our much older X11 backend has a GL implementation using GLX, and there doesn’t seem to be a way to get a dmabuf imported into a GLX context.
So we had to do a little bit of extra work, and make our X11 backend use EGL as well. Thankfully Emmanuele had an old unfinished branch with such a conversion from a few years ago, which could be made to work (after some initial head scratching why it would not render anything – as always the case when doing GL work).
It turns out that importing dmabufs with EGL can be done outside of GTK just fine, so we don’t need to add Linux-specific API for it. To save you the trouble of writing such code yourself, here is what I’ve come up with.
After we had already decided to port the X11 backend to EGL, I learned that another possibility for importing dmabufs might be to use DRI3PixmapFromBuffer to create an X11 pixmap from a dmabuf, turn it in a GLXPixmap and use glxBindTexImageEXT to make a texture.
This release is the result of the initial round of feedback from the application developers porting their projects to GTK4, so it mostly consists of bug fixes and improvements to the API—but we also added new features, like a new GL renderer; various improvements in how the toolkit handles Compose and dead key sequences; build system improvements for compiling GTK on Windows and macOS; and a whole new API reference, generated from the same introspection data that language bindings also consume.
Thanks to the hard work of Christian Hergert, the NGL renderer is now the default renderer for Linux, Windows, and macOS. We’ve had really positive feedback from users on mobile platforms using drivers like Lima, with noticeable improvements in frames per second, as well as power and CPU usage; the latter two are also going to impact positively desktop and laptop users. The NGL renderer is just at the beginning: the new code base will allow us even more improvements down the line.
For the time being, we have kept the old GL renderer available; you can use export GSK_RENDERER=gl in your environment to go back to the 4.0 GL renderer—but make sure to file an issue if you need to do so, to give us the chance to fix the NGL renderer.
Matthias wrote a whole blog post about the handling of Compose and dead keys input sequences, so you can just read it. The dead key handling has seen a few iterations, to deal with oddities and workarounds that have been introduced in the lower layers of the input stack.
There is one known issue with the handling of dead acute accents vs apostrophes in some keyboard layouts, which is still being investigated. If you notice other problems with keyboard input, specifically around Compose sequences or dead keys, please file an issue.
One of the goals of GTK is to have a “turn key” build system capable of going from a clone of the Git repository to a fully deployable installation of the toolkit, without having to go through all the dependencies manually, or using weird contraptions. You can see how this works on Windows, using native tools, in this article from our friends at Collabora.
Additionally, we now ensure that you can use GTK as a Meson sub-project; this means you can build GTK and all its dependencies as part of your own application’s build environment, and you can easily gather all the build artifacts for you to distribute alongside your application, using the toolchain of your choice.
One of the most notorious issues for newcomers to GTK has been the documentation. Application developers not acquainted with our API have often found it hard to find information in our documentation; additionally, the style and structure of the API reference hasn’t been refreshed in ages. To improve the first impression, and the use of our documentation, GTK has switched to a new documentation generator, called gi-docgen. This new tool adds new features to the API reference, like client-side search of terms in the documentation; as well as nice little usability improvements, like:
a “Copy to clipboard” button for code fragments and examples
a visual hierarchy of ancestors and interfaces for each class
the list of inherited properties, signals, and methods in a class
a responsive design, which makes it easier to use the API reference on small screens
An API is only as good as it allows developers to use it in the most idiomatic way. GTK not only has a C API, it also exposes a whole API for language bindings to consume, through GObject-Introspection. The new documentation uses the same data, which not only allows us to cut down the built time in half, but it also generates common bits of documentation from the annotations in the source, making the API reference more consistent and reliable; finally, the C API reference matches what language binding authors see when consuming the introspection data, which means we are going to tighten the feedback loop between toolkit and bindings developers when introducing new API.
Pango and GdkPixbuf have also switched to gi-docgen, which allows us to build the API reference for various dependencies through our CI pipeline, and publish it to a whole new website: docs.gtk.org. You’ll always find the latest version of the GTK documentation there.
Odds and ends
Of course, alongside these visible changes we have smaller ones:
performance improvements all across the board, from GLSL shaders used to render our content, to the accessibility objects created on demand instead of upfront
sub-pixel positioning of text, when using a newer version of Cairo with the appropriate API
a responsive layout for the emoji chooser
improved rendering of shadows in popover widgets
localized digits in spin buttons
improved support for the Wayland input method protocol
improved scrolling performance of the text view widget
GTK 4.2 is the result of four months of development, with 1268 individual changes from 54 developers; a total of 73950 lines were added, and 60717 removed.
My last update talked about better visual feedback for Compose sequences in GTK’s input methods. I did not explicitly mention dead keys back then, but historically, X11 has treated dead keys and Compose sequences in exactly the same way.
Dead keys are a feature of certain keyboard layouts where you can hit a key that does not produce a character by itself, but modifies the next key you type. Typically, this is used for accents that can be combined with different base characters. For example, type <dead_acute> <a> to produce á or <dead_acute> <o> to produce ó.
Traditionally, dead keys were really dead – you didn’t get any visual feedback before the final result appears. With the improvements described in the last update, we now show dead keys as they are entered:
That is a nice improvement. But as it turned out, not everybody was happy.
The shared treatment of Compose sequences and dead keys has some implications: one is that entering a non-existing sequence such as <dead_grave> <x> will produce a beep, and no output. That is acceptable for a Compose sequence that you explicitly started with the Compose key, but not so great when you maybe meant to enter `x.
The people who decided to use Compose sequences for dead keys foresaw the need to actually enter spacing accents every now and then, and added sequences such as <dead_grave> <space> and <dead_grave> <dead_grave> for producing a single ` character.
While that is a nice thought, it is still pretty inconvenient, since you need to type <dead_grave> six time to produce ```, e.g. for entering code examples in markdown.
After thinking about this for a while and comparing what other systems do, we’ve made two changes, that will hopefully make dead keys as convenient to use as any other keys on your keyboard.
When a <dead key> <key> sequence does not match one of our Compose sequences, commit the individual keys
When a <dead key> follows another <dead key>, commit the first one, and treat the second as the beginning of a new Compose sequence
Together, this makes it so that typing <dead_acute> <a> produces á, typing <dead_grave> <x> produces `x, and you only need to type <dead_grave> three times to enter ```:
GTK 4.2 is due out in March – it will not be an enormous release, just incremental improvements. But besides the usual bug fixes and performance improvements, there are a few things that are worth calling out indvidually.
A new GL Renderer
Christian Hergert has been hard at work, creating a new GL renderer for GTK. The initial motivation for this work was the desire to improve our rendering performance on MacOS, where the GL drivers are not quite as forgiving as on Linux. Apart from that, starting over with a new renderer gives us a chance to apply all the things we’ve learned while working on our current GL renderer, and to reorganize the code with an eye towards future improvements, such as reordering and batching of draw commands.
The new renderer hasn’t been merged yet, but it is closing in on feature parity and may well make it into 4.2. We will likely include both the old and the new renderer, at least for a while.
Ever since GtkPopover was introduced with its signature ‘beak’, popovers have clipped everything outside their border, since we needed the tip of the beak to be consistently placed. With the new xdg-popup based implementation in GTK4, we have an positioning protocol that is expressive enough to place popovers in a way that makes the ‘beak’ point where it is supposed to while allowing shadows underneath and around the popover. As with window shadows, the popover shadows are outside of the input region, so clicks go through to the underlying window.
This is a minor thing, but it may have a noticeable impact in giving the UI depth and structure.
GtkIMContextSimple is the input method implementation that is built into GTK. It is used when we don’t have a platform method to use, such as the Wayland text protocol. GtkIMContextSimple only does a few things. One of them is to interpret hexadecimal input for Unicode characters, with Control-Shift-u. Another is that it handles Compose sequences, such as
<Compose Key> <a> <acute>
to enter an á character.
Most Compose sequences start with that Compose Key, and the keyboard settings in GNOME 40 will include a way to assign a key on your keyboard to this function.
On the GTK side, we’ve addressed a few longstanding complaints with the Compose sequence support. Apart from its built-in sequences, GTK parses X11 Compose files. The format of these files is described in Compose(5), but until now, GTKs support for this format was pretty incomplete. With GTK 4.2, we’re improving this to
Allow sequences of up to 20 keys (previously, the limit was 7)
Generate multiple characters (notably, this allows Unicode Emoji sequences)
Support hexadecimal codepoints
These are nice improvements for people who make their own Compose sequences by editing ~/.Compose. But what about the rest of us? One traditionally difficult aspect of using Compose sequence is that you have to know the sequences by heart, and type them blindly. There is no visual feedback at all until the sequence is complete and the final character appears. A while ago, IBus improved on this by showing the characters of the incomplete sequence as underlined preedit text, similar to what we do for hexadecimal Unicode input.
After copying their approach for GTK, initial user feedback was mixed, mainly because the official glyph for the Compose Key (⎄) is a bit distracting when it appears unexpectedly. So I went back to the drawing board and came up with a different approach:
I hope this works better. Feedback welcome!
All of these input changes will also appear in GTK 3.24.26.
We all took a bit of a break after 4.0 and did some other things, but now it is time for GTK 4.0.1.
This is the first release after 4.0, and it naturally contains a lot of small bug fixes, theme and documentation improvements, and the like. But there are a few highlights that are worth pointing out.
Better media support
Among the bigger advances in this release: we managed to make the gstreamer media backend use GL textures, which avoids bouncing frame data between gpu and cpu when using hardware acceleration for decoding, such as vaapi. This requires careful orchestration to bridge the differences in how gstreamer and GTK treat GL, but we managed to make it work in many cases.
Does this mean GtkVideo is now ready to support fully-featured media player applications? Far from it. It still just lets you play media from a file or url, and does not support multi-channel audio, video overlays, device selection, input, and other things that you probably want in a media player.
It would be really nice if somebody took the code in the GTK media backend and turned it inside out to make a GStreamer plugin with a sink that exposes its video frames as GdkPaintable. That would let you use gstreamer API to get all of the aforementioned features, while still integrating smoothly in GTK.
In order to keep our new MacOS backend in working shape, we’ve started to set up CI builds for this platform, both for GTK itself, and for its dependencies (pango, gdk-pixbuf).
GTK 4 has been a colossal, multi-year development endeavor that started in October 2016 and ended in December 2020. Now that the 4.0 release is finally out, it’s time to look back to the incredible amount of work done by hundreds of contributors over these four years.
Back in 2016 we were definitely a bit optimistic on the time table, and thought we would be able to release 4.0 in three years, by the end of 2019. The plan was to start by changing the rendering pipeline of GTK, by moving it to a retained graph of operations that could be submitted to the GPU, as opposed to the immediate mode rendering that we had since the very beginning of the toolkit, and which survived two major API cycles—first by abstracting Xlib drawing commands, and then by moving to Cairo operations. Of course, we also knew we wanted to improve other sub-systems, like input and the windowing system API, to move away from X11-isms and towards a design more in line with the requirements of Wayland (and other windowing systems). What we got, after all was said and done, is a deep redesign of the internals of the toolkit, as well as a different programming model that favors more delegation through ancillary objects, and fewer leaky abstractions and deep type hierarchies; additionally, we pared down the exposed internals, to ensure that the toolkit, and the applications using it, will be more maintainable in the future. The downside is that GTK is less of a “meta toolkit”, whose internal state can be poked at from the outside while expecting to work across multiple releases; that approach was, in the long term, unsustainable given the available resources, and left us unable to optimise or improve the internals of GTK, to the detriment of every user.
We don’t expect the next major development cycle to take this much time, but you know as they say: no plan of operations extends with any certainty beyond the first contact with the main hostile force. The important thing, though, is that we still see potential for improvement; and while we want to celebrate the release of GTK4, as well as everyone who contributed to it, we also want to communicate that the plan outlined in 2016 is still very much in effect. We already started collecting items for a GTK5 development cycle in our GitLab project page, and we plan to have more discussions with various stakeholders for future work in that direction.
Starting from commit 4cce6104 on October 5th, 2016:
The most interesting thing is that, for all that work, we ended up with a total of 50 lines of code removed from the existing code base, which includes tests and documentation.
Per year breakdown
We only had a couple of months in 2016, and the largest effort between October and December was the removal of the deprecated API, and various changes to cope with the renaming from GTK3 to GTK4. Nevertheless, GSK initially landed in November/December. On November 21st, GTK 3.89.1 was released, the first development snapshot of the new GTK 4 API.
In 2017, GSK had with multiple iterations over its API: new render nodes were added to implement CSS drawing primitives, and widgets were moved to the GtkSnapshot API from the old Cairo rendering primitives. Additionally, the new clipboard API was introduced, with a stream-based implementation. On March 31st, GTK 3.90.0 was released, followed by 3.92.0 in October.
In 2018, things seem to slow down, but mostly because we moved to GitLab. Suddenly, we had access to a CI pipeline and merge requests, and we became progressively more confident in our development process; lots of work happened in development branches, especially large refactorings, like the renaming of GdkWindow to GdkSurface; the move to GtkGesture objects and the removal of per-widget event signals; or making leaf classes not derivable. GTK 3.94.0 was released in June.
In 2019, development pace picked up once again:
no more GtkMenu
scope object for GtkBuilder
GtkNative and GtkRoot interfaces
simplified GdkSurface sub-types
Plus, of course, lots of performance and functionality improvements in the rendering pipeline. GTK 3.96.0 was released in May.
Finally, we arrive at 2020:
new drag and drop API, based on event controllers
new macOS backend in GDK, replacing the old Quartz one
new accessibility API, dropping ATK
no more GtkContainer
no more GtkRadioButton
simplified GdkDevice API
new keyboard shortcuts API
new expressions and filter models
new model-based list and tree widgets
GTK 3.98.0 was released in February; and, finally, 3.99.0 in July, as the first true beta towards GTK 4.0.
Top 20 by commit
Top 20 by changes
As usual, Matthias towers over every other contributor, both in terms of sheer number of commits and in terms of code changes.
While Red Hat employees affect the most changes, we still have a very large number of contributors from the community—both using their GNOME email address and using their work address even when contributing on a personal level. We also have multiple contributors from various companies in the GNOME and free software at large ecosystems, signalling a healthy community around the project.
The big news in last weeks GTK 3.99.3 release is that we have a first non-trivial backend for our new accessibility implementation. Therefore, now is a good time to take a deeper look at accessibility in GTK 4.
Lets start with a quick review of how accessibility works on Linux. The actors in this are applications and assistive technologies (ATs) such as screen readers (for instance, Orca), magnifiers and the like.
The purpose of ATs generally is to provide users with alternative ways to interact with the application that are tailored to their needs (say, an enlarged view, text read out aloud, or voice commands). To do this, ATs need a lot of detailed information about the applications UI, and this is where the accessibility stack comes into play—it is the connecting layer between the application (or its toolkit) and the ATs.
Applications and ATs talk to each other on the accessibility bus, which is a separate instance of a D-Bus session bus, using the interfaces described by the AT-SPI project. The UI elements of the application are represented on as objects on the bus that implement somewhat abstracted interfaces, such as Text or Value. Applications emit signals to communicate changes in the UI, and ATs can call methods on the objects to get information or make changes (e.g. change the current value of a Value interface to move the GtkScale that it represents).
What has changed
In GTK 2 and 3, this was done in an awkwardly indirect way: GTK widgets have auxiliary accessible objects that are implementations of ATK interfaces (translation 1: GTK ➙ ATK). These are then turned in AT-SPI objects (translation 2: ATK ➙ AT-SPI) that are represented on the accessibility bus by adapter code in at-spi2-atk. On the other end, ATs then use pyatspi to convert the AT-SPI interfaces into Python objects (translation 3: AT-SPI ➙ Python).
This multi-step process was inefficient, lossy, and hard to maintain; it required implementing the same functionality over at least three components, and it led to discrepancies between the documented AT-SPI methods and properties, and the ones actually sent over the accessibility bus.
In GTK 4, we are simplifying the application side by cutting out ATK and at-spi2-atk. Widgets now implement a GtkAccessible interface that lets them set a number of roles, states, properties and relations that are more or less directly taken from the WAI-ARIA spec published by the W3C. The AT-SPI backend for GTKs accessibility API then takes these ARIA-inspired attributes (and the knowledge of the widgets themselves) and represents the widgets as objects on the accessibility bus, implementing the relevant AT-SPI interfaces for them.
This is a much more direct approach, and matches what Qt and web browsers already do.
Here are the highlights of the accessibility API that you are most likely to run into when using GTK 4 in applications:
Setting an accessible role. A role is a description of the semantics of a widget, and ATs will use it to decide what kind of behavior should be presented to their users. Setting a role is a one-time operation, which means it has to be done at widget creation time, either in class_init, or during instance initialization:
The GTK reference documentation has an overview of the accessibility API, which includes guidance for application developers and widget writers.
What’s next ?
For GTK 4.0, we are focusing on completing the AT-SPI backend. But with the new API and the backend separation, we have a clear path towards making accessibility backends for other platforms, which is something we want to look into for subsequent GTK 4 releases.
On Linux, we want to work with other stakeholders on modernizing the AT-SPI interfaces to finally overcome the CORBA legacy that is still visible in some places. A part of that will be moving away from an accessibility bus toward peer-to-peer connections between the application and the ATs; this would enhance the security of the accessibility stack and plug a hole in the sandboxing used by technologies such as Flatpak.
In the future we want to introduce tools to ensure that application developers will be aware of missing accessibility annotations, such as providing a label attribute, or a labelled-by relation, to icons and images in their UIs; or ensure that every UI element is correctly represented in the accessible tree. We already have a test backend for the GtkAccessible interface which can be used to write unit tests and verify that roles and attributes are updated where necessary.
The GTK 3.99.2 release continues the topics from 3.99.1: api cleanup, new and polished demos, better documentation. You can see the details here.
One small note on the topic of documentation is that we are relying on some unreleased gtk-doc features. Therefore, we now include gtk-doc as a subproject in the gtk release tarball. If you are a distributor, don’t be surprised that building GTK installs gtk-doc tools now.
The big news in this snapshot is our work on exposing the power of the new GL-based rendering stack a bit more.
gtk4-demo includes a Shadertoy demo now.
The demo using a GtkGLArea widget to run GLSL snipplets that are compatible with the ones found on shadertoy.com. Many of the examples found there will work, if you paste them into the editor of this demo.
This is fun, but somewhat limited. The GLSL is confined to its ‘sandbox’, the GtkGLArea widget, which is using GL api to compile and use the shaders.
Shaders as first-class objects
This is not our first attempt to make a shadertoy lookalike. When we first looked at it, we thought that we would make a shader abstraction that applications could use. We put it to the side when it turned out that making it work across different renderers and backends would require us to write our own shader compiler—too much work.
But after our shadertoy success, we revisited the idea of shaders as first-class objects, with more modest goals: We use GLSL, and don’t attempt to make the shaders work with anything but the OpenGL renderer.
In 3.99.2, we now have:
GskGLShader – a wrapper object around a GLSL fragment shader
GskGLShaderNode – a render node that lets us embed a GskGLShader in the scene graph
With these pieces in place, we made a demo that shows various uses of shaders. It is maybe a bit overloaded, and some of the effects are a bit over-the-top, but it gets the point across: you can use shaders in your widgets.
What we haven’t done yet is adding widgets that have shader support built-in. The demo showcases a few likely candidates:
A shader paintable. As you may recall, GdkPaintable is a very flexible interface for anything that can ‘paint’. Shaders certainly qualify. The GskShaderPaintable in gtk-demo uses a shader without input textures to just produce pixels, and we add it to a GtkPicture widget to make it appear in the widget tree.
A shader bin. This is a very simple container that can use shaders to draw effects on top of a child widget. It works with shaders that take a single input texture (for the child widget).
A shader stack. This is a stack-like container that shows one of many child widgets, and uses a shader for the transition whenever the visible child changes. It works with shaders that expect two input textures (for the old and new active child).
Thankfully, making custom widgets is a lot easier in GTK 4 than it used to be, so the render node API should be enough to get you started on some fun experiments. You can of course take the gtk4-demo code as a starting point.
You can debug it
Apart from widgets, the shader support is fully integrated. The GTK inspector can handle shader nodes like any other render nodes, you can serialize them and e.g. load the resulting file in gtk4-node-editor:
If you need to see the input that GTK sends to the shader compiler, setting the environment variable
can be helpful.
After this GL adventure we’ll now focus on landing more of the new accessibility infrastructure.
One thing that I left unfinished in my recent series on list views and models in GTK 4 is a detailed look at GtkColumnView. This will easily be the most complicated part of the series. We are entering into the heartland of GtkTreeView—anything aiming to replace most its features will be a complicated beast.
As we did for GtkListView, we’ll start with a high-level overview and with a picture.
If you look back at the listview picture, you’ll remember that we use a list item factory to create a widget for each item in our model that needs to be displayed.
In a column view, we need multiple widgets for each item—one for each column. The way we do this is by giving each column its own list item factory. Whenever we need to display a new item, we combine the widgets from each columns factory into a row for the new item.
Internally, the column view is actually using a list view to hold the rows. This is nice in that all the things I explained in the previous post about item reuse and about how to use list item factories apply just the same.
Of course, some things are different. For example, the column view has organize the size allocation so that the widgets in all rows line up to form proper columns.
Note: Just like GtkListView, the colum view only creates widgets for the segment of the model that is currently in view, so it shares the vertical scalability. The same is not true in the horizontal direction—every row is fully populated with a widget for each column, even if they are out of view to the left or right. So if you add lots of columns, things will get slow.
Titles, and other complications
The column objects contain other data as well, such as titles. The column view is using those to display a header for each column. If the column view is marked as reorderable, you can rearrange the columns by drag-and-drop of the the header widgets. And if the columns are marked as resizable, you can drag the border between two columns to resize them.
If you payed attention, you may now wonder how this resizing goes together with the fact that the cells in the rows can be arbitrary widgets which expect to have at least their minimum size available for drawing their content. The answer is that we are using another new feature of the GTK 4 rendering machinery: Widgets can control how drawing outside their boundaries (by child widgets) is treated, with
Sorting, selections, and the quest for treeview parity
Since we want to match GtkTreeview, feature-wise, we are not done yet. Another thing that users like to do in tree views is to click on headers, to sort the content by that column. GtkColumnView headers allow this, too.
You may remember from the last post that sorting is done by wrapping your data in a GtkSortListModel, and giving it a suitable sorter object. Since we want to have a different sort order, depending on what column header you clicked, we give each column its own sorter, which you can set with
But how do we get the right sorter from the column you just clicked, and attach it to the sort model? Keep in mind that the sort model is not going to be the outmost model that we pass to the column view, since that is always a selection model, so the column view can’t just switch the sorter on the sort list model on its own.
The solution we’ve come up with is to make the column view provide a sorter that internally uses the column sorters, with
You can give this sorter to your sort model once, when you set up your model, and then things will automagically updates when the user clicks on column headers to activate different column sorters.
This sounds complicated, but it works surprisingly well. A nice benefit of this approach is that we can actually sort by more than one column at a time—since we have all the column sorters available, and we know which one you clicked last.
Selection handling is easy, by comparison. It works just the same as it does in GtkListView.
GtkColumnView is a complex widget, but I hope this series of posts will make it a little easier to start using it.
It is very minimal; which makes it easy to implement
The API is in terms of positions and only deals with changes in list membership—keeping track of changes to the items themselves is up to you
A list model zoo
GTK ships a sizable collection of list model implementations. Under closer inspection, they fall into several distinct groups.
List model construction kit
The first group is what could be called the list model construction kit: models that let you build new models by modifying or combining models that you already have.
The first model in this group, GtkSliceListModel, take a slice of an existing model, given by an offset and a size, and makes a new model containing just those items. This is useful if you want to present a big list in a paged view—the forward and back buttons will simply increase or decrease the offset by the size. A slice model can also be used to incrementally populate a list, by making the slice bigger over time. GTK is using this technique in some places.
The next model in this group, GtkFlattenListModel, takes several list models and combines them into one. Since this is all about list models, the models to combine are handed to the flatten model in the form of a list model of list models. This is useful whenever you need to combine data from multiple sources, as for example GTK does for the paper sizes in the print dialog.
Note that the original models continue to exist behind the flatten model, and their updates will be propagated by the flatten list model, as expected.
Sometimes, you have your data in a list model, but it is not quite in the right form. In this case, you can use a GtkMapListModel replace every item in the original model with different one.
GTK and its dependencies include a number of concrete models for the types of data that we deal with ourselves.
The first example here are Pango objects that are implementing the list model interface for their data: PangoFontMap is a list model of PangoFontFamily objects, and PangoFontFamily is a list model of PangoFontFace objects. The font chooser is using these models.
The next example are the GtkDirectoryList and GtkBookmarkList objects that will be used in the file chooser to represent directory contents and bookmarks. An interesting detail about these is that they both need to do IO to populate their content, and they do it asynchronously to avoid blocking the UI for extended times.
The last model in this group is a little less concrete: GtkStringList is a simple list model wrapper around the all-too-common string arrays. An example where this kind of list model will be frequently used is with GtkDropDown. This is so common that GtkDropDown has a convenience constructor that takes a string array and creates the GtkStringList for you:
So you can get the selection information for an individual item, or as a whole, in the form of a bitset. Of course, there is also a ::selection-changed signal that works in a very similar way to the ::items-changed signal of GListModel.
The GtkGridView colors demo shows a multi-selection in action, with rubberbanding:
You are very likely to encounter selection models when working with GTK’s new list widgets, since they all expect their models to be selection models.
The big ones
The last group of models I want to mention are the ones doing the typical operations you expect in lists: filtering and sorting. The models are GtkFilterListModel and GtkSortListModel. The both use auxiliary objects to implement their operations: GtkFilter and GtkSorter. Both of these have subclasses to handle common cases: sorting and filtering strings or numbers, or using callbacks.
We have spent considerable effort on these two models in the run-up to GTK 3.99, and made them do their work incrementally, to avoid blocking the UI for extended times when working with big models.
The GtkListView words demo show interactive filtering of a list of 500.000 words: