Skip to content

Commit

Permalink
feat(core): set macOS app icon in development (#4385)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Jun 19, 2022
1 parent c7d13a1 commit 307c2eb
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 6 deletions.
7 changes: 7 additions & 0 deletions .changes/dev-dock-icon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri-codegen": patch
"tauri-macros": patch
"tauri": patch
---

Set the application icon in development mode on macOS.
64 changes: 59 additions & 5 deletions core/tauri-codegen/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,21 +192,23 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
// handle default window icons for Windows targets
#[cfg(windows)]
let default_window_icon = {
let mut icon_path = find_icon(
let icon_path = find_icon(
&config,
&config_parent,
|i| i.ends_with(".ico"),
"icons/icon.ico",
);
if !icon_path.exists() {
icon_path = find_icon(
if icon_path.exists() {
ico_icon(&root, &out_dir, icon_path)?
} else {
let icon_path = find_icon(
&config,
&config_parent,
|i| i.ends_with(".png"),
"icons/icon.png",
);
png_icon(&root, &out_dir, icon_path)?
}
ico_icon(&root, &out_dir, icon_path)?
};
#[cfg(target_os = "linux")]
let default_window_icon = {
Expand All @@ -221,6 +223,29 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
#[cfg(not(any(windows, target_os = "linux")))]
let default_window_icon = quote!(None);

#[cfg(target_os = "macos")]
let app_icon = if dev {
let mut icon_path = find_icon(
&config,
&config_parent,
|i| i.ends_with(".icns"),
"icons/icon.png",
);
if !icon_path.exists() {
icon_path = find_icon(
&config,
&config_parent,
|i| i.ends_with(".png"),
"icons/icon.png",
);
}
raw_icon(&out_dir, icon_path)?
} else {
quote!(None)
};
#[cfg(not(target_os = "macos"))]
let app_icon = quote!(None);

let package_name = if let Some(product_name) = &config.package.product_name {
quote!(#product_name.to_string())
} else {
Expand Down Expand Up @@ -353,6 +378,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
#config,
::std::sync::Arc::new(#assets),
#default_window_icon,
#app_icon,
#system_tray_icon,
#package_info,
#info_plist,
Expand Down Expand Up @@ -403,6 +429,35 @@ fn ico_icon<P: AsRef<Path>>(
Ok(icon)
}

#[cfg(target_os = "macos")]
fn raw_icon<P: AsRef<Path>>(out_dir: &Path, path: P) -> Result<TokenStream, EmbeddedAssetsError> {
use std::fs::File;
use std::io::Write;

let path = path.as_ref();
let bytes = std::fs::read(&path)
.unwrap_or_else(|_| panic!("failed to read icon {}", path.display()))
.to_vec();

let out_path = out_dir.join(path.file_name().unwrap());
let mut out_file = File::create(&out_path).map_err(|error| EmbeddedAssetsError::AssetWrite {
path: out_path.clone(),
error,
})?;

out_file
.write_all(&bytes)
.map_err(|error| EmbeddedAssetsError::AssetWrite {
path: path.to_owned(),
error,
})?;

let out_path = out_path.display().to_string();

let icon = quote!(Some(include_bytes!(#out_path).to_vec()));
Ok(icon)
}

fn png_icon<P: AsRef<Path>>(
root: &TokenStream,
out_dir: &Path,
Expand Down Expand Up @@ -445,7 +500,6 @@ fn png_icon<P: AsRef<Path>>(
Ok(icon)
}

#[cfg(any(windows, target_os = "linux"))]
fn find_icon<F: Fn(&&String) -> bool>(
config: &Config,
config_parent: &Path,
Expand Down
24 changes: 23 additions & 1 deletion core/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,29 @@ fn on_event_loop_event<R: Runtime, F: FnMut(&AppHandle<R>, RunEvent) + 'static>(
label,
event: event.into(),
},
RuntimeRunEvent::Ready => RunEvent::Ready,
RuntimeRunEvent::Ready => {
// set the app icon in development
#[cfg(all(dev, target_os = "macos"))]
unsafe {
use cocoa::{
appkit::NSImage,
base::{id, nil},
foundation::NSData,
};
use objc::*;
if let Some(icon) = app_handle.manager.inner.app_icon.clone() {
let ns_app: id = msg_send![class!(NSApplication), sharedApplication];
let data = NSData::dataWithBytes_length_(
nil,
icon.as_ptr() as *const std::os::raw::c_void,
icon.len() as u64,
);
let app_icon = NSImage::initWithData_(NSImage::alloc(nil), data);
let _: () = msg_send![ns_app, setApplicationIconImage: app_icon];
}
}
RunEvent::Ready
}
RuntimeRunEvent::Resumed => RunEvent::Resumed,
RuntimeRunEvent::MainEventsCleared => RunEvent::MainEventsCleared,
RuntimeRunEvent::UserEvent(t) => t.into(),
Expand Down
4 changes: 4 additions & 0 deletions core/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ pub struct Context<A: Assets> {
pub(crate) config: Config,
pub(crate) assets: Arc<A>,
pub(crate) default_window_icon: Option<Icon>,
pub(crate) app_icon: Option<Vec<u8>>,
pub(crate) system_tray_icon: Option<Icon>,
pub(crate) package_info: PackageInfo,
pub(crate) _info_plist: (),
Expand All @@ -458,6 +459,7 @@ impl<A: Assets> fmt::Debug for Context<A> {
let mut d = f.debug_struct("Context");
d.field("config", &self.config)
.field("default_window_icon", &self.default_window_icon)
.field("app_icon", &self.app_icon)
.field("system_tray_icon", &self.system_tray_icon)
.field("package_info", &self.package_info)
.field("pattern", &self.pattern);
Expand Down Expand Up @@ -548,6 +550,7 @@ impl<A: Assets> Context<A> {
config: Config,
assets: Arc<A>,
default_window_icon: Option<Icon>,
app_icon: Option<Vec<u8>>,
system_tray_icon: Option<Icon>,
package_info: PackageInfo,
info_plist: (),
Expand All @@ -558,6 +561,7 @@ impl<A: Assets> Context<A> {
config,
assets,
default_window_icon,
app_icon,
system_tray_icon,
package_info,
_info_plist: info_plist,
Expand Down
3 changes: 3 additions & 0 deletions core/tauri/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ pub struct InnerWindowManager<R: Runtime> {
config: Arc<Config>,
assets: Arc<dyn Assets>,
default_window_icon: Option<Icon>,
pub(crate) app_icon: Option<Vec<u8>>,

package_info: PackageInfo,
/// The webview protocols protocols available to all windows.
Expand All @@ -231,6 +232,7 @@ impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
.field("state", &self.state)
.field("config", &self.config)
.field("default_window_icon", &self.default_window_icon)
.field("app_icon", &self.app_icon)
.field("package_info", &self.package_info)
.field("menu", &self.menu)
.field("pattern", &self.pattern)
Expand Down Expand Up @@ -303,6 +305,7 @@ impl<R: Runtime> WindowManager<R> {
config: Arc::new(context.config),
assets: context.assets,
default_window_icon: context.default_window_icon,
app_icon: context.app_icon,
package_info: context.package_info,
pattern: context.pattern,
uri_scheme_protocols,
Expand Down
1 change: 1 addition & 0 deletions core/tauri/src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
},
assets: Arc::new(assets),
default_window_icon: None,
app_icon: None,
system_tray_icon: None,
package_info: crate::PackageInfo {
name: "test".into(),
Expand Down

0 comments on commit 307c2eb

Please sign in to comment.