How to set custom icons?

How would I be able to set custom icons via CSS?

menubutton arrow {
    /* -gtk-icon-source: -gtk-icontheme('window-close'); */
    -gtk-icon-source: image('close.png');
}

This doesn’t seem to be possible, even though the documentation says “-gtk-icon-source” accepts " Image, builtin or none".

Looking up the link, it shows how to use the image() CSS function, so why doesn’t it work? What’s the correct way of setting a custom icon for GTK?

Say I want to set the X button from the WindowControls to instead be a SVG from Google Material Icons, how would I do that?

Hi,

Looking at the source code, it looks like the WindowControls are not themable by CSS, as they use GtkImage widgets with hardcoded icon names, and as far as i understand GtkImages will override whatever CSS icon is assigned (should have used a simple widget like gtk_builtin_icon instead for this to work).

Looks like you have to:

  • create a new icon theme, let’s say “SuperAdwaita”, by copying the folders structure and index.theme from the Adwaita one.
  • in the index.theme file, inherit from Adwaita:
[Icon Theme]
Name=SuperAdwaita
Inherits=Adwaita
  • just add the new “window-close-symbolic” icons in appropriate subfolders, no need to add any other icons.
  • set “SuperAdwaita” as your icon theme in the settings.

Side notes:

  • in CSS3 “image” is a typedef, for getting an image reference I think you should use “url” instead:
    -gtk-icon-source: url("close.png");
  • but anyway themed symbolic icons (i.e. -gtk-icontheme) should be preferred, because they automatically recolor on dark/light themes.
1 Like

Hello,

Thanks for the reply! Since I’m using gtkrs, how would I exactly be able to do this?

  • set “SuperAdwaita” as your icon theme in the settings.

My guess is if I’m changing the GTK Icon theme to SuperAdwaita on the system level, it won’t export when I build the project as an executable.

Is there some sort of function that I can use when initializing the window that sets the GTK Icon theme?

Ah, it’s for a single application only, not system-wide?

In this case, no need of CSS or custom icon themes; just name your new icon to window-close-symbolic.svg and embed it as GResource.

You will need a resource XML file (replace “/org/example/App” by your app-ID):

<gresources>
  <gresource prefix="/org/example/App/icons/symbolic/ui">
    <file>window-close-symbolic.svg</file>
  </gresource>
</gresources>

There is a guide how to embed a GResource with Rust in the doc (the example is for composite templates, but works the same way for icons).

See also the GTK icons doc.

1 Like

Thanks for the reply!

I’ve tried your solution and it worked - but the icon wasn’t found.
image
My guess is that the icon_name is invalid, here’s how I set it:

    gtk::gio::resources_register_include!("icons.gresource").unwrap();
    // [...]
    let x = gtk::Button::builder().css_name("tab-close").build();

    x.set_icon_name("close");

And here’s how the GResource looks like:

<gresources>
  <gresource prefix="/org/a/b/icons/symbolic/ui">
    <file>close.svg</file>
  </gresource>
</gresources>

I’m curious how the gresource finds the name for the file icon, does it take everything before the .[extension]? Maybe I’m missing an attribute for the icon name, although looking at the GTK icons docs, my code seems about right.

Here’s the file structure in case it helps!
image

There is some info in the GtkApplication docs:

GtkApplication will also automatically setup an icon search path for the default icon theme by appending “icons” to the resource base path.

Not sure what’s wrong here, your example looks correct.

Do you use a GtkApplication for auto-loading? and do you call resources_register_include before calling the application’s run() ?

Do you use a GtkApplication for auto-loading? and do you call resources_register_include before calling the application’s run() ?

Yeah, here’s the main function:

fn main() -> glib::ExitCode {
    gtk::gio::resources_register_include!("icons.gresource").unwrap();

    let app = adw::Application::builder().application_id(APP_ID).build();

    app.connect_startup(|_| load_css());
    app.connect_activate(build_ui);

    app.run()
}

Maybe the last 2 parts of the gresource prefix have a connection to this? Since I haven’t seen them be used anywhere else in the icons docs
<gresource prefix="/org/a/b/icons/symbolic/ui">

The icon seems to be set correctly in the GTK inspector, so I have no clue what went wrong either
image

These subpaths are defined in the default index.theme which is embedded in the libgtk library.

Well, now that I look at it, indeed this “symbolic/ui” subpath isn’t listed there… (I took the subpath based on my local Adwaita icon theme, that may be incorrect…)

When I look into the libgtk resouces, there are actually multiple instances of the window-close-symbolic icons, in scalable and raster (png) formats. I suspect that when a raster is present, gtk will use it, to avoid expensive SVG conversions. But exactly which resolution will depend on the scaling factor, I think (by 1:1 the 16x16 should be the one used I suppose)

I fear that you’ll have to override all the occurrences of window-close-symbolic to be sure to always load your version.

There is a debug variable to print infos about how gtk resolves its themed icons, let me recheck…

Found it, it’s
GTK_DEBUG=icontheme
(source)

Well, now that I look at it, indeed this “symbolic/ui” subpath isn’t listed there

That was it!
The icon showing up

It works if the prefix is like this:

<gresources>
  <gresource prefix="/org/a/b/icons/">
    <file>close.svg</file>
  </gresource>
</gresources>

I’m gonna try to list all the necessary code for people that run into the same problems.

The Rust source code:

// main.rs
gtk::gio::resources_register_include!("icons.gresource").unwrap();
// build.rs
fn main() {
    glib_build_tools::compile_resources(
        &["src/resources"],
        "src/resources/icons.gresource.xml",
        "icons.gresource",
    );
}
// whereever you have a GTK widget
variable.set_icon_name("close");

File structure:
image

One last question - how can I set the icon names for the WindowControls widget?
image
image

I suppose I have to create a new WindowControls and replace the existing one, then loop through each button and set their icons, but if I recall correctly creating another WindowControls wasn’t the correct way of doing it.

Assuming the close icon is already registered in the application, I tried the -gtk-icon-source CSS property on .close class, yet nothing changed.

Great news! :slight_smile:

Regarding CSS, it’s not possible to use -gtk-icon-source to change the icon. Only widget that call gtk_css_style_snapshot_icon() in their snapshot() can support that, which is not the case of Gtk.Image.

Looping through the WindowControls and calling set_icon_name() is a possible solution.
Or create your own widget (a GtkBox respecting the decoration-layout) with custom buttons.

1 Like