From aefbb9b9f9471507f277900261ea1d099c13178e Mon Sep 17 00:00:00 2001 From: Jacob Stephens Date: Sun, 31 May 2026 10:39:05 -0400 Subject: [PATCH] windows: add real app icon (embedded .exe icon + window icon) Generate a multi-resolution app.ico (16-256px) from the web shell's brand icon and wire it in two places the unpackaged app needs: - embeds it in Cascade.exe (Explorer / taskbar / Alt-Tab). - MainWindow sets it via AppWindow.SetIcon for the live window title bar. Previously the app showed the generic default icon. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/windows/Cascade/Assets/app.ico | Bin 0 -> 9660 bytes apps/windows/Cascade/Cascade.csproj | 6 ++++++ apps/windows/Cascade/MainWindow.xaml.cs | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 apps/windows/Cascade/Assets/app.ico diff --git a/apps/windows/Cascade/Assets/app.ico b/apps/windows/Cascade/Assets/app.ico new file mode 100644 index 0000000000000000000000000000000000000000..94a75f8d647936ec495be7384ac90586af3503b1 GIT binary patch literal 9660 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 WsrBm{`cbqW9DX810.0.19041.0 Cascade app.manifest + + Assets\app.ico x64;arm64 win-x64;win-arm64 true @@ -54,6 +56,10 @@ scripts/build-asset.ps1; replace with proper Square*Logo / Wide310x150 assets before shipping a real MSIX. --> + + + PreserveNewest + diff --git a/apps/windows/Cascade/MainWindow.xaml.cs b/apps/windows/Cascade/MainWindow.xaml.cs index e3503a0..679085e 100644 --- a/apps/windows/Cascade/MainWindow.xaml.cs +++ b/apps/windows/Cascade/MainWindow.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using Cascade.Services; using Cascade.ViewModels; using Microsoft.UI.Dispatching; @@ -15,10 +16,25 @@ public sealed partial class MainWindow : Window public MainWindow() { InitializeComponent(); + SetWindowIcon(); ViewModel = new AppViewModel(DispatcherQueue.GetForCurrentThread()); Closed += (_, _) => ViewModel.Dispose(); } + /// + /// Set the title-bar / taskbar icon for this unpackaged window. The .exe + /// already embeds the icon via <ApplicationIcon> (Explorer/Alt-Tab), + /// but the live window needs it set explicitly through AppWindow. + /// + private void SetWindowIcon() + { + var iconPath = Path.Combine(AppContext.BaseDirectory, "Assets", "app.ico"); + if (!File.Exists(iconPath)) return; + var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this); + var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd); + Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId).SetIcon(iconPath); + } + /// /// Slider raises ValueChanged on every motion frame; ignore the initial /// load callback (where IntermediateValue == OldValue) so we don't