feat(linux): Wayland/Hyprland parity + consumable Nix package#86
Open
nephalemsec wants to merge 11 commits into
Open
feat(linux): Wayland/Hyprland parity + consumable Nix package#86nephalemsec wants to merge 11 commits into
nephalemsec wants to merge 11 commits into
Conversation
Add a `window_decorations` general-setting (default on). When toggled off on Linux the native titlebar is removed and a custom in-app close button (WindowControls, in the Settings titlebar) takes over — useful on tiling WMs. - config: window_decorations field (serde default true) - capability: core:window:allow-set-decorations (+ minimize/maximize); without it setDecorations() silently no-ops - lib.rs: apply the saved preference at startup (Linux) - Overview: a "Window Decorations" Switch beside "Show in Dock" (Linux only) - Settings: custom close button shown when decorations are off
Under Vite 8 + @tailwindcss/vite 4.3 + vite-plugin-svelte 7, the Tailwind transform matches Svelte's `&lang.css` virtual modules and intermittently receives the raw `.svelte` source, throwing `Invalid declaration: \`invoke\`` 500s in the dev server. Exclude `.svelte?` modules from Tailwind's transform — no component style uses Tailwind directives (sole entry is src/app.css), so output is unchanged.
Adds an opt-in `parakeet-cuda` feature that runs Parakeet on an NVIDIA GPU through sherpa-onnx's CUDA execution provider. Default builds are unchanged (Parakeet stays CPU; macOS stays CoreML). - Cargo: `parakeet-cuda = ["parakeet", "sherpa-onnx/shared"]`. sherpa-onnx is now `default-features = false` so the link mode is explicit — the default `parakeet` feature still resolves to static CPU (sherpa-onnx-sys defaults to static when no link feature is set), so nothing changes for current builds. - parakeet.rs: under `parakeet-cuda` on Linux, request the `cuda` provider and fall back to CPU if the EP can't initialise (mirrors the macOS CoreML path). - flake: a `cuda` dev shell fetches the k2-fsa CUDA prebuilt (CUDA 12 / cuDNN 9) and wires SHERPA_ONNX_LIB_DIR + LD_LIBRARY_PATH (sherpa libs, cuDNN, cudart, cublas, driver) so the CUDA provider loads at build and runtime. Build/run: nix develop .#cuda pnpm tauri dev --no-default-features --features parakeet-cuda,vulkan Verified: links against the CUDA sherpa-onnx (libonnxruntime_providers_cuda.so) and the default CPU build is unaffected. Real GPU engagement should be confirmed on-device with `nvidia-smi` during a transcription — onnxruntime silently falls back to CPU if cuDNN/driver libs aren't found.
The onnxruntime CUDA provider dlopen()s libcublasLt/cublas/curand/cufft/cudart/ cudnn; a single missing one aborts the process (no CPU fallback). The cuda dev shell only had cudnn/cudart/cublas, so it failed on libcurand.so.10. Add libcurand, libcufft, libcusparse to LD_LIBRARY_PATH (cublasLt ships with cublas).
main pastes by setting the clipboard with arboard and synthesising a wtype/enigo keystroke. On wlroots compositors (Hyprland) arboard's clipboard isn't readable by other clients and the synthetic keystroke doesn't land, so paste silently fails. On Wayland, set the clipboard with wl-copy and dispatch the paste through the compositor: Hyprland uses 'hyprctl dispatch sendshortcut CTRL,v' for GUI apps and wtype Ctrl+Shift+V for terminals (detected via hyprctl activewindow); other compositors keep the wtype/enigo path.
The Overview System status checked is_transcription_ready once at mount; if the model was downloaded but the warm-up thread hadn't finished, it stuck on 'Loading…' until the next pane visit. Poll every 1s (max 30s) until ready.
On Hyprland the XDG GlobalShortcuts portal registers a shortcut but never binds a key (the binding comes back empty in the activation log), so global hotkeys never fire. Detect Hyprland (HYPRLAND_INSTANCE_SIGNATURE) and bind the configured accelerators with 'hyprctl keyword bind/bindr', whose exec dispatcher writes the shortcut id to a FIFO; a listener thread routes each id through manager::dispatch_shortcut_action — the same dispatcher used by the X11/macOS plugin callback. Modifier-only keys (e.g. Right Shift) use bindr + keycodes.
Adds packages.default so the flake is consumable as an input:
inputs.thoth.url = "github:poodle64/thoth";
environment.systemPackages = [ inputs.thoth.packages.${system}.default ];
buildRustPackage with parakeet-cuda + vulkan, linking the pinned CUDA
sherpa-onnx via SHERPA_ONNX_LIB_DIR; the binary is wrapped with wl-clipboard,
wtype, gsettings, canberra and the CUDA/Vulkan runtime libraries (hyprctl is
taken from the host PATH). pnpmDeps hash pinned; cargoHash left as a one-time
TODO (crates.io rate-limited the vendor fetch where this was authored).
buildRustPackage's default cargoHash uses fetch-cargo-vendor-util, which bulk- fetches every crate from crates.io's api/v1 download endpoint in parallel and gets random 403s (rate-limiting) — the whole vendor FOD then fails and re-fetches from scratch. Switch to cargoLock: each crate is its own fetchurl derivation, so successful fetches cache and only failures retry. Build with --max-jobs 2 to stay under the limit. No cargoHash needed (registry checksums come from Cargo.lock); the one git dep (fluidaudio-rs) is pinned in outputHashes.
pkgs.rustPlatform uses the pinned nixpkgs' rustc, which is too old for some deps (libsqlite3-sys 0.38.1 uses the cfg_select! macro). Build with the same newer rust-overlay toolchain the dev shell uses, via makeRustPlatform.
This was referenced Jun 12, 2026
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
Brings Linux — and Wayland/Hyprland specifically — to first-class parity, and makes the Nix flake consumable as an input so NixOS users can install Thoth from their system flake. All 11 commits sit directly on top of current
main(0 behind, 11 ahead), and every Linux-specific change is feature- orcfg-gated so macOS and X11 behaviour is unchanged.Tested live on NixOS + Hyprland (wlroots): GPU Parakeet confirmed via
nvidia-smi, keybinds firing, paste landing in both GUI and terminal windows, and the packaged binary built and wrapped end-to-end.What's in it
Window decorations + custom close button (
b176ca4)Adds a decorations toggle with a custom in-app close button (Linux starts borderless by default). Wires the missing
core:window:allow-set-decorationscapability that made the old toggle a silent no-op.Dev overlay fix — keep Tailwind out of Svelte styles (
12ece40)Vite 8 +
@tailwindcss/vitewas intercepting Svelte component<style>blocks and throwing "Invalid declaration" overlays. The transform now skips.svelte?modules.Optional GPU (CUDA) Parakeet (
159d013,41309f1)New opt-in
parakeet-cudaCargo feature (["parakeet", "sherpa-onnx/shared"]) that links the k2-fsa CUDA prebuilt and selects thecudaONNX execution provider, falling back to CPU if init fails. Default builds are unchanged — CPU static Parakeet, no CUDA pulled in. The flake's.#cudadevShell and the package supply the full CUDA math-lib set (cuDNN, curand, cufft, cublas, cudart) the EP needs at runtime.Native Hyprland global shortcuts (
d1ee8f2)On Hyprland the XDG GlobalShortcuts portal registers a shortcut but never binds a key, so hotkeys never fire. New
shortcuts/hyprland.rsbinds directly viahyprctl keyword bind/bindrwith anexecdispatcher writing to a FIFO we listen on; each id routes through the samemanager::dispatch_shortcut_actionthe X11/macOS path uses. Detection is runtime (HYPRLAND_INSTANCE_SIGNATURE); non-Hyprland Wayland still uses the portal.Wayland paste via wl-copy + hyprctl (
0996ca8)wtype/enigodon't reliably inject into Wayland clients, so paste now sets the clipboard withwl-copyand triggers paste withhyprctl dispatch sendshortcut(GUI) /wtype Ctrl+Shift+V(terminals, detected via window class).Transcription readiness polling (
353d3a9)The Overview "Transcription: Loading…" label never updated once the model was ready. It now polls
is_transcription_readyand flips to ready (bounded, self-clearing).Consumable Nix package (
a34733c,01623fb,dc62ccd)packages.defaultbuilds the full app (GPU Parakeet + Whisper Vulkan) and wraps it with the runtime deps on PATH/LD_LIBRARY_PATH (wl-clipboard, wtype, CUDA/Vulkan libs). Vendoring usescargoLock(per-cratefetchurl) to dodge the crates.io bulk-download rate-limit 403s, and the package builds with the rust-overlay toolchain so edition-2024 crates compile. Consumers can now doinputs.thoth.packages.${system}.default.Testing done
nvidia-sminix build .#packages.x86_64-linux.defaultcompletes and produces a correctly wrapped binaryNotes for review
cargo buildandpnpm tauri devare CPU Parakeet as before.#[cfg(target_os = ...)]/ feature flags), so no cross-platform surface area changes.