Well, another cycle has passed.
This one was fairly slow, but nevertheless has a major new feature.
Adaptive Dialogs
The biggest feature this time is the new dialog widgetry.
Traditionally, dialogs have been separate windows. While this approach generally works, we never figured out how to reasonably support that on mobile. There was a downstream patch for auto-maximizing dialogs, which in turn required them to be resizable, which is not great on desktop, and the patch was hacky and never really supported upstream.
Another problem is close buttons – we want to keep them in dialogs instead of needing to go to overview to close every dialog, and that’s why mobile gnome-shell doesn’t hide close buttons at all atm. Ideally we want to keep them in dialogs, but be able to remove them everywhere else.
While it would be possible to have shell present dialogs differently, another approach is to move them to the client instead. That’s not a new approach, here are some existing examples:
This has both upsides and downsides. One upside is that the toolkit/app has much more control over them. For example, it’s very easy to ensure their size doesn’t exceed the parent window. While this is possible with windows (AdwMessageDialog
does this), it’s hacky and can still break fairly easily with e.g. maximize – in fact, I’m not confident it works across compositors and in both Wayland and X11.
Having dialogs not exceed the parent’s size means not needing to limit their size quite so aggressively – previously it was needed so that the dialog doesn’t get ridiculously large on top of a small window.
The dimming behind the dialog can also vary between light and dark styles – shell cannot do that because it doesn’t know if this particular window is light or dark, only what the whole system prefers.
In future this should also allow to support per-tab dialogs. For apps like web browsers, a background tab spawning a dialog that takes over the whole window is not great.
Meanwhile the main downside is the same thing as was listed in upsides: these dialogs cannot exceed the parent window’s size. Sometimes it’s still needed, e.g. if the parent window is really small.
Bottom Sheets
So, how does that help on mobile? Well, aside from just implementing the existing size constraints on AdwMessageDialog
more cleanly, it allows to present these dialogs as bottom sheets on mobile, instead of centered floating sheets.
A previous design has presented dialogs as pages with back buttons, but that had many other problems, especially on small windows on desktop. For example, what happens if you close the window? A dialog and a “regular” subpage would look identical, so you’d probably expect the close button to close the entire window? But if it’s floating above a larger window?
Bottom sheets avoid this issue – you still see the parent window with its own close button, so it’s obvious that they are closed separately – while still being allowed to take full width like a subpage.
They can also be swiped down, though because of GTK limitations this does not work together with scrolling content. It’s still possible to swipe down from header bar or the empty space above the sheet.
And the fact they are attached to the bottom edge makes them easier to reach on huge phones.
Meanwhile, AdwHeaderBar
always shows a close button within dialogs, regardless of the system layout. The only hint it takes from the system is whether to display the close button on the right or left side.
API
For the most part they are used similarly to GtkWindow
. The main differences are with presenting and closing dialogs.
The :transient-for
property has been replaced with a parameter in adw_dialog_present()
. It also doesn’t necessarily take a window anymore, but can accept any widget within that window as well. Currently it just fetches the root widget, but once we have per-tab dialogs, that can be controlled with a simple flag instead of needing a new variant of adw_tab_present()
that would take a tab page instead of a window.
The ::close-request
signal has been replaced as well. Because the dialogs can be swiped down on mobile, we need to know if they can be closed before the gesture starts. So, instead there’s a :can-close
property that apps set ahead of time if there’s unsaved data or some other reason to prevent closing.
For close confirmation, there’s a ::close-attempt
signal, which will be fired when trying to close a dialog using a close button or a shortcut while :can-close
is set to FALSE
(or calling adw_dialog_close()
). For actual closing, there’s ::closed
instead.
Finally, adw_dialog_force_close()
closes the dialog while ignoring :can-close
. It can be used to close the dialog after confirmation without needing to fiddle with :can-close
or repeat ::close-attempt
emissions.
If this works well, AdwWindow
may have something similar in future.
The rest is fairly straightforward and is modelled after GtkWindow
. See AdwDialog
docs and migration guide for more details.
Since AdwPreferencesWindow
and other widgets can’t be ported to new dialogs without a significant API break, they have been replaced:
AdwPreferencesWindow
withAdwPreferencesDialog
AdwAboutWindow
withAdwAboutDialog
AdwMessageDialog
withAdwAlertDialog
For the most part they are identical, with a few differences:
AdwPreferencesDialog
has search disabled by default, and gets rid of deprecated subpage APIAdwAlertDialog
can scroll contents, so apps that add their own scrolled windows may want to remove them
Since the new widgets landed right at the end of the cycle, the old widgets are not deprecated yet. However, they will be deprecated next cycle, so it’s recommended to migrate your apps anyway.
Standalone bottom sheets (like in audio players) are not available yet either, but will be in future.
Esc to Close
Traditionally, dialogs have been done via GtkDialog
which handled this automatically. But for the last few years, apps have been steadily moving away from GtkDialog
and by now it’s deprecated. While that’s not really a problem on its own, one thing that GtkDialog
was doing automatically and custom dialogs don’t is closing when pressing Esc. While it’s pretty easy to add that manually, a lot of apps forget to do so.
But since we have dedicated dialog API again, Esc to close is once again automatic.
What about standalone dialogs?
Some dialogs don’t have a parent window. Those are still presented as a window. Note that it still doesn’t work well on mobile: while there will be a close button, the sizing will work just as badly as before, so it’s recommended to avoid them.
Dialogs will also be presented as a window if you try to ad them to a parent that can’t host dialogs (anything that’s not an AdwWindow
or AdwApplicationWindow
), or the parent is not resizable. The reason for the last one is to accommodate apps like Emblem, which has a small non-resizable window, where dialogs won’t fully fit, and since it’s non-resizable, it doesn’t work on mobile anyway.
What about “Attach Modal Dialogs”
Since we have the window-backed mode, it would be fairly easy to support that preference… except there’s no way to read it from sandboxed apps.
What about portals?
This approach obviously doesn’t work for portals, since they are in a separate process. We do have a plan for them, involving a private protocol in mutter, but it didn’t make it for 46. So, next time.
What about GTK built-in dialogs?
Those will be replaced as well, but it takes time. For now yes, GtkShortcutsWindow
etc won’t match other dialogs.
Other Changes
As usual, there are some smaller changes.
- Jamie added the
:text-length
property toAdwEntryRow
. AdwMessageDialog
now hasremove_response()
. While this widget is to be deprecated,AdwAlertDialog
has an equivalent as well.AdwBreakpointBin
now allows to programmatically remove breakpoints.AdwSwipeTracker
now has a flag to allow swiping over header bars – used in bottom sheets.- Shade colors are now lighter in dark style. This was needed for dialog dimming to look good, but also it was previously too dark elsewhere, e.g. in scroll undershoots.
As always, thanks to all the contributors who helped to make this release happen.