Add system tray with minimize-to-tray (Tartube parity 1.6)

Uses ksni (StatusNotifierItem via zbus) so we keep our pure-Rust /
no-GTK stack — zbus is already pulled in by notify-rust and rfd.

Behavior:
- Tray icon shows the bundled icon.png; left-click brings the window
  back to focus
- Right-click menu: Show / Hide / Quit
- Clicking the window's X button minimizes to tray instead of exiting
- Ctrl+Q (or the tray's Quit item) actually exits

Failure modes are silent and non-blocking: no DBus → app behaves as if
tray flag was off. No StatusNotifier host (e.g. GNOME without the
AppIndicator extension) → icon invisible but app still runs normally,
and the X-button close cancellation only fires when the tray spawn
returned a handle.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Luna 2026-05-27 02:17:10 -07:00
parent 5fd63de903
commit abe7d63794
5 changed files with 264 additions and 2 deletions

View file

@ -24,6 +24,7 @@ mod platform;
mod plex;
mod stats;
mod theme;
mod tray;
mod web;
mod ytdlp_bin;
@ -46,6 +47,16 @@ fn main() -> eframe::Result<()> {
web::run(cfg);
}
// Start the optional system tray. Returns None if the icon decode
// fails (shouldn't happen — it's embedded) or the thread won't spawn.
// A Some result does NOT guarantee a visible tray icon — that depends
// on whether a StatusNotifier host is registered (KDE: yes; GNOME:
// requires AppIndicator extension; others: varies). When no host
// exists, ksni quietly does nothing and the app behaves as if the
// tray flag were off.
const TRAY_ICON_PNG: &[u8] = include_bytes!("../icon.png");
let tray = tray::start(TRAY_ICON_PNG);
let native_options = eframe::NativeOptions {
viewport: eframe::egui::ViewportBuilder::default()
.with_inner_size([1280.0, 820.0])
@ -56,6 +67,6 @@ fn main() -> eframe::Result<()> {
eframe::run_native(
"yt-offline",
native_options,
Box::new(|cc| Ok(Box::new(app::App::new(cc)))),
Box::new(|cc| Ok(Box::new(app::App::new(cc, tray)))),
)
}