Repository navigation
Conversation
… module Ports Flow to compile and run natively on Linux (Arch, verified) while keeping every Windows code path untouched: - Gate the `windows`/`winreg` crates to cfg(windows) only, so Cargo no longer tries to build Windows-only bindings on Linux. - Add Linux Vosk linking to build.rs: resolves libvosk.so via FLOW_VOSK_LIB_DIR override, a vendored copy, or the system library (ldconfig), with rpath set for portable/vendored builds. - Add packaging/linux/fetch-vosk.sh to fetch and checksum-verify a vendored libvosk.so for AppImage/deb/rpm builds that shouldn't depend on a system vosk-api install. - Add packaging/linux/flow-launcher.sh, forcing GDK_BACKEND=x11 (XWayland) by default since the overlay's always-on-top/positioning/global hotkeys don't work under native Wayland, plus the WebKitGTK DMABUF renderer workaround. - Add src-tauri/src/platform/ with a Linux session_type() helper. - Filter cpal's ALSA device enumeration on Linux down to the devices that make sense to pick as a microphone (raw enumeration mixes in ALSA plugin internals and output-only topology variants). - Add tauri-plugin-single-instance (Unix only) so a second `flow --toggle-clickthrough/--show/--hide` invocation controls the running instance instead of opening a second window - needed on native Wayland where the app can't register its own global hotkeys. - Use Tauri's cross-platform `.parent()` instead of the Windows-only `.owner()` for the remote-inbox window relationship. Verified on Arch Linux/KDE under XWayland: builds clean, Vosk model loads and decodes without ABI issues against the system vosk-api package, tray icon and its menu work end-to-end, global shortcuts register and fire correctly. See plan/notes/ for full verification detail.
…, UI
Phase 4 of the Linux port - brings feature parity where possible and
honestly reports where it isn't, plus fixes a pre-existing (not
Linux-specific) window dragging bug found during manual testing.
Platform parity (src-tauri/src/platform/linux.rs):
- Sleep/screensaver prevention via D-Bus: org.freedesktop.ScreenSaver
Inhibit/UnInhibit and org.freedesktop.login1.Manager.Inhibit("idle"),
used together since desktop environments vary in which one they honor.
Verified against `systemd-inhibit --list`.
- Startup error dialog fallback chain: kdialog -> zenity -> notify-send
-> stderr, since nothing GTK-based can be assumed to work at the point
this fires. Verified for real: kdialog isn't installed on this KDE
system, so the fallback to zenity is exercised, not just theoretical.
- New get_platform_capabilities command reports what's actually
available on this session (os, X11/Wayland, capture protection,
global shortcuts, in-app updater) instead of assuming Windows-level
capability everywhere. Fixed a priority bug found while wiring this
up: session_type() checked XDG_SESSION_TYPE before GDK_BACKEND, so it
misreported "wayland" even when the launcher's GDK_BACKEND=x11 forces
the app onto XWayland where those features do work.
Frontend (src/core/platform.js + consumers):
- New platform.js module mirrors distribution.js's cache/promise
pattern, fails open (assumes full capability) if the query fails, so
Windows behavior can't regress.
- Settings UI hides capture protection when unavailable (with an
explanatory line instead of just disappearing), adds a hint about the
--toggle-clickthrough CLI flags when global shortcuts aren't
available, and shows a package-manager hint instead of the update
button when the in-app updater isn't. New i18n strings added in all
8 languages, not just English.
- Both updater paths (services/updater.js's manual check and
teleprompter/auto-updater.js's background timer) now gate on
in-app-updater availability the same way they already gate on
Microsoft Store builds, so non-AppImage Linux builds don't poll the
update endpoint or run a dead interval.
- Font fallback chains extended with Inter/Noto Sans/DejaVu Sans and
Fira Code/DejaVu Sans Mono, Segoe entries kept first so Windows
rendering is untouched.
Window dragging fix (not Linux-specific):
- Settings, About, and the text editor window had no drag region at
all, unlike the main window - noticed only now because the main
window has its own drag-handle overlay and a settings-based position
picker, so nobody had tried grabbing the others by their header.
Fixing this took two changes: `data-tauri-drag-region` has to be on
the exact element the mousedown lands on (Tauri's drag script checks
e.target directly, it doesn't walk up to parents), and the
`core:window:allow-start-dragging` permission was missing from
capabilities/default.json entirely - without it every drag attempt
was silently rejected by the ACL, main window included.
… X11 center_aux_window_on_active_monitor() queried monitor geometry via Window::current_monitor(), which returned incorrect coordinates on a dual-monitor X11/XWayland setup and placed the window in an unrelated corner of the desktop instead of centering it — making it easy to miss entirely (reported as "About window doesn't appear"). Center over the anchor (main) window's own outer bounds instead, which sidesteps monitor enumeration entirely and is more robust across different multi-monitor configurations.
- packaging/linux/flow.desktop, hicolor icons, and AppStream metainfo for desktop-menu integration (KDE Discover, GNOME Software). Both validate cleanly with desktop-file-validate and appstreamcli. - src-tauri/tauri.linux.conf.json: Tauri merge-config for `tauri build --config` on Linux (appimage/deb/rpm bundle targets, runtime deps, vendored libvosk.so as a bundle resource). tauri.conf.json itself is untouched, per the Linux-port ground rules.
Sources a GitHub tag tarball (sha256 left as SKIP with a TODO — this Linux port has no tagged release yet). build() stages the system vosk-api package's libvosk.so into the vendored resource path before compiling, since tauri-build hard-requires that vendored file to exist at build time even though the package only needs vosk-api at runtime. Verified end-to-end with a throwaway git+file:// source variant (not committed): makepkg -si builds and packages cleanly, namcap reports no real issues on either the PKGBUILD or the built package. Final `pacman -U` install step needs to be run interactively (requires a sudo password this sandboxed session doesn't have).
pacman's built-in gtk-update-icon-cache hook only triggers on a brand-new top-level icon theme directory; it doesn't cover an application package adding files into the already-installed shared "hicolor" theme. Confirmed by hand: after installing the PKGBUILD-built package, the app menu showed a generic icon instead of Flow's icon until the cache was refreshed. Adds flow-teleprompter.install running gtk-update-icon-cache and update-desktop-database on install/upgrade/remove, and the two packages that provide those binaries to depends.
gtk-update-icon-cache/update-desktop-database alone weren't enough on a real KDE Plasma test install: the app menu still showed a generic icon until kbuildsycoca6 (KDE's own service/desktop-file cache) was rebuilt. Guarded with `command -v` so it stays a no-op on non-KDE systems rather than becoming a hard dependency on KDE Frameworks.
…sion Root-caused the "generic icon in app menu" report the hard way: files were staged correctly, kbuildsycoca6/gtk-update-icon-cache ran, plasmashell was even restarted — none of it helped. GTK's own icon-theme lookup for "flow" resolved to /usr/share/icons/Papirus/64x64/apps/flow.svg instead of ours; papirus-icon-theme (a very common third-party theme, active here as Papirus-Dark) already ships an icon literally named "flow", which the active theme's search order prefers over our hicolor fallback icon. Renaming to the more specific "flow-teleprompter" (verified no collision in Papirus/Papirus-Dark) sidesteps this entirely. StartupWMClass stays "flow" (matches the real WM_CLASS, unrelated to icon lookup).
…hen) Root-caused the icon still not showing after the flow-teleprompter rename: kiconfinder6 (KIconLoader's own exact lookup tool) resolved "flow-teleprompter" to Papirus's unrelated flow.svg, not our hicolor icon. The freedesktop icon-naming spec's fallback algorithm strips everything after the *last hyphen* and retries within the active theme (and its inheritance chain) before ever consulting hicolor as the final fallback. "flow-teleprompter" truncates to "flow", which papirus-icon-theme happens to ship — so the truncated match wins before hicolor is ever reached. Any hyphenated name is at risk of this for as long as some prefix collides with an icon in the user's active theme. Switching to the dotted app-id form used by AppStream/Flatpak conventions sidesteps the hyphen-fallback path entirely (verified via kiconfinder6: no match anywhere before adding our own file, so no collision risk). Renames the desktop file, all icon files, and the metainfo launchable together for consistency.
Sources the lightweight source tag tarball for desktop/icon/metainfo/ license assets plus a prebuilt flow-linux-$CARCH.tar.gz release asset for the binary itself, avoiding a full from-source compile. That release asset doesn't exist yet (depends on Phase 6.3's not-yet-built release workflow) — flagged in a comment for whoever implements it. Added mutual provides/conflicts between flow-teleprompter and flow-teleprompter-bin so pacman treats them as interchangeable. Verified with a throwaway local variant (git+file:// source + a tarball built from the already-compiled release binary): makepkg builds and packages cleanly, namcap shows nothing beyond already-investigated warnings from the source package plus an expected "unstripped ELF" from my un-stripped test binary (real CI output would be pre-stripped).
…hase 6.1) Tauri's AppImage bundling (linuxdeploy + linuxdeploy-plugin-gtk) vendors Wayland/X11/XCB client protocol libraries, which must match the exact protocol/ABI version of the host's compositor/X server. Bundling them means the AppImage's own RUNPATH shadows the host's matching copies, breaking EGL context creation on any system whose graphics stack differs enough from the AppImage's build host (reproduced building on Ubuntu 22.04, running on a much newer Arch system: "Could not create default EGL display: EGL_BAD_PARAMETER"). fix-appimage-libs.sh extracts a built AppImage, removes the known-bad libraries (libwayland-client/-server/-egl/-cursor, libxcb-randr/-render/ -shm, libxkbcommon), and repacks it. Verified end-to-end: the resulting AppImage launches with a fully rendering UI and an empty stderr log, confirmed both via wmctrl/screenshot and by direct user observation on their desktop. Also verified (in a fresh vosk-api-free Ubuntu 22.04 container, via ldd) that the AppImage's vendored libvosk.so resolves correctly without any system Vosk installation, closing out Task 6.1's core acceptance criterion.
…ase 6.2) Two real bugs found by actually installing the built packages: 1. Launch-blocking: neither .deb nor .rpm bundled libvosk.so at all (only the AppImage's top-level bundle.resources entry covered that). vosk-api isn't a real Debian/Ubuntu/Fedora package (apt-cache search returns nothing), so the binary failed at dynamic-link time before main() ran: "error while loading shared libraries: libvosk.so: cannot open shared object file". Fixed with a deb/rpm-specific `files` mapping to /usr/lib/flow/libvosk.so, matching the binary's own RUNPATH. 2. Same icon-name-collision class of bug as the Arch package (5.3): Tauri's default deb/rpm bundler auto-generates Icon=flow with empty Categories and a stale Windows-only Comment, colliding with papirus-icon-theme's own pre-existing "flow" icon -- a real risk on any distro, not just Arch, since Papirus is popular everywhere. Fixed by pointing desktopTemplate/files at the already-tested packaging/linux/app.flowteleprompter.Flow.desktop and hicolor icons instead of Tauri's auto-generated ones. Verified end-to-end: .deb installs and launches on a fresh Ubuntu 24.04 container, .rpm installs and launches on a fresh Fedora 40 container, both confirmed via wmctrl and direct observation, both showing the correct custom desktop entry/icon and no library-loading errors.
Discovered while writing the workflow: every tauri build invocation this whole session (deb, rpm, and appimage alike) has been exiting with a non-zero status due to "A public key has been found, but no private key" -- harmless for local testing since the bundle file gets created before that final step runs, but this would mark every CI step as failed despite producing the right artifact. Root cause: the base (Windows) tauri.conf.json sets createUpdaterArtifacts: true globally for the existing Windows updater, and omitting the key from tauri.linux.conf.json only means "inherit from base" in JSON-merge semantics, not "reset to the schema default of false". Fixed by explicitly setting createUpdaterArtifacts: false in tauri.linux.conf.json (so deb/rpm/plain appimage builds no longer attempt signing) and adding tauri.linux.appimage.conf.json as a small additional --config overlay that re-enables it only for the specific build that wants updater artifacts, verified via a direct build of each combination. .github/workflows/build-linux.yml builds AppImage/deb/rpm on ubuntu-22.04 (the RELR/strip-incompatibility-avoiding runner already established in Phase 6.1), reusing packaging/linux/fetch-vosk.sh and fix-appimage-libs.sh. The AppImage step only enables updater artifacts if TAURI_SIGNING_PRIVATE_KEY is configured as a repo secret, so this workflow doesn't hard-depend on Phase 6.4's key setup landing first. No existing Windows release automation was touched -- there wasn't any: neither this checkout nor the actual GitHub repo (checked via the public API) has a .github/workflows directory at all, so Windows releases are evidently built and uploaded manually today.
Replicated the entire build-linux.yml step sequence end-to-end inside a fresh ubuntu-22.04 container from a clean checkout (no push access to origin or `act` available to trigger real Actions from here). Found and fixed three real bugs that would have failed in actual CI: - fetch-vosk.sh needs `unzip`, missing from the runner's apt-get list. - linuxdeploy's AppImage bundler reuses the deb bundler's desktopTemplate internally (no separate field in AppImageConfig), so it inherited our custom Icon=app.flowteleprompter.Flow reference, but the icon file was only staged via deb.files/rpm.files, which the AppImage bundler doesn't read. Added a matching linux.appimage.files section. - appimagetool needs the `file` command, also missing from the runner. Verified the corrected sequence end-to-end in one continuous run: AppImage, .deb, and .rpm all build with exit code 0, and fix-appimage-libs.sh processes the AppImage successfully in the same container.
Repacking the AppImage to strip bundled Wayland/X11/XCB libraries changes its bytes, which invalidates any updater .sig generated for the original file before this script ran. Without this fix, a CI-built AppImage with createUpdaterArtifacts enabled would ship a signature that no longer matches the actual shipped file, silently breaking updater signature verification for every real user. Found and verified by hand during Phase 6.4 updater testing: a full end-to-end self-update test (real packaged AppImage, Flow's own JS update flow, local HTTPS-exempted test feed) failed signature verification until the .sig was regenerated to match the post-fix file. After the fix, the same test succeeded end-to-end (v1 AppImage replaced in place with byte-identical v2 content).
Covers per-distro prerequisites (Debian/Ubuntu, Arch, Fedora/openSUSE), how to fetch/vendor libvosk.so, build commands for the dev build and all three packaged formats, and the known Linux-specific limitations (Wayland/XWayland, DMA-BUF blank window workaround, missing screen-capture protection, the Remote Control feature's port 43127 firewall requirement, and why fix-appimage-libs.sh must run after every AppImage build).
README.md and README.de.md get a fully localized "Linux (community port)" section with an honest limitations table (no screen-capture protection, XWayland-by-default, the Remote Control port 43127 firewall requirement, and AppImage-only in-app auto-update) plus a Linux platform badge next to the existing Windows one. The other six translations (es/tr/ar/fr/pt/fi) get the same section and badge inserted in English, since translating them accurately isn't something to guess at — the PR description asks maintainers/translators for help translating those six.
Owner
|
Thanks for putting this together. Right now my focus is strictly on the Windows version, refining it, and improving core features. Linux and macOS support might happen in the future, but they are not on the current roadmap and would interfere with the plans already in place. Because I cannot test or maintain Linux builds myself, I am closing this PR. You are completely welcome to keep maintaining and distributing these builds on your own fork under the GPL license though. Once the project gets to the point where Linux is actively on the development roadmap, we can always revisit it. |
Emanschi
added a commit
to Emanschi/Flow
that referenced
this pull request
Sep 5, 2026
LumoRez07 closed the upstream PR (github.com/LumoRez07/pull/3): Linux isn't on their roadmap and they can't test/maintain it, but they explicitly authorized this fork to keep distributing it under GPL. That makes this permanently a standalone fork rather than a pending contribution, so the docs needed to say so clearly instead of reading like a feature branch of the original project. - README.md/README.de.md: replaced the duplicated feature list, screenshots, and Windows-focused sections with a prominent fork notice and a short, Linux-only README that links to the upstream project for everything not specific to this fork (features, screenshots, official downloads, roadmap). Badges/star-history now point at this fork instead of upstream. - The other six README translations (es/tr/ar/fr/pt/fi) are replaced with a short translated fork notice pointing to upstream's own translation, this fork's English/German README, and BUILDING-LINUX.md, rather than maintaining eight long, duplicated documents for a niche Linux fork. - BUILDING-LINUX.md: added a one-line fork-context banner at the top. - packaging/arch/PKGBUILD(-bin): fixed source tarball/release URLs to pull from the fork (Emanschi/Flow) instead of upstream, which will never have these Linux packaging files -- this was a real bug, not just a clarity issue, since building against upstream's tag would have failed outright. - AppStream metainfo: bugtracker/vcs-browser now point at the fork, plus an added description paragraph noting the fork relationship. - privacy-policy.md: added a note clarifying this is upstream's original policy, unchanged in substance for this fork since no data-handling code was modified.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a native Linux build of Flow, packaged as an AppImage,
.deb,.rpm, and an ArchPKGBUILD— without touching the existing Windows build path (#[cfg(windows)]code andtauri.conf.jsonare untouched; Linux-specific config lives intauri.linux.conf.jsonandtauri.linux.appimage.conf.json, merged in only for Linux builds).libvosk.sohandling..desktopfile, AppStream metainfo, hicolor icons..deb/.rpm(vendoringlibvosk.sosince it isn't a real Debian/Fedora package), an ArchPKGBUILD(using the systemvosk-apipackage instead)..github/workflows/build-linux.ymlbuilds and uploads all three formats, entirely separate from the existing Windows release process..deb/.rpm/PKGBUILDupdate through the distro's package manager instead.README.md/README.de.md, and in English to the other six translations pending community translation help.What doesn't work / known limitations
FLOW_ALLOW_WAYLAND=1) but breaks those three features.linux-x86_64entry in the productionlatest.json) is a maintainer decision for after merge.How this was tested
Everything below was verified by hand, not just "it compiles":
libvosk.so.vosk-api/webkit2gtkinstalled beyond what the AppImage bundles, confirming it's genuinely self-contained. Also used for a full end-to-end in-app updater test: a real packaged AppImage, running its own unmodified JS update-check flow (no test hooks), against a local test feed — confirmed the running binary was replaced in place with byte-identical v2 content after a real download + signature verification + install cycle..deb: built, then installed viaapt-get install ./flow_*.debon a clean Ubuntu 24.04 container — resolves all declared dependencies, launches with a real window..rpm: built, then installed viadnf install ./flow-*.rpmon a clean Fedora 40 container — same verification as the.deb.PKGBUILD: built and installed viamakepkg/pacman -Uon the host, including the icon-cache/desktop-database refresh scriptlet and a check for icon-name collisions withpapirus-icon-theme.unzip/filepackages, an icon-lookup failure specific to the AppImage bundler's shared desktop-template handling, and an updater-artifact exit-code bug) before ever touching a real GitHub Actions run.Test matrix
vosk-api)Windows build/behavior was not touched and was not re-tested as part of this PR (no Windows-specific files were modified).