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.
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.
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=falseIcon= 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/applicationsInto 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/hicolorInstall 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.xmlAppStream
is
authoritative for the format.
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/mimeFor an existing type such as EPUB, no registration is needed — just
write
MimeType=application/epub+zip;.
This is the part that matters here.
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 "$@"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.
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.
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.MyReaderStartupWMClass is also what ties your window to its
icon. If the taskbar
shows a generic icon, this is what is wrong.
# .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')"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.