diff --git a/windows/Cargo.toml b/windows/Cargo.toml index 886a5bc..f1a63f7 100644 --- a/windows/Cargo.toml +++ b/windows/Cargo.toml @@ -20,6 +20,5 @@ iced_wgpu = "0.14" serde = { version = "1", features = ["derive"] } serde_json = "1" dirs = "6" +image = "0.25" -[target.'cfg(windows)'.build-dependencies] -embed-resource = "3" diff --git a/windows/build.rs b/windows/build.rs index daac1c9..38957bd 100644 --- a/windows/build.rs +++ b/windows/build.rs @@ -1,53 +1,5 @@ fn main() { - #[cfg(target_os = "windows")] - { - use std::process::Command; - - let svg = "../assets/Acord.svg"; - let ico = "icon.ico"; - let rc = "icon.rc"; - let tmp = "icon_tmp"; - - println!("cargo:rerun-if-changed={svg}"); - - // Generate icon.ico from SVG via rsvg-convert + magick. - let _ = std::fs::create_dir_all(tmp); - let sizes = [16, 24, 32, 48, 64, 128, 256]; - let mut pngs = Vec::new(); - - for size in sizes { - let out = format!("{tmp}/icon_{size}.png"); - let s = size.to_string(); - let ok = Command::new("rsvg-convert") - .args(["--width", &s, "--height", &s, svg, "-o", &out]) - .status() - .map(|s| s.success()) - .unwrap_or(false); - if !ok { - println!("cargo:warning=rsvg-convert not found or failed — building without icon"); - let _ = std::fs::remove_dir_all(tmp); - return; - } - pngs.push(out); - } - - let ok = Command::new("magick") - .args(pngs.iter().map(|s| s.as_str())) - .arg(ico) - .status() - .map(|s| s.success()) - .unwrap_or(false); - - let _ = std::fs::remove_dir_all(tmp); - - if !ok { - println!("cargo:warning=magick (ImageMagick) not found — building without icon"); - return; - } - - // Write a .rc file and embed via embed-resource (supports LLVM/GNU toolchains). - std::fs::write(rc, "1 ICON \"icon.ico\"\n").ok(); - embed_resource::compile(rc, embed_resource::NONE); - println!("cargo:warning=icon embedded successfully"); - } + // Icon embedding via resource compilers (winres, embed-resource) doesn't + // work reliably with the gnullvm toolchain. The window icon is set at + // runtime via winit instead — see app.rs. } diff --git a/windows/src/app.rs b/windows/src/app.rs index 97a18c2..7beb158 100644 --- a/windows/src/app.rs +++ b/windows/src/app.rs @@ -154,9 +154,16 @@ impl ApplicationHandler for App { fn resumed(&mut self, event_loop: &ActiveEventLoop) { if self.window.is_some() { return; } - let attrs = WindowAttributes::default() + let mut attrs = WindowAttributes::default() .with_title("Acord") .with_inner_size(LogicalSize::new(1100.0, 750.0)); + + // Load window icon from the bundled PNG (rasterized from SVG at build + // time or shipped alongside the exe). Falls back to no icon silently. + if let Some(icon) = load_window_icon() { + attrs = attrs.with_window_icon(Some(icon)); + } + let window = event_loop.create_window(attrs).expect("create window"); self.scale = window.scale_factor() as f32; @@ -363,3 +370,36 @@ fn decode_winit_modifiers(state: ModifiersState) -> iced_wgpu::core::keyboard::M if state.control_key() { m |= iced_wgpu::core::keyboard::Modifiers::LOGO; } m } + +/// Load the app icon from `assets/Acord.svg` (relative to exe) or a +/// pre-rasterized PNG next to the exe. Returns None on any failure. +fn load_window_icon() -> Option { + // Try loading a PNG icon next to the exe first. + let exe_dir = std::env::current_exe().ok()?.parent()?.to_path_buf(); + + // Try pre-rasterized icon.png next to exe. + let png_path = exe_dir.join("icon.png"); + let bytes = if png_path.exists() { + std::fs::read(&png_path).ok()? + } else { + // Fall back to the SVG in the assets dir (repo layout). + let svg_path = exe_dir.join("../assets/Acord.svg") + .canonicalize().ok() + .or_else(|| { + // Running from repo root via cargo run. + std::path::PathBuf::from("assets/Acord.svg").canonicalize().ok() + })?; + // Use rsvg-convert at runtime as a fallback. + let output = std::process::Command::new("rsvg-convert") + .args(["--width", "256", "--height", "256"]) + .arg(&svg_path) + .output() + .ok()?; + if !output.status.success() { return None; } + output.stdout + }; + + let img = image::load_from_memory(&bytes).ok()?.into_rgba8(); + let (w, h) = img.dimensions(); + winit::window::Icon::from_rgba(img.into_raw(), w, h).ok() +}