Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
eb6817a
Add Linux build support: cross-platform build, Vosk linking, platform…
Emanschi Aug 29, 2026
c3a1f9b
Add Linux platform parity: sleep inhibit, error dialogs, capabilities…
Emanschi Aug 29, 2026
b0e0c4b
Fix aux window (About/Settings/Input) mispositioning on multi-monitor…
Emanschi Aug 29, 2026
82c595a
Add Linux desktop integration and release-bundle config (Phase 5.1/5.2)
Emanschi Aug 29, 2026
a5eec38
Add Arch PKGBUILD for flow-teleprompter (Phase 5.3)
Emanschi Aug 29, 2026
24eaca7
Add icon-cache/desktop-database refresh scriptlet for flow-teleprompter
Emanschi Aug 29, 2026
34f4f98
Rebuild KDE's ksycoca cache too in flow-teleprompter's install scriptlet
Emanschi Aug 29, 2026
1eebd1d
Rename Flow's icon to flow-teleprompter to avoid a Papirus name colli…
Emanschi Aug 29, 2026
8825124
Rename desktop file/icon to app.flowteleprompter.Flow (dotted, no hyp…
Emanschi Aug 29, 2026
ef34325
Add flow-teleprompter-bin PKGBUILD (Phase 5.4)
Emanschi Aug 29, 2026
38b4eba
Add AppImage post-processing fix for bundled Wayland/XCB libraries (P…
Emanschi Aug 29, 2026
07d86f7
Fix deb/rpm: vendor libvosk.so and use our own desktop file/icons (Ph…
Emanschi Aug 29, 2026
f85577e
Add Linux CI workflow and fix updater-signing exit-code bug (Phase 6.3)
Emanschi Aug 29, 2026
7be2f4c
Fix CI workflow bugs found by a full clean-room dry run (Phase 6.3)
Emanschi Aug 29, 2026
888848a
fix(linux): re-sign AppImage after fix-appimage-libs.sh repacking
Emanschi Aug 29, 2026
1978f9c
docs(linux): add BUILDING-LINUX.md
Emanschi Aug 29, 2026
a9ffa7e
docs: add Linux section and platform badge to all README translations
Emanschi Aug 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Flow - A high-performance teleprompter for Windows.
# Copyright (C) 2026 Waled Alturkmani (LumoRez07)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Builds Flow's Linux packages (AppImage, .deb, .rpm) and uploads them as
# workflow artifacts. Separate from and does not touch the existing
# (manual, Windows-only) release process.
#
# Runs on ubuntu-22.04 deliberately, not a newer Ubuntu: linuxdeploy's
# bundled `strip` doesn't understand the RELR relocations that newer
# glibc/binutils toolchains emit by default, which breaks AppImage bundling
# entirely on more recent distros. This was reproduced and confirmed by
# hand during Phase 6.1 of the Linux port.
#
# The AppImage build additionally works around two more environment-
# specific issues also found and fixed by hand in Phase 6.1:
# - linuxdeploy's own AppImage tries to FUSE-mount itself, which sandboxed/
# containerized CI runners commonly can't do; APPIMAGE_EXTRACT_AND_RUN=1
# makes every AppImage runtime involved (including nested plugin
# AppImages) fall back to extracting instead.
# - linuxdeploy's dependency scanner runs `ldd` on the compiled binary to
# decide what to bundle, but can't resolve the vendored (not system-
# installed) libvosk.so unless it's on LD_LIBRARY_PATH at bundle time.
# The binary's own runtime resolution goes through its RUNPATH, not
# this variable - this is only needed to help linuxdeploy find the file
# to copy in the first place.
#
# packaging/linux/fix-appimage-libs.sh removes a handful of bundled Wayland/
# XCB client libraries that linuxdeploy-plugin-gtk pulls in but which must
# come from the host's own compositor/X server to avoid version-mismatch
# EGL failures (also found and fixed by hand in Phase 6.1, reproduced on a
# real desktop after building on Ubuntu 22.04).
#
# TAURI_SIGNING_PRIVATE_KEY is expected to be the same key already used for
# the existing Windows updater artifacts (see Phase 6.4 - the plan calls
# for reusing it, not creating a new one). If it isn't configured as a
# repository secret yet, the AppImage is still built, just without updater
# artifacts, so this workflow doesn't hard-depend on Phase 6.4 being done
# first.

name: Build Linux

on:
push:
branches:
- linux-native-build
paths:
- "src/**"
- "src-tauri/**"
- "packaging/linux/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/build-linux.yml"
pull_request:
paths:
- "src/**"
- "src-tauri/**"
- "packaging/linux/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/build-linux.yml"
workflow_dispatch:

jobs:
build:
name: Build AppImage / deb / rpm
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install system build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
libasound2-dev \
libssl-dev \
pkg-config \
xdg-utils \
unzip \
file

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Cache cargo build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri -> target

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install npm dependencies
run: npm ci

- name: Fetch vendored Vosk library
run: bash packaging/linux/fetch-vosk.sh

- name: Build AppImage
env:
FLOW_LINUX_PACKAGE: appimage
APPIMAGE_EXTRACT_AND_RUN: "1"
LD_LIBRARY_PATH: ${{ github.workspace }}/src-tauri/resources/vosk/linux-x64
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: |
if [ -n "${TAURI_SIGNING_PRIVATE_KEY}" ]; then
echo "Signing key configured - building AppImage with updater artifacts"
npx tauri build \
--config src-tauri/tauri.linux.conf.json \
--config src-tauri/tauri.linux.appimage.conf.json \
--bundles appimage
else
echo "::warning::TAURI_SIGNING_PRIVATE_KEY not configured - building AppImage without updater artifacts"
npx tauri build \
--config src-tauri/tauri.linux.conf.json \
--bundles appimage
fi

- name: Fix bundled Wayland/XCB libraries in AppImage
run: |
APPIMAGE_PATH="$(find src-tauri/target/release/bundle/appimage -maxdepth 1 -name '*.AppImage')"
bash packaging/linux/fix-appimage-libs.sh "${APPIMAGE_PATH}"

- name: Build .deb
env:
FLOW_LINUX_PACKAGE: deb
run: npx tauri build --config src-tauri/tauri.linux.conf.json --bundles deb

- name: Build .rpm
env:
FLOW_LINUX_PACKAGE: rpm
run: npx tauri build --config src-tauri/tauri.linux.conf.json --bundles rpm

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: flow-linux-x86_64
path: |
src-tauri/target/release/bundle/appimage/*.AppImage
src-tauri/target/release/bundle/appimage/*.AppImage.sig
src-tauri/target/release/bundle/deb/*.deb
src-tauri/target/release/bundle/rpm/*.rpm
if-no-files-found: error
retention-days: 14
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dist-ssr
*.local
src-tauri/target/
src-tauri/gen/
src-tauri/resources/vosk/linux-x64/*.so
tools/
tmp/
src/pro
Expand Down
178 changes: 178 additions & 0 deletions BUILDING-LINUX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<!--
Flow - A high-performance teleprompter for Windows.
Copyright (C) 2026 Waled Alturkmani (LumoRez07)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-->

# Building Flow on Linux

Flow is primarily a Windows application, but this branch adds a native
Linux build (AppImage, `.deb`, `.rpm`, and an Arch `PKGBUILD`). This
document covers everything needed to build and run it from source on
Linux, plus the known platform limitations.

## Prerequisites

You need Rust (stable), Node.js 20+, and the Tauri v2 native
dependencies for your distro.

### Debian / Ubuntu (22.04+)

```bash
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
libasound2-dev \
libssl-dev \
pkg-config \
xdg-utils \
unzip \
file
```

(`unzip` and `file` are only needed to run `fetch-vosk.sh` and to build
an AppImage; skip them if you only want a debug build for development.)

### Arch Linux

```bash
sudo pacman -S --needed webkit2gtk-4.1 gtk3 libayatana-appindicator \
alsa-lib vosk-api hicolor-icon-theme gtk-update-icon-cache \
desktop-file-utils rust nodejs npm pkgconf
```

Arch's `vosk-api` package is used directly (see [Speech recognition
library (Vosk)](#speech-recognition-library-vosk) below) — you do not
need `fetch-vosk.sh` on Arch. A ready-to-use `PKGBUILD` is provided at
[packaging/arch/PKGBUILD](packaging/arch/PKGBUILD).

### Fedora / openSUSE (rpm-based)

Package names vary by distro/version; the runtime dependencies a built
`.rpm` declares are `webkit2gtk4.1`, `gtk3`, `libayatana-appindicator-
gtk3`, and `alsa-lib` (see
[tauri.linux.conf.json](src-tauri/tauri.linux.conf.json)) — install
their `-devel` equivalents to build from source.

## Speech recognition library (Vosk)

Flow's voice engine links against `libvosk.so` at runtime. Two ways to
provide it:

- **System package** (Arch): install the distro's `vosk-api` package;
`FLOW_LINUX_PACKAGE=pacman` tells the build to expect it on the
system instead of vendoring a copy (see
[packaging/arch/PKGBUILD](packaging/arch/PKGBUILD)).
- **Vendored copy** (AppImage/deb/rpm, or plain development builds on
distros without a `vosk-api` package): run
[packaging/linux/fetch-vosk.sh](packaging/linux/fetch-vosk.sh) once.
It downloads the official prebuilt `libvosk.so` (pinned to v0.3.45 —
the last version with published binary release assets, see the
script's comments) into
`src-tauri/resources/vosk/linux-x64/libvosk.so`, verifying its
SHA-256 against a hardcoded value. `src-tauri/build.rs` picks it up
automatically once present.

## Building

```bash
npm ci
bash packaging/linux/fetch-vosk.sh # skip on Arch if using system vosk-api
```

**Development build (debug, runs in place):**

```bash
cd src-tauri && cargo build
./packaging/linux/flow-launcher.sh # or run target/debug/flow directly
```

**Packaged builds**, each via `tauri build` with the Linux config
overlay (`tauri.linux.conf.json` merges automatically-shared settings
from `tauri.conf.json`; nothing there needs editing per-package):

```bash
# AppImage
FLOW_LINUX_PACKAGE=appimage npx tauri build \
--config src-tauri/tauri.linux.conf.json \
--bundles appimage
bash packaging/linux/fix-appimage-libs.sh \
src-tauri/target/release/bundle/appimage/*.AppImage

# .deb
FLOW_LINUX_PACKAGE=deb npx tauri build \
--config src-tauri/tauri.linux.conf.json --bundles deb

# .rpm
FLOW_LINUX_PACKAGE=rpm npx tauri build \
--config src-tauri/tauri.linux.conf.json --bundles rpm
```

`fix-appimage-libs.sh` is **required** after every AppImage build — see
[Known issues](#known-issues) below for why. It re-signs the AppImage
if a `.sig` file (updater artifact) exists next to it and
`TAURI_SIGNING_PRIVATE_KEY` is set in the environment, since repacking
changes the file's signature-relevant bytes.

To also produce a signed updater artifact (`.AppImage.sig`), add
`--config src-tauri/tauri.linux.appimage.conf.json` as a second
`--config` flag to the AppImage build above, with
`TAURI_SIGNING_PRIVATE_KEY` (and `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`,
even if empty) set — this is the same signing key already used for
Windows releases, not a separate one.

[.github/workflows/build-linux.yml](.github/workflows/build-linux.yml)
runs this exact sequence in CI (on `ubuntu-22.04` — see the workflow's
own comments for why not a newer Ubuntu) and uploads all three package
formats as artifacts on every push/PR to `linux-native-build`.

## Known issues and platform limitations

- **Wayland**: Flow is an always-on-top overlay that relies on absolute
window positioning, always-on-top, and global hotkeys. Native
Wayland's security model doesn't allow any of these for regular
applications, and neither GTK3 nor `tao` (Tauri's windowing layer on
Linux) work around that. [flow-launcher.sh](packaging/linux/flow-launcher.sh)
therefore forces the app onto XWayland by default
(`GDK_BACKEND=x11`); set `FLOW_ALLOW_WAYLAND=1` to opt out and run
under native Wayland, with the caveat that window positioning,
always-on-top, and global hotkeys will not work correctly.
- **Blank/black window (DMA-BUF renderer)**: on some AMD/Mesa driver
combinations, WebKitGTK's DMA-BUF renderer fails to initialize the
window contents. `flow-launcher.sh` sets
`WEBKIT_DISABLE_DMABUF_RENDERER=1` by default to work around this;
unset it explicitly if you've verified your system doesn't need it.
- **Screen-capture protection is not available on Linux.** The
Windows build can hide the teleprompter window from screen
recording/sharing (via a Windows-only API); there is no equivalent
mechanism on X11 or Wayland, so this feature is disabled on Linux.
- **Remote Control needs a firewall exception.** The "Remote Control"
feature runs a small local HTTP relay on TCP port **43127** so
another device on the same network can send text to Flow directly
(see `REMOTE_RELAY_PORT` in
[src-tauri/src/lib.rs](src-tauri/src/lib.rs)). Most desktop Linux
distros ship a default-deny firewall (`ufw`, `firewalld`) with no
interactive per-app prompt like Windows Defender Firewall shows on
first launch — you need to open the port yourself if you want to use
this feature from another device on your LAN, e.g.:
```bash
sudo ufw allow 43127/tcp # ufw (Debian/Ubuntu)
sudo firewall-cmd --add-port=43127/tcp --permanent && sudo firewall-cmd --reload # firewalld (Fedora)
```
- **AppImage and bundled Wayland/XCB libraries**: `linuxdeploy-plugin-
gtk` bundles Wayland/X11/XCB client libraries and `libxkbcommon`
into the AppImage, but these must match the exact protocol/ABI
version of the host's own compositor or X server. A version mismatch
causes WebKitGTK to fail EGL/GL context creation entirely (`Could
not create default EGL display: EGL_BAD_PARAMETER`).
[fix-appimage-libs.sh](packaging/linux/fix-appimage-libs.sh) strips
these specific libraries out and repacks the AppImage so the dynamic
linker falls through to the host's own copies instead — this is why
the script must run after every AppImage build, not just optionally.
16 changes: 16 additions & 0 deletions README.ar.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<img src="https://img.shields.io/sourceforge/dm/flowteleprompter.svg?style=flat-square" alt="SourceForge Downloads" />
</a>
<img src="https://img.shields.io/badge/platform-Windows%2010%20%7C%2011-0078D6?style=flat-square&logo=windows&logoColor=white" alt="Windows" />
<img src="https://img.shields.io/badge/platform-Linux%20(community)-FCC624?style=flat-square&logo=linux&logoColor=black" alt="Linux (community port)" />
<img src="https://img.shields.io/badge/backend-Rust%20%2B%20Tauri%20v2-FFC131?style=flat-square&logo=tauri&logoColor=black" alt="Tauri + Rust" />
<img src="https://img.shields.io/badge/license-GPLv3-22c55e?style=flat-square" alt="GPLv3 License" />
</p>
Expand Down Expand Up @@ -227,6 +228,21 @@ npm run tauri build

---

## Linux (community port)

Flow also builds natively on Linux, as an AppImage, `.deb`, `.rpm`, or an Arch `PKGBUILD`. This is a community-maintained port; Windows remains the primary, officially supported platform. See [BUILDING-LINUX.md](BUILDING-LINUX.md) for prerequisites and build instructions — there is no official pre-built binary release yet, so building from source (or grabbing an artifact from the [Linux CI workflow](.github/workflows/build-linux.yml)) is currently required.

Honest limitations compared to Windows:

| Feature | Linux |
| --- | --- |
| Screen-capture protection | Not available — the underlying API is Windows-only, with no X11/Wayland equivalent. |
| Wayland | Runs via XWayland by default (always-on-top, absolute positioning, and global hotkeys need it); native Wayland is opt-in but breaks those three. |
| Remote Control | Works, but needs a one-time manual firewall exception for TCP port 43127 (most Linux desktops default-deny inbound connections, unlike Windows' first-launch prompt). |
| In-app auto-update | Works for the AppImage; `.deb`/`.rpm`/`PKGBUILD` installs update through your distro's package manager instead. |

---

## الخصوصية

- يتم تخزين معظم البيانات محلياً على جهازك.
Expand Down
Loading