From 3cabb64dbcb1559517718d3201530088283a7f7f Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Thu, 7 May 2026 18:59:55 +0200 Subject: [PATCH] fix(tray): resume rendering on second-launch restore (#497) (#501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(tray): resume rendering on second-launch restore (#497) The single-instance plugin callback that handles a second launch (e.g. via desktop / start-menu shortcut while the main window is hidden in the tray) was missing the RESUME_RENDERING_JS injection that the tray- icon restore path already does. When the main window is closed to the tray, PAUSE_RENDERING_JS sets window.__psyHidden = true, marks , and zeroes --psy-anim-speed. A global CSS rule then pauses every animation under . Page wrappers across the app use .animate-fade-in (animation: fadeIn ... both) which starts at opacity: 0 — so when a route mounts after navigation the new wrapper stays frozen at opacity: 0 and the page looks blank. Restoring via the tray icon worked because that path injects RESUME_RENDERING_JS before show(); only the second-launch path was missing it. Mirror the same eval here so both restore paths are consistent. Reported by netherguy4. * docs: changelog entry for PR #501 Logs the tray second-launch restore-rendering fix in v1.46.0 "## Fixed". --- CHANGELOG.md | 8 ++++++++ src-tauri/src/lib.rs | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d225d02b..8c7f6881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -213,6 +213,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * The currently-playing track in any tracklist (**AlbumDetail**, **ArtistDetail**, **PlaylistDetail**, **Favorites**, **RandomMix**) ran an **`opacity` pulse** on the entire row plus three **`transform` keyframe** EQ-bar siblings — both compositor properties, but on **WebKitGTK without compositing** (Linux + NVIDIA proprietary + `WEBKIT_DISABLE_COMPOSITING_MODE=1`) every animated row falls back to a full **software repaint** of the subtree per frame. On AlbumDetail the combined cost held the WebProcess at **~80 % CPU** for the duration of playback; CPU dropped immediately on pause/stop. * `.track-row.active` keeps the **accent-tinted background** but no longer pulses. The "now playing" indicator becomes a single Lucide **`AudioLines` icon** (one SVG per active row instead of three animated spans). Cleanup: dead `track-pulse` + `eq-bounce` keyframes and a duplicate, shadowed `.eq-bar` block in `theme.css`. +### Tray — broken navigation after restoring via desktop / start-menu shortcut + +**By [@Psychotoxical](https://github.com/Psychotoxical), reported by netherguy4, PR [#501](https://github.com/Psychotoxical/psysonic/pull/501)** + +* When the main window was closed to the tray and then re-opened via the **desktop / start-menu shortcut** (instead of the tray icon), the window came back but the **next navigation rendered a blank page**. Restoring via the **tray icon** worked correctly. +* Root cause: closing to the tray injects a "pause rendering" snippet that sets `data-psy-native-hidden="true"` on `` and pauses every CSS animation. The tray-icon restore path injects the matching "resume rendering" snippet before showing the window — the second-launch restore path (handled by the **single-instance plugin**) was **missing that step**, so route wrappers using `.animate-fade-in` (`animation: fadeIn … both`, starts at `opacity: 0`) stayed frozen invisible. +* Fix: mirror the tray-icon restore path and resume rendering before `show()` in the single-instance callback. Both restore paths are now consistent. + ## [1.45.0] - 2026-05-04 ## Added diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 593ba5fb..115d6646 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -649,6 +649,13 @@ pub fn run() { .plugin(tauri_plugin_single_instance::init(|app, argv, _cwd| { if !crate::cli::handle_cli_on_primary_instance(app, &argv) { let window = app.get_webview_window("main").expect("no main window"); + // The window may have been hidden via the close-to-tray path, + // which injects PAUSE_RENDERING_JS (sets `__psyHidden=true`, + // pauses CSS animations). Tray-icon restore mirrors this with + // RESUME_RENDERING_JS — second-launch restore must do the same, + // otherwise the webview comes back with rendering still paused + // and navigation looks blank (issue #497). + let _ = window.eval(RESUME_RENDERING_JS); let _ = window.show(); let _ = window.unminimize(); let _ = window.set_focus();