feat(tray): system-tray status icon for the host (Windows + Linux)
New crates/punktfunk-tray — a small per-user companion showing the host service state at a glance (running / stopped / starting / degraded / failed + the live session in the tooltip) with one-click actions: open web console, approve a pending pairing request, start/stop/restart, open logs. No more digging through logs to learn whether the service came back after a reboot or an update. Status is service-manager-FIRST (SCM / systemd user unit — a port squatter can never fake Running), then the new loopback-only unauthenticated GET /api/v1/local/summary (counts/booleans only; the mgmt token and cert.pem are SYSTEM/Admins-DACL'd on Windows, so a non-elevated tray cannot bearer-auth). Windows: windows_subsystem binary (a console exe in the Run key would flash a terminal at sign-in), Shell_NotifyIcon + hidden window, per-session single instance, TaskbarCreated re-add, --quit for the uninstaller; service actions elevate per click via ShellExecuteW "runas" onto the new `punktfunk-host service restart` (stop → wait Stopped → start). Linux: ksni/StatusNotifierItem over zbus, systemctl --user actions (no polkit), /etc/xdg/autostart entry whose --autostart self-gates to actual host users. Icons: scripts/gen-tray-icons.py (pure stdlib) renders the brand lens + status dot into committed .ico/hicolor assets; deb/rpm/arch ship binary+autostart+icons. Live-validated: Linux on the headless KDE session (SNI registration, state transitions, menu-driven start, dbusmenu layout); Windows on the RTX box (session-1 launch with no NIM_ADD failure, single instance, --quit, restart round-trip, summary loopback-200/LAN-401). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
//! Embed the Windows version-info + icon resources into `punktfunk-tray.exe`: ordinal 1 is the
|
||||
//! exe/file icon, ordinals 2–6 are the status-variant tray icons `src/win.rs` loads by id
|
||||
//! (running / stopped / error / streaming / degraded). Same winresource pattern as
|
||||
//! `clients/windows/build.rs`.
|
||||
|
||||
fn main() {
|
||||
// cfg(windows) is the HOST (skips the Linux/macOS workspace stub build); CARGO_CFG_WINDOWS
|
||||
// is the TARGET (mirrors the Windows client's build.rs).
|
||||
#[cfg(windows)]
|
||||
if std::env::var_os("CARGO_CFG_WINDOWS").is_some() {
|
||||
let branding = "../../packaging/windows/branding";
|
||||
let icons = [
|
||||
(format!("{branding}/punktfunk.ico"), "1"),
|
||||
(format!("{branding}/punktfunk-tray-running.ico"), "2"),
|
||||
(format!("{branding}/punktfunk-tray-stopped.ico"), "3"),
|
||||
(format!("{branding}/punktfunk-tray-error.ico"), "4"),
|
||||
(format!("{branding}/punktfunk-tray-streaming.ico"), "5"),
|
||||
(format!("{branding}/punktfunk-tray-degraded.ico"), "6"),
|
||||
];
|
||||
let mut res = winresource::WindowsResource::new();
|
||||
for (path, id) in &icons {
|
||||
println!("cargo:rerun-if-changed={path}");
|
||||
res.set_icon_with_id(path, id);
|
||||
}
|
||||
res.compile().expect("embed windows icon resources");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user