diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ff0963497..d5a54d008 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -78,13 +78,53 @@ jobs:
- name: Build
run: cargo build --release
- - name: Upload exe to release
+ - 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: |
+ $version = "${{ github.ref_name }}" -replace '^v', ''
+ if (-not $version) { $version = "0.0.0" }
+ # WiX Toolset 3.x is pre-installed on windows-latest; $env:WIX
+ # points to the install root. candle compiles .wxs → .wixobj
+ # and light links it into the final .msi.
+ $candle = Join-Path $env:WIX "bin\candle.exe"
+ $light = Join-Path $env:WIX "bin\light.exe"
+ & $candle -arch x64 `
+ -dVersion=$version `
+ -dSource=target\release\OpenCADStudio.exe `
+ -dIcon=packaging\windows\AppIcon.ico `
+ packaging\windows\main.wxs `
+ -out packaging\windows\main.wixobj
+ if ($LASTEXITCODE -ne 0) { throw "candle failed" }
+ & $light packaging\windows\main.wixobj -out OpenCADStudio.msi
+ if ($LASTEXITCODE -ne 0) { throw "light failed" }
+
+ - name: Upload artifacts to release
if: github.event_name == 'release'
+ shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- mv target/release/OpenCADStudio.exe OpenCADStudio-${{ github.ref_name }}-windows-x86_64.exe
- gh release upload ${{ github.ref_name }} OpenCADStudio-${{ github.ref_name }}-windows-x86_64.exe --clobber --repo ${{ github.repository }}
+ $tag = "${{ github.ref_name }}"
+ # Ship both the bare .exe (portable, no install) and the
+ # .msi (installer with Start Menu shortcut + .dwg / .dxf
+ # file association). Users pick the form they want.
+ Move-Item target\release\OpenCADStudio.exe "OpenCADStudio-$tag-windows-x86_64.exe"
+ Move-Item OpenCADStudio.msi "OpenCADStudio-$tag-windows-x86_64.msi"
+ gh release upload $tag `
+ "OpenCADStudio-$tag-windows-x86_64.exe" `
+ "OpenCADStudio-$tag-windows-x86_64.msi" `
+ --clobber --repo ${{ github.repository }}
build-macos:
runs-on: macos-14 # Apple Silicon (arm64) only
diff --git a/packaging/OpenCADStudio.desktop b/packaging/OpenCADStudio.desktop
index 6b9fe9931..bd685a973 100644
--- a/packaging/OpenCADStudio.desktop
+++ b/packaging/OpenCADStudio.desktop
@@ -1,11 +1,11 @@
[Desktop Entry]
Name=Open CAD Studio
Comment=A CAD application for 2D/3D drawing and design
-Exec=OpenCADStudio
+Exec=OpenCADStudio %f
Icon=io.github.HakanSeven12.OpenCadStudio
Terminal=false
Type=Application
Categories=Graphics;Engineering;
-MimeType=image/vnd.dxf;
-Keywords=CAD;DXF;drawing;design;engineering;2D;3D;
+MimeType=image/vnd.dwg;image/vnd.dxf;
+Keywords=CAD;DWG;DXF;drawing;design;engineering;2D;3D;
StartupWMClass=OpenCADStudio
diff --git a/packaging/windows/main.wxs b/packaging/windows/main.wxs
new file mode 100644
index 000000000..c619d60fa
--- /dev/null
+++ b/packaging/windows/main.wxs
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/mod.rs b/src/app/mod.rs
index a929ffdae..dceb55b45 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -1036,7 +1036,22 @@ impl OpenCADStudio {
Message::UpdateCheckResult,
);
let focus_cmd = s.focus_cmd_input();
- (s, Task::batch([open_main, check_update, focus_cmd]))
+ // Open a file path passed on the command line. Used by the
+ // OS file association: double-clicking a .dwg in the file
+ // explorer launches the binary with the file path as the
+ // first positional argument. Unknown / flag-style args are
+ // ignored. `Message::OpenRecent` does the existence check
+ // and reports a clean error if the path is bogus.
+ let cli_open: Task = std::env::args_os()
+ .nth(1)
+ .map(PathBuf::from)
+ .filter(|p| !p.as_os_str().to_string_lossy().starts_with('-'))
+ .map(|p| Task::done(Message::OpenRecent(p)))
+ .unwrap_or_else(Task::none);
+ (
+ s,
+ Task::batch([open_main, check_update, focus_cmd, cli_open]),
+ )
}
}