GTK4 Supported Themes Proposal
A proposal for explicit opt-in declaration of allowed themes by applications and libraries, and explicit opt-in end-user theme override.
GTK themes can introduce issues in applications which do not support them. This has led some applications or libraries to print errors when the theme is unsupported (such as nemo), or only support a specific set of themes to be loaded (such as libadwaita). This flexibility is useful for some applications, but limited, and difficult to code. Additionally, without making this explicit, users of applications may be surprised when their theme preferences are not applied.
In the interest of providing applications and end users with the most flexibility, I propose creating a GTKApplication interface for supporting specific themes to be loaded. This interface would be opt-in, and backwards compatible. Widget libraries like libadwaita could choose to utilize it by default, instead of a custom implementation. Applications could choose to either support all themes, like the current behavior, or only a specific set.
Here is some Rust flavored psuedocode that demonstrates the potential interface. Alternatively, it could be named "SupportedStyles" if that is clearer. I also tried the word "Allow" instead of "Support", and thought it could work, but was not as specific to what it is doing.
I would also want to consider adding a GTK command line option allowing the override of this. This
would allow the supported themes to be overriden by an end user, by passing an argument explicitly
like --gtk-force-unsupported-theme
.
use glib::g_warning;
use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, SupportedThemes, SupportedThemesLoad};
fn main() {
// Create a new supported themes object. This will filter the theme from the default gtk
// settings to what the application (or library) supports.
let supported_themes = SupportedThemes::new();
// Defaults to true, which makes this backwards compatible. Setting to false will force the
// application to load the default GTK stylesheet unless the selected theme is supported
// (depending on the unsupported signal)
supported_themes.support_any(false);
// Support some themes. In this case, I have explicitly supported only the light theme
// variants of some common themes.
supported_themes.support("Arc");
supported_themes.support("Pop");
supported_themes.support("Yaru");
// Set a handler for when the theme is unsupported. By default, unsupported themes will not be
// loaded, printing a message that the GTK default will be loaded instead. An override like
// this can print a different message and decide to load unsupported themes anyways. This will
// be called any time the theme is changed and is not supported.
supported_themes.connect_unsupported(|_supported_themes, theme_name| {
g_warning!("SupportedThemesExample does not support the '{}' theme", theme_name);
g_warning!("Please report issues to the theme developer instead");
// Return Allow to continue loading the theme, Deny to load the GTK default theme. This
// lets an application decide if they want to warn the user about an unsupported theme or
// just not load it.
SupportedThemesLoad::Allow
});
// Application now has a supported_themes settings. If not provided, it defaults to supporting
// any theme (same as supported_themes.support_any(true)).
let app = Application::builder()
.application_id("org.gnome.SupportedThemesExample")
.supported_themes(&supported_themes)
.build();
// The rest is boilerplate for launching a window, with a supported theme
app.connect_activate(|app| {
let window = ApplicationWindow::builder()
.application(app)
.default_width(320)
.default_height(200)
.title("Supported Themes Example")
.build();
window.show();
});
app.run();
}