I was bored.

Still need a libhandy version for GTK3, and need to discuss the whole approach and the portal key name.

But it works. The code in Builder shows how it looks like from an app's side, that's the whole thing other than meson/flatpak bits.

The one unified cross-desktop entry point here is the settings portal, meaning e.g. @elementary can easily support it in their portal implementation, while still storing their backing preference wherever wanted.

Oh, and don't pay attention to that plain switch in settings, this is mostly about backend/libadwaita/app side. How it would look in settings can be figured out separately.

One thing that I didn't like in the elementary implementation is the app-side API. It was pretty finicky having to bind gtk-application-dark-theme manually.

So this one is higher level, but also less flexible. There's an AdwApplication:color-scheme property which takes values: light, light-dark, dark-light, dark, inspired by CSS `color-scheme`. Their values are as follows:

light: always light;
light-dark: light normally; dark in prefer-dark;
dark-light: dark normally; light in prefer-light;
dark: always dark;

The default value is light.

From a more practical point of view:

light-dark is for regular apps that want to follow the preference;
dark-light is for media apps that want dark appearance but still want to support light with the high contrast pref;
light and dark are for hardcoding appearance.

This is less free-form as apps can't do things such as having dark appearance in light variant and vice versa. But realistically it's not going to be a very common use.

Additionally, high contrast's actual high contrastness is not opt-in. But the prefer-light part is.

Separately from that, there are read-only boolean properties `dark` and `high-contrast`, which can be used for querying the current appearance as controlled via app and system color schemes.

To clarify here a bit - what it means is apps can't do things such as having inverse of the system color scheme - light when the system is dark and vice versa at the same time.

I'm open to adding more app color-scheme values if needed though.

Also, color scheme can be changed in runtime, so for example, a text editor can easily switch between `light` and `dark` without the system pref interfering.

In practice, I don't think it really matters, but it seemed significant enough to mention.

Now works with inspector too. Also libhandy and libadwaita try to do their best to block CSS transitions; sadly it's not possible to do in a 100% reliable way without GTK-side changes.

With no app-side transitions, it should be possible to crossfade everything on compositor.


This looks like it's per application. As you are touching this code, would you consider to make this per window?

For some applications it does make sense to have the color scheme per window. Example would be a chat app that also supports video calls - the chat window would be light-dark, but the window with the video call would be rather dark-light.

Back in the days, Empathy had the hack to run the video call window in another process, so that its GtkApplication can be dark theme.

@larma I wish it could be possible, but it's not. Styles can be:

1. global
2. per-widget _non-recursively_

@larma technically you could track children via `gtk_widget_observe_children()`, but it would slow things to a crawl in certain cases - just try scrolling a `GtkListView` with >200 items in it while looking at it in inspector, for example. It will be like 1 fps.

@larma so really you'd need GTK-level support for this. This would have also helped a lot for accent color.

The perfect solution from libadwaita pov would be CSS variables. We could quite easily reduce dark variant to just a different set of variables and apply it to windows and let them propagate. But of course GTK doesn't support that and `@define-color` is global as well.

@larma although there's a slightly less horrible way, but still not nice: have a display per window. We could provide API to override this for a specific display.

@larma and we do now. You can use adw_style_manager_get_for_display() and override colors for the specific display there. It's still not seamless, but better than 2 processes at least.

Each of the windows which has an override switch in that demo runs on a separate GdkDisplay, the 2 without switches are on the default one. All in the same GApplication.

Sign in to participate in the conversation

For people who care about, support, or build Free, Libre, and Open Source Software (FLOSS).