Taiko2k / GTK4PythonTutorial

GTK4 + Python tutorial with code examples
438 stars 33 forks source link

Adding an application icon #6

Open zevlee opened 2 years ago

zevlee commented 2 years ago

Has anyone had success with adding an application icon for Wayland sessions? I'm posting this issue both to ask for help and to show what I've done so far.

The "right" way to do it

GTK4 applications are expected to follow the Freedesktop Icon Theme Specification. Icons should be installed to the icon directory, typically /usr/share/icons or ~/.local/share/icons. The icon is supposed to be named according to the application ID, such as com.example.myapp.svg

Then the application icon can be set for a window by using the set_icon_name method.

my_window = Gtk.Window()
my_window.set_icon_name("com.example.myapp")

However, this doesn't work for all use cases, such as AppImages. When using an AppImage intergration program like AppImageLauncher, icons are saved to the desktop with a hash, using a format similar to appimagekit_3e227aae859f2298ca6d5802f48f6f5b_com.example.myapp.svg so these icons won't be found using the above code. There is, however, a workaround.

The workaround

By adapting some code found in this StackExchange question, we can get an icon to show for our application.

icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
icon_theme.add_search_path("/path/to/resource/directory")

This, in addition to the earlier code block for our window, will allow us to add an icon for our application. There's one problem, though. Adding an application icon only seems to work for Xorg sessions. I've been unsuccessful at getting this method to work for Wayland.

I'm honestly a bit stumped with this one. Anyone have a clue as to how to get this working?

ergoithz commented 2 years ago

I might add that, in general, using importlib is the recommended pythonic way of pointing to module resources, in this case to get a path for Gtk.IconTheme.add_search_path .

Updating that example (tested on Python 3.9+), assuming your module is my_package with a subdirectory (aka PEP 420 python namespace) called icons (containing an directory tree like hicolor/scalable/apps/icon.svg):

icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
module_spec = importlib.util.find_spec('my_package.icons')
search_locations = module_spec.submodule_search_locations if module_spec else ()
for path in search_locations:
    icon_theme.add_search_path(path)

Just don't forget to specify zip_save=False on your package metadata and add that icon package namespace to your package data.