Skip to content

Commit 8c93587

Browse files
authored
refactor(core): move png and ico behind Cargo features (#3588)
1 parent a332b09 commit 8c93587

File tree

24 files changed

+298
-134
lines changed

24 files changed

+298
-134
lines changed

.changes/icon-compile-time.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri": patch
3+
"tauri-codegen": patch
4+
---
5+
6+
Parse window icons at compile time.

.changes/icon-feature.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": patch
3+
"tauri-runtime": patch
4+
"tauri-runtime-wry": patch
5+
---
6+
7+
**Breaking change:** Move `ico` and `png` parsing behind `icon-ico` and `icon-png` Cargo features.

core/tauri-codegen/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ zstd = { version = "0.10", optional = true }
2727
regex = { version = "1", optional = true }
2828
uuid = { version = "0.8", features = [ "v4" ] }
2929

30+
[target."cfg(windows)".dependencies]
31+
ico = "0.1"
32+
33+
[target."cfg(not(windows))".dependencies]
34+
png = "0.16"
35+
3036
[features]
3137
default = [ "compression" ]
3238
compression = [ "zstd", "tauri-utils/compression" ]

core/tauri-codegen/src/context.rs

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,25 +165,28 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
165165
};
166166

167167
// handle default window icons for Windows targets
168-
let default_window_icon = if cfg!(windows) {
168+
#[cfg(windows)]
169+
let default_window_icon = {
169170
let icon_path = find_icon(
170171
&config,
171172
&config_parent,
172173
|i| i.ends_with(".ico"),
173174
"icons/icon.ico",
174175
);
175-
quote!(Some(include_bytes!(#icon_path).to_vec()))
176-
} else if cfg!(target_os = "linux") {
176+
ico_icon(&root, icon_path)
177+
};
178+
#[cfg(target_os = "linux")]
179+
let default_window_icon = {
177180
let icon_path = find_icon(
178181
&config,
179182
&config_parent,
180183
|i| i.ends_with(".png"),
181184
"icons/icon.png",
182185
);
183-
quote!(Some(include_bytes!(#icon_path).to_vec()))
184-
} else {
185-
quote!(None)
186+
png_icon(&root, icon_path)
186187
};
188+
#[cfg(not(any(windows, target_os = "linux")))]
189+
let default_window_icon = quote!(None);
187190

188191
let package_name = if let Some(product_name) = &config.package.product_name {
189192
quote!(#product_name.to_string())
@@ -213,12 +216,12 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
213216
.join(system_tray_icon_path)
214217
.display()
215218
.to_string();
216-
quote!(Some(#root::Icon::File(::std::path::PathBuf::from(#system_tray_icon_path))))
219+
quote!(Some(#root::TrayIcon::File(::std::path::PathBuf::from(#system_tray_icon_path))))
217220
} else {
218221
let system_tray_icon_file_path = system_tray_icon_path.to_string_lossy().to_string();
219222
quote!(
220223
Some(
221-
#root::Icon::File(
224+
#root::TrayIcon::File(
222225
#root::api::path::resolve_path(
223226
&#config,
224227
&#package_info,
@@ -242,7 +245,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
242245
.join(system_tray_icon_path)
243246
.display()
244247
.to_string();
245-
quote!(Some(#root::Icon::Raw(include_bytes!(#system_tray_icon_path).to_vec())))
248+
quote!(Some(#root::TrayIcon::Raw(include_bytes!(#system_tray_icon_path).to_vec())))
246249
} else {
247250
quote!(None)
248251
};
@@ -337,6 +340,46 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
337340
)))
338341
}
339342

343+
#[cfg(windows)]
344+
fn ico_icon<P: AsRef<Path>>(root: &TokenStream, path: P) -> TokenStream {
345+
let path = path.as_ref();
346+
let bytes = std::fs::read(&path)
347+
.unwrap_or_else(|_| panic!("failed to read window icon {}", path.display()))
348+
.to_vec();
349+
let icon_dir = ico::IconDir::read(std::io::Cursor::new(bytes))
350+
.unwrap_or_else(|_| panic!("failed to parse window icon {}", path.display()));
351+
let entry = &icon_dir.entries()[0];
352+
let rgba = entry
353+
.decode()
354+
.unwrap_or_else(|_| panic!("failed to decode window icon {}", path.display()))
355+
.rgba_data()
356+
.to_vec();
357+
let width = entry.width();
358+
let height = entry.height();
359+
let rgba_items = rgba.into_iter();
360+
quote!(Some(#root::Icon::Rgba { rgba: vec![#(#rgba_items),*], width: #width, height: #height }))
361+
}
362+
363+
#[cfg(not(windows))]
364+
fn png_icon<P: AsRef<Path>>(root: &TokenStream, path: P) -> TokenStream {
365+
let path = path.as_ref();
366+
let bytes = std::fs::read(&path)
367+
.unwrap_or_else(|_| panic!("failed to read window icon {}", path.display()))
368+
.to_vec();
369+
let decoder = png::Decoder::new(std::io::Cursor::new(bytes));
370+
let (info, mut reader) = decoder
371+
.read_info()
372+
.unwrap_or_else(|_| panic!("failed to read window icon {}", path.display()));
373+
let mut buffer: Vec<u8> = Vec::new();
374+
while let Ok(Some(row)) = reader.next_row() {
375+
buffer.extend(row);
376+
}
377+
let rgba_items = buffer.into_iter();
378+
let width = info.width;
379+
let height = info.height;
380+
quote!(Some(#root::Icon::Rgba { rgba: vec![#(#rgba_items),*], width: #width, height: #height }))
381+
}
382+
340383
fn find_icon<F: Fn(&&String) -> bool>(
341384
config: &Config,
342385
config_parent: &Path,

core/tauri-runtime-wry/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,15 @@ wry = { version = "0.13.3", default-features = false, features = [ "file-drop",
1717
tauri-runtime = { version = "0.3.2", path = "../tauri-runtime" }
1818
tauri-utils = { version = "1.0.0-rc.2", path = "../tauri-utils" }
1919
uuid = { version = "0.8.2", features = [ "v4" ] }
20-
infer = "0.4"
2120

2221
[target."cfg(windows)".dependencies]
23-
ico = "0.1"
2422
webview2-com = "0.13.0"
2523

2624
[target."cfg(windows)".dependencies.windows]
2725
version = "0.30.0"
2826
features = [ "Win32_Foundation" ]
2927

3028
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
31-
png = "0.16"
3229
gtk = { version = "0.15", features = [ "v3_20" ] }
3330

3431
[features]

core/tauri-runtime-wry/src/lib.rs

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use tauri_runtime::{
1616
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
1717
DetachedWindow, JsEventListenerKey, PendingWindow, WindowEvent,
1818
},
19-
ClipboardManager, Dispatch, Error, ExitRequestedEventAction, GlobalShortcutManager, Icon, Result,
20-
RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType,
19+
ClipboardManager, Dispatch, Error, ExitRequestedEventAction, GlobalShortcutManager, Result,
20+
RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType, WindowIcon,
2121
};
2222

2323
use tauri_runtime::window::MenuEvent;
@@ -56,7 +56,7 @@ use wry::{
5656
MenuItemAttributes as WryMenuItemAttributes, MenuType,
5757
},
5858
monitor::MonitorHandle,
59-
window::{Fullscreen, Icon as WindowIcon, UserAttentionType as WryUserAttentionType},
59+
window::{Fullscreen, Icon as WryWindowIcon, UserAttentionType as WryUserAttentionType},
6060
},
6161
http::{
6262
Request as WryHttpRequest, RequestParts as WryRequestParts, Response as WryHttpResponse,
@@ -84,7 +84,6 @@ use std::{
8484
HashMap, HashSet,
8585
},
8686
fmt,
87-
fs::read,
8887
ops::Deref,
8988
path::PathBuf,
9089
sync::{
@@ -482,52 +481,18 @@ impl ClipboardManager for ClipboardManagerWrapper {
482481
}
483482

484483
/// Wrapper around a [`wry::application::window::Icon`] that can be created from an [`Icon`].
485-
pub struct WryIcon(WindowIcon);
484+
pub struct WryIcon(WryWindowIcon);
486485

487486
fn icon_err<E: std::error::Error + Send + 'static>(e: E) -> Error {
488487
Error::InvalidIcon(Box::new(e))
489488
}
490489

491-
impl TryFrom<Icon> for WryIcon {
490+
impl TryFrom<WindowIcon> for WryIcon {
492491
type Error = Error;
493-
fn try_from(icon: Icon) -> std::result::Result<Self, Self::Error> {
494-
let image_bytes = match icon {
495-
Icon::File(path) => read(path).map_err(icon_err)?,
496-
Icon::Raw(raw) => raw,
497-
_ => unimplemented!(),
498-
};
499-
let extension = infer::get(&image_bytes)
500-
.expect("could not determine icon extension")
501-
.extension();
502-
match extension {
503-
#[cfg(windows)]
504-
"ico" => {
505-
let icon_dir = ico::IconDir::read(std::io::Cursor::new(image_bytes)).map_err(icon_err)?;
506-
let entry = &icon_dir.entries()[0];
507-
let icon = WindowIcon::from_rgba(
508-
entry.decode().map_err(icon_err)?.rgba_data().to_vec(),
509-
entry.width(),
510-
entry.height(),
511-
)
512-
.map_err(icon_err)?;
513-
Ok(Self(icon))
514-
}
515-
#[cfg(target_os = "linux")]
516-
"png" => {
517-
let decoder = png::Decoder::new(std::io::Cursor::new(image_bytes));
518-
let (info, mut reader) = decoder.read_info().map_err(icon_err)?;
519-
let mut buffer = Vec::new();
520-
while let Ok(Some(row)) = reader.next_row() {
521-
buffer.extend(row);
522-
}
523-
let icon = WindowIcon::from_rgba(buffer, info.width, info.height).map_err(icon_err)?;
524-
Ok(Self(icon))
525-
}
526-
_ => panic!(
527-
"image `{}` extension not supported; please file a Tauri feature request",
528-
extension
529-
),
530-
}
492+
fn try_from(icon: WindowIcon) -> std::result::Result<Self, Self::Error> {
493+
WryWindowIcon::from_rgba(icon.rgba, icon.width, icon.height)
494+
.map(Self)
495+
.map_err(icon_err)
531496
}
532497
}
533498

@@ -851,7 +816,7 @@ impl WindowBuilder for WindowBuilderWrapper {
851816
self
852817
}
853818

854-
fn icon(mut self, icon: Icon) -> Result<Self> {
819+
fn icon(mut self, icon: WindowIcon) -> Result<Self> {
855820
self.inner = self
856821
.inner
857822
.with_window_icon(Some(WryIcon::try_from(icon)?.0));
@@ -975,7 +940,7 @@ pub enum WindowMessage {
975940
SetPosition(Position),
976941
SetFullscreen(bool),
977942
SetFocus,
978-
SetIcon(WindowIcon),
943+
SetIcon(WryWindowIcon),
979944
SetSkipTaskbar(bool),
980945
DragWindow,
981946
UpdateMenuItem(u16, MenuUpdate),
@@ -1001,7 +966,7 @@ pub enum WebviewEvent {
1001966
pub enum TrayMessage {
1002967
UpdateItem(u16, MenuUpdate),
1003968
UpdateMenu(SystemTrayMenu),
1004-
UpdateIcon(Icon),
969+
UpdateIcon(TrayIcon),
1005970
#[cfg(target_os = "macos")]
1006971
UpdateIconAsTemplate(bool),
1007972
Close,
@@ -1392,7 +1357,7 @@ impl Dispatch for WryDispatcher {
13921357
)
13931358
}
13941359

1395-
fn set_icon(&self, icon: Icon) -> Result<()> {
1360+
fn set_icon(&self, icon: WindowIcon) -> Result<()> {
13961361
send_user_message(
13971362
&self.context,
13981363
Message::Window(
@@ -1790,7 +1755,7 @@ impl Runtime for Wry {
17901755
let icon = system_tray
17911756
.icon
17921757
.expect("tray icon not set")
1793-
.into_tray_icon();
1758+
.into_platform_icon();
17941759

17951760
let mut items = HashMap::new();
17961761

@@ -2208,7 +2173,7 @@ fn handle_user_message(
22082173
}
22092174
TrayMessage::UpdateIcon(icon) => {
22102175
if let Some(tray) = &*tray_context.tray.lock().unwrap() {
2211-
tray.lock().unwrap().set_icon(icon.into_tray_icon());
2176+
tray.lock().unwrap().set_icon(icon.into_platform_icon());
22122177
}
22132178
}
22142179
#[cfg(target_os = "macos")]

core/tauri-runtime-wry/src/system_tray.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub use tauri_runtime::{
77
Menu, MenuEntry, MenuItem, MenuUpdate, Submenu, SystemTrayMenu, SystemTrayMenuEntry,
88
SystemTrayMenuItem, TrayHandle,
99
},
10-
Icon, SystemTrayEvent,
10+
SystemTrayEvent, TrayIcon,
1111
};
1212
pub use wry::application::{
1313
event::TrayEvent,
@@ -41,7 +41,7 @@ pub struct SystemTrayHandle {
4141
}
4242

4343
impl TrayHandle for SystemTrayHandle {
44-
fn set_icon(&self, icon: Icon) -> Result<()> {
44+
fn set_icon(&self, icon: TrayIcon) -> Result<()> {
4545
self
4646
.proxy
4747
.send_event(Message::Tray(TrayMessage::UpdateIcon(icon)))

0 commit comments

Comments
 (0)