Skip to content

Commit

Permalink
refactor(core): move png and ico behind Cargo features (#3588)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Mar 5, 2022
1 parent a332b09 commit 8c93587
Show file tree
Hide file tree
Showing 24 changed files with 298 additions and 134 deletions.
6 changes: 6 additions & 0 deletions .changes/icon-compile-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri": patch
"tauri-codegen": patch
---

Parse window icons at compile time.
7 changes: 7 additions & 0 deletions .changes/icon-feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri": patch
"tauri-runtime": patch
"tauri-runtime-wry": patch
---

**Breaking change:** Move `ico` and `png` parsing behind `icon-ico` and `icon-png` Cargo features.
6 changes: 6 additions & 0 deletions core/tauri-codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ zstd = { version = "0.10", optional = true }
regex = { version = "1", optional = true }
uuid = { version = "0.8", features = [ "v4" ] }

[target."cfg(windows)".dependencies]
ico = "0.1"

[target."cfg(not(windows))".dependencies]
png = "0.16"

[features]
default = [ "compression" ]
compression = [ "zstd", "tauri-utils/compression" ]
Expand Down
61 changes: 52 additions & 9 deletions core/tauri-codegen/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,25 +165,28 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
};

// handle default window icons for Windows targets
let default_window_icon = if cfg!(windows) {
#[cfg(windows)]
let default_window_icon = {
let icon_path = find_icon(
&config,
&config_parent,
|i| i.ends_with(".ico"),
"icons/icon.ico",
);
quote!(Some(include_bytes!(#icon_path).to_vec()))
} else if cfg!(target_os = "linux") {
ico_icon(&root, icon_path)
};
#[cfg(target_os = "linux")]
let default_window_icon = {
let icon_path = find_icon(
&config,
&config_parent,
|i| i.ends_with(".png"),
"icons/icon.png",
);
quote!(Some(include_bytes!(#icon_path).to_vec()))
} else {
quote!(None)
png_icon(&root, icon_path)
};
#[cfg(not(any(windows, target_os = "linux")))]
let default_window_icon = quote!(None);

let package_name = if let Some(product_name) = &config.package.product_name {
quote!(#product_name.to_string())
Expand Down Expand Up @@ -213,12 +216,12 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
.join(system_tray_icon_path)
.display()
.to_string();
quote!(Some(#root::Icon::File(::std::path::PathBuf::from(#system_tray_icon_path))))
quote!(Some(#root::TrayIcon::File(::std::path::PathBuf::from(#system_tray_icon_path))))
} else {
let system_tray_icon_file_path = system_tray_icon_path.to_string_lossy().to_string();
quote!(
Some(
#root::Icon::File(
#root::TrayIcon::File(
#root::api::path::resolve_path(
&#config,
&#package_info,
Expand All @@ -242,7 +245,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
.join(system_tray_icon_path)
.display()
.to_string();
quote!(Some(#root::Icon::Raw(include_bytes!(#system_tray_icon_path).to_vec())))
quote!(Some(#root::TrayIcon::Raw(include_bytes!(#system_tray_icon_path).to_vec())))
} else {
quote!(None)
};
Expand Down Expand Up @@ -337,6 +340,46 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
)))
}

#[cfg(windows)]
fn ico_icon<P: AsRef<Path>>(root: &TokenStream, path: P) -> TokenStream {
let path = path.as_ref();
let bytes = std::fs::read(&path)
.unwrap_or_else(|_| panic!("failed to read window icon {}", path.display()))
.to_vec();
let icon_dir = ico::IconDir::read(std::io::Cursor::new(bytes))
.unwrap_or_else(|_| panic!("failed to parse window icon {}", path.display()));
let entry = &icon_dir.entries()[0];
let rgba = entry
.decode()
.unwrap_or_else(|_| panic!("failed to decode window icon {}", path.display()))
.rgba_data()
.to_vec();
let width = entry.width();
let height = entry.height();
let rgba_items = rgba.into_iter();
quote!(Some(#root::Icon::Rgba { rgba: vec![#(#rgba_items),*], width: #width, height: #height }))
}

#[cfg(not(windows))]
fn png_icon<P: AsRef<Path>>(root: &TokenStream, path: P) -> TokenStream {
let path = path.as_ref();
let bytes = std::fs::read(&path)
.unwrap_or_else(|_| panic!("failed to read window icon {}", path.display()))
.to_vec();
let decoder = png::Decoder::new(std::io::Cursor::new(bytes));
let (info, mut reader) = decoder
.read_info()
.unwrap_or_else(|_| panic!("failed to read window icon {}", path.display()));
let mut buffer: Vec<u8> = Vec::new();
while let Ok(Some(row)) = reader.next_row() {
buffer.extend(row);
}
let rgba_items = buffer.into_iter();
let width = info.width;
let height = info.height;
quote!(Some(#root::Icon::Rgba { rgba: vec![#(#rgba_items),*], width: #width, height: #height }))
}

fn find_icon<F: Fn(&&String) -> bool>(
config: &Config,
config_parent: &Path,
Expand Down
3 changes: 0 additions & 3 deletions core/tauri-runtime-wry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,15 @@ wry = { version = "0.13.3", default-features = false, features = [ "file-drop",
tauri-runtime = { version = "0.3.2", path = "../tauri-runtime" }
tauri-utils = { version = "1.0.0-rc.2", path = "../tauri-utils" }
uuid = { version = "0.8.2", features = [ "v4" ] }
infer = "0.4"

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

[target."cfg(windows)".dependencies.windows]
version = "0.30.0"
features = [ "Win32_Foundation" ]

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

[features]
Expand Down
65 changes: 15 additions & 50 deletions core/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use tauri_runtime::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
DetachedWindow, JsEventListenerKey, PendingWindow, WindowEvent,
},
ClipboardManager, Dispatch, Error, ExitRequestedEventAction, GlobalShortcutManager, Icon, Result,
RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType,
ClipboardManager, Dispatch, Error, ExitRequestedEventAction, GlobalShortcutManager, Result,
RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType, WindowIcon,
};

use tauri_runtime::window::MenuEvent;
Expand Down Expand Up @@ -56,7 +56,7 @@ use wry::{
MenuItemAttributes as WryMenuItemAttributes, MenuType,
},
monitor::MonitorHandle,
window::{Fullscreen, Icon as WindowIcon, UserAttentionType as WryUserAttentionType},
window::{Fullscreen, Icon as WryWindowIcon, UserAttentionType as WryUserAttentionType},
},
http::{
Request as WryHttpRequest, RequestParts as WryRequestParts, Response as WryHttpResponse,
Expand Down Expand Up @@ -84,7 +84,6 @@ use std::{
HashMap, HashSet,
},
fmt,
fs::read,
ops::Deref,
path::PathBuf,
sync::{
Expand Down Expand Up @@ -482,52 +481,18 @@ impl ClipboardManager for ClipboardManagerWrapper {
}

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

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

impl TryFrom<Icon> for WryIcon {
impl TryFrom<WindowIcon> for WryIcon {
type Error = Error;
fn try_from(icon: Icon) -> std::result::Result<Self, Self::Error> {
let image_bytes = match icon {
Icon::File(path) => read(path).map_err(icon_err)?,
Icon::Raw(raw) => raw,
_ => unimplemented!(),
};
let extension = infer::get(&image_bytes)
.expect("could not determine icon extension")
.extension();
match extension {
#[cfg(windows)]
"ico" => {
let icon_dir = ico::IconDir::read(std::io::Cursor::new(image_bytes)).map_err(icon_err)?;
let entry = &icon_dir.entries()[0];
let icon = WindowIcon::from_rgba(
entry.decode().map_err(icon_err)?.rgba_data().to_vec(),
entry.width(),
entry.height(),
)
.map_err(icon_err)?;
Ok(Self(icon))
}
#[cfg(target_os = "linux")]
"png" => {
let decoder = png::Decoder::new(std::io::Cursor::new(image_bytes));
let (info, mut reader) = decoder.read_info().map_err(icon_err)?;
let mut buffer = Vec::new();
while let Ok(Some(row)) = reader.next_row() {
buffer.extend(row);
}
let icon = WindowIcon::from_rgba(buffer, info.width, info.height).map_err(icon_err)?;
Ok(Self(icon))
}
_ => panic!(
"image `{}` extension not supported; please file a Tauri feature request",
extension
),
}
fn try_from(icon: WindowIcon) -> std::result::Result<Self, Self::Error> {
WryWindowIcon::from_rgba(icon.rgba, icon.width, icon.height)
.map(Self)
.map_err(icon_err)
}
}

Expand Down Expand Up @@ -851,7 +816,7 @@ impl WindowBuilder for WindowBuilderWrapper {
self
}

fn icon(mut self, icon: Icon) -> Result<Self> {
fn icon(mut self, icon: WindowIcon) -> Result<Self> {
self.inner = self
.inner
.with_window_icon(Some(WryIcon::try_from(icon)?.0));
Expand Down Expand Up @@ -975,7 +940,7 @@ pub enum WindowMessage {
SetPosition(Position),
SetFullscreen(bool),
SetFocus,
SetIcon(WindowIcon),
SetIcon(WryWindowIcon),
SetSkipTaskbar(bool),
DragWindow,
UpdateMenuItem(u16, MenuUpdate),
Expand All @@ -1001,7 +966,7 @@ pub enum WebviewEvent {
pub enum TrayMessage {
UpdateItem(u16, MenuUpdate),
UpdateMenu(SystemTrayMenu),
UpdateIcon(Icon),
UpdateIcon(TrayIcon),
#[cfg(target_os = "macos")]
UpdateIconAsTemplate(bool),
Close,
Expand Down Expand Up @@ -1392,7 +1357,7 @@ impl Dispatch for WryDispatcher {
)
}

fn set_icon(&self, icon: Icon) -> Result<()> {
fn set_icon(&self, icon: WindowIcon) -> Result<()> {
send_user_message(
&self.context,
Message::Window(
Expand Down Expand Up @@ -1790,7 +1755,7 @@ impl Runtime for Wry {
let icon = system_tray
.icon
.expect("tray icon not set")
.into_tray_icon();
.into_platform_icon();

let mut items = HashMap::new();

Expand Down Expand Up @@ -2208,7 +2173,7 @@ fn handle_user_message(
}
TrayMessage::UpdateIcon(icon) => {
if let Some(tray) = &*tray_context.tray.lock().unwrap() {
tray.lock().unwrap().set_icon(icon.into_tray_icon());
tray.lock().unwrap().set_icon(icon.into_platform_icon());
}
}
#[cfg(target_os = "macos")]
Expand Down
4 changes: 2 additions & 2 deletions core/tauri-runtime-wry/src/system_tray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub use tauri_runtime::{
Menu, MenuEntry, MenuItem, MenuUpdate, Submenu, SystemTrayMenu, SystemTrayMenuEntry,
SystemTrayMenuItem, TrayHandle,
},
Icon, SystemTrayEvent,
SystemTrayEvent, TrayIcon,
};
pub use wry::application::{
event::TrayEvent,
Expand Down Expand Up @@ -41,7 +41,7 @@ pub struct SystemTrayHandle {
}

impl TrayHandle for SystemTrayHandle {
fn set_icon(&self, icon: Icon) -> Result<()> {
fn set_icon(&self, icon: TrayIcon) -> Result<()> {
self
.proxy
.send_event(Message::Tray(TrayMessage::UpdateIcon(icon)))
Expand Down
Loading

0 comments on commit 8c93587

Please sign in to comment.