Skip to content

Commit ae10298

Browse files
authored
refactor(core): read tray icon only on desktop, refactor Context (#6719)
1 parent 86488a6 commit ae10298

File tree

6 files changed

+147
-54
lines changed

6 files changed

+147
-54
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri-codegen": patch
3+
"tauri": patch
4+
---
5+
6+
Refactor the `Context` conditional fields and only parse the tray icon on desktop.

core/tauri-codegen/src/context.rs

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ enum Target {
125125
Ios,
126126
}
127127

128+
impl Target {
129+
fn is_mobile(&self) -> bool {
130+
matches!(self, Target::Android | Target::Ios)
131+
}
132+
133+
fn is_desktop(&self) -> bool {
134+
!self.is_mobile()
135+
}
136+
}
137+
128138
/// Build a `tauri::Context` for including in application code.
129139
pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsError> {
130140
let ContextData {
@@ -247,15 +257,15 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
247257
"icons/icon.ico",
248258
);
249259
if icon_path.exists() {
250-
ico_icon(&root, &out_dir, icon_path)?
260+
ico_icon(&root, &out_dir, icon_path).map(|i| quote!(::std::option::Option::Some(#i)))?
251261
} else {
252262
let icon_path = find_icon(
253263
&config,
254264
&config_parent,
255265
|i| i.ends_with(".png"),
256266
"icons/icon.png",
257267
);
258-
png_icon(&root, &out_dir, icon_path)?
268+
png_icon(&root, &out_dir, icon_path).map(|i| quote!(::std::option::Option::Some(#i)))?
259269
}
260270
} else if target == Target::Linux {
261271
// handle default window icons for Linux targets
@@ -265,9 +275,9 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
265275
|i| i.ends_with(".png"),
266276
"icons/icon.png",
267277
);
268-
png_icon(&root, &out_dir, icon_path)?
278+
png_icon(&root, &out_dir, icon_path).map(|i| quote!(::std::option::Option::Some(#i)))?
269279
} else {
270-
quote!(None)
280+
quote!(::std::option::Option::None)
271281
}
272282
};
273283

@@ -288,7 +298,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
288298
}
289299
raw_icon(&out_dir, icon_path)?
290300
} else {
291-
quote!(None)
301+
quote!(::std::option::Option::None)
292302
};
293303

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

315-
let system_tray_icon = if let Some(tray) = &config.tauri.system_tray {
316-
let system_tray_icon_path = config_parent.join(&tray.icon_path);
317-
let ext = system_tray_icon_path.extension();
318-
if ext.map_or(false, |e| e == "ico") {
319-
ico_icon(&root, &out_dir, system_tray_icon_path)?
320-
} else if ext.map_or(false, |e| e == "png") {
321-
png_icon(&root, &out_dir, system_tray_icon_path)?
325+
let with_system_tray_icon_code = if target.is_desktop() {
326+
if let Some(tray) = &config.tauri.system_tray {
327+
let system_tray_icon_path = config_parent.join(&tray.icon_path);
328+
let ext = system_tray_icon_path.extension();
329+
if ext.map_or(false, |e| e == "ico") {
330+
ico_icon(&root, &out_dir, system_tray_icon_path)
331+
.map(|i| quote!(context.set_system_tray_icon(#i);))?
332+
} else if ext.map_or(false, |e| e == "png") {
333+
png_icon(&root, &out_dir, system_tray_icon_path)
334+
.map(|i| quote!(context.set_system_tray_icon(#i);))?
335+
} else {
336+
quote!(compile_error!(
337+
"The tray icon extension must be either `.ico` or `.png`."
338+
))
339+
}
322340
} else {
323-
quote!(compile_error!(
324-
"The tray icon extension must be either `.ico` or `.png`."
325-
))
341+
quote!()
326342
}
327343
} else {
328-
quote!(None)
344+
quote!()
329345
};
330346

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

411427
#[cfg(feature = "shell-scope")]
412-
let shell_scope_config = {
428+
let with_shell_scope_code = {
413429
use regex::Regex;
414430
use tauri_utils::config::ShellAllowlistOpen;
415431

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

418-
let shell_scope_open = match &config.tauri.allowlist.shell.open {
419-
ShellAllowlistOpen::Flag(false) => quote!(::std::option::Option::None),
420-
ShellAllowlistOpen::Flag(true) => {
421-
quote!(::std::option::Option::Some(#root::regex::Regex::new(r#"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+"#).unwrap()))
422-
}
434+
let shell_scope_constructor = match &config.tauri.allowlist.shell.open {
435+
ShellAllowlistOpen::Flag(false) => quote!(#root::ShellScopeConfig::new().skip_validation()),
436+
ShellAllowlistOpen::Flag(true) => quote!(#root::ShellScopeConfig::new()),
423437
ShellAllowlistOpen::Validate(regex) => match Regex::new(regex) {
424-
Ok(_) => quote!(::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap())),
438+
Ok(_) => {
439+
quote!(#root::ShellScopeConfig::with_validator(#root::regex::Regex::new(#regex).unwrap()))
440+
}
425441
Err(error) => {
426442
let error = error.to_string();
427443
quote!({
428444
compile_error!(#error);
429-
::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap())
445+
#root::ShellScopeConfig::with_validator(#root::regex::Regex::new(#regex).unwrap())
430446
})
431447
}
432448
},
433449
_ => panic!("unknown shell open format, unable to prepare"),
434450
};
451+
let shell_scope = quote!(#shell_scope_constructor.set_allowed_commands(#shell_scopes));
435452

436-
quote!(#root::ShellScopeConfig {
437-
open: #shell_scope_open,
438-
scopes: #shell_scopes
439-
})
453+
quote!(context.set_shell_scope(#shell_scope);)
440454
};
441455

442456
#[cfg(not(feature = "shell-scope"))]
443-
let shell_scope_config = quote!();
444-
445-
Ok(quote!(#root::Context::new(
446-
#config,
447-
::std::sync::Arc::new(#assets),
448-
#default_window_icon,
449-
#app_icon,
450-
#system_tray_icon,
451-
#package_info,
452-
#info_plist,
453-
#pattern,
454-
#shell_scope_config
455-
)))
457+
let with_shell_scope_code = quote!();
458+
459+
Ok(quote!({
460+
#[allow(unused_mut, clippy::let_and_return)]
461+
let mut context = #root::Context::new(
462+
#config,
463+
::std::sync::Arc::new(#assets),
464+
#default_window_icon,
465+
#app_icon,
466+
#package_info,
467+
#info_plist,
468+
#pattern,
469+
);
470+
#with_system_tray_icon_code
471+
#with_shell_scope_code
472+
context
473+
}))
456474
}
457475

458476
fn ico_icon<P: AsRef<Path>>(
@@ -483,7 +501,7 @@ fn ico_icon<P: AsRef<Path>>(
483501

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

486-
let icon = quote!(Some(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height }));
504+
let icon = quote!(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height });
487505
Ok(icon)
488506
}
489507

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

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

504-
let icon = quote!(Some(include_bytes!(#out_path).to_vec()));
522+
let icon = quote!(::std::option::Option::Some(
523+
include_bytes!(#out_path).to_vec()
524+
));
505525
Ok(icon)
506526
}
507527

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

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

536-
let icon = quote!(Some(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height }));
556+
let icon = quote!(#root::Icon::Rgba { rgba: include_bytes!(#out_path).to_vec(), width: #width, height: #height });
537557
Ok(icon)
538558
}
539559

core/tauri/src/lib.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ pub struct Context<A: Assets> {
539539
pub(crate) assets: Arc<A>,
540540
pub(crate) default_window_icon: Option<Icon>,
541541
pub(crate) app_icon: Option<Vec<u8>>,
542+
#[cfg(desktop)]
542543
pub(crate) system_tray_icon: Option<Icon>,
543544
pub(crate) package_info: PackageInfo,
544545
pub(crate) _info_plist: (),
@@ -553,9 +554,12 @@ impl<A: Assets> fmt::Debug for Context<A> {
553554
d.field("config", &self.config)
554555
.field("default_window_icon", &self.default_window_icon)
555556
.field("app_icon", &self.app_icon)
556-
.field("system_tray_icon", &self.system_tray_icon)
557557
.field("package_info", &self.package_info)
558558
.field("pattern", &self.pattern);
559+
560+
#[cfg(desktop)]
561+
d.field("system_tray_icon", &self.system_tray_icon);
562+
559563
#[cfg(shell_scope)]
560564
d.field("shell_scope", &self.shell_scope);
561565
d.finish()
@@ -600,12 +604,14 @@ impl<A: Assets> Context<A> {
600604
}
601605

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

608613
/// A mutable reference to the icon to use on the system tray UI.
614+
#[cfg(desktop)]
609615
#[inline(always)]
610616
pub fn system_tray_icon_mut(&mut self) -> &mut Option<Icon> {
611617
&mut self.system_tray_icon
@@ -644,25 +650,38 @@ impl<A: Assets> Context<A> {
644650
assets: Arc<A>,
645651
default_window_icon: Option<Icon>,
646652
app_icon: Option<Vec<u8>>,
647-
system_tray_icon: Option<Icon>,
648653
package_info: PackageInfo,
649654
info_plist: (),
650655
pattern: Pattern,
651-
#[cfg(shell_scope)] shell_scope: scope::ShellScopeConfig,
652656
) -> Self {
653657
Self {
654658
config,
655659
assets,
656660
default_window_icon,
657661
app_icon,
658-
system_tray_icon,
662+
#[cfg(desktop)]
663+
system_tray_icon: None,
659664
package_info,
660665
_info_plist: info_plist,
661666
pattern,
662667
#[cfg(shell_scope)]
663-
shell_scope,
668+
shell_scope: Default::default(),
664669
}
665670
}
671+
672+
/// Sets the app tray icon.
673+
#[cfg(desktop)]
674+
#[inline(always)]
675+
pub fn set_system_tray_icon(&mut self, icon: Icon) {
676+
self.system_tray_icon.replace(icon);
677+
}
678+
679+
/// Sets the app shell scope.
680+
#[cfg(shell_scope)]
681+
#[inline(always)]
682+
pub fn set_shell_scope(&mut self, scope: scope::ShellScopeConfig) {
683+
self.shell_scope = scope;
684+
}
666685
}
667686

668687
// TODO: expand these docs

core/tauri/src/manager.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ pub struct InnerWindowManager<R: Runtime> {
219219
assets: Arc<dyn Assets>,
220220
pub(crate) default_window_icon: Option<Icon>,
221221
pub(crate) app_icon: Option<Vec<u8>>,
222+
#[cfg(desktop)]
222223
pub(crate) tray_icon: Option<Icon>,
223224

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

241242
impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
242243
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243-
f.debug_struct("InnerWindowManager")
244-
.field("plugins", &self.plugins)
244+
let mut d = f.debug_struct("InnerWindowManager");
245+
246+
d.field("plugins", &self.plugins)
245247
.field("state", &self.state)
246248
.field("config", &self.config)
247249
.field("default_window_icon", &self.default_window_icon)
248250
.field("app_icon", &self.app_icon)
249-
.field("tray_icon", &self.tray_icon)
250251
.field("package_info", &self.package_info)
251252
.field("menu", &self.menu)
252-
.field("pattern", &self.pattern)
253-
.finish()
253+
.field("pattern", &self.pattern);
254+
255+
#[cfg(desktop)]
256+
d.field("tray_icon", &self.tray_icon);
257+
258+
d.finish()
254259
}
255260
}
256261

@@ -322,6 +327,7 @@ impl<R: Runtime> WindowManager<R> {
322327
assets: context.assets,
323328
default_window_icon: context.default_window_icon,
324329
app_icon: context.app_icon,
330+
#[cfg(desktop)]
325331
tray_icon: context.system_tray_icon,
326332
package_info: context.package_info,
327333
pattern: context.pattern,

core/tauri/src/scope/shell.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use regex::Regex;
1212

1313
use std::collections::HashMap;
1414

15+
const DEFAULT_OPEN_REGEX: &str = r#"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+"#;
16+
1517
/// Allowed representation of `Execute` command arguments.
1618
#[derive(Debug, Clone, serde::Deserialize)]
1719
#[serde(untagged, deny_unknown_fields)]
@@ -67,6 +69,45 @@ pub struct ScopeConfig {
6769
pub scopes: HashMap<String, ScopeAllowedCommand>,
6870
}
6971

72+
impl Default for ScopeConfig {
73+
fn default() -> Self {
74+
Self {
75+
open: Some(Regex::new(DEFAULT_OPEN_REGEX).unwrap()),
76+
scopes: Default::default(),
77+
}
78+
}
79+
}
80+
81+
impl ScopeConfig {
82+
/// Creates a new scope configuration with the default validation regex ^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+.
83+
pub fn new() -> Self {
84+
Self::default()
85+
}
86+
87+
/// Creates a new scope configuration with the specified validation regex.
88+
pub fn with_validator(regex: Regex) -> Self {
89+
Self {
90+
open: Some(regex),
91+
scopes: Default::default(),
92+
}
93+
}
94+
95+
/// Unsets the validator regex, allowing any path to be opened.
96+
pub fn skip_validation(mut self) -> Self {
97+
self.open = None;
98+
self
99+
}
100+
101+
/// Sets the commands that are allowed to be executed.
102+
pub fn set_allowed_commands<I: IntoIterator<Item = (String, ScopeAllowedCommand)>>(
103+
mut self,
104+
scopes: I,
105+
) -> Self {
106+
self.scopes = scopes.into_iter().collect();
107+
self
108+
}
109+
}
110+
70111
/// A configured scoped shell command.
71112
#[derive(Debug, Clone)]
72113
pub struct ScopeAllowedCommand {

core/tauri/src/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
6060
assets: Arc::new(assets),
6161
default_window_icon: None,
6262
app_icon: None,
63+
#[cfg(desktop)]
6364
system_tray_icon: None,
6465
package_info: crate::PackageInfo {
6566
name: "test".into(),

0 commit comments

Comments
 (0)