source/__assets/linux/appimage/README.md
Files used to build and distribute ImageGlass as an AppImage.
| File | Purpose |
|---|---|
io.github.d2phap.imageglass.desktop | Desktop entry for the AppDir. Same as the Flatpak one except Exec=AppRun %F — an AppImage installs nothing on PATH. |
ig-appimage-integrate | Optional desktop integration: offers, on first run, to add a launcher entry + icons to ~/.local/share. |
README.md | This file. |
Everything else is generated by the pack script and not committed: AppRun, .DirIcon,
the icons (copied from __assets/logo_c_512.png / logo_c.svg), the X-AppImage-*
version keys, and the AppDir itself. The AppStream metadata is shared with the
Flatpak — the script reads ../flatpak/io.github.d2phap.imageglass.metainfo.xml, because
it describes the app rather than the packaging, and Flathub's stricter validator keeps it
honest for both.
Build script: ../script-pack-linux-x64-appimage.sh
(VS Code task: pack-linux-x64-appimage).
bash __assets/linux/script-pack-linux-x64-appimage.sh
No prerequisites: the script publishes a fresh AOT build itself and downloads
appimagetool into __artifacts/tools/ on first run (no distro packages it). It prints
the download's sha256 — pin it on later runs so a moving continuous tag cannot swap the
tool silently:
APPIMAGETOOL_SHA256=<hex> bash __assets/linux/script-pack-linux-x64-appimage.sh
Output: __artifacts/bundle/ImageGlass_<version>_linux-x64.AppImage.
appimagetool prints AppStream upstream metadata is missing on every run. It is looking
for the legacy <app-id>.appdata.xml; we ship the modern <app-id>.metainfo.xml, which is
what the AppStream spec, Flathub and the desktop integration tools want, and which
appstreamcli validate accepts. The warning is expected — do not "fix" it by adding a
duplicate .appdata.xml.
Other env overrides: GPG_KEY (sign the image), COMP (zstd default, xz, gzip),
APPIMAGETOOL (use your own copy), NO_APPSTREAM=1, SKIP_PUBLISH=1 (debug only — it
can ship stale code under a new version number).
Unlike the Flatpak, which ships its own runtime, an AppImage runs against the host glibc and host libraries. The script prints the glibc floor of the shipped binaries on every run; check it before a release.
The host must provide:
libX11.so.6, libICE.so.6, libSM.so.6, libXcursor.so.1, libXext.so.6,
libXi.so.6, libXrandr.so.2 (release builds pin .UseX11(), so Wayland goes through
XWayland)libGL.so.1, libfontconfig.so.1libicuuc, libicui18n (DOTNET_ICU_VERSION_OVERRIDE is the
escape hatch on an exotic distro)xdg-utils (xdg-open), glib2 (gdbus), cups-client
(lpr, printing), one of paplay/pw-play/aplay/ffplay (notification sound),
xdg-desktop-portal (set as wallpaper)Debian/Ubuntu: sudo apt install libx11-6 libice6 libsm6 libfontconfig1.
Fedora/RHEL: sudo dnf install libX11 libICE libSM fontconfig.
libgdiplus is not required, despite appearing in Avalonia's install line — that
line targets Avalonia XPF, which uses System.Drawing. ImageGlass renders through
SkiaSharp.
libgomp.so.1 (needed by the Magick codecs) is the only library bundled, and it is used
only when the host has none — LD_LIBRARY_PATH is searched before ld.so.cache, so an
unconditional entry would shadow the host's own glibc-matched copy.
Nothing else is bundled on purpose: libGL is coupled to the host's GPU driver,
libfontconfig must see the user's font configuration, and both are on the AppImage
excludelist.
Settings live in ~/.local/share/ImageGlass, shared with the tarball install. The mount
is read-only, so portable mode is never used and .igportable must never ship inside the
image (the script asserts this — the app would abort at startup). For the same reason a
machine-wide igconfig.admin.json or a Pro license can only be deployed to
~/.local/share/ImageGlass, never next to the app.
AppImages do not install themselves. The app asks, not the packaging: Quick Setup shows
an "Applications menu" step on a first run, and Settings > File type associations has an
"Applications menu" group with Register / Unregister that is always available (Quick Setup
does not run for someone upgrading from the tarball, since both share
~/.local/share/ImageGlass, nor for someone who hits Skip). Both call
ig-appimage-integrate --install, so the Desktop Entry escaping lives in one place.
Registering is an unmanaged setting, and the UI says so: the .desktop entry and the
icons are written to ~/.local/share, outside anything the app owns, so deleting the
.AppImage cannot remove them. TryExec= does keep a stale entry from showing (GLib
refuses to load an entry whose TryExec is missing), but the files remain — unregister
before deleting the image.
The installed entry is the only state; there is no marker file. AppRun runs --maybe on
every launch, which does one thing: re-point an already-registered entry after the
.AppImage is moved or renamed. It never prompts and never registers on its own — a
blocking dialog launched from inside the image would hold the read-only mount open after
the app exits.
Manual control, from inside the mounted or extracted image:
usr/bin/ig-appimage-integrate --install # or --remove
Gear Lever and AppImageLauncher can manage the image instead; they write their own entry and are unaffected by the above.
Upload the .AppImage to the release matching the tag
(<IgVersion>[-<IgReleaseType>]). Users download it, chmod +x, and run it — no
installer, no root.
GPG_KEY="<your-key-id-or-email>" bash __assets/linux/script-pack-linux-x64-appimage.sh
Signing is optional. AppImage signature-verification tooling is rarely installed, so publish the sha256 the script prints — that is the check most people will actually run.
If the image will not start on an older host, it is almost always the glibc floor; the
error is version 'GLIBC_2.xx' not found. A FUSE-less host needs:
./ImageGlass_<version>_linux-x64.AppImage --appimage-extract-and-run