Resource Bundles

Some Relm4 apps require static assets or resources (such as icons or images) to function.

In GTK apps, static assets are transformed into GResource bundles, which are then loaded by the app. This guide shows how to set up GResource bundles within a Relm4 project.

Cargo

This demonstrates a Cargo-only approach to including resources (i.e. it does not require extra build tools like Meson, or out-of-band shell scripts).

data directory

We add the static resources (in this example, icon files), plus a gresource descriptor, to the project's data folder:

data/
  icons/
    icon-foo.svg
    icon-bar.svg
  icons.gresource.xml

The icons are placed under the data/icons directory.

The icons.gresource.xml file looks like this (adapt it as required, e.g. using -symbolic icon names):

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
    <gresource prefix="com/example/Foobar/icons/24x24/actions/">
        <file preprocess="xml-stripblanks" alias="icon-foo.svg">icons/icon-foo.svg</file>
        <file preprocess="xml-stripblanks" alias="icon-bar.svg">icons/icon-bar.svg</file>
    </gresource>
</gresources>

Cargo.toml

In Cargo.toml, we add a build dependency on glib-build-tools. This gives us access to the glib_build_tools::compile_resources function which we will need later:

[package]
name = "foobar"

[build-dependencies]
glib-build-tools = "0.17.10"

Note: you should ensure that the glib-build-tools version aligns with the general GLib version you are building for.

build.rs

In build.rs, we call the compile_resources function which creates a GResource bundle from the icons:

use glib_build_tools::compile_resources;

fn main() {
    compile_resources(
        &["data"],
        "data/icons.gresource.xml",
        "icons.gresource",
    );
}

main.rs

In main.rs (or wherever you initialise your Relm4 app), we load the icons.gresource bundle that Cargo generates:

fn initialize_custom_icons() {
    gio::resources_register_include!("icons.gresource").unwrap();

    let display = gdk::Display::default().unwrap();
    let theme = gtk::IconTheme::for_display(&display);
    theme.add_resource_path("/com/example/Foobar/icons");
}

fn main() {
    let app = RelmApp::new("com.example.Foobar");

    // (optional) initialize default icons
    relm4_icons::initialize_icons();

    // custom icons
    initialize_custom_icons();
}

It should now be possible to reference the resources by name within your app, for example:

#![allow(unused)]
fn main() {
view! {
    gtk::Button {
        set_icon_name: "icon-foo"
    }
}
}