Block B5 of the miniplayer/tray contract. The tray settings rows have rendered and persisted since the Settings port and driven nothing; this is what they drive. src/tray_linux.rs (new) — the ksni StatusNotifierItem: the twelve icon pixmaps, the variant ladder, the tooltip, the six-item menu, left/middle click and scroll, and the qbz-tray-updater thread every mutation crosses. Note the filename inversion it reproduces: tray-light-* holds the BLACK glyph, so the "mono-light" setting loads tray-dark-*.png. src/tray_qt.rs (new) — the portable half: init's three gates, the window verbs, the 400 ms toggle debounce, the transport dispatchers and in_gamescope(). toggle_window is mini-aware — while the mini is open a tray click raises the MINI, because a mini-blind toggle would put the main window beside a live mini on the first click. src/tray_bridge.rs (new) — QbzTray: trayLive, closeToTray, and the four signals the ksni thread reaches QML through. Rust cannot touch a QQuickWindow, so every verb is a signal. icons/ — the twelve PNGs, copied rather than include_bytes!'d across crates, so this crate does not depend on a file inside the Slint binary crate. src/playback_qt.rs — the three live-update pushes: set_track and clear_track in both arms of refresh_now_playing (the publisher with 23 call sites, so a QConnect or cast track change updates the tooltip too), and set_playing in BOTH is_playing != was_playing blocks, each beside the existing discord_push. src/settings_qt.rs — tray() widened to pub(crate) for the session-entry read; the tray_close_to_tray snapshot default corrected from false to true, which was cosmetic while nothing consumed it and becomes behavioural now; and the tray-icon-theme select arm re-themes the running icon with no restart. Cargo.toml + Cargo.lock — ksni 0.3 with default-features off. Never the tokio feature: the blocking API panics inside tokio and the panic is swallowed, which is why the two dedicated threads exist. src/main.rs, build.rs, qml/Main.qml — the registrations, and tray_qt::init in on_session_entered. That call site is also deliberately the process's first settings_qt::tray(), because the store binds per user and a read from the bridge's construction seed would latch an empty one at the login screen. The Connections block that answers the four signals lands with B6, together with the window verbs it calls. Until then the tray renders, its tooltip and menu are live, and its clicks reach Rust and stop there. cc
970 B
32x32px
970 B
32x32px