How to install icons in Julia or Python Gtk4

I can’t seem to figure out how to install custom icons using the Julia bindings for Gtk4 (Gtk4.jl). I came across this thread which directed me to the themed icons tutorial but this wasn’t helpful unfortunately. I’m wondering if I can ask someone to provide a complete minimum working example in Julia or point me in the right direction, but Python is fine since it seems the binding is more mature.

From the tutorial it seems I need a gresource which is compiled from an XML file, a directory layout that matches the hicolor theme, which I built from the index.theme for hicolor. Matching the template in the tutorial I’ve written for my case the following file named icons.xml located in the ./data/icons subdirectory of the working directory.

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
    <gresource prefix="./data/icons">
        <file>./16x16/actions/my_icon.png</file>
    </gresource>
</gresources>

I compiled this using the glib-compile-resources program in MSYS2 which gives me a file called icons.gresource.

Per the tutorial, the resource is added to the icon theme for the current display in Python as so (modified for the directories in this case)

theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
theme.add_resource_path("./data/icons")

In Julia the functional equivalent is done with this code

using Gtk4
gl = Gtk4.GLib;
theme = GtkIconTheme(Gtk4.G_.get_default());
Gtk4.G_.add_resource_path(theme, "./data/icons");

Finally, the attempt to use the icon in a GtkImage on a GtkWindow is done with the following Julia script

img = GtkImage(icon_name = "my_icon");
win = GtkWindow("test");
push!(win,img);
show(win)

but yields the super sad broken image icon
image

I’m out of ideas so really any support on this is very much appreciated. Thanks and hope to hear from you soon.

Hi,

<gresource prefix="./data/icons">

The “prefix” is a virtual path inside the resources bundle, using relative paths doesn’t make sense, I’m not even sure if that works…
Prefer “/data/icons”, or, even better, use your app ID if you have one, like: “/org/example/app/icons”, so you can skip calling add_resource_path()

Also, you shall load and register the compiled resource file, see GResource doc.

This is fantastic thank you!

I wasn’t sure what that application ID was for the Julia binding or if it’s any different from an application written in C, but I used the following Julia code to get the default resource path for the IconTheme

using Gtk4
gl = Gtk4.GLib;
# get the icon-theme for the default GDK display
theme = GtkIconTheme(Gtk4.G_.get_default());
Gtk4.G_.get_resource_path(theme)

with the result in the REPL as follows. Is this the App ID you’re referring to?

1-element Vector{String}:
 "/org/gtk/libgtk/icons/"

I changed the XML file below accordingly and compiled again with my_icon.png in a temp directory along with the XML file using glib-compile-resources as before to get the resource file.

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
    <gresource prefix="/org/gtk/libgtk/icons/16x16/actions/">
        <file>my_icon.png</file>
    </gresource>
</gresources>

I placed that gresource file in a folder called “icons” in the working directory for the Julia script. The structure within this subdirectory matches hicolor and the prefix in the icons.xml file. Finally I added the load and register bits to the Julia script as shown below along with removing the add_resource_path bit and it works!!!

using Gtk4
gl = Gtk4.GLib;
#load the resource located in the icons directory and register
gl.G_._register(gl.G_.resource_load("./icons/icons.gresource"));
#get theme for default GDK display
theme = GtkIconTheme(Gtk4.G_.get_default());

img = GtkImage(icon_name = "my_icon");
win = GtkWindow("test")
push!(win,img);
show(win);

I’m still fuzzy though on the virtual paths. It feels like a stupid question but how does that work? That path has to inform the program somehow so that it lands at a resource in absolute space, right? And if I wanted to add my own resource path for whatever reason, how would that work? To me this looks like “/org/gtk/libgtk/” is the default resource path setup by the Julia binding in the C runtime and the “/icons/” bit at the end is a relative path to the icons folders of the working directory of the Julia script. Sounds like I’m talking in circles. Set me straight :slight_smile:

Again, many thanks for the support. This is fascinating.

1 Like

Virtual path means that is doesn’t depend on anything (like real path on your disk), so you can theoretically put whatever you want as path. Then you can get that data at runtime from your app with g_resource_lookup_data(), using the path you defined.

However, there are some rules and conventions to follow if you want to benefit of some automated gtk/glib features.

  • when using icons, respect the folders hierarchy from the “index.theme”, as you noticed above.
  • the gtk library puts its embedded data under “/org/gtk/libgtk/”, by convention.
  • also by convention, programs using a GtkApplication or GApplication should assign themselves an application-id , like “org.example.App”, then gtk will use that ID to build a default path “/org/example/App/” in which it will lookup and try to load various things like icon themes, as described in Automatic resources.

You don’t seem to use a GtkApplication in your code, so hijacking the gtk paths like you did is a possible solution, or, to avoid mixing things up, you can use your own self-defined prefix and declare it to the GtkIconTheme with add_resource_path().

Apologies for the delay. This is awesome information. I can’t say I fully understand it but I feel dangerous now :slight_smile:

Towards the end of the Julia binding manual there’s a section for using Gtk4 outside of the REPL using GtkApplication with a minimum example shown below.

using Gtk4

function activate(app)
    win = GtkApplicationWindow(app, "my title")
    show(win)
end

app = GtkApplication()

Gtk4.signal_connect(activate, app, :activate)

run(app)

The GtkApplication function has the following signature (with many different methods), noting the _application_id as the first parameter. Per your guidance I used this method with a chosen application ID and it worked!

GtkApplication(_application_id::Maybe(Union{AbstractString, Symbol}), _flags; kwargs...)

I’ve marked your initial reply as the solution and I appreciate the extra time to teach the additional detail. Many thanks!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.