Custom Style

GTK+ is using css for styling widgets nowadays. While it is not a 10% conformant css implementation, it is getting more and more complete and expressive. Applications can use this powerful machinery to change how widgets are rendered - both its own custom widgets and stock GTK+ widgets.

A possible problem here is that custom styles may look fantastic with the theme that the developer was using at the time, but appear out-of-place (or even unusable) with another theme.

This HowDoI page aims to show best practices to get the most out of custom CSS while minimizing the downsides.

Standard Style Classes

UI elements with similar functions should look similar, to help the user infer the function. GTK+ defines style classes for a broad range of 'standard' widgets, which you should use where appropriate, to 'inherit' theming for your custom widgets.

E.g. if you have a MyEntry widget that works similar to an entry, it is a good idea to reuse the predefined "entry" style class. In C code, you would place this fragment in your instance init function:

  context = gtk_widget_get_style_context (widget);
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY);

If you are using a template to define your widget, you can also place this information in the .ui file:

    <class name="entry"/>

Custom Style Classes

You are not limited to using the style classes that are predefined in GTK+, you can add your own, and refer to them from your custom CSS. This is preferable to hardcoding the class name in the CSS. But be aware that it is unlikely that 3rd party themes will provide styling for your custom style classes, so you should have a default style that works reasonably.

Custom CSS

Custom CSS style sheets can be associated with individual widgets, or applied for the whole application. In most cases, the latter will be more practical. To avoid extra disk I/O, it is common to store custom CSS in resources. This can look as follows:

  screen = gdk_screen_get_default ();
  provider = gtk_css_provider_new ();
  gtk_css_provider_load_from_resource (provider, "/application/xyz/custom.css");
  gtk_style_context_add_provider_for_screen (screen, provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

And you must not forget to set up the resource for inclusion in your .gresource.xml file:

  <gresource prefix="/application/xyz">

Theme Changes

GTK+ includes the Adwaita and HighContrast themes, but users are equally likely to use 3rd party themes. To work well in this case, you should consider only loading custom CSS for themes that you have tested it with. To achieve this, you should set up a signal handler that listens to theme changes, and reloads the style provider accordingly:

static void
theme_changed (GtkSettings *settings, GParamSpec *pspec, MyApplication *app)
  g_autofree gchar *theme = NULL;

  g_object_get (settings, "gtk-theme-name", &theme, NULL);
  if (g_strcmp0 (theme, "HighContrast") == 0)
    gtk_css_provider_load_from_resource (app->provider, "/application/xyz/highcontrast.css");
  else if (g_strcmp0 (theme, "Adwaita") == 0)
    gtk_css_provider_load_from_resource (app->provider, "/application/xyz/adwaita.css");
    gtk_css_provider_load_from_resource (app->provider, "/application/xyz/default.css");

  g_signal_connect (gtk_settings_get_default (), "notify::gtk-theme-name",
                    G_CALLBACK (theme_changed), app);

Of course, you can include suitable css for other themes as well.