Skip to content

Commit

Permalink
refactor(core): read tray icon only on desktop, refactor Context (#6719)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Apr 19, 2023
1 parent 86488a6 commit ae10298
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 54 deletions.
6 changes: 6 additions & 0 deletions .changes/remove-tray-icon-mobile.md
@@ -0,0 +1,6 @@
---
"tauri-codegen": patch
"tauri": patch
---

Refactor the `Context` conditional fields and only parse the tray icon on desktop.
108 changes: 64 additions & 44 deletions core/tauri-codegen/src/context.rs
Expand Up @@ -125,6 +125,16 @@ enum Target {
Ios,
}

impl Target {
fn is_mobile(&self) -> bool {
matches!(self, Target::Android | Target::Ios)
}

fn is_desktop(&self) -> bool {
!self.is_mobile()
}
}

/// Build a `tauri::Context` for including in application code.
pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsError> {
let ContextData {
Expand Down Expand Up @@ -247,15 +257,15 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
"icons/icon.ico",
);
if icon_path.exists() {
ico_icon(&root, &out_dir, icon_path)?
ico_icon(&root, &out_dir, icon_path).map(|i| quote!(::std::option::Option::Some(#i)))?
} else {
let icon_path = find_icon(
&config,
&config_parent,
|i| i.ends_with(".png"),
"icons/icon.png",
);
png_icon(&root, &out_dir, icon_path)?
png_icon(&root, &out_dir, icon_path).map(|i| quote!(::std::option::Option::Some(#i)))?
}
} else if target == Target::Linux {
// handle default window icons for Linux targets
Expand All @@ -265,9 +275,9 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
|i| i.ends_with(".png"),
"icons/icon.png",
);
png_icon(&root, &out_dir, icon_path)?
png_icon(&root, &out_dir, icon_path).map(|i| quote!(::std::option::Option::Some(#i)))?
} else {
quote!(None)
quote!(::std::option::Option::None)
}
};

Expand All @@ -288,7 +298,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
}
raw_icon(&out_dir, icon_path)?
} else {
quote!(None)
quote!(::std::option::Option::None)
};

let package_name = if let Some(product_name) = &config.package.product_name {
Expand All @@ -312,20 +322,26 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
}
);

let system_tray_icon = if let Some(tray) = &config.tauri.system_tray {
let system_tray_icon_path = config_parent.join(&tray.icon_path);
let ext = system_tray_icon_path.extension();
if ext.map_or(false, |e| e == "ico") {
ico_icon(&root, &out_dir, system_tray_icon_path)?
} else if ext.map_or(false, |e| e == "png") {
png_icon(&root, &out_dir, system_tray_icon_path)?
let with_system_tray_icon_code = if target.is_desktop() {
if let Some(tray) = &config.tauri.system_tray {
let system_tray_icon_path = config_parent.join(&tray.icon_path);
let ext = system_tray_icon_path.extension();
if ext.map_or(false, |e| e == "ico") {
ico_icon(&root, &out_dir, system_tray_icon_path)
.map(|i| quote!(context.set_system_tray_icon(#i);))?
} else if ext.map_or(false, |e| e == "png") {
png_icon(&root, &out_dir, system_tray_icon_path)
.map(|i| quote!(context.set_system_tray_icon(#i);))?
} else {
quote!(compile_error!(
"The tray icon extension must be either `.ico` or `.png`."
))
}
} else {
quote!(compile_error!(
"The tray icon extension must be either `.ico` or `.png`."
))
quote!()
}
} else {
quote!(None)
quote!()
};

#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -409,50 +425,52 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
};

#[cfg(feature = "shell-scope")]
let shell_scope_config = {
let with_shell_scope_code = {
use regex::Regex;
use tauri_utils::config::ShellAllowlistOpen;

let shell_scopes = get_allowed_clis(&root, &config.tauri.allowlist.shell.scope);

let shell_scope_open = match &config.tauri.allowlist.shell.open {
ShellAllowlistOpen::Flag(false) => quote!(::std::option::Option::None),
ShellAllowlistOpen::Flag(true) => {
quote!(::std::option::Option::Some(#root::regex::Regex::new(r#"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+"#).unwrap()))
}
let shell_scope_constructor = match &config.tauri.allowlist.shell.open {
ShellAllowlistOpen::Flag(false) => quote!(#root::ShellScopeConfig::new().skip_validation()),
ShellAllowlistOpen::Flag(true) => quote!(#root::ShellScopeConfig::new()),
ShellAllowlistOpen::Validate(regex) => match Regex::new(regex) {
Ok(_) => quote!(::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap())),
Ok(_) => {
quote!(#root::ShellScopeConfig::with_validator(#root::regex::Regex::new(#regex).unwrap()))
}
Err(error) => {
let error = error.to_string();
quote!({
compile_error!(#error);
::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap())
#root::ShellScopeConfig::with_validator(#root::regex::Regex::new(#regex).unwrap())
})
}
},
_ => panic!("unknown shell open format, unable to prepare"),
};
let shell_scope = quote!(#shell_scope_constructor.set_allowed_commands(#shell_scopes));

quote!(#root::ShellScopeConfig {
open: #shell_scope_open,
scopes: #shell_scopes
})
quote!(context.set_shell_scope(#shell_scope);)
};

#[cfg(not(feature = "shell-scope"))]
let shell_scope_config = quote!();

Ok(quote!(#root::Context::new(
#config,
::std::sync::Arc::new(#assets),
#default_window_icon,
#app_icon,
#system_tray_icon,
#package_info,
#info_plist,
#pattern,
#shell_scope_config
)))
let with_shell_scope_code = quote!();

Ok(quote!({
#[allow(unused_mut, clippy::let_and_return)]
let mut context = #root::Context::new(
#config,
::std::sync::Arc::new(#assets),
#default_window_icon,
#app_icon,
#package_info,
#info_plist,
#pattern,
);
#with_system_tray_icon_code
#with_shell_scope_code
context
}))
}

fn ico_icon<P: AsRef<Path>>(
Expand Down Expand Up @@ -483,7 +501,7 @@ fn ico_icon<P: AsRef<Path>>(

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

let icon = quote!(Some(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height }));
let icon = quote!(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height });
Ok(icon)
}

Expand All @@ -501,7 +519,9 @@ fn raw_icon<P: AsRef<Path>>(out_dir: &Path, path: P) -> Result<TokenStream, Embe

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

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

Expand Down Expand Up @@ -533,7 +553,7 @@ fn png_icon<P: AsRef<Path>>(

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

let icon = quote!(Some(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height }));
let icon = quote!(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height });
Ok(icon)
}

Expand Down
29 changes: 24 additions & 5 deletions core/tauri/src/lib.rs
Expand Up @@ -539,6 +539,7 @@ pub struct Context<A: Assets> {
pub(crate) assets: Arc<A>,
pub(crate) default_window_icon: Option<Icon>,
pub(crate) app_icon: Option<Vec<u8>>,
#[cfg(desktop)]
pub(crate) system_tray_icon: Option<Icon>,
pub(crate) package_info: PackageInfo,
pub(crate) _info_plist: (),
Expand All @@ -553,9 +554,12 @@ impl<A: Assets> fmt::Debug for Context<A> {
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);

#[cfg(desktop)]
d.field("system_tray_icon", &self.system_tray_icon);

#[cfg(shell_scope)]
d.field("shell_scope", &self.shell_scope);
d.finish()
Expand Down Expand Up @@ -600,12 +604,14 @@ impl<A: Assets> Context<A> {
}

/// The icon to use on the system tray UI.
#[cfg(desktop)]
#[inline(always)]
pub fn system_tray_icon(&self) -> Option<&Icon> {
self.system_tray_icon.as_ref()
}

/// A mutable reference to the icon to use on the system tray UI.
#[cfg(desktop)]
#[inline(always)]
pub fn system_tray_icon_mut(&mut self) -> &mut Option<Icon> {
&mut self.system_tray_icon
Expand Down Expand Up @@ -644,25 +650,38 @@ impl<A: Assets> Context<A> {
assets: Arc<A>,
default_window_icon: Option<Icon>,
app_icon: Option<Vec<u8>>,
system_tray_icon: Option<Icon>,
package_info: PackageInfo,
info_plist: (),
pattern: Pattern,
#[cfg(shell_scope)] shell_scope: scope::ShellScopeConfig,
) -> Self {
Self {
config,
assets,
default_window_icon,
app_icon,
system_tray_icon,
#[cfg(desktop)]
system_tray_icon: None,
package_info,
_info_plist: info_plist,
pattern,
#[cfg(shell_scope)]
shell_scope,
shell_scope: Default::default(),
}
}

/// Sets the app tray icon.
#[cfg(desktop)]
#[inline(always)]
pub fn set_system_tray_icon(&mut self, icon: Icon) {
self.system_tray_icon.replace(icon);
}

/// Sets the app shell scope.
#[cfg(shell_scope)]
#[inline(always)]
pub fn set_shell_scope(&mut self, scope: scope::ShellScopeConfig) {
self.shell_scope = scope;
}
}

// TODO: expand these docs
Expand Down
16 changes: 11 additions & 5 deletions core/tauri/src/manager.rs
Expand Up @@ -219,6 +219,7 @@ pub struct InnerWindowManager<R: Runtime> {
assets: Arc<dyn Assets>,
pub(crate) default_window_icon: Option<Icon>,
pub(crate) app_icon: Option<Vec<u8>>,
#[cfg(desktop)]
pub(crate) tray_icon: Option<Icon>,

package_info: PackageInfo,
Expand All @@ -240,17 +241,21 @@ pub struct InnerWindowManager<R: Runtime> {

impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InnerWindowManager")
.field("plugins", &self.plugins)
let mut d = f.debug_struct("InnerWindowManager");

d.field("plugins", &self.plugins)
.field("state", &self.state)
.field("config", &self.config)
.field("default_window_icon", &self.default_window_icon)
.field("app_icon", &self.app_icon)
.field("tray_icon", &self.tray_icon)
.field("package_info", &self.package_info)
.field("menu", &self.menu)
.field("pattern", &self.pattern)
.finish()
.field("pattern", &self.pattern);

#[cfg(desktop)]
d.field("tray_icon", &self.tray_icon);

d.finish()
}
}

Expand Down Expand Up @@ -322,6 +327,7 @@ impl<R: Runtime> WindowManager<R> {
assets: context.assets,
default_window_icon: context.default_window_icon,
app_icon: context.app_icon,
#[cfg(desktop)]
tray_icon: context.system_tray_icon,
package_info: context.package_info,
pattern: context.pattern,
Expand Down
41 changes: 41 additions & 0 deletions core/tauri/src/scope/shell.rs
Expand Up @@ -12,6 +12,8 @@ use regex::Regex;

use std::collections::HashMap;

const DEFAULT_OPEN_REGEX: &str = r#"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+"#;

/// Allowed representation of `Execute` command arguments.
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(untagged, deny_unknown_fields)]
Expand Down Expand Up @@ -67,6 +69,45 @@ pub struct ScopeConfig {
pub scopes: HashMap<String, ScopeAllowedCommand>,
}

impl Default for ScopeConfig {
fn default() -> Self {
Self {
open: Some(Regex::new(DEFAULT_OPEN_REGEX).unwrap()),
scopes: Default::default(),
}
}
}

impl ScopeConfig {
/// Creates a new scope configuration with the default validation regex ^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+.
pub fn new() -> Self {
Self::default()
}

/// Creates a new scope configuration with the specified validation regex.
pub fn with_validator(regex: Regex) -> Self {
Self {
open: Some(regex),
scopes: Default::default(),
}
}

/// Unsets the validator regex, allowing any path to be opened.
pub fn skip_validation(mut self) -> Self {
self.open = None;
self
}

/// Sets the commands that are allowed to be executed.
pub fn set_allowed_commands<I: IntoIterator<Item = (String, ScopeAllowedCommand)>>(
mut self,
scopes: I,
) -> Self {
self.scopes = scopes.into_iter().collect();
self
}
}

/// A configured scoped shell command.
#[derive(Debug, Clone)]
pub struct ScopeAllowedCommand {
Expand Down
1 change: 1 addition & 0 deletions core/tauri/src/test/mod.rs
Expand Up @@ -60,6 +60,7 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
assets: Arc::new(assets),
default_window_icon: None,
app_icon: None,
#[cfg(desktop)]
system_tray_icon: None,
package_info: crate::PackageInfo {
name: "test".into(),
Expand Down

0 comments on commit ae10298

Please sign in to comment.