Putting it on the desktop

Author: BlinkGTK Project
Version: 1.2.0-build2

Once your application runs, the next step is making it look like an
application
: appearing in the app list, having an icon, showing up in the
software centre. This page covers that.

Very little of it is BlinkGTK-specific — it is the ordinary work of a GTK4
application
. So the specifications themselves are left to freedesktop.org and
GNOME, and what follows concentrates on what to watch out for when the app is
built on BlinkGTK
.

Choose an application ID

This comes first. Use reverse-domain form.

org.example.MyReader

Use that same string everywhere:

Where Form
.desktop filename org.example.MyReader.desktop
AppStream filename org.example.MyReader.metainfo.xml
Icon filename org.example.MyReader.svg
GtkApplication ID gtk_application_new("org.example.MyReader", ...)

If they do not match, no icon appears. The desktop matches your window to
its icon through this ID.

Appear in the app list (.desktop)

Install to /usr/share/applications/org.example.MyReader.desktop.

[Desktop Entry]
Type=Application
Name=My Reader
Comment=An e-book reader
Exec=/usr/bin/my-reader %f
Icon=org.example.MyReader
Categories=Office;Viewer;
MimeType=application/epub+zip;
Terminal=false

Icon= takes neither an extension nor a path — just the application ID.

The Desktop Entry Specification
is authoritative for the format.

Then refresh the index:

sudo update-desktop-database /usr/share/applications

Install an icon

Into the hicolor theme, named after the application ID. One SVG is enough.

/usr/share/icons/hicolor/scalable/apps/org.example.MyReader.svg

If you also ship PNGs, put them in per-size directories:

/usr/share/icons/hicolor/48x48/apps/org.example.MyReader.png
/usr/share/icons/hicolor/256x256/apps/org.example.MyReader.png

Refresh the cache:

sudo gtk4-update-icon-cache /usr/share/icons/hicolor

Appear in software centres (AppStream)

Install to /usr/share/metainfo/org.example.MyReader.metainfo.xml.

<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
  <id>org.example.MyReader</id>
  <name>My Reader</name>
  <summary>An e-book reader</summary>
  <metadata_license>CC0-1.0</metadata_license>
  <project_license>MIT</project_license>
  <description>
    <p>Reads EPUB 3 with vertical Japanese typesetting.</p>
  </description>
  <launchable type="desktop-id">org.example.MyReader.desktop</launchable>
  <screenshots>
    <screenshot type="default">
      <image>https://example.org/screenshot.png</image>
    </screenshot>
  </screenshots>
  <releases>
    <release version="1.0.0" date="2026-08-05"/>
  </releases>
</component>

You can validate it:

appstreamcli validate /usr/share/metainfo/org.example.MyReader.metainfo.xml

AppStream is
authoritative for the format.

Associate file types

List them in MimeType= in the .desktop file. If your format is your own,
register the MIME type as well:

<!-- /usr/share/mime/packages/org.example.MyReader.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
  <mime-type type="application/x-myreader-book">
    <comment>My Reader book</comment>
    <glob pattern="*.mrb"/>
  </mime-type>
</mime-info>
sudo update-mime-database /usr/share/mime

For an existing type such as EPUB, no registration is needed — just write
MimeType=application/epub+zip;.


What to watch out for with BlinkGTK

This is the part that matters here.

Say that it needs Wayland

BlinkGTK runs only on Wayland. It will not start in an X11 session.

Launched from a .desktop entry, all the user sees is "I clicked it and nothing
happened". Stating the requirement in the AppStream <description> lets them
find out before installing.

<p>Requires a Wayland session. Does not run on X11.</p>

Checking in a launcher script and failing visibly is another option:

#!/bin/sh
if [ -z "$WAYLAND_DISPLAY" ]; then
  echo "This application requires a Wayland session." >&2
  exit 1
fi
exec /usr/libexec/my-reader "$@"

Derive resource paths from the executable

BlinkGTK needs Chromium's resources (icudtl.dat, the .pak files, the V8
snapshots). When launched from a .desktop entry the working directory is
undefined
, so anything relative will not be found.

/* Decide from the install location. Never rely on the working directory */
blink_gtk_set_resources_path("/usr/lib64/my-reader");
blink_gtk_set_icu_data_path("/usr/lib64/my-reader");

If an application that works from a terminal fails to start via its .desktop
entry, suspect this first.

If you want a single instance

Using GtkApplication's single-instance behaviour needs care with the main
loop
. g_application_run() does not turn Chromium's loop, so on its own
nothing renders.

The shape is in Integrate into your application.

Make startup look responsive

BlinkGTK brings up Chromium's processes at startup, so nothing appears for
about a second
. These lines let the desktop show that something is starting:

StartupNotify=true
StartupWMClass=org.example.MyReader

StartupWMClass is also what ties your window to its icon. If the taskbar
shows a generic icon
, this is what is wrong.


Check your work

# .desktop format
desktop-file-validate /usr/share/applications/org.example.MyReader.desktop

# AppStream format
appstreamcli validate /usr/share/metainfo/org.example.MyReader.metainfo.xml

# Can the icon be found?
python3 -c "
import gi; gi.require_version('Gtk','4.0')
from gi.repository import Gtk, Gdk
Gtk.init()
t = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
print('found' if t.has_icon('org.example.MyReader') else 'not found')"

Shipping in a package

For an RPM or DEB, install these four:

/usr/share/applications/org.example.MyReader.desktop
/usr/share/icons/hicolor/scalable/apps/org.example.MyReader.svg
/usr/share/metainfo/org.example.MyReader.metainfo.xml
/usr/share/mime/packages/org.example.MyReader.xml   (own formats only)

Package managers refresh the indexes for you, so %post scriptlets are normally
unnecessary.