From 66c0ecbc1f8e2de085ed5046ac455b1c60be6fa9 Mon Sep 17 00:00:00 2001 From: Psychotoxical Date: Sat, 18 Apr 2026 20:20:24 +0200 Subject: [PATCH] fix(windows): tray double-click flicker + GPU use when minimized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Tray double-click (reported by @cucadmuh's brother-in-law): Windows fires a Click event on *both* halves of a double-click, so our left-click handler toggled visibility twice — the window popped up and immediately vanished. Switch the Windows branch to the `TrayIconEvent::DoubleClick` variant (Windows-only in tray-icon); other platforms keep the Click-on-Up behaviour. Matches the standard Windows tray convention (Discord, Telegram, etc). 2. GPU use while minimized: WebView2 on Windows keeps compositing infinite CSS animations (mesh-aura-a/b, portrait-drift, eq-bounce, track-pulse, led-pulse …) even when the window is minimized — steady visible GPU load on systems that should be idle. App.tsx now toggles a `data-app-hidden="true"` attribute on on `visibilitychange`, and a single CSS rule pauses every `animation` at once via `animation-play-state: paused !important`. Zero cost when visible, catches all current and future infinite animations without per-element listeners. Co-Authored-By: Claude Sonnet 4.6 --- src-tauri/src/lib.rs | 25 ++++++++++++++++++++----- src/App.tsx | 14 ++++++++++++++ src/styles/components.css | 12 ++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 8af01bd6..8c52a858 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -2432,11 +2432,26 @@ fn build_tray_icon(app: &tauri::AppHandle) -> tauri::Result { _ => {} }) .on_tray_icon_event(|tray, event| { - if let TrayIconEvent::Click { - button: MouseButton::Left, - button_state: MouseButtonState::Up, - .. - } = event { + // Windows fires a Click on *every* half of a double-click, so a + // double-click would toggle the window visibility twice and end up + // back where it started (the bug #cucadmuh reported). Switch to the + // Windows-only DoubleClick event there and ignore single clicks; + // that matches the standard Windows tray convention (Discord, etc). + #[cfg(target_os = "windows")] + let should_toggle = matches!( + event, + TrayIconEvent::DoubleClick { button: MouseButton::Left, .. } + ); + #[cfg(not(target_os = "windows"))] + let should_toggle = matches!( + event, + TrayIconEvent::Click { + button: MouseButton::Left, + button_state: MouseButtonState::Up, + .. + } + ); + if should_toggle { let app = tray.app_handle(); if let Some(win) = app.get_webview_window("main") { if win.is_visible().unwrap_or(false) { diff --git a/src/App.tsx b/src/App.tsx index 8598b4a8..fc9dd3c9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -325,6 +325,20 @@ function AppShell() { }; }, []); + // Pause CSS animations when the window is minimized / hidden. + // WebView2 on Windows keeps compositing infinite-loop animations (mesh-aura, + // portrait-drift, eq-bounce, …) even when the app is minimized, which shows + // up as steady GPU usage. The CSS rule `html[data-app-hidden="true"]` in + // components.css pauses all running animations while this flag is set. + useEffect(() => { + const update = () => { + document.documentElement.dataset.appHidden = document.hidden ? 'true' : 'false'; + }; + document.addEventListener('visibilitychange', update); + update(); + return () => document.removeEventListener('visibilitychange', update); + }, []); + const isMobilePlayer = isMobile && location.pathname === '/now-playing'; return ( diff --git a/src/styles/components.css b/src/styles/components.css index 07f728e4..d49b8545 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -8804,3 +8804,15 @@ html.no-compositing .fsr-lyric-line.fsrl-active .fsr-lyric-word.active { .device-sync-row-name { flex: 1; font-size: 0.85rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .device-sync-row-meta { font-size: 0.75rem; color: var(--text-secondary); flex-shrink: 0; } + +/* ── Pause CSS animations when the window is hidden / minimized ──────────── + Set via App.tsx on `visibilitychange`. WebView2 on Windows keeps compositing + infinite CSS animations (mesh-aura, portrait-drift, eq-bounce, track-pulse, + led-pulse, …) even when the app is minimized, causing constant GPU use. + Pausing them cuts that to near zero while hidden without touching the + running Rust/audio threads. */ +html[data-app-hidden="true"] *, +html[data-app-hidden="true"] *::before, +html[data-app-hidden="true"] *::after { + animation-play-state: paused !important; +}