feat(flatpak): add Flatpak packaging for universal distribution (#484)

* feat(flatpak): add Flatpak packaging for universal distribution

Adds a Flathub-ready Flatpak for the whisper.cpp engine, plus the minimal
runtime adaptations Flatpak actually needs — deliberately scoped down from the
earlier attempts (#416, #428), which bundled unrelated whisper.cpp GPU, audio,
and clipboard changes.

Packaging (packaging/flatpak/):
- app manifest, AppStream metainfo, and desktop entry (com.vocalinux.Vocalinux)
- generated offline Python dependency modules (flatpak-pip-generator)
- bundled shared modules: PortAudio, libayatana-appindicator, xdotool, xsel

Runtime changes (Flatpak-only, behaviour unchanged outside a sandbox):
- utils/paths.py: honour XDG_CONFIG_HOME/XDG_DATA_HOME so config, models and
  runtime data live under ~/.var/app/<app-id> in the sandbox
- autostart uses `flatpak run <app-id>` (the host launcher is always on PATH)
- text injection and keyboard backend detect a Wayland host reached via XWayland
  (no Wayland socket granted) and route through xdotool / pynput-on-X11
- tray indicator references the exported `<app-id>-*` host icon theme names

Also: a CI workflow building x86_64 + aarch64 bundles, and README / packaging
README / distro-compatibility doc updates.

Verified with a full flatpak-builder build + bundle install on aarch64:
pywhispercpp loads its native libraries without LD_LIBRARY_PATH, XDG paths
redirect correctly, bundled tools are present, and the entrypoint runs.
Manifest and builddir lint are clean and AppStream metadata validates.

Closes #167

* chore(flatpak): sync metainfo version to 0.14.0-beta

Also ignore flatpak-build-dir/ so local builder output stays untracked.

* refactor(flatpak): trim docs and comments after ponytail review

Drop redundant packaging README command blocks, shrink path/tray/autostart
comments, and stop ignoring a non-canonical build-dir name.

* fix(flatpak): close readiness gaps for v0.14.0-beta

Route log files through XDG data dirs so Flatpak keeps them under
~/.var/app, refresh AppStream screenshots to vocalinux.com, and use
the SPDX GPL-3.0-only license id.

* fix(flatpak): enable global hotkeys via evdev and --device=input

pynput over XWayland only receives keys for the focused X client. Prefer
evdev inside Flatpak and grant /dev/input so shortcuts work app-wide.

* fix(flatpak): inject text with ydotool/uinput on Wayland

xdotool only reaches XWayland clients, so typing appeared to succeed but
never hit native apps. Ship ydotool, grant --device=all for uinput, start
ydotoold on demand, and type via uinput inside the Flatpak.

* fix(flatpak): paste via wl-copy + Ctrl+V instead of typing

ydotool type injects character-by-character. Ship wl-clipboard, grant
--socket=wayland, and prefer clipboard paste for instant insertion.

* test(text-injection): expect ydotool default key-delay of 2

Matches the shipped VOCALINUX_YDOTOOL_KEY_DELAY default used when
clipboard paste falls back to character typing.
This commit is contained in:
Jatin K Malik
2026-07-16 00:03:30 -07:00
committed by GitHub
parent 48a4dd6374
commit 3deb523efd
34 changed files with 1361 additions and 69 deletions
@@ -0,0 +1,20 @@
{
"name": "intltool",
"cleanup": [ "*" ],
"sources": [
{
"type": "archive",
"url": "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz",
"mirror-urls": [
"https://sources.suse.com/SUSE:SLE-15-SP7:Update:BCI/000product/ca527df4d03bf96a67854a8ed2f0c64b/INCLUDED/SUSE:SLE-15-SP6:GA::intltool::45f77273c3f2ef792fa697b444183beb/intltool-0.51.0.tar.gz",
"https://mirror-hk.koddos.net/lfs/lfs-packages/12.0/intltool-0.51.0.tar.gz",
"https://gstreamer.freedesktop.org/src/mirror/intltool-0.51.0.tar.gz"
],
"sha256": "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd"
},
{
"type": "patch",
"path": "intltool-perl5.26-regex-fixes.patch"
}
]
}
@@ -0,0 +1,59 @@
Description: Escape "{", to prevent complaints from perl 5.22 and 5.26
Author: Roderich Schupp <roderich.schupp@gmail.com>
Author: gregor herrmann <gregoa@debian.org>
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=788705
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=826471
Bug-Upstream: https://bugs.launchpad.net/intltool/+bug/1490906
Index: intltool-0.51.0/intltool-update.in
===================================================================
--- intltool-0.51.0.orig/intltool-update.in 2017-07-23 17:24:35.113169465 +0200
+++ intltool-0.51.0/intltool-update.in 2017-07-23 17:24:35.109169052 +0200
@@ -1062,13 +1062,13 @@
}
}
- if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/)
+ if ($str =~ /^(.*)\$\{?([A-Z_]+)}?(.*)$/)
{
my $rest = $3;
my $untouched = $1;
my $sub = "";
# Ignore recursive definitions of variables
- $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\${?$2}?/;
+ $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\$\{?$2}?/;
return SubstituteVariable ("$untouched$sub$rest");
}
@@ -1190,10 +1190,10 @@
$name =~ s/\(+$//g;
$version =~ s/\(+$//g;
- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/);
- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/);
- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/);
- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/);
+ $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\$\{?AC_PACKAGE_NAME}?/);
+ $varhash{"PACKAGE"} = $name if (not $name =~ /\$\{?PACKAGE}?/);
+ $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\$\{?AC_PACKAGE_VERSION}?/);
+ $varhash{"VERSION"} = $version if (not $name =~ /\$\{?VERSION}?/);
}
if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)[,]?([^,\)]+)?/m)
@@ -1219,11 +1219,11 @@
$version =~ s/\(+$//g;
$bugurl =~ s/\(+$//g if (defined $bugurl);
- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/);
- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/);
- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/);
- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/);
- $varhash{"PACKAGE_BUGREPORT"} = $bugurl if (defined $bugurl and not $bugurl =~ /\${?\w+}?/);
+ $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\$\{?AC_PACKAGE_NAME}?/);
+ $varhash{"PACKAGE"} = $name if (not $name =~ /\$\{?PACKAGE}?/);
+ $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\$\{?AC_PACKAGE_VERSION}?/);
+ $varhash{"VERSION"} = $version if (not $name =~ /\$\{?VERSION}?/);
+ $varhash{"PACKAGE_BUGREPORT"} = $bugurl if (defined $bugurl and not $bugurl =~ /\$\{?\w+}?/);
}
# \s makes this not work, why?
@@ -0,0 +1,50 @@
From 729546c51806a1b3ea6cb6efb7a115b1baa811f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Mon, 18 Nov 2019 19:58:53 +0100
Subject: [PATCH 1/1] Fix HAVE_VALGRIND AM_CONDITIONAL
The AM_CONDITIONAL should also be run with --disable-tests, otherwise
HAVE_VALGRIND is undefined.
---
configure | 4 ++--
configure.ac | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/configure b/configure
index 831a3bb..8913b9b 100644
--- a/configure
+++ b/configure
@@ -14801,6 +14801,8 @@ else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
have_valgrind=yes
+fi
+
fi
if test "x$have_valgrind" = "xyes"; then
HAVE_VALGRIND_TRUE=
@@ -14811,8 +14813,6 @@ else
fi
-fi
-
diff --git a/configure.ac b/configure.ac
index ace54d1..cbd38a6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -120,8 +120,8 @@ PKG_CHECK_MODULES(DBUSMENUTESTS, json-glib-1.0 >= $JSON_GLIB_REQUIRED_VERSION
[have_tests=yes]
)
PKG_CHECK_MODULES(DBUSMENUTESTSVALGRIND, valgrind, have_valgrind=yes, have_valgrind=no)
-AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"])
])
+AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"])
AC_SUBST(DBUSMENUTESTS_CFLAGS)
AC_SUBST(DBUSMENUTESTS_LIBS)
--
2.46.2
@@ -0,0 +1,43 @@
From 8a09e6ad33c58c017c0c8fd756da036fc39428ea Mon Sep 17 00:00:00 2001
From: Alexander Koskovich <akoskovich@pm.me>
Date: Sun, 29 Sep 2024 13:47:54 -0400
Subject: [PATCH 1/1] Make introspection configurable
---
CMakeLists.txt | 1 +
src/CMakeLists.txt | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e13fcd..f3e9ec0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,7 @@ endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
option(ENABLE_TESTS "Enable all tests and checks" OFF)
option(ENABLE_COVERAGE "Enable coverage reports (includes enabling all tests and checks)" OFF)
option(ENABLE_WERROR "Treat all build warnings as errors" OFF)
+option(ENABLE_INTROSPECTION "Enable introspection" ON)
if(ENABLE_COVERAGE)
set(ENABLE_TESTS ON)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5b3638d..aca9481 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -108,6 +108,8 @@ install(TARGETS "ayatana-ido3-0.4" LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIB
# AyatanaIdo3-0.4.gir
+if (ENABLE_INTROSPECTION)
+
find_package(GObjectIntrospection REQUIRED QUIET)
if (INTROSPECTION_FOUND)
@@ -183,3 +185,5 @@ if (INTROSPECTION_FOUND)
endif ()
endif ()
+
+endif ()
--
2.46.2
@@ -0,0 +1,121 @@
{
"name": "libayatana-appindicator",
"buildsystem": "cmake-ninja",
"cleanup": [
"/include",
"/lib/pkgconfig"
],
"config-opts": [
"-DENABLE_BINDINGS_MONO=NO",
"-DENABLE_BINDINGS_VALA=NO",
"-DENABLE_GTKDOC=NO"
],
"modules": [
"../intltool/intltool-0.51.json",
{
"name": "libdbusmenu",
"buildsystem": "autotools",
"build-options": {
"cflags": "-Wno-error"
},
"cleanup": [
"*.la",
"/include",
"/lib/pkgconfig",
"/libexec",
"/share/doc",
"/share/gtk-doc"
],
"config-opts": [
"--with-gtk=3",
"--disable-dumper",
"--disable-static",
"--disable-tests",
"--disable-gtk-doc",
"--enable-introspection=no",
"--disable-vala"
],
"sources": [
{
"type": "archive",
"url": "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz",
"mirror-urls": [
"https://sources.suse.com/SUSE:SLFO:Main:Build/libdbusmenu/a5b3e4717f09f90f9cd5568a5f933e8d/libdbusmenu-16.04.0.tar.gz",
"https://mirror.math.princeton.edu/pub/frugalware/frugalware-2.1/source/xlib/libdbusmenu/libdbusmenu-16.04.0.tar.gz",
"https://ftp.fr.openbsd.org/pub/OpenBSD/distfiles/libdbusmenu-16.04.0.tar.gz"
],
"sha256": "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a"
},
{
"type": "patch",
"paths": [
"0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch"
]
}
]
},
{
"name": "ayatana-ido",
"buildsystem": "cmake-ninja",
"cleanup": [
"/include",
"/lib/pkgconfig"
],
"config-opts": [
"-DENABLE_INTROSPECTION=OFF"
],
"sources": [
{
"type": "git",
"url": "https://github.com/AyatanaIndicators/ayatana-ido.git",
"tag": "0.10.4",
"commit": "f968079b09e2310fefc3fc307359025f1c74b3eb",
"x-checker-data": {
"type": "git",
"tag-pattern": "^([\\d.]+)$"
}
},
{
"type": "patch",
"paths": [
"0001-Make-introspection-configurable.patch"
]
}
]
},
{
"name": "libayatana-indicator",
"buildsystem": "cmake-ninja",
"cleanup": [
"/include",
"/lib/pkgconfig",
"/libexec",
"/share"
],
"sources": [
{
"type": "git",
"url": "https://github.com/AyatanaIndicators/libayatana-indicator.git",
"tag": "0.9.4",
"commit": "611bb384b73fa6311777ba4c41381a06f5b99dad",
"x-checker-data": {
"type": "git",
"tag-pattern": "^([\\d.]+)$"
}
}
]
}
],
"sources": [
{
"type": "git",
"url": "https://github.com/AyatanaIndicators/libayatana-appindicator.git",
"tag": "0.5.94",
"commit": "31e8bb083b307e1cc96af4874a94707727bd1e79",
"x-checker-data": {
"type": "git",
"tag-pattern": "^([\\d.]+)$"
}
}
]
}