//! На Windows вшивает в exe иконку и описание — их видят проводник, «Пуск» и поиск. #[allow(dead_code)] #[path = "src/icon_pixels.rs"] mod icon_pixels; use std::path::PathBuf; fn main() { println!("cargo:rerun-if-changed=src/icon_pixels.rs"); if std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") { return; } let ico = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("qulyp.ico"); std::fs::write(&ico, make_ico(&[16, 24, 32, 48, 64, 256])).expect("write ico"); let mut res = winresource::WindowsResource::new(); res.set_icon(ico.to_str().unwrap()) .set("ProductName", "Qulyp") .set("FileDescription", "Qulyp — менеджер паролей") .set("LegalCopyright", "MIT"); if let Err(e) = res.compile() { // Без Windows SDK exe всё равно соберётся, просто без иконки. println!("cargo:warning=иконка не вшита: {e}"); } } /// ICO из нескольких 32-битных BMP-образов. fn make_ico(sizes: &[usize]) -> Vec { let images: Vec> = sizes.iter().map(|&n| bmp_image(n)).collect(); let mut out = Vec::new(); out.extend_from_slice(&[0, 0, 1, 0]); out.extend_from_slice(&(sizes.len() as u16).to_le_bytes()); let mut offset = 6 + 16 * sizes.len(); for (&n, img) in sizes.iter().zip(&images) { let b = if n >= 256 { 0 } else { n as u8 }; out.extend_from_slice(&[b, b, 0, 0]); out.extend_from_slice(&1u16.to_le_bytes()); // planes out.extend_from_slice(&32u16.to_le_bytes()); // bpp out.extend_from_slice(&(img.len() as u32).to_le_bytes()); out.extend_from_slice(&(offset as u32).to_le_bytes()); offset += img.len(); } for img in images { out.extend_from_slice(&img); } out } fn bmp_image(n: usize) -> Vec { let rgba = icon_pixels::rgba(n); let mask_row = n.div_ceil(32) * 4; let mut out = Vec::new(); // BITMAPINFOHEADER: высота удвоена (XOR-картинка + AND-маска) for v in [40u32, n as u32, (n * 2) as u32] { out.extend_from_slice(&v.to_le_bytes()); } out.extend_from_slice(&1u16.to_le_bytes()); out.extend_from_slice(&32u16.to_le_bytes()); for v in [0u32, (n * n * 4 + mask_row * n) as u32, 0, 0, 0, 0] { out.extend_from_slice(&v.to_le_bytes()); } for y in (0..n).rev() { for x in 0..n { let i = (y * n + x) * 4; out.extend_from_slice(&[rgba[i + 2], rgba[i + 1], rgba[i], rgba[i + 3]]); } } out.extend(std::iter::repeat_n(0u8, mask_row * n)); // прозрачность берётся из альфы out }