Skip to content

Add Flatpak support for Linux#185

Open
candrewlee14 wants to merge 6 commits intoblackboardsh:mainfrom
candrewlee14:flatpak-support
Open

Add Flatpak support for Linux#185
candrewlee14 wants to merge 6 commits intoblackboardsh:mainfrom
candrewlee14:flatpak-support

Conversation

@candrewlee14
Copy link

@candrewlee14 candrewlee14 commented Feb 22, 2026

Adds end-to-end Flatpak support for Linux builds.

What's in here

Native wrapper (nativeWrapper.cpp)

  • File choosers use GtkFileChooserNative so they route through org.freedesktop.portal.FileChooser in the sandbox
  • openFileManager() uses g_app_info_launch_default_for_uri() (GIO/portal-aware) instead of system("xdg-open ...")
  • openURL() drops the system() fallback — it doesn't work inside a sandbox anyway
  • showNotification() calls org.freedesktop.portal.Notification over D-Bus instead of system("notify-send ...")
  • Tray icon falls back to the theme icon name ($FLATPAK_ID) when running inside Flatpak, so the host compositor can find it
  • XDG base dirs (XDG_CACHE_HOME, XDG_DATA_HOME, XDG_RUNTIME_DIR) take precedence over hardcoded ~/.cache etc.

CLI (cli/index.ts)

  • New flatpak config section under build.linux: enabled, runtimeVersion, categories, extraFinishArgs
  • createFlatpakBundle() generates a Flatpak manifest, .desktop file, and AppStream metainfo, then runs flatpak-builder and flatpak build-bundle to produce a .flatpak artifact
  • Uses org.gnome.Platform (includes libwebkit2gtk-4.1) with default runtime version "48"
  • collectExtraLibs() uses readelf -d + ldconfig -p to walk the dep tree of libNativeWrapper.so, bundling only libs not provided by the runtime (in practice: the ayatana appindicator stack). Uses direct DT_NEEDED edges rather than ldd's full transitive closure to avoid pulling in WebKit's ~100 deps and hitting ABI version conflicts with the runtime's own copies.
  • Gracefully skips if flatpak/flatpak-builder aren't installed

Kitchen config

  • flatpak.enabled: true added as a live example and to keep the feature tested

Runtime requirements (build host)

  • flatpak and flatpak-builder
  • readelf (binutils)
  • org.gnome.Platform//48 and org.gnome.Sdk//48 installed via Flathub

🤖 Generated with Claude Code

Native wrapper (nativeWrapper.cpp):
- Respect XDG_CACHE_HOME/XDG_DATA_HOME/XDG_RUNTIME_DIR instead of
  hardcoding ~/.cache and ~/.local/share paths
- Replace gtk_file_chooser_dialog_new with GtkFileChooserNative so file
  choosers route through org.freedesktop.portal.FileChooser in sandbox
- Replace system("xdg-open"/"gio open") in openFileManager with
  g_app_info_launch_default_for_uri (portal-aware GIO)
- Remove system("xdg-open") fallback in openURL/openPath
- Replace system("notify-send") with org.freedesktop.portal.Notification
  D-Bus call so notifications work inside Flatpak sandbox
- Use theme icon name (FLATPAK_ID) for tray icon when running in Flatpak
  so the host compositor can resolve the icon

CLI (cli/index.ts):
- Add linux.flatpak config section (enabled, runtimeVersion, categories,
  extraFinishArgs)
- Add generateFlatpakManifest(), generateFlatpakDesktopFile(),
  generateFlatpakAppdata() helpers
- Add createFlatpakBundle() which runs flatpak-builder + flatpak
  build-bundle to produce a .flatpak artifact when flatpak.enabled is set

mise.toml:
- Add cmake as a managed tool dependency for the Linux native wrapper build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
candrewlee14 and others added 3 commits February 21, 2026 22:30
nativeWrapper.cpp:
- Add getXdgRuntimeDir() helper with correct /tmp fallback (fixes bug
  where XDG_RUNTIME_DIR unset resolved to $HOME/tmp instead of /tmp)
- Use per-notification atomic counter ID so rapid notifications don't
  overwrite each other
- Fix setImage() to use theme icon name inside Flatpak (same logic as
  the constructor — was using raw absolute path before)
- Restore xdg-open fallback in openExternal/openPath for non-Flatpak
  environments where GIO may not have a handler registered

cli/index.ts:
- Add xmlEscape() helper; use it throughout generateFlatpakAppdata()
- Validate app ID is reverse-DNS format before writing YAML manifest
- Validate extraFinishArgs entries contain no newlines
- Fix --talk-name: org.freedesktop.portal.Desktop (not the legacy
  org.freedesktop.Notifications libnotify bus)
- Add metainfo install command to manifest build-commands so the
  AppStream file is actually bundled
- Add mkdirSync for flatpakBuildDir so --repo path parent exists
- Add StartupWMClass to .desktop file for consistency
- Wrap createFlatpakBundle() call in try/catch so a build failure
  doesn't leave the app bundle folder behind

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch collectExtraLibs() from ldd (full transitive closure) to readelf -d
(direct DT_NEEDED only) with ldconfig -p for path resolution. Recurse only
into non-runtime libs, stopping at GTK/GLib/OpenSSL/WebKit deps that the
org.gnome.Platform runtime already provides. This avoids bundling ~100 libs
from the host that conflict with the runtime's own matched versions (e.g.
libcrypto.so.3 from Fedora conflicting with the Ubuntu-built libssl.so.3 in
the GNOME runtime). Result: 5 libs bundled (ayatana appindicator stack +
libasar) instead of 109.

Also expand the runtime prefix exclusion list to cover OpenSSL, GnuTLS,
Kerberos, GStreamer, ICU, image codecs, and other GNOME runtime libs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@candrewlee14 candrewlee14 marked this pull request as ready for review February 22, 2026 06:46
candrewlee14 and others added 2 commits February 22, 2026 00:05
The native wrapper forces GDK_BACKEND=x11 before gtk_init, so the app
runs as an X11 app under XWayland. --socket=fallback-x11 only provides
the X11 socket when there is no Wayland compositor, so on a Wayland
session DISPLAY was never set and the app silently failed to launch from
the app launcher. --socket=x11 always sets up XWayland and DISPLAY.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When CEF is absent, remove the GDK_BACKEND=x11 override so GTK
initialises natively on Wayland. CEF has no native Wayland support so
the override is kept when CEF is present. Also guard XSetErrorHandler
behind a GDK_IS_X11_DISPLAY() check — the Wayland GDK backend handles
protocol errors internally and has no equivalent global error hook.

All gdk_x11_get_default_xdisplay() calls in the codebase are inside
CEF-only code paths so they are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@candrewlee14
Copy link
Author

@YoavCodes I did some manual testing here on getting the flatpak running, and all the browser tests passed on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant