Common interface for platform libraries
GTK4 embraced the concept of platform libraries, and while some desktops aren't interested in having one, there are 2 prominent libraries: libadwaita and Granite (elementary).
They handle things like color scheme and accent color independently of GTK.
Right now GTK still has a way to tell if a particular app is light or dark using GtkSettings:gtk-application-prefer-dark-theme
but it will go away in GTK5.
As for accent color, the only generic way to tell the current accent color is to use gtk_style_context_lookup_color()
, which is deprecated and doesn't work with variables.
Most of the time this is fine, since the platform libraries already provide API for querying things. However, there are a few areas where it's not enough:
-
@media (prefers-color-scheme: dark)
needs to know the current color scheme. So doeslight-dark()
. -
Libraries like WebKitGTK need to know the app's current color scheme, accent color and whether it's using high contrast without depending on any specific platform library and don't have a way forward atm
-
GTK uses
gtk-application-prefer-color-scheme
to control X11 titlebar color scheme. One way to fix this would be to drop X11 support, but right now it exists and it's worth mentioning
Potential solutions
There are multiple ways to deal with this:
-
Platform libraries could be responsible for setting some flag on their css providers to make
prefers-color-scheme
andlight-dark()
work, but that would mean apps would need to set it manually, and libraries like webkit still don't have a way to set it -
GTK could handle accents and color schemes itself. Plenty of problems here, e.g. the fact the current platform libraries already disagree on how to handle them, so I'm not sure GTK would be able to reconcile it. Note that it does not boil down to reading a preference from portal for 2 reasons:
-
We care about the app's current color scheme and accent here, not what the system prefers. If the app is currently dark when the system says "color-scheme: no-preference", then it's dark. Same with accent. So GTK would need API for controlling that too, and that gets messy very fast.
-
We need some way to get those prefs without portal too, so that GNOME and elementary portals themselves can be implemented without infinite recursion of reading settings from themselves. And GNOME and elementary store accent-color and color-scheme in very different places (elementary isn't even using gsettings).
-
Libadwaita exposes them in inspector, which is very useful for testing. Ideally anything we come up with should still work with that.
-
It also has environment variables for running with a specific configuration, that Builder exposes in its UI (not accent color yet since it's very recent, only color scheme and high contrast).
- There could be a common API that platform libraries can plug into and report their styles. This seems the most promising as it gives a generic API to GTK and webkit and leaves all the decisions to platform libraries.
Potential API
#define GTK_TYPE_PLATFORM (gtk_platform_get_type ())
G_DECLARE_INTERFACE (GtkPlatform, gtk_platform, GTK, ICON_PROVIDER, GObject)
struct _GtkPlatformInterface
{
GTypeInterface g_iface;
gboolean (* get_is_dark) (GtkPlatform *platform);
gboolean (* get_is_high_contrast) (GtkPlatform *platform);
void (* get_accent_color) (GtkPlatform *platform,
GtkWidget *widget,
GdkRGBA *rgba);
};
gboolean gtk_platform_get_is_dark (GtkPlatform *self);
gboolean gtk_platform_get_high_contrast (GtkPlatform *self);
void gtk_platform_get_accent_color (GtkPlatform *platform,
GtkWidget *widget,
GdkRGBA *rgba);
/* called by platform libraries in their _init(),
* possibly should be global instead of per-display */
void gtk_platform_set_for_display (GdkDisplay *display,
GtkPlatform *platform);
GtkPlatform *gtk_platform_get_for_display (GdkDisplay *display);
GtkPlatform *gtk_platform_get_default (void);
Note that accent color has to be per-widget. Libadwaita already has plenty of widgets using separate accents even in its own styles (e.g. white for .osd
, red for .error
etc).
It could also encompass GtkIconProvider
in future, whether as a separate interface or just merged together.
Problems
One big problem I can see is that libadwaita doesn't really have a way to fetch the accent color atm. It can fetch the system color just fine, but the current accent color is a CSS variable, and we don't have a way to read them. A workaround right now is lookup_color()
and legacy colors, but since it's deprecated and doesn't work with variables, it defeats the point. So we'd need to figure out something for this first.
Feedback from Granite people (and anyone else interested) would be appreciated.
CC @sonny