Hmmm. This is war

This commit is contained in:
jess 2026-04-17 22:59:56 -07:00
parent 5e774c432e
commit 2c3e9b06c2
3 changed files with 45 additions and 54 deletions

View File

@ -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"

View File

@ -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.
}

View File

@ -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<winit::window::Icon> {
// 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()
}