From 7cab80e722a88de14e0fe30c496b07bf4708fc72 Mon Sep 17 00:00:00 2001 From: Razshy <88072010+Razshy@users.noreply.github.com> Date: Wed, 15 Apr 2026 03:28:32 +0000 Subject: [PATCH 1/3] fix(codegen): select largest ICO entry instead of first --- .changes/fix-ico-largest-entry.md | 5 +++++ crates/tauri-codegen/src/image.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changes/fix-ico-largest-entry.md diff --git a/.changes/fix-ico-largest-entry.md b/.changes/fix-ico-largest-entry.md new file mode 100644 index 000000000000..60db04d07cfc --- /dev/null +++ b/.changes/fix-ico-largest-entry.md @@ -0,0 +1,5 @@ +--- +"tauri-codegen": patch:bug +--- + +Select the largest entry from ICO files instead of the first, fixing blurry window icons on Windows. diff --git a/crates/tauri-codegen/src/image.rs b/crates/tauri-codegen/src/image.rs index 49546082a9b7..da1790166756 100644 --- a/crates/tauri-codegen/src/image.rs +++ b/crates/tauri-codegen/src/image.rs @@ -54,7 +54,7 @@ impl CachedIcon { let icon_dir = ico::IconDir::read(Cursor::new(&buf)) .unwrap_or_else(|e| panic!("failed to parse icon {}: {}", icon.display(), e)); - let entry = &icon_dir.entries()[0]; + let entry = icon_dir.entries().iter().max_by_key(|e| e.width()).unwrap(); let rgba = entry .decode() .unwrap_or_else(|e| panic!("failed to decode icon {}: {}", icon.display(), e)) From d29f5f00a34c500494bef49ac082a4c52fb127af Mon Sep 17 00:00:00 2001 From: Razshy <88072010+Razshy@users.noreply.github.com> Date: Mon, 20 Apr 2026 22:57:21 +0000 Subject: [PATCH 2/3] fix(runtime-wry): use exe resource icon on Windows --- .changes/fix-ico-largest-entry.md | 3 ++- crates/tauri-runtime-wry/src/lib.rs | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.changes/fix-ico-largest-entry.md b/.changes/fix-ico-largest-entry.md index 60db04d07cfc..976b7c1e446a 100644 --- a/.changes/fix-ico-largest-entry.md +++ b/.changes/fix-ico-largest-entry.md @@ -1,5 +1,6 @@ --- "tauri-codegen": patch:bug +"tauri-runtime-wry": patch:bug --- -Select the largest entry from ICO files instead of the first, fixing blurry window icons on Windows. +On Windows, load the window icon from the exe-embedded resource so both the titlebar (`ICON_SMALL`) and taskbar (`ICON_BIG`) use the multi-size ICO instead of a single RGBA buffer. Also select the largest ICO entry in codegen as a fallback. diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 6c537de6cf43..a8fcb47bea63 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -48,7 +48,7 @@ use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS} ))] use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix}; #[cfg(windows)] -use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows}; +use tao::platform::windows::{IconExtWindows, WindowBuilderExtWindows, WindowExtWindows}; #[cfg(windows)] use webview2_com::{ContainsFullScreenElementChangedEventHandler, FocusChangedEventHandler}; #[cfg(windows)] @@ -1219,6 +1219,19 @@ impl WindowBuilder for WindowBuilderWrapper { } fn icon(mut self, icon: Icon) -> Result { + #[cfg(windows)] + { + let small = TaoWindowIcon::from_resource(32512, Some(TaoPhysicalSize::new(16, 16))); + let big = TaoWindowIcon::from_resource(32512, None); + if let (Ok(small_icon), Ok(big_icon)) = (small, big) { + self.inner = self + .inner + .with_window_icon(Some(small_icon)) + .with_taskbar_icon(Some(big_icon)); + return Ok(self); + } + } + self.inner = self .inner .with_window_icon(Some(TaoIcon::try_from(icon)?.0)); From 55d4be545fb5034ffd0eaf248154399498808af3 Mon Sep 17 00:00:00 2001 From: Razshy <88072010+Razshy@users.noreply.github.com> Date: Tue, 21 Apr 2026 05:00:51 +0000 Subject: [PATCH 3/3] fix: cap codegen icon at 32x32, use exe resource for ICON_BIG --- .changes/fix-ico-largest-entry.md | 2 +- crates/tauri-codegen/src/image.rs | 6 +++++- crates/tauri-runtime-wry/src/lib.rs | 17 ++++++----------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.changes/fix-ico-largest-entry.md b/.changes/fix-ico-largest-entry.md index 976b7c1e446a..eceebc37741a 100644 --- a/.changes/fix-ico-largest-entry.md +++ b/.changes/fix-ico-largest-entry.md @@ -3,4 +3,4 @@ "tauri-runtime-wry": patch:bug --- -On Windows, load the window icon from the exe-embedded resource so both the titlebar (`ICON_SMALL`) and taskbar (`ICON_BIG`) use the multi-size ICO instead of a single RGBA buffer. Also select the largest ICO entry in codegen as a fallback. +On Windows, set `ICON_BIG` from the exe-embedded ICO resource via `IconExtWindows::from_resource` for crisp taskbar and alt-tab icons. Cap the codegen ICO entry at 32x32 for `ICON_SMALL` to reduce binary size. diff --git a/crates/tauri-codegen/src/image.rs b/crates/tauri-codegen/src/image.rs index da1790166756..e9c7384104f4 100644 --- a/crates/tauri-codegen/src/image.rs +++ b/crates/tauri-codegen/src/image.rs @@ -54,7 +54,11 @@ impl CachedIcon { let icon_dir = ico::IconDir::read(Cursor::new(&buf)) .unwrap_or_else(|e| panic!("failed to parse icon {}: {}", icon.display(), e)); - let entry = icon_dir.entries().iter().max_by_key(|e| e.width()).unwrap(); + let entry = icon_dir + .entries() + .iter() + .min_by_key(|e| e.width().abs_diff(32)) + .unwrap(); let rgba = entry .decode() .unwrap_or_else(|e| panic!("failed to decode icon {}: {}", icon.display(), e)) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index a8fcb47bea63..b6cb3baadb6a 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -1219,22 +1219,17 @@ impl WindowBuilder for WindowBuilderWrapper { } fn icon(mut self, icon: Icon) -> Result { + self.inner = self + .inner + .with_window_icon(Some(TaoIcon::try_from(icon)?.0)); + #[cfg(windows)] { - let small = TaoWindowIcon::from_resource(32512, Some(TaoPhysicalSize::new(16, 16))); - let big = TaoWindowIcon::from_resource(32512, None); - if let (Ok(small_icon), Ok(big_icon)) = (small, big) { - self.inner = self - .inner - .with_window_icon(Some(small_icon)) - .with_taskbar_icon(Some(big_icon)); - return Ok(self); + if let Ok(resource_icon) = TaoWindowIcon::from_resource(32512, None) { + self.inner = self.inner.with_taskbar_icon(Some(resource_icon)); } } - self.inner = self - .inner - .with_window_icon(Some(TaoIcon::try_from(icon)?.0)); Ok(self) }