From bd4bd02a126ee9fe9c2519facf1ef890246bafc4 Mon Sep 17 00:00:00 2001 From: InstaZDLL Date: Wed, 30 Sep 2026 05:21:31 +0200 Subject: [PATCH] fix(linux): stop the immersive view flashing and the motion cover failing on webkitgtk 2.54 Fedora's WebKitGTK 2.54 hands video frames through a DMA-BUF sink the page cannot read back, so the loop-frame copy failed four times a second (Cannot map External OES textures). Its video sink is switched to GL on Linux. The immersive view also opens without its fade there: a video mounting inside the animating full-window layer blacked the window out three times. --- docs/features/ui.md | 4 ++-- src-tauri/crates/app/src/render_mode.rs | 10 ++++++++++ src/components/player/ImmersiveView.tsx | 19 +++++++++++++++---- src/hooks/usePlayableVideo.ts | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/docs/features/ui.md b/docs/features/ui.md index 6a49689a..182620f3 100644 --- a/docs/features/ui.md +++ b/docs/features/ui.md @@ -166,7 +166,7 @@ The line being sung takes a colour of the user's choosing in the immersive lyric Entry points in the [`PlayerBar`](../../src/components/player/PlayerBar.tsx): clicking the cover (mirrors Spotify) or the Immersive button, plus the Maximize2 icon in the side `LyricsPanel` header. `PlayerContext` exposes `immersiveOpen` + `immersiveInitialTab` + `openImmersive`/`closeImmersive`; the old `openFullscreenNowPlaying`/`openFullscreenLyrics`/`close*` names stay as back-compat aliases that all drive the one merged view. -**Transition hygiene** — the view paints a solid `bg-zinc-950` on the outer wrapper from the first frame; the `animate-fade-in` keyframe lives on the inner backdrop + foreground layers, not the wrapper. Without that opaque base the wrapper's own opacity ramp (0 → 1 over 300 ms) would let the page underneath bleed through during the transition. +**Transition hygiene** — the view paints a solid `bg-zinc-950` on the outer wrapper from the first frame; the `animate-fade-in` keyframe lives on the inner backdrop + foreground layers, not the wrapper. Without that opaque base the wrapper's own opacity ramp (0 → 1 over 300 ms) would let the page underneath bleed through during the transition. **Linux opens without the fade.** WebKitGTK 2.54 rebuilds its layers each time a video appears inside a full-window layer that is still animating, and a motion cover mounting during the fade blacked the window out three times. Without the fade one short flash is left, WebKit creating the video layer; neither the backdrop blur nor the clip's own 700 ms fade played a part, each ruled out on its own. The AppImage's older WebKit never flashed. **Skin neutrality** — the immersive view carries `role="dialog"` + a `shadow-2xl` cover, which the skins' modal / surface / text-colour chrome would otherwise capture (Liquid-light + Editorial repainted it as a light glass slab with dark, invisible text + washed-out controls; Lounge / Pulse flattened the cover backdrop). The root is tagged `data-immersive` + a nested `dark` context (so the shared `PlaybackControls` / `VolumeControl` / `ProgressBar` render their dark-theme variants over the always-dark backdrop), and every skin's relevant rules carry `:not([data-immersive]):not([data-immersive] *)` so the view renders identically across skins. @@ -184,7 +184,7 @@ Entry points in the [`PlayerBar`](../../src/components/player/PlayerBar.tsx): cl **Playing a local clip on Linux.** WebKitGTK plays `