fix(windows): embed the app icon into the .exe

The Windows executable carried no icon, so Explorer, the taskbar, the
Start-menu tile and file-association entries showed a generic icon. Embed
AppIcon.ico via winresource in build.rs, and generate the .ico from the logo
before the build (it was produced after the build, too late to embed). Local
and non-Windows builds skip the step when the .ico is absent.

Fixes #107.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-16 04:10:01 +03:00
commit 084dfb1bdb
4 changed files with 75 additions and 12 deletions

View file

@ -75,6 +75,18 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Convert SVG icon to ICO
shell: pwsh
run: |
# ImageMagick is pre-installed on windows-latest. The
# auto-resize generates every size Explorer / Add-Remove
# Programs / the Start Menu shortcut may request from a
# single source SVG. Must run BEFORE the build so build.rs
# can embed the icon into the .exe (issue #107).
magick assets/logo.svg `
-define icon:auto-resize=16,24,32,48,64,128,256 `
packaging/windows/AppIcon.ico
- name: Build
run: cargo build --release
@ -96,17 +108,6 @@ jobs:
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Convert SVG icon to ICO
shell: pwsh
run: |
# ImageMagick is pre-installed on windows-latest. The
# auto-resize generates every size Explorer / Add-Remove
# Programs / the Start Menu shortcut may request from a
# single source SVG.
magick assets/logo.svg `
-define icon:auto-resize=16,24,32,48,64,128,256 `
packaging/windows/AppIcon.ico
- name: Build MSI installer
shell: pwsh
run: |

43
Cargo.lock generated
View file

@ -36,6 +36,7 @@ dependencies = [
"truck-shapeops",
"ureq",
"windows-sys 0.61.2",
"winresource",
]
[[package]]
@ -3137,7 +3138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b577e2d69827c4740cba2b52efaad1c4cc7c73042860b199710b3575c68438d"
dependencies = [
"bytecount",
"memchr 1.0.2",
"memchr 2.8.1",
"nom 8.0.0",
]
@ -4829,6 +4830,15 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "serde_spanned"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
dependencies = [
"serde_core",
]
[[package]]
name = "servo_arc"
version = "0.1.1"
@ -5446,6 +5456,21 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
dependencies = [
"indexmap",
"serde_core",
"serde_spanned",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
"toml_writer",
"winnow 1.0.3",
]
[[package]]
name = "toml_datetime"
version = "0.6.11"
@ -5493,6 +5518,12 @@ dependencies = [
"winnow 1.0.3",
]
[[package]]
name = "toml_writer"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
[[package]]
name = "tracing"
version = "0.1.44"
@ -6776,6 +6807,16 @@ dependencies = [
"memchr 2.8.1",
]
[[package]]
name = "winresource"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0986a8b1d586b7d3e4fe3d9ea39fb451ae22869dcea4aa109d287a374d866087"
dependencies = [
"toml",
"version_check",
]
[[package]]
name = "wit-bindgen"
version = "0.51.0"

View file

@ -7,6 +7,11 @@ build = "build.rs"
[workspace]
members = ["crates/ocs_plugin_api"]
# Embed the application icon into the Windows .exe so Explorer, the taskbar,
# the Start-menu tile and file-association entries show it (issue #107).
[target.'cfg(windows)'.build-dependencies]
winresource = "0.1"
[dependencies]
# Stable, dependency-free add-on contract (manifest + ribbon/CadModule types).
# Plugin authors target this crate's semver, not OpenCADStudio internals.

View file

@ -26,6 +26,22 @@ use std::path::Path;
const PRIORITY: &[&str] = &["home", "model", "insert", "annotate", "view", "manage"];
fn main() {
// Windows: embed AppIcon.ico into the .exe so the executable carries its
// own icon (Explorer, taskbar, Start-menu tile, file associations). The
// .ico is produced from assets/logo.svg by the release workflow before the
// build; when it is absent (local/dev builds) this is skipped. See #107.
#[cfg(windows)]
{
println!("cargo:rerun-if-changed=packaging/windows/AppIcon.ico");
if Path::new("packaging/windows/AppIcon.ico").exists() {
let mut res = winresource::WindowsResource::new();
res.set_icon("packaging/windows/AppIcon.ico");
if let Err(e) = res.compile() {
println!("cargo:warning=failed to embed Windows icon: {e}");
}
}
}
let mods_dir = Path::new("src/modules");
println!("cargo:rerun-if-changed=src/modules");