Compare commits

..

2 Commits

Author SHA1 Message Date
raistlin7447
93a82af6b4 Fix top row tile order in YOLO perfectionist flow calibration (#14132)
Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-06-10 18:24:46 -03:00
Noisyfox
06eefe7c1e Make sure mouse position is updated before hit test (#14139) 2026-06-11 02:47:33 +08:00
19 changed files with 8 additions and 1103 deletions

View File

@@ -14,7 +14,6 @@ on:
- 'resources/**'
- ".github/workflows/build_*.yml"
- 'scripts/flatpak/**'
- 'scripts/msix/**'
pull_request:
branches:
@@ -31,7 +30,6 @@ on:
- 'build_release_vs2022.bat'
- 'build_release_macos.sh'
- 'scripts/flatpak/**'
- 'scripts/msix/**'
schedule:

View File

@@ -371,25 +371,6 @@ jobs:
asset_content_type: application/x-msdownload
max_releases: 1
- name: Build MSIX Store package Win
if: runner.os == 'Windows' && !vars.SELF_HOSTED
working-directory: ${{ github.workspace }}
shell: pwsh
run: |
./scripts/msix/build_msix.ps1 `
-InstallDir "${{ github.workspace }}/build/OrcaSlicer" `
-OutputPath "${{ github.workspace }}/build/OrcaSlicer_Windows_MSIX_${{ env.ver }}.msix" `
-IdentityName "${{ vars.ORCA_MSIX_IDENTITY_NAME || 'OrcaSlicer.Dev' }}" `
-Publisher "${{ vars.ORCA_MSIX_PUBLISHER || 'CN=00000000-0000-0000-0000-000000000000' }}" `
-PublisherDisplayName "${{ vars.ORCA_MSIX_PUBLISHER_DISPLAY_NAME || 'OrcaSlicer (dev)' }}"
- name: Upload artifacts Win MSIX
if: runner.os == 'Windows' && !vars.SELF_HOSTED
uses: actions/upload-artifact@v7
with:
name: OrcaSlicer_Windows_MSIX_${{ env.ver }}
path: ${{ github.workspace }}/build/OrcaSlicer_Windows_MSIX_${{ env.ver }}.msix
# Ubuntu
- name: Apt-Install Dependencies
if: runner.os == 'Linux' && !vars.SELF_HOSTED

View File

@@ -73,9 +73,8 @@ jobs:
- name: Download release artifacts from build run
run: |
# Windows_V* (not Windows_*) keeps the MSIX Store artifact out: it goes to Partner Center, not GitHub releases.
gh run download "$RUN_ID" --repo "$GITHUB_REPOSITORY" --dir artifacts \
-p 'OrcaSlicer_Windows_V*' \
-p 'OrcaSlicer_Windows_*' \
-p 'OrcaSlicer_Mac_universal_*' \
-p 'OrcaSlicer_Linux_ubuntu_*' \
-p 'OrcaSlicer-Linux-flatpak_*' \

View File

@@ -1,645 +0,0 @@
# MSIX Microsoft Store Build Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Build an unsigned MSIX Store package of OrcaSlicer in CI from the existing Windows install tree, and make the app behave correctly in packaged context (no self-update, no runtime registry-based file associations).
**Architecture:** A hand-written `AppxManifest.xml` template + PowerShell pack script under `scripts/msix/` (precedent: `scripts/flatpak/`), one new CI step in the Windows job of `.github/workflows/build_orca.yml`, and a small packaged-context detection helper in `src/slic3r/GUI/GUI_Utils.{hpp,cpp}` used to gate the updater and association code. Everything is additive: NSIS/portable outputs are untouched, all runtime gates are no-ops in classic builds.
**Tech Stack:** PowerShell 5.1+ (System.Drawing, makeappx from Windows SDK), GitHub Actions, C++17/wxWidgets (Win32 `GetCurrentPackageFullName`/`GetCurrentPackageFamilyName` from `appmodel.h`, kernel32).
**Spec:** `docs/superpowers/specs/2026-06-11-msix-store-build-design.md`
**Branch:** `msix-store-build` (already created; spec is committed on it)
**Why no TDD here:** none of this is unit-testable in this repo — the C++ changes live in the wxWidgets GUI module which no test target links (tests cover `libslic3r`), and the behavior under test is Windows shell/packaging behavior. Each task instead has concrete verification steps (script output checks, XML well-formedness, full app build), and Task 8 collects the manual verification documented in the PR per the repo's review guidelines.
**Windows build command** (required for any task touching C++; plain shells fail without the VS environment — run via PowerShell):
```
cmd /c '"C:\Program Files\Microsoft Visual Studio\18\Community\VC\Auxiliary\Build\vcvars64.bat" >nul && cmake --build build --config RelWithDebInfo --target OrcaSlicer 2>&1'
```
The `'vswhere.exe' is not recognized` line vcvars prints is harmless. Expected: build completes with exit code 0 (warnings OK). Incremental builds are fast when warm.
---
### Task 1: MSIX logo assets + generator script
**Files:**
- Create: `scripts/msix/generate_assets.ps1`
- Create (generated): `scripts/msix/assets/Square150x150Logo.png`, `scripts/msix/assets/Square44x44Logo.png`, `scripts/msix/assets/Square44x44Logo.targetsize-44_altform-unplated.png`, `scripts/msix/assets/StoreLogo.png`
- [ ] **Step 1: Write the generator script**
Create `scripts/msix/generate_assets.ps1` with exactly this content:
```powershell
# Generates the MSIX package logo assets from the 192px master logo.
# Run once on Windows (re-run if the logo changes), then commit the PNGs in assets/.
# Scale-200 variants would need a >192px master; regenerate from OrcaSlicer.svg if ever needed.
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing
$repoRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$source = Join-Path $repoRoot 'resources\images\OrcaSlicer_192px.png'
$outDir = Join-Path $PSScriptRoot 'assets'
New-Item -ItemType Directory -Force $outDir | Out-Null
$sizes = @{
'Square150x150Logo.png' = 150
'Square44x44Logo.png' = 44
'Square44x44Logo.targetsize-44_altform-unplated.png' = 44
'StoreLogo.png' = 50
}
$src = [System.Drawing.Image]::FromFile($source)
foreach ($name in $sizes.Keys) {
$px = $sizes[$name]
$bmp = New-Object System.Drawing.Bitmap($px, $px)
$gfx = [System.Drawing.Graphics]::FromImage($bmp)
$gfx.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$gfx.DrawImage($src, 0, 0, $px, $px)
$gfx.Dispose()
$bmp.Save((Join-Path $outDir $name), [System.Drawing.Imaging.ImageFormat]::Png)
$bmp.Dispose()
Write-Output "Wrote $name (${px}x${px})"
}
$src.Dispose()
```
- [ ] **Step 2: Run it**
Run (PowerShell, from repo root): `./scripts/msix/generate_assets.ps1`
Expected output: four `Wrote <name> (<px>x<px>)` lines, no errors.
- [ ] **Step 3: Verify the generated dimensions**
```powershell
Add-Type -AssemblyName System.Drawing
Get-ChildItem scripts/msix/assets/*.png | ForEach-Object { $i = [System.Drawing.Image]::FromFile($_.FullName); "$($_.Name): $($i.Width)x$($i.Height)"; $i.Dispose() }
```
Expected: `Square150x150Logo.png: 150x150`, `Square44x44Logo.png: 44x44`, `Square44x44Logo.targetsize-44_altform-unplated.png: 44x44`, `StoreLogo.png: 50x50`.
- [ ] **Step 4: Commit**
```bash
git add scripts/msix/generate_assets.ps1 scripts/msix/assets
git commit -m "ci: add MSIX logo asset generator and generated assets"
```
---
### Task 2: AppxManifest.xml template
**Files:**
- Create: `scripts/msix/AppxManifest.xml`
- [ ] **Step 1: Write the manifest template**
Create `scripts/msix/AppxManifest.xml` with exactly this content. The four `@...@` tokens are substituted by `build_msix.ps1` (Task 3). Namespace URIs and the virtualization/MigrationProgIds element shapes were verified against learn.microsoft.com (flexible-virtualization and element-rescap3-migrationprogids pages) on 2026-06-11. `MigrationProgId` is `Orca.Slicer.1` — note the classic build writes the registry ProgID with a leading space (`GUI_App.cpp:9119`), which MigrationProgIds cannot express, so migration from existing NSIS installs is best-effort (Windows shows both apps in "Open with"); deliberately NOT fixed here.
```xml
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:rescap3="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/3"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
IgnorableNamespaces="uap rescap rescap3 desktop6 virtualization">
<Identity Name="@MSIX_IDENTITY_NAME@"
Publisher="@MSIX_PUBLISHER@"
Version="@MSIX_VERSION@"
ProcessorArchitecture="x64" />
<Properties>
<DisplayName>OrcaSlicer</DisplayName>
<PublisherDisplayName>@MSIX_PUBLISHER_DISPLAY_NAME@</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
<!-- Keep config in the real %APPDATA%\OrcaSlicer so it survives uninstall and
is shared with the classic (NSIS/portable) install.
Win10 1903+: coarse switch disables AppData write virtualization entirely.
Win11+: fine-grained exclusion below takes precedence over the coarse switch. -->
<desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
<virtualization:FileSystemWriteVirtualization>
<virtualization:ExcludedDirectories>
<virtualization:ExcludedDirectory>$(KnownFolder:RoamingAppData)\OrcaSlicer</virtualization:ExcludedDirectory>
</virtualization:ExcludedDirectories>
</virtualization:FileSystemWriteVirtualization>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.26100.0" />
</Dependencies>
<Resources>
<Resource Language="en-us" />
</Resources>
<Applications>
<Application Id="OrcaSlicer" Executable="orca-slicer.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
DisplayName="OrcaSlicer"
Description="Open-source slicer for FDM 3D printers"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png" />
<Extensions>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="orcaslicer-models">
<uap:SupportedFileTypes>
<uap:FileType>.3mf</uap:FileType>
<uap:FileType>.stl</uap:FileType>
<uap:FileType>.step</uap:FileType>
<uap:FileType>.stp</uap:FileType>
<uap:FileType>.gcode</uap:FileType>
<uap:FileType>.drc</uap:FileType>
</uap:SupportedFileTypes>
<rescap3:MigrationProgIds>
<rescap3:MigrationProgId>Orca.Slicer.1</rescap3:MigrationProgId>
</rescap3:MigrationProgIds>
</uap:FileTypeAssociation>
</uap:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="orcaslicer" />
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
</Capabilities>
</Package>
```
- [ ] **Step 2: Verify XML is well-formed**
Run (PowerShell): `[xml](Get-Content scripts/msix/AppxManifest.xml -Raw) | Out-Null; 'XML OK'`
Expected: `XML OK` (no exception).
- [ ] **Step 3: Commit**
```bash
git add scripts/msix/AppxManifest.xml
git commit -m "ci: add MSIX AppxManifest template"
```
---
### Task 3: build_msix.ps1 pack script
**Files:**
- Create: `scripts/msix/build_msix.ps1`
- [ ] **Step 1: Write the pack script**
Create `scripts/msix/build_msix.ps1` with exactly this content:
```powershell
<#
Builds the unsigned MSIX Store package from an existing install tree.
The package is intentionally NOT signed: the Microsoft Store strips and
re-signs uploads with Microsoft's certificate. For local installs use
Developer Mode loose-layout registration instead:
./scripts/msix/build_msix.ps1 -StageOnly
Add-AppxPackage -Register <staging>\AppxManifest.xml
Requires the Windows SDK (makeappx.exe) unless -StageOnly is used.
#>
param(
[string]$InstallDir = "build/OrcaSlicer",
[string]$OutputPath = "build/OrcaSlicer_Windows_MSIX.msix",
[string]$StagingDir = "",
[switch]$StageOnly,
[string]$IdentityName = "OrcaSlicer.Dev",
[string]$Publisher = "CN=00000000-0000-0000-0000-000000000000",
[string]$PublisherDisplayName = "OrcaSlicer (dev)"
)
$ErrorActionPreference = 'Stop'
$repoRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
# MSIX version = MAJOR.MINOR.PATCH.0 from the SoftFever_VERSION semver triplet
# (Store requires the revision field to be 0).
$versionContent = Get-Content (Join-Path $repoRoot 'version.inc') -Raw
if ($versionContent -notmatch 'set\(SoftFever_VERSION "(\d+)\.(\d+)\.(\d+)') {
throw "Could not parse SoftFever_VERSION from version.inc"
}
$msixVersion = "$($Matches[1]).$($Matches[2]).$($Matches[3]).0"
Write-Output "MSIX version: $msixVersion"
if (-not (Test-Path (Join-Path $InstallDir 'orca-slicer.exe'))) {
throw "orca-slicer.exe not found in '$InstallDir' - build the install tree first"
}
if ([string]::IsNullOrEmpty($StagingDir)) {
$StagingDir = Join-Path ([System.IO.Path]::GetTempPath()) 'orca-msix-staging'
}
if (Test-Path $StagingDir) { Remove-Item $StagingDir -Recurse -Force }
New-Item -ItemType Directory -Force $StagingDir | Out-Null
Copy-Item -Path (Join-Path $InstallDir '*') -Destination $StagingDir -Recurse
Copy-Item -Path (Join-Path $PSScriptRoot 'assets') -Destination (Join-Path $StagingDir 'Assets') -Recurse
$manifest = Get-Content (Join-Path $PSScriptRoot 'AppxManifest.xml') -Raw
$manifest = $manifest.Replace('@MSIX_VERSION@', $msixVersion)
$manifest = $manifest.Replace('@MSIX_IDENTITY_NAME@', $IdentityName)
$manifest = $manifest.Replace('@MSIX_PUBLISHER@', $Publisher)
$manifest = $manifest.Replace('@MSIX_PUBLISHER_DISPLAY_NAME@', $PublisherDisplayName)
Set-Content -Path (Join-Path $StagingDir 'AppxManifest.xml') -Value $manifest -Encoding utf8
if ($StageOnly) {
Write-Output "Staged loose layout at: $StagingDir"
exit 0
}
$makeappx = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.*\x64\makeappx.exe" -ErrorAction SilentlyContinue |
Sort-Object { [version]$_.Directory.Parent.Name } -Descending |
Select-Object -First 1 -ExpandProperty FullName
if (-not $makeappx) {
throw "makeappx.exe not found under '${env:ProgramFiles(x86)}\Windows Kits\10\bin' - install the Windows SDK"
}
Write-Output "Using makeappx: $makeappx"
& $makeappx pack /d $StagingDir /p $OutputPath /o
if ($LASTEXITCODE -ne 0) { throw "makeappx pack failed with exit code $LASTEXITCODE" }
Write-Output "Packed: $OutputPath"
```
- [ ] **Step 2: Verify locally (conditional)**
If `build/OrcaSlicer/orca-slicer.exe` exists on this machine, run from repo root:
`./scripts/msix/build_msix.ps1 -OutputPath build/OrcaSlicer_test.msix`
Expected: `MSIX version: 2.4.0.0` (current `version.inc`), `Using makeappx: ...`, makeappx output ending in package creation succeeded, `Packed: build/OrcaSlicer_test.msix`. Then delete the test package: `Remove-Item build/OrcaSlicer_test.msix`.
If the install tree does NOT exist, run only the parse/staging guard paths instead:
`./scripts/msix/build_msix.ps1 -InstallDir nonexistent` — expected: throws `orca-slicer.exe not found in 'nonexistent' - build the install tree first`. Full pack then gets verified by the CI run (Task 8).
- [ ] **Step 3: Commit**
```bash
git add scripts/msix/build_msix.ps1
git commit -m "ci: add MSIX packaging script"
```
---
### Task 4: CI step in build_orca.yml
**Files:**
- Modify: `.github/workflows/build_orca.yml` (insert after the "Create installer Win" step, currently lines 295-299, before "Pack app")
- [ ] **Step 1: Add the MSIX build + upload steps**
In `.github/workflows/build_orca.yml`, directly after this existing block:
```yaml
- name: Create installer Win
if: runner.os == 'Windows' && !vars.SELF_HOSTED
working-directory: ${{ github.workspace }}/build
run: |
cpack -G NSIS
```
insert:
```yaml
- name: Build MSIX Store package Win
if: runner.os == 'Windows' && !vars.SELF_HOSTED
working-directory: ${{ github.workspace }}
shell: pwsh
run: |
./scripts/msix/build_msix.ps1 `
-InstallDir "${{ github.workspace }}/build/OrcaSlicer" `
-OutputPath "${{ github.workspace }}/build/OrcaSlicer_Windows_MSIX_${{ env.ver }}.msix" `
-IdentityName "${{ vars.ORCA_MSIX_IDENTITY_NAME || 'OrcaSlicer.Dev' }}" `
-Publisher "${{ vars.ORCA_MSIX_PUBLISHER || 'CN=00000000-0000-0000-0000-000000000000' }}" `
-PublisherDisplayName "${{ vars.ORCA_MSIX_PUBLISHER_DISPLAY_NAME || 'OrcaSlicer (dev)' }}"
```
and after the existing "Upload artifacts Win installer" step (uploads `build/OrcaSlicer*.exe`), insert:
```yaml
- name: Upload artifacts Win MSIX
if: runner.os == 'Windows' && !vars.SELF_HOSTED
uses: actions/upload-artifact@v7
with:
name: OrcaSlicer_Windows_MSIX_${{ env.ver }}
path: ${{ github.workspace }}/build/OrcaSlicer_Windows_MSIX_${{ env.ver }}.msix
```
Notes: gating mirrors the NSIS installer step (`!vars.SELF_HOSTED` — github-hosted runners are guaranteed to have the Windows SDK). The unset-variable fallbacks (`|| '...'`) keep fork/pre-reservation builds green with placeholder identity. Do NOT touch any existing step.
- [ ] **Step 2: Verify YAML parses**
Run (PowerShell): `python -c "import yaml; yaml.safe_load(open('.github/workflows/build_orca.yml', encoding='utf-8')); print('YAML OK')"`
Expected: `YAML OK`. (If python/pyyaml is unavailable, fall back to careful diff review — `git diff .github/workflows/build_orca.yml` — checking indentation matches sibling steps at 6 spaces; final validation is the CI run in Task 8.)
- [ ] **Step 3: Commit**
```bash
git add .github/workflows/build_orca.yml
git commit -m "ci: build MSIX Store package in Windows job"
```
---
### Task 5: packaged-context helpers in GUI_Utils
**Files:**
- Modify: `src/slic3r/GUI/GUI_Utils.hpp` (declarations after `format_nozzle_diameter`, ~line 69)
- Modify: `src/slic3r/GUI/GUI_Utils.cpp` (include + implementations after `format_nozzle_diameter`, ~line 47)
- [ ] **Step 1: Declare the helpers**
In `src/slic3r/GUI/GUI_Utils.hpp`, after the line
`wxString format_nozzle_diameter(float diameter);`
add:
```cpp
// True when running inside an MSIX package (Microsoft Store build); always false on non-Windows.
bool is_running_in_msix();
// Opens the Microsoft Store product page for the current package. No-op when not packaged.
void open_ms_store_product_page();
```
- [ ] **Step 2: Implement them**
In `src/slic3r/GUI/GUI_Utils.cpp`, extend the existing Windows include block (lines 10-14)
```cpp
#ifdef _WIN32
#include <Windows.h>
#include "libslic3r/AppConfig.hpp"
#include <wx/msw/registry.h>
#endif // _WIN32
```
to
```cpp
#ifdef _WIN32
#include <Windows.h>
#include <appmodel.h>
#include "libslic3r/AppConfig.hpp"
#include <wx/msw/registry.h>
#endif // _WIN32
```
and add `#include <wx/utils.h>` to the wx include group (after `#include <wx/display.h>`, line 26).
Then, after the `format_nozzle_diameter` function body (ends ~line 47), add:
```cpp
bool is_running_in_msix()
{
#ifdef _WIN32
// Null-buffer probe: returns ERROR_INSUFFICIENT_BUFFER when packaged,
// APPMODEL_ERROR_NO_PACKAGE when running unpackaged.
static const bool packaged = []() {
UINT32 length = 0;
return ::GetCurrentPackageFullName(&length, nullptr) != APPMODEL_ERROR_NO_PACKAGE;
}();
return packaged;
#else
return false;
#endif
}
void open_ms_store_product_page()
{
#ifdef _WIN32
UINT32 length = 0;
if (::GetCurrentPackageFamilyName(&length, nullptr) != ERROR_INSUFFICIENT_BUFFER)
return;
std::wstring family_name(length, L'\0');
if (::GetCurrentPackageFamilyName(&length, family_name.data()) != ERROR_SUCCESS)
return;
family_name.resize(length > 0 ? length - 1 : 0); // drop the terminating null
wxLaunchDefaultBrowser(wxString(L"ms-windows-store://pdp/?PFN=") + family_name.c_str());
#endif
}
```
- [ ] **Step 3: Build**
Run the Windows build command from the plan header (target `OrcaSlicer`). Expected: exit code 0.
- [ ] **Step 4: Commit**
```bash
git add src/slic3r/GUI/GUI_Utils.hpp src/slic3r/GUI/GUI_Utils.cpp
git commit -m "feat: add MSIX packaged-context detection helpers"
```
---
### Task 6: gate the updater in packaged context
**Files:**
- Modify: `src/slic3r/GUI/GUI_App.cpp` (~line 934, startup auto-check)
- Modify: `src/slic3r/GUI/MainFrame.cpp` (~line 2578, Help menu "Check for Updates")
Both files already include `GUI_Utils.hpp` (GUI_App.cpp directly; MainFrame.cpp via MainFrame.hpp) and are inside `namespace Slic3r::GUI`, so the helpers are callable unqualified.
- [ ] **Step 1: Gate the startup auto-check**
In `src/slic3r/GUI/GUI_App.cpp`, change (inside the `CallAfter` at ~line 934):
```cpp
this->check_new_version_sf();
```
to:
```cpp
// Store builds update through the Microsoft Store, never self-update.
if (!is_running_in_msix())
this->check_new_version_sf();
```
- [ ] **Step 2: Redirect the manual menu check**
In `src/slic3r/GUI/MainFrame.cpp`, change (~lines 2578-2583):
```cpp
append_menu_item(helpMenu, wxID_ANY, _L("Check for Updates"), _L("Check for Updates"),
[](wxCommandEvent&) {
wxGetApp().check_new_version_sf(true, 1);
}, "", nullptr, []() {
return true;
});
```
to:
```cpp
append_menu_item(helpMenu, wxID_ANY, _L("Check for Updates"), _L("Check for Updates"),
[](wxCommandEvent&) {
if (is_running_in_msix())
open_ms_store_product_page();
else
wxGetApp().check_new_version_sf(true, 1);
}, "", nullptr, []() {
return true;
});
```
- [ ] **Step 3: Build**
Run the Windows build command from the plan header (target `OrcaSlicer`). Expected: exit code 0.
- [ ] **Step 4: Commit**
```bash
git add src/slic3r/GUI/GUI_App.cpp src/slic3r/GUI/MainFrame.cpp
git commit -m "feat: suppress self-update in MSIX Store build"
```
---
### Task 7: gate runtime file associations in packaged context
**Files:**
- Modify: `src/slic3r/GUI/GUI_App.cpp` (`associate_files` ~9112, `disassociate_files` ~9137, `associate_url` ~9188, `disassociate_url` ~9213 — line numbers shifted ~+2 by Task 6)
- Modify: `src/slic3r/GUI/Preferences.cpp` (Associate tab, ~lines 1848-1883)
- [ ] **Step 1: Early-return in the four association functions**
In `src/slic3r/GUI/GUI_App.cpp`, add an early return as the first statement inside the `#ifdef WIN32` block of each of the four functions. In `associate_files`:
```cpp
void GUI_App::associate_files(std::wstring extend)
{
#ifdef WIN32
// MSIX: shell integration is declared in the package manifest; registry
// writes from a packaged process are virtualized and invisible to the shell.
if (is_running_in_msix())
return;
wchar_t app_path[MAX_PATH];
```
In `disassociate_files`, `associate_url`, and `disassociate_url`, add the same guard without repeating the comment — first statement inside `#ifdef WIN32`:
```cpp
if (is_running_in_msix())
return;
```
(`associate_url` keeps its Linux `#elif` branch untouched — the guard goes only in the WIN32 branch.)
- [ ] **Step 2: Hide the Associate tab in Preferences**
In `src/slic3r/GUI/Preferences.cpp`, wrap the body of the Associate-tab block (lines 1848-1883). Change:
```cpp
#ifdef _WIN32
m_pref_tabs->AppendItem(_L("Associate"));
```
to:
```cpp
#ifdef _WIN32
// MSIX: associations are declared in the package manifest and defaults are
// managed by Windows Settings; the runtime registry toggles below cannot work.
if (!is_running_in_msix()) {
m_pref_tabs->AppendItem(_L("Associate"));
```
and change the end of that block:
```cpp
g_sizer->AddSpacer(FromDIP(10));
sizer_page->Add(g_sizer, 0, wxEXPAND);
#endif // _WIN32
//////////////////////////
//// DEVELOPER TAB
```
to:
```cpp
g_sizer->AddSpacer(FromDIP(10));
sizer_page->Add(g_sizer, 0, wxEXPAND);
}
#endif // _WIN32
//////////////////////////
//// DEVELOPER TAB
```
(Keep the inner lines at their current indentation — a re-indent would bloat the diff; the `{`/`}` pair at statement level matches the file's pragmatic style. Skipping the whole block keeps `m_pref_tabs` items and `f_sizers` entries paired, which is what the tab-switching logic relies on. This also removes the only `check_url_association` consumers, so no other prompt suppression is needed.)
- [ ] **Step 3: Build**
Run the Windows build command from the plan header (target `OrcaSlicer`). Expected: exit code 0.
- [ ] **Step 4: Sanity-check classic behavior is unchanged**
Launch the freshly built classic exe: `build/src/RelWithDebInfo/orca-slicer.exe` (path per local layout). Open Preferences — the Associate tab must still be present with all checkboxes (we are not packaged, so `is_running_in_msix()` is false). Close the app.
- [ ] **Step 5: Commit**
```bash
git add src/slic3r/GUI/GUI_App.cpp src/slic3r/GUI/Preferences.cpp
git commit -m "feat: suppress runtime file associations in MSIX Store build"
```
---
### Task 8: end-to-end verification + PR
No new files. This is the verification gate the PR description documents (repo guideline: behavior changes need documented verification).
- [ ] **Step 1: Push branch and open a draft PR**
```bash
git push -u origin msix-store-build
gh pr create --draft --title "Add Microsoft Store MSIX package build" --body "<composed per below>"
```
(Compose the body first — pass it via `--body` with a here-string, not `--body-file -`, which blocks on stdin in non-interactive shells.) PR body must include: motivation (SAC blocks unsigned NSIS installer; Store re-signs), summary of the four-token identity scheme + the three repo variables to set after Partner Center name reservation (`ORCA_MSIX_IDENTITY_NAME`, `ORCA_MSIX_PUBLISHER`, `ORCA_MSIX_PUBLISHER_DISPLAY_NAME`), the spec path, and the manual-verification checklist from Steps 3-5 below with results.
- [ ] **Step 2: Verify CI**
Wait for the PR's Windows job. Expected: new "Build MSIX Store package Win" step succeeds with placeholder identity; artifact `OrcaSlicer_Windows_MSIX_PR<N>` contains one `.msix`; NSIS installer and portable zip artifacts still produced unchanged.
- [ ] **Step 3: Local loose-layout install test (Developer Mode required)**
```powershell
./scripts/msix/build_msix.ps1 -StageOnly
Add-AppxPackage -Register "$env:TEMP\orca-msix-staging\AppxManifest.xml"
```
Then verify, with results recorded in the PR:
- App launches from Start menu ("OrcaSlicer (dev)" entry).
- Preferences has NO Associate tab; Help > Check for Updates opens the Store app (placeholder PFN won't resolve to a listing — that's expected pre-reservation; the point is it does NOT run the classic downloader).
- Right-click a `.3mf` file > Open with — packaged OrcaSlicer is listed and opens the file. Visit `orcaslicer://` from a browser — packaged app activates.
- Single-instance hand-off: with the packaged app running, open a second `.3mf` the same way — it loads in the existing instance instead of spawning a new one.
- Config interop: profiles created by the classic install are visible in the packaged app and vice versa (`%APPDATA%\OrcaSlicer` is shared; requires Win11 for the fine-grained exclusion on a loose layout).
- Bambu network plugin: install/download plugin from inside the packaged app succeeds and loads.
- Uninstall the packaged app (right-click in Start) — `%APPDATA%\OrcaSlicer` still exists.
Remove the test registration when done: `Get-AppxPackage *OrcaSlicer.Dev* | Remove-AppxPackage`
- [ ] **Step 4: WACK (optional but recommended)**
On a machine with the Windows SDK: pack a real `.msix` (Task 3 script), then run the Windows App Certification Kit GUI against it. Record pass/fail + any triaged warnings in the PR. (Restricted-capability warnings about `unvirtualizedResources` are expected and justified at submission time.)
- [ ] **Step 5: Mark PR ready for review**
```bash
gh pr ready
```
---
## Post-merge (NOT part of this plan — tracked in MSIX_STORE_HANDOFF.md)
Once the Partner Center company account is approved: reserve the app name, set the three repo variables from Product identity, download the next CI `.msix` artifact, and do the first manual Store submission (listing, IARC, `runFullTrust` + `unvirtualizedResources` justifications). True SAC verification happens post-certification via a private-audience listing.

View File

@@ -1,190 +0,0 @@
# MSIX Microsoft Store Build — Design
Date: 2026-06-11. Status: approved (design review with maintainer).
Planning/requirements background: `MSIX_STORE_HANDOFF.md` (repo root,
validated against Microsoft Learn docs and Store Policies v7.19).
## Goal
Produce an unsigned `.msix` of OrcaSlicer in CI, built from the same
Windows install tree as the NSIS installer, suitable for manual upload to
Partner Center. The Store re-signs with Microsoft's certificate, which
makes the Store build install cleanly on Smart App Control (SAC) machines
that block the unsigned NSIS installer.
Everything is additive: existing build outputs (NSIS exe, portable zip)
are untouched, and every runtime behavior change is gated behind a
packaged-context check so classic builds behave exactly as today.
## Decisions (already made)
- Packaging path: hand-written `AppxManifest.xml` + `makeappx pack` over
the existing install tree. No CPack MSIX generator exists.
- Minimum Windows: 10 1903 (`MinVersion 10.0.18362.0`), declaring BOTH
virtualization elements (Win11 fine-grained exclusion + Win10 coarse
disable). Each OS honors the one it supports.
- Network plugin: keep the runtime downloader, do NOT bundle Bambu's
closed-source DLLs in the package.
- Config stays at the real `%APPDATA%\OrcaSlicer` via manifest
virtualization exclusions + `unvirtualizedResources` restricted
capability. No `data_dir` code changes.
- Submission is manual via Partner Center (first submission must be);
CI only produces the artifact.
## Components
### 1. `scripts/msix/` — packaging files (new)
Precedent: platform packaging already lives under `scripts/` (flatpak).
**`AppxManifest.xml`** — template with four substitution tokens:
`@MSIX_VERSION@`, `@MSIX_IDENTITY_NAME@`, `@MSIX_PUBLISHER@`,
`@MSIX_PUBLISHER_DISPLAY_NAME@` (all three identity strings must match
the Partner Center-assigned values exactly).
Key contents (exact schema/namespace details verified against the MSIX
schema reference during implementation; `makeappx`/WACK validate):
- `TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0"`.
- Capabilities: `runFullTrust` + `rescap:unvirtualizedResources`.
- Under `Properties`, both virtualization elements:
- `virtualization:FileSystemWriteVirtualization` with
`ExcludedDirectory = $(KnownFolder:RoamingAppData)\OrcaSlicer`
(Windows 11 fine-grained), and
- `desktop6:FileSystemWriteVirtualization = disabled`
(Windows 10 1903+ coarse fallback).
- `Application Executable="orca-slicer.exe"
EntryPoint="Windows.FullTrustApplication"` (launcher output name set
at `src/CMakeLists.txt:189`).
- Extensions:
- `windows.fileTypeAssociation` for `.3mf`, `.stl`, `.step`/`.stp`,
`.gcode`, `.drc`. Note: `.gcode` and `.drc` are opt-in in the
classic build; manifest declarations are static, so they are
always declared. Declaring an FTA only adds OrcaSlicer to "Open
with" — the user controls defaults via Windows Settings, so this is
not a behavior regression.
- `windows.protocol` for `orcaslicer://`. The classic build also
offers opt-in handlers for `prusaslicer://`, `bambustudio://` and
`cura://` (Preferences "Associate" tab); those are NOT declared in
the manifest for now (possible follow-up) and their toggles are
hidden in packaged context.
- `rescap3:MigrationProgIds` declaring `Orca.Slicer.1`.
KNOWN LIMITATION: the classic build writes its ProgID with a
leading space (`L" Orca.Slicer.1"`, `GUI_App.cpp:9119`), which
MigrationProgIds cannot express. Migration hand-off from existing
NSIS installs may therefore be partial; Windows shows both apps in
"Open with" and the user picks once. The legacy ProgID is NOT fixed
in this change (separate change with its own migration risk).
**`assets/`** — committed PNGs generated once from
`resources/images/OrcaSlicer.svg`: Square44x44Logo, Square150x150Logo,
StoreLogo (50x50), plus standard scale variants. Committed rather than
generated in CI so the pack step has no extra tool dependencies.
**`build_msix.ps1`** — single script, runnable in CI and locally (needs
Windows SDK for `makeappx`):
1. Parse `version.inc` `SoftFever_VERSION` (`2.4.0-dev` → `2.4.0.0`;
MAJOR.MINOR.PATCH from the leading semver triplet, revision fixed
at 0 as the Store requires).
2. Stage: copy the install tree (`build/OrcaSlicer`) + token-substituted
manifest + `assets/` into a temp layout.
3. `makeappx pack` → `OrcaSlicer_Windows_MSIX_<version>.msix`.
Parameters: `-InstallDir`, `-OutputPath`, `-IdentityName`, `-Publisher`,
`-PublisherDisplayName` (identity defaults are obvious placeholders). NO signing — the Store
strips and re-signs; local testing uses Developer Mode loose-layout
registration instead.
### 2. CI — `.github/workflows/build_orca.yml`
One new step in the Windows job, after the install tree exists (adjacent
to the portable-zip step): run `build_msix.ps1`, upload the `.msix` as a
workflow artifact. Identity comes from repo variables
(`vars.ORCA_MSIX_IDENTITY_NAME`, `vars.ORCA_MSIX_PUBLISHER`,
`vars.ORCA_MSIX_PUBLISHER_DISPLAY_NAME`); when unset,
placeholder defaults still produce a valid artifact (not Store-uploadable,
which is fine pre-approval). The step must not fail the job when repo
variables are absent (forks).
### 3. Runtime changes (Windows-only, packaged-context-gated)
**New helper** — `bool is_running_in_msix()` in
`src/slic3r/GUI/GUI_Utils.{hpp,cpp}`: cached null-buffer
`GetCurrentPackageFullName` probe (`ERROR_INSUFFICIENT_BUFFER` ⇒
packaged, `APPMODEL_ERROR_NO_PACKAGE` ⇒ not); constant `false` on
non-Windows.
**Updater redirection (R4)** — Store apps must not self-update, but
OrcaSlicer's version check is notification-only (it never
auto-downloads), so the check itself stays enabled when packaged:
- The startup auto-check (`check_new_version_sf()`) and the manual
"Check for updates" menu action run unchanged.
- The new-version dialog (`UpdateVersionDialog`) changes when packaged:
the Download button is hidden, the info text tells the user to update
OrcaSlicer from the Microsoft Store, and the "Check on Github"
hyperlink becomes "Open Microsoft Store", which opens the Store
listing via `ms-windows-store://pdp/?PFN=<family>`. The package
family name comes from `GetCurrentPackageFamilyName` at runtime — no
build-time ProductId define or extra repo variable needed, and it
works identically in pre- and post-reservation builds. The packaged
build never opens the GitHub release page.
**Association suppression (R3)** — the manifest owns shell integration;
runtime registry writes are virtualized and invisible:
- Early-return in `associate_files`, `disassociate_files`,
`associate_url`, `disassociate_url` when packaged.
- Hide the whole "Associate" tab in Preferences
(`Preferences.cpp:1848-1883`) in packaged context — the
file-association checkboxes and the `prusaslicer://` /
`bambustudio://` / `cura://` URL-handler rows all rely on runtime
registry writes that are virtualized. The `check_url_association`
consumers live exclusively in that tab, so no other prompt suppression
is needed.
## What does NOT change
- `data_dir` / config location code — `%APPDATA%\OrcaSlicer` everywhere.
- NSIS/CPack packaging, portable zip, all non-Windows builds.
- Bambu network plugin download flow (works against the real AppData
path; SAC behavior verified per the test plan).
- Classic-build association/updater behavior (gates are packaged-only).
## Verification
No meaningful unit-test surface (Windows shell + packaging behavior);
the PR documents manual verification per repo review guidelines:
1. Local loose-layout install (Developer Mode,
`Add-AppxPackage -Register AppxManifest.xml` over the staged layout):
app launches; `.3mf` open-with and `orcaslicer://` activation work;
single-instance hand-off works when launched via the package alias.
2. Config interop: profiles created by a classic install are visible in
the packaged app and vice versa (Win11 machine); profiles survive
packaged-app uninstall.
3. Updater: version check runs as in the classic build (startup +
menu); the new-version dialog hides the Download button, asks the
user to update from the Microsoft Store, and its "Open Microsoft
Store" link opens the Store listing.
4. Network plugin: download + load succeeds in packaged context.
5. WACK run against the CI artifact passes (or failures triaged).
6. CI: Windows job produces the `.msix` artifact with correct version;
NSIS and portable artifacts byte-identical in content to before
(spot-check).
7. Post-certification only: SAC end-to-end test via private-audience
listing (cannot be done locally; Store signature is the variable
under test).
## Sequencing / rollout
The PR lands before Partner Center account approval — placeholder
identity builds a valid artifact. Once the account clears and the app
name is reserved, set the three repo variables (identity name, publisher
`CN=<GUID>`, publisher display name); the next CI run produces the
uploadable package. First Store submission is manual (listing, IARC,
`runFullTrust` + `unvirtualizedResources` justifications) per the
handoff doc's "Submission process" section.
Main external risk (tracked in handoff doc R2.5): Store approval of
`unvirtualizedResources` for a non-game app is not guaranteed; fallback
is documented there and does not change this design's code shape.

View File

@@ -1,75 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:rescap3="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/3"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
IgnorableNamespaces="uap rescap rescap3 desktop6 virtualization">
<Identity Name="@MSIX_IDENTITY_NAME@"
Publisher="@MSIX_PUBLISHER@"
Version="@MSIX_VERSION@"
ProcessorArchitecture="x64" />
<Properties>
<DisplayName>OrcaSlicer</DisplayName>
<PublisherDisplayName>@MSIX_PUBLISHER_DISPLAY_NAME@</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
<!-- Keep config in the real %APPDATA%\OrcaSlicer so it survives uninstall and
is shared with the classic (NSIS/portable) install.
Win10 1903+: coarse switch disables AppData write virtualization entirely.
Win11+: fine-grained exclusion below takes precedence over the coarse switch. -->
<desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
<virtualization:FileSystemWriteVirtualization>
<virtualization:ExcludedDirectories>
<virtualization:ExcludedDirectory>$(KnownFolder:RoamingAppData)\OrcaSlicer</virtualization:ExcludedDirectory>
</virtualization:ExcludedDirectories>
</virtualization:FileSystemWriteVirtualization>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.26100.0" />
</Dependencies>
<Resources>
<Resource Language="en-us" />
</Resources>
<Applications>
<Application Id="OrcaSlicer" Executable="orca-slicer.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
DisplayName="OrcaSlicer"
Description="Open-source slicer for FDM 3D printers"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png" />
<Extensions>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="orcaslicer-models">
<uap:SupportedFileTypes>
<uap:FileType>.3mf</uap:FileType>
<uap:FileType>.stl</uap:FileType>
<uap:FileType>.step</uap:FileType>
<uap:FileType>.stp</uap:FileType>
<uap:FileType>.gcode</uap:FileType>
<uap:FileType>.drc</uap:FileType>
</uap:SupportedFileTypes>
<rescap3:MigrationProgIds>
<rescap3:MigrationProgId>Orca.Slicer.1</rescap3:MigrationProgId>
</rescap3:MigrationProgIds>
</uap:FileTypeAssociation>
</uap:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="orcaslicer" />
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
</Capabilities>
</Package>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,67 +0,0 @@
<#
Builds the unsigned MSIX Store package from an existing install tree.
The package is intentionally NOT signed: the Microsoft Store strips and
re-signs uploads with Microsoft's certificate. For local installs use
Developer Mode loose-layout registration instead:
./scripts/msix/build_msix.ps1 -StageOnly
Add-AppxPackage -Register <staging>\AppxManifest.xml
Requires the Windows SDK (makeappx.exe) unless -StageOnly is used.
#>
param(
[string]$InstallDir = "build/OrcaSlicer",
[string]$OutputPath = "build/OrcaSlicer_Windows_MSIX.msix",
[string]$StagingDir = "",
[switch]$StageOnly,
[string]$IdentityName = "OrcaSlicer.Dev",
[string]$Publisher = "CN=00000000-0000-0000-0000-000000000000",
[string]$PublisherDisplayName = "OrcaSlicer (dev)"
)
$ErrorActionPreference = 'Stop'
$repoRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
# MSIX version = MAJOR.MINOR.PATCH.0 from the SoftFever_VERSION semver triplet
# (Store requires the revision field to be 0).
$versionContent = Get-Content (Join-Path $repoRoot 'version.inc') -Raw
if ($versionContent -notmatch 'set\(SoftFever_VERSION "(\d+)\.(\d+)\.(\d+)') {
throw "Could not parse SoftFever_VERSION from version.inc"
}
$msixVersion = "$($Matches[1]).$($Matches[2]).$($Matches[3]).0"
Write-Output "MSIX version: $msixVersion"
if (-not (Test-Path (Join-Path $InstallDir 'orca-slicer.exe'))) {
throw "orca-slicer.exe not found in '$InstallDir' - build the install tree first"
}
if ([string]::IsNullOrEmpty($StagingDir)) {
$StagingDir = Join-Path ([System.IO.Path]::GetTempPath()) 'orca-msix-staging'
}
if (Test-Path $StagingDir) { Remove-Item $StagingDir -Recurse -Force }
New-Item -ItemType Directory -Force $StagingDir | Out-Null
Copy-Item -Path (Join-Path $InstallDir '*') -Destination $StagingDir -Recurse
Copy-Item -Path (Join-Path $PSScriptRoot 'assets') -Destination (Join-Path $StagingDir 'Assets') -Recurse
$manifest = Get-Content (Join-Path $PSScriptRoot 'AppxManifest.xml') -Raw
$manifest = $manifest.Replace('@MSIX_VERSION@', $msixVersion)
$manifest = $manifest.Replace('@MSIX_IDENTITY_NAME@', $IdentityName)
$manifest = $manifest.Replace('@MSIX_PUBLISHER@', $Publisher)
$manifest = $manifest.Replace('@MSIX_PUBLISHER_DISPLAY_NAME@', $PublisherDisplayName)
Set-Content -Path (Join-Path $StagingDir 'AppxManifest.xml') -Value $manifest -Encoding utf8
if ($StageOnly) {
Write-Output "Staged loose layout at: $StagingDir"
return
}
$makeappx = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.*\x64\makeappx.exe" -ErrorAction SilentlyContinue |
Sort-Object { [version]$_.Directory.Parent.Name } -Descending |
Select-Object -First 1 -ExpandProperty FullName
if (-not $makeappx) {
throw "makeappx.exe not found under '${env:ProgramFiles(x86)}\Windows Kits\10\bin' - install the Windows SDK"
}
Write-Output "Using makeappx: $makeappx"
& $makeappx pack /d $StagingDir /p $OutputPath /o
if ($LASTEXITCODE -ne 0) { throw "makeappx pack failed with exit code $LASTEXITCODE" }
Write-Output "Packed: $OutputPath"

View File

@@ -1,32 +0,0 @@
# Generates the MSIX package logo assets from the 192px master logo.
# Run once on Windows (re-run if the logo changes), then commit the PNGs in assets/.
# Scale-200 variants would need a >192px master; regenerate from OrcaSlicer.svg if ever needed.
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing
$repoRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$source = Join-Path $repoRoot 'resources\images\OrcaSlicer_192px.png'
$outDir = Join-Path $PSScriptRoot 'assets'
New-Item -ItemType Directory -Force $outDir | Out-Null
$sizes = [ordered]@{
'Square150x150Logo.png' = 150
'Square44x44Logo.png' = 44
'Square44x44Logo.targetsize-44_altform-unplated.png' = 44
'StoreLogo.png' = 50
}
$src = [System.Drawing.Image]::FromFile($source)
foreach ($name in $sizes.Keys) {
$px = $sizes[$name]
$bmp = New-Object System.Drawing.Bitmap($px, $px)
$gfx = [System.Drawing.Graphics]::FromImage($bmp)
$gfx.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$gfx.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
$gfx.DrawImage($src, 0, 0, $px, $px)
$gfx.Dispose()
$bmp.Save((Join-Path $outDir $name), [System.Drawing.Imaging.ImageFormat]::Png)
$bmp.Dispose()
Write-Output "Wrote $name (${px}x${px})"
}
$src.Dispose()

View File

@@ -807,6 +807,8 @@ wxAuiToolBarItem* BBLTopbar::FindToolByCurrentPosition()
}
#ifdef __WXMSW__
#include <windowsx.h>
WXLRESULT CenteredTitle::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
switch (nMsg) {
@@ -823,6 +825,8 @@ WXLRESULT BBLTopbar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam
{
switch (nMsg) {
case WM_NCHITTEST: {
m_last_mouse_position = ScreenToClient({GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)});
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
if (item != NULL && item->GetWindow() != m_title_ctrl) {
break;

View File

@@ -2859,11 +2859,7 @@ bool GUI_App::on_init_inner()
switch (dialog.ShowModal())
{
case wxID_YES:
// Store builds get updates from the Microsoft Store, not the GitHub release page.
if (is_running_in_msix())
open_ms_store_product_page();
else
wxLaunchDefaultBrowser(version_info.url);
wxLaunchDefaultBrowser(version_info.url);
break;
case wxID_NO:
break;
@@ -9116,10 +9112,6 @@ static bool del_win_registry(HKEY hkeyHive, const wchar_t *pszVar, const wchar_t
void GUI_App::associate_files(std::wstring extend)
{
#ifdef WIN32
// MSIX: shell integration is declared in the package manifest; registry
// writes from a packaged process are virtualized and invisible to the shell.
if (is_running_in_msix())
return;
wchar_t app_path[MAX_PATH];
::GetModuleFileNameW(nullptr, app_path, sizeof(app_path));
@@ -9145,8 +9137,6 @@ void GUI_App::associate_files(std::wstring extend)
void GUI_App::disassociate_files(std::wstring extend)
{
#ifdef WIN32
if (is_running_in_msix())
return;
wchar_t app_path[MAX_PATH];
::GetModuleFileNameW(nullptr, app_path, sizeof(app_path));
@@ -9198,8 +9188,6 @@ bool GUI_App::check_url_association(std::wstring url_prefix, std::wstring& reg_b
void GUI_App::associate_url(std::wstring url_prefix)
{
#ifdef WIN32
if (is_running_in_msix())
return;
boost::filesystem::path binary_path(boost::filesystem::canonical(boost::dll::program_location()));
wxString wbinary = from_path(binary_path);
BOOST_LOG_TRIVIAL(info) << "Downloader registration: Path of binary: " << wbinary.ToUTF8().data();
@@ -9225,8 +9213,6 @@ void GUI_App::associate_url(std::wstring url_prefix)
void GUI_App::disassociate_url(std::wstring url_prefix)
{
#ifdef WIN32
if (is_running_in_msix())
return;
wxRegKey key_full(wxRegKey::HKCU, "Software\\Classes\\" + url_prefix + "\\shell\\open\\command");
if (!key_full.Exists()) {
return;

View File

@@ -24,7 +24,6 @@
#include <wx/font.h>
#include <wx/fontutil.h>
#include <wx/display.h>
#include <wx/utils.h>
#include "libslic3r/Config.hpp"
@@ -172,42 +171,6 @@ template<class F> typename F::FN winapi_get_function(const wchar_t *dll, const c
}
#endif
bool is_running_in_msix()
{
#ifdef _WIN32
// The package identity APIs are Win8+ - resolved dynamically so the exe still loads on Win7
// (same treatment as the DPI APIs below). Null-buffer probe: returns ERROR_INSUFFICIENT_BUFFER
// when packaged, APPMODEL_ERROR_NO_PACKAGE when running unpackaged.
struct GetCurrentPackageFullName_t { typedef LONG (WINAPI *FN)(UINT32 *length, PWSTR full_name); };
static const bool packaged = []() {
auto fn = winapi_get_function<GetCurrentPackageFullName_t>(L"Kernel32.dll", "GetCurrentPackageFullName");
UINT32 length = 0;
return fn != nullptr && fn(&length, nullptr) != APPMODEL_ERROR_NO_PACKAGE;
}();
return packaged;
#else
return false;
#endif
}
void open_ms_store_product_page()
{
#ifdef _WIN32
struct GetCurrentPackageFamilyName_t { typedef LONG (WINAPI *FN)(UINT32 *length, PWSTR family_name); };
static auto fn = winapi_get_function<GetCurrentPackageFamilyName_t>(L"Kernel32.dll", "GetCurrentPackageFamilyName");
if (fn == nullptr)
return;
UINT32 length = 0;
if (fn(&length, nullptr) != ERROR_INSUFFICIENT_BUFFER)
return;
std::wstring family_name(length, L'\0');
if (fn(&length, family_name.data()) != ERROR_SUCCESS)
return;
family_name.resize(length > 0 ? length - 1 : 0); // drop the terminating null
wxLaunchDefaultBrowser(wxString(L"ms-windows-store://pdp/?PFN=") + family_name.c_str());
#endif
}
// If called with nullptr, a DPI for the primary monitor is returned.
int get_dpi_for_window(const wxWindow *window)
{

View File

@@ -67,10 +67,6 @@ wxDECLARE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent);
wxTopLevelWindow* find_toplevel_parent(wxWindow *window);
wxString format_nozzle_diameter(float diameter);
// True when running inside an MSIX package (Microsoft Store build); always false on non-Windows.
bool is_running_in_msix();
// Opens the Microsoft Store product page for the current package. No-op when not packaged.
void open_ms_store_product_page();
void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback);

View File

@@ -1846,9 +1846,6 @@ void PreferencesDialog::create_items()
//// ASSOCIATE TAB
/////////////////////////////////////
#ifdef _WIN32
// MSIX: associations are declared in the package manifest and defaults are
// managed by Windows Settings; the runtime registry toggles below cannot work.
if (!is_running_in_msix()) {
m_pref_tabs->AppendItem(_L("Associate"));
f_sizers.push_back(new wxFlexGridSizer(1, 1, v_gap, 0));
g_sizer = f_sizers.back();
@@ -1883,7 +1880,6 @@ void PreferencesDialog::create_items()
g_sizer->AddSpacer(FromDIP(10));
sizer_page->Add(g_sizer, 0, wxEXPAND);
}
#endif // _WIN32
//////////////////////////

View File

@@ -5,7 +5,6 @@
#include "libslic3r/Thread.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "GUI_Preview.hpp"
#include "MainFrame.hpp"
#include "format.hpp"
@@ -253,9 +252,7 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
m_text_up_info = new Label(this, Label::Head_14, wxEmptyString, LB_AUTO_WRAP);
m_text_up_info->SetForegroundColour(wxColour(0x26, 0x2E, 0x30));
// Store builds get updates from the Microsoft Store: wxID_YES opens the Store
// product page there (see the EVT_SLIC3R_VERSION_ONLINE handler) instead of GitHub.
auto github_link = new HyperLink(this, is_running_in_msix() ? _L("Open Microsoft Store") : _L("Check on Github"), "", LB_AUTO_WRAP);
auto github_link = new HyperLink(this, _L("Check on Github"), "", LB_AUTO_WRAP);
github_link->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) {
EndModal(wxID_YES);
});
@@ -312,9 +309,6 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
EndModal(wxID_YES);
});
if (is_running_in_msix())
m_button_download->Hide();
m_button_skip_version = new Button(this, _L("Skip this Version"));
m_button_skip_version->SetStyle(ButtonStyle::Regular, ButtonType::Choice);
@@ -485,10 +479,7 @@ void UpdateVersionDialog::update_version_info(wxString release_note, wxString ve
// else {
//m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
m_simplebook_release_note->SetSelection(1);
if (is_running_in_msix())
m_text_up_info->SetLabel(wxString::Format(_L("New version available: %s. Please update OrcaSlicer from the Microsoft Store."), version));
else
m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version));
m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version));
auto data_buf_in = release_note.utf8_str();
auto bg_color = StateColor::darkModeColorFor(wxColour("#FFFFFF")).GetAsString();
auto fg_color = StateColor::darkModeColorFor(wxColour("#262E30")).GetAsString();