Libadwaita 1.8
12 Sep 2025
Another six months have passed, and with that comes another libadwaita release to go with GNOME 49.
This cycle doesn't have a lot of changes due to numerous IRL circumstances I've been dealing with, but let's look at them anyway.
Shortcuts dialog
Last cycle GTK deprecated GtkShortcutsWindow and all of the related classes. Unfortunately, this left it with no replacement, despite being widely used. So, now there is a replacement: AdwShortcutsDialog. Same as shortcuts window, it has very minimal API and is intended to be static and constructed from UI files.
Structure
While the new dialog has a similar feature set to the old one, it has a very different organization, and is not a drop-in replacement.
The old dialog was structured as: GtkShortcutsWindow → GtkShortcutsSection → GtkShortcutsGroup → GtkShortcutsShortcut.
Most apps only have a single shortcuts section, but those that have multiple would have them shown in a dropdown in the dialog's header bar, as seen in Builder:
Each section would have one or more shortcuts groups. When a section has too many groups, it would be paginated. Each group has a title and optionally a view, we'll talk about that a bit later.
Finally each groups contains shortcuts. Or shortcuts shortcuts, I suppose - which describe the actual shortcuts.
When sections and groups specify a view, the dialog can be launched while only showing a subset of shortcuts. This can be seen in Clocks, but was never very widely used. And specifically in Clocks it was also a bit silly, since the dialog actually becomes shorter when the button is clicked.
The new dialog drops the rarely used sections and views, so it has a simpler structure: AdwShortcutsDialog → AdwShortcutsSection → AdwShortcutsItem.
Sections here are closer to the old groups, but are slightly different. Their titles are optional, and sections without titles behave as if they were a part of the previous section with an extra gap. This allows to subdivide the sections further, without adding an extra level of hierarchy when it's not necessary.
Since shortcuts are shown as boxed lists, apps should avoid having too many in a single section. It was already not great with the old dialog, but is much worse in the new one.
Finally, AdwShortcutsItem is functionally identical to GtkShortcutsShortcut, except it doesn't support specifying gestures and icons.
Why not gestures?
This feature was always rather questionable, and sometimes doing more harm than good. For example, take these 2 apps - the old and the current image viewer, also known as Eye of GNOME and Loupe respectively:
👁 Screenshot of EoG shortcuts window
👁 Screenshot of Loupe shortcuts window
Both of them specify a two-finger swipe left/right to go to the next/previous image. Well, does it work? The answer depends on what input device you're using.
In Loupe it will work on a touchpad, but not touchscreen: on a touchscreen you use one finger instead.
Meanwhile, in EoG it only works on touchscreen instead. On touchpad 2-finger swipe scrolls the current image if it's zoomed in.
So - while both of these apps have a swipe gesture, they are completely different - yet the dialog makes no distinction between them.
It's also not discoverable. HIG recommends naming the menu entry Keyboard Shortcuts, and it doesn't make a lot of sense that these gestures would be in there too - they have nothing to do with keyboard or shortcuts.
A much better place to document this would be help pages. And of course, ideally apps should have all of the typical gestures people are used to from other systems (pinch to zoom and rotate, double tap to zoom, swipes to navigate, long press to open context menus when it's not available via other means), and clear feedback while those gestures are performed - so that there's less of a need to remember which app has which gestures in the first place and they can be documented system-wide instead.
Why not icons?
As for icons, the only app I'm aware of that did this was gnome-games - it used them to show gamepad navigation:
👁 Shortcuts window from GNOME Games. Half of it is gamepad navigation rather than shortcuts
This was problematic in a similar way, but also there was no way to open this dialog using a gamepad in the first place. A much better solution (and pretty much the standard for gamepad navigation) would have been always visible hints at the bottom of the window or inline.
Auto-loading
Most apps using GtkShortcutsWindow weren't creating it programmatically - GtkApplication loads it automatically and creates an action for it. So, we do the same thing: if a resource with the name shortcuts-dialog.ui is present in the resource base path, AdwApplication will create the app.shortcuts action which will create and show the dialog in the active window when activated.
Some apps were already using an action with this name, in these cases no action will be created.
One thing that's not possible anymore is overriding the dialog for specific windows (gtk_application_window_set_help_overlay()). This feature was extremely rarely used, and apps that really want different dialogs for different windows can just create the dialogs themselves instead of using auto-loading - this is just convenience API for the most common case.
Shortcut label
One of the widgets that was deprecated is GtkShortcutLabel. However, it had uses outside of the shortcuts dialog as well. So, libadwaita has a replacement as well - AdwShortcutLabel. Unlike the dialog itself, this is a direct fork of the GTK widget, and works the same way - though the separation between individual keycaps looks a bit different now, hopefully to make it clearer:
It also has a slightly different style, but it's been backported for GtkShortcutLabel as well for the most part.
And, unlike the shortcuts dialog, AdwShortcutLabel is a drop-in replacement.
CSS improvements
Media queries
This cycle, GTK has added support for CSS media queries, allowing to define styles for light and dark, as well as regular and high contrast styles in the same file.
Media queries is fully supported on libadwaita side, and apps are encouraged to use them instead of style-dark.css, style-hc.css and style-hc-dark.css. Since this happened right at the end of the cycle (after the feature and API freeze, in fact, since GTK doesn't follow it), they are not deprecated just yet, but will be early next cycle.
Since we now have support for both variables and media queries, it's possible to do things like this now:
:root {
--card-border: var(--card-shade-color);
}
@media (prefers-contrast: more) {
:root {
--card-border: var(--border-color);
}
}
.card-separator {
background: var(--card-border);
}
Typography
Last cycle, I added document and monospace font variables and mentioned that the document font may change in future to be distinct from the UI font.
This has happened now, and it is actually distinct - Adwaita Sans 12pt instead of 11pt.
So - to mirror .monospace, there's now a .document style class as well. It uses the document font, and also increases the line height for better readability.
Additionally, the formerly mostly useless .body style class increases line height as well now, instead of just setting the default font size and weight. Apps should use it when displaying medium-long text, and libadwaita is using it in a bunch of standard widgets, such as in preferences group and status page descriptions, alert dialog body, or various pages in the about dialog.
Fractal and Podcasts are already making use of both, and hopefully soon more apps will follow suit.
Other changes
-
AdwPreferencesGroupcan now be used with list models viaadw_preferences_group_bind_model(). -
For convenience, it also allows adding rows that aren't
AdwPreferencesRowto the internal list now, rather than treating them as other widgets. These rows will just not be searchable inAdwPreferencesDialog. -
AdwPreferencesPagehas a way to insert groups anywhere now, rather than just append them at the end. -
Both
AdwPreferencesGroupandAdwPreferencesPagenow have a way to inspect their groups/rows without peeking into their implementation:adw_preferences_page_get_group()andadw_preferences_group_get_row(). -
AdwWrapBoxnow has a way to remove all children at once. -
GtkFlowBoxchildren have hover and active styles by default. Apps that use flowboxes in non-standard ways may need to disable this from CSS in some cases. -
AdwHeaderBarnow supports native window controls on macOS, same asGtkHeaderBarfrom the last cycle. -
Window, dialog and sheet shadows have been reduced to increase performance.
Future
While this cycle was pretty short and unexciting, there's a thing in works for the next cycle.
One of the most glaring omissions right now is sidebars. While we have split views, we don't have anything pre-built that could go into the sidebar pane - it's up to the apps to invent something using GtkListBox or GtkListView, combined with the .navigation-sidebar style class.
This is a lot messier than it may seem, and results in every app having sidebars that look and behave slightly different. We have helpers for boxed lists, so why not sidebars too?
There is also GtkStackSidebar, but it's not flexible at all and doesn't play well with mobile phones.
Additionally, on mobile especially sidebars look and behave extremely out of place, and it would be nice to do something about - e.g. use boxed lists instead.
So, next cycle we'll (hopefully) have both a generic sidebar widget, and a stack sidebar replacement. They won't cover all of the use cases (I expect it to be useful for Builder's preferences dialog but not the main window), but a lot of apps don't do anything extraordinary and it should save them a lot of effort.
Thanks to the GNOME STF Team for providing the funding for this work. Also thanks to the GNOME Foundation for their support and thanks to all the contributors who made this release possible.
