mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-03 16:41:26 +01:00
fix(app,packaging): keep libmpv and the taskbar icon across Windows upgrades
An MSI upgrade left the app without libmpv-2.dll until it was installed a second time (B62). Costing runs before RemoveExistingProducts, saw the old DLL at the same version and skipped the copy, and removing the old product then deleted it. Both installer definitions now set REINSTALLMODE=amus; every file is private to the install directory. A taskbar pin lost its icon after a while (B63). The exe carried no icon resource, and the Start Menu shortcut's icon lived in the per-ProductCode installer cache that each upgrade deletes. build.rs now compiles the .ico into proton-stream.exe, and the shortcut has no Icon of its own (and in the WiX build is no longer advertised), so both show the exe's icon.
This commit is contained in:
1 parent
67cf3044f1
commit
6239780978
9 files changed
+150
-6
No files matched your search
Generated
+45
@@ -1866,6 +1866,20 @@ dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embed-resource"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"memchr",
|
||||
"rustc_version",
|
||||
"toml",
|
||||
"vswhom",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "endi"
|
||||
version = "1.1.1"
|
||||
@@ -4387,6 +4401,7 @@ dependencies = [
|
||||
"eframe",
|
||||
"egui",
|
||||
"egui-phosphor",
|
||||
"embed-resource",
|
||||
"futures",
|
||||
"image",
|
||||
"parking_lot",
|
||||
@@ -6248,6 +6263,26 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "vswhom"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"vswhom-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vswhom-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
@@ -7161,6 +7196,16 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.57.1"
|
||||
|
||||
@@ -103,6 +103,8 @@ dbus = "0.9"
|
||||
windows-sys = "0.61"
|
||||
# Toasts on Windows. Linux notifications go over the `dbus` above.
|
||||
tauri-winrt-notification = "0.8"
|
||||
# The exe's own icon resource, which is what Explorer and a taskbar pin draw.
|
||||
embed-resource = "3"
|
||||
rpassword = "7"
|
||||
libloading = "0.8"
|
||||
lru = "0.18"
|
||||
|
||||
@@ -34,6 +34,9 @@ directories.workspace = true
|
||||
chrono.workspace = true
|
||||
souvlaki.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
embed-resource.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
skrifa.workspace = true
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//! Compiles `proton-stream.rc` into the Windows exe; nothing on any other
|
||||
//! target. `rc.exe` on an MSVC build, mingw's `windres` on the cross build
|
||||
//! from Linux.
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=proton-stream.rc");
|
||||
println!("cargo:rerun-if-changed=../../packaging/windows/proton-stream.ico");
|
||||
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") {
|
||||
return;
|
||||
}
|
||||
// Only the GUI gets the icon; `pstr` is a console tool.
|
||||
embed_resource::compile_for("proton-stream.rc", ["proton-stream"], embed_resource::NONE)
|
||||
.manifest_optional()
|
||||
.expect("compile the icon resource");
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// The exe's icon. The window sets one at runtime too, but that only lasts as
|
||||
// long as the window: Explorer, the Start menu and a taskbar pin read the icon
|
||||
// out of the file, and without this one they fall back to the generic one.
|
||||
1 ICON "../../packaging/windows/proton-stream.ico"
|
||||
@@ -146,6 +146,54 @@ and [B44](#b44--r8-broke-the-app-under-instrumentation-in-five-places).
|
||||
|
||||
## Fixed
|
||||
|
||||
### B63 — a taskbar pin on Windows lost its icon
|
||||
|
||||
**Symptom.** Proton Stream pinned to the Windows taskbar showed its icon at
|
||||
first, then after a while — reliably after an update — the generic program
|
||||
icon.
|
||||
|
||||
**Cause.** Two, each enough on its own. `proton-stream.exe` carried no icon
|
||||
resource: the window sets one at runtime, which is what a pin shows while the
|
||||
icon cache still holds it, but a pin made from the running window points at
|
||||
the exe, and once the cache is rebuilt the exe has nothing to give. A pin made
|
||||
from the Start Menu shortcut instead took the shortcut's `Icon`, which Windows
|
||||
Installer keeps in `C:\Windows\Installer\{ProductCode}`. Every upgrade has a
|
||||
new ProductCode and deletes the old product's folder, icon included.
|
||||
|
||||
**Fix.** `crates/pstr-app/build.rs` compiles `proton-stream.rc`, which embeds
|
||||
`packaging/windows/proton-stream.ico`, into the GUI exe: `rc.exe` on MSVC,
|
||||
mingw's `windres` on the cross build. Both installer definitions drop the
|
||||
shortcut's `Icon` (and the WiX one `Advertise`), so the shortcut shows the
|
||||
exe's icon too. A pin that already lost its icon keeps the dead reference;
|
||||
unpin and pin again once.
|
||||
|
||||
**Verified.** `objdump -p` on the cross-built exe lists the `RT_ICON` entries,
|
||||
all seven sizes. `msiinfo export … Shortcut` on a wixl build has an empty
|
||||
`Icon_` column. Not yet checked on a Windows taskbar across an upgrade.
|
||||
|
||||
### B62 — an MSI upgrade left the app without libmpv
|
||||
|
||||
**Symptom.** Installing a new `.msi` over an old one ended with an app that
|
||||
would not start for want of mpv. Installing the same `.msi` a second time
|
||||
fixed it.
|
||||
|
||||
**Cause.** Both installers remove the old product early — the wixl one at
|
||||
`RemoveExistingProducts` after `InstallInitialize`, WiX's `MajorUpgrade` by
|
||||
default after `InstallValidate` — but costing runs before either, at
|
||||
`CostFinalize`. Costing found the old `libmpv-2.dll` on disk with the same
|
||||
version as the new one, since mpv is pinned, and decided not to copy it. Then
|
||||
removing the old product deleted it. The second install found no DLL on disk,
|
||||
so it copied one.
|
||||
|
||||
**Fix.** `REINSTALLMODE=amus` in both installer definitions, which copies every
|
||||
file whatever is on disk. Every file is private to the install directory, so
|
||||
the forced overwrite can downgrade nothing shared.
|
||||
|
||||
**Verified.** `msiinfo export … InstallExecuteSequence` on a wixl build shows
|
||||
`FileCost` 900 and `CostFinalize` 1000 ahead of `RemoveExistingProducts` 1501,
|
||||
and `msiinfo export … Property` has `REINSTALLMODE amus`. Not yet checked as an
|
||||
upgrade on Windows.
|
||||
|
||||
### B61 — later seasons were captioned with season one's episode names
|
||||
|
||||
**Symptom.** On a 42-title AniList library, Attack on Titan seasons 2–4 and
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ The `.icns` is rasterized from `io.narl.proton-stream.svg` when `rsvg-convert` o
|
||||
| `io.narl.proton-stream.desktop` / `.svg` | Freedesktop entry and icon |
|
||||
| `macos/Info.plist.in` | `.app` bundle plist; `@VERSION@`/`@BIN@`/`@APP_ID@` substituted at build time |
|
||||
| `windows/proton-stream.wxs` | WiX v4+ installer definition |
|
||||
| `windows/proton-stream.ico` | MSI and shortcut icon, rasterized from the SVG |
|
||||
| `windows/proton-stream.ico` | Exe and Add/Remove Programs icon, rasterized from the SVG; `crates/pstr-app/build.rs` compiles it into `proton-stream.exe` |
|
||||
| `windows/license.rtf` | Fallback for the installer's license dialog; the repo's own `LICENSE` is preferred when it exists |
|
||||
|
||||
The Debian `control` file has no template — `scripts/build.sh` writes it, because
|
||||
|
||||
@@ -78,6 +78,15 @@
|
||||
<RemoveExistingProducts After="InstallInitialize" />
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<!-- Copy every file on an upgrade, whatever is on disk. Costing runs
|
||||
before RemoveExistingProducts, so it sees the old libmpv-2.dll — the
|
||||
same version, since mpv is pinned — and decides not to copy it. The
|
||||
removal of the old product then deletes it, and the upgrade ends with
|
||||
no DLL: "mpv missing" until a second install, which finds nothing on
|
||||
disk and copies it. Every file here is private to INSTALLDIR, so
|
||||
overwriting unconditionally downgrades nothing shared. -->
|
||||
<Property Id="REINSTALLMODE" Value="amus" />
|
||||
|
||||
<Media Id="1" Cabinet="proton_stream.cab" EmbedCab="yes" />
|
||||
|
||||
<Icon Id="proton-stream.ico" SourceFile="$(var.IconFile)" />
|
||||
@@ -98,14 +107,19 @@
|
||||
and writes the advertised form anyway, with the feature name in
|
||||
Shortcut/Target. What selects the non-advertised form is being
|
||||
a child of the Component rather than of the File, plus an
|
||||
explicit formatted Target. Keep it out of the <File>. -->
|
||||
explicit formatted Target. Keep it out of the <File>.
|
||||
|
||||
No Icon either. A shortcut's Icon is copied to
|
||||
C:\Windows\Installer\{ProductCode}, and every upgrade has a
|
||||
new ProductCode and deletes the old folder — taking the icon
|
||||
of every taskbar pin made from the shortcut with it. Without
|
||||
one, the shortcut shows the exe's own icon resource. -->
|
||||
<Shortcut Id="StartMenuShortcut"
|
||||
Directory="ProgramMenuFolder"
|
||||
Name="Proton Stream"
|
||||
Description="Browse and stream a Proton Drive public link"
|
||||
Target="[INSTALLDIR]proton-stream.exe"
|
||||
WorkingDirectory="INSTALLDIR"
|
||||
Icon="proton-stream.ico" />
|
||||
WorkingDirectory="INSTALLDIR" />
|
||||
</Component>
|
||||
|
||||
<!-- The CLI, and the PATH entry that makes it worth installing. Tied
|
||||
|
||||
@@ -26,6 +26,15 @@
|
||||
DowngradeErrorMessage="A newer version of Proton Stream is already installed." />
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
|
||||
<!-- Copy every file on an upgrade, whatever is on disk. Costing runs
|
||||
before RemoveExistingProducts, so it sees the old libmpv-2.dll — the
|
||||
same version, since mpv is pinned — and decides not to copy it. The
|
||||
removal of the old product then deletes it, and the upgrade ends with
|
||||
no DLL: "mpv missing" until a second install, which finds nothing on
|
||||
disk and copies it. Every file here is private to INSTALLFOLDER, so
|
||||
overwriting unconditionally downgrades nothing shared. -->
|
||||
<Property Id="REINSTALLMODE" Value="amus" />
|
||||
|
||||
<Icon Id="AppIcon" SourceFile="$(var.IconFile)" />
|
||||
<Property Id="ARPPRODUCTICON" Value="AppIcon" />
|
||||
<Property Id="ARPURLINFOABOUT" Value="https://github.com/narrrl/proton-stream" />
|
||||
@@ -45,12 +54,16 @@
|
||||
<ComponentGroup Id="AppComponents" Directory="INSTALLFOLDER">
|
||||
<Component Guid="623c8cb8-b826-4d57-a054-e5be56f24c19">
|
||||
<File Id="AppExe" Source="$(var.BinDir)\proton-stream.exe" KeyPath="yes" />
|
||||
<!-- Not advertised, and no Icon: either one puts the shortcut's icon
|
||||
in C:\Windows\Installer\{ProductCode}, which the next upgrade
|
||||
deletes along with the icon of every taskbar pin made from the
|
||||
shortcut. This way it shows the exe's own icon resource. -->
|
||||
<Shortcut Id="StartMenuShortcut"
|
||||
Directory="ProgramMenuFolder"
|
||||
Name="Proton Stream"
|
||||
Description="Browse and stream a Proton Drive public link"
|
||||
Icon="AppIcon"
|
||||
Advertise="yes" />
|
||||
Target="[#AppExe]"
|
||||
WorkingDirectory="INSTALLFOLDER" />
|
||||
</Component>
|
||||
|
||||
<!-- The CLI, and the PATH entry that makes it worth installing. Tied to
|
||||
|
||||
Reference in new issue
Block a user