From ad70ce5ea9735409d13bbf0b50af7663652dcb39 Mon Sep 17 00:00:00 2001 From: Mollusk Date: Tue, 26 May 2026 05:24:25 -0400 Subject: [PATCH] fix(gui): give the window a real icon instead of the Wayland fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the Wayland app_id to `pixelpass` so the compositor matches the installed pixelpass.desktop and uses its Icon= in the titlebar/taskbar, replacing the generic fallback. Also embed a 256px PNG (rendered from assets/pixelpass.svg) and set it via with_icon for X11 _NET_WM_ICON, and add StartupWMClass=pixelpass to the desktop entry for robust window↔entry matching across desktop environments. No new deps — eframe already pulls the image crate, and icon_data::from_png_bytes decodes the embed. Co-Authored-By: Claude Opus 4.7 --- assets/pixelpass-256.png | Bin 0 -> 8062 bytes assets/pixelpass.desktop | 1 + src/gui/mod.rs | 22 ++++++++++++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 assets/pixelpass-256.png diff --git a/assets/pixelpass-256.png b/assets/pixelpass-256.png new file mode 100644 index 0000000000000000000000000000000000000000..601c8dc0612dc3d0b9652fbaeb6e5c5531f2e13c GIT binary patch literal 8062 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 anyhow::Result<()> { + // `app_id` must match the installed `pixelpass.desktop`: on Wayland the + // compositor sources the titlebar/taskbar icon from that desktop file's + // `Icon=` keyed by app_id — not from any pixels the app sets. + let mut viewport = egui::ViewportBuilder::default() + .with_app_id("pixelpass") + .with_inner_size([520.0, 480.0]) + .with_min_inner_size([460.0, 380.0]) + .with_title("PixelPass"); + + // Pixel icon for X11 titlebars (`_NET_WM_ICON`), embedded at compile time + // so the single binary stays self-contained. Non-fatal on failure: Wayland + // already has its icon via app_id, and X11 just keeps the generic fallback. + match eframe::icon_data::from_png_bytes(include_bytes!("../../assets/pixelpass-256.png")) { + Ok(icon) => viewport = viewport.with_icon(icon), + Err(e) => tracing::warn!("could not load embedded window icon: {e}"), + } + let options = eframe::NativeOptions { - viewport: egui::ViewportBuilder::default() - .with_inner_size([520.0, 480.0]) - .with_min_inner_size([460.0, 380.0]) - .with_title("PixelPass"), + viewport, ..Default::default() };