Skip to content

Commit c8a82ad

Browse files
authored
fix(core): fix deadlock when using resources_table in menu/image/tray plugins (#9379)
* fix(core): fix deadlock when using resources_table in menu/image/tray plugins closes #9369 * document the resources_table requirement
1 parent 48a7a78 commit c8a82ad

File tree

6 files changed

+58
-31
lines changed

6 files changed

+58
-31
lines changed

.changes/core-jsimage-intoimg.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": "patch:breaking"
3+
---
4+
5+
Changed `JsImage::into_img` to take a reference to a `ResourceTable` instead of a `Manager`.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": "patch:bug"
3+
---
4+
5+
Fix deadlock when using the menu/tray/image JS APIs.

core/tauri/src/image/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub(crate) mod plugin;
99
use std::borrow::Cow;
1010
use std::sync::Arc;
1111

12-
use crate::{Manager, Resource, ResourceId, Runtime};
12+
use crate::{Resource, ResourceId, ResourceTable};
1313

1414
/// An RGBA Image in row-major order from top to bottom.
1515
#[derive(Debug, Clone)]
@@ -165,9 +165,14 @@ pub enum JsImage {
165165

166166
impl JsImage {
167167
/// Converts this intermediate image format into an actual [`Image`].
168-
pub fn into_img<R: Runtime, M: Manager<R>>(self, manager: &M) -> crate::Result<Arc<Image<'_>>> {
168+
///
169+
/// This will retrieve the image from the passed [`ResourceTable`] if it is [`JsImage::Resource`]
170+
/// and will return an error if it doesn't exist in the passed [`ResourceTable`] so make sure
171+
/// the passed [`ResourceTable`] is the same one used to store the image, usually this should be
172+
/// the webview [resources table](crate::webview::Webview::resources_table).
173+
pub fn into_img(self, resources_table: &ResourceTable) -> crate::Result<Arc<Image<'_>>> {
169174
match self {
170-
Self::Resource(rid) => manager.resources_table().get::<Image<'static>>(rid),
175+
Self::Resource(rid) => resources_table.get::<Image<'static>>(rid),
171176
#[cfg(any(feature = "image-ico", feature = "image-png"))]
172177
Self::Path(path) => Image::from_path(path).map(Arc::new).map_err(Into::into),
173178

core/tauri/src/menu/plugin.rs

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
plugin::{Builder, TauriPlugin},
1616
resources::ResourceId,
1717
sealed::ManagerBase,
18-
Manager, RunEvent, Runtime, State, Webview, Window,
18+
Manager, ResourceTable, RunEvent, Runtime, State, Webview, Window,
1919
};
2020
use tauri_macros::do_menu_item;
2121

@@ -46,12 +46,12 @@ pub(crate) struct AboutMetadata {
4646
}
4747

4848
impl AboutMetadata {
49-
pub fn into_metadata<R: Runtime, M: Manager<R>>(
49+
pub fn into_metadata(
5050
self,
51-
manager: &M,
51+
resources_table: &ResourceTable,
5252
) -> crate::Result<super::AboutMetadata<'_>> {
5353
let icon = match self.icon {
54-
Some(i) => Some(i.into_img(manager)?.as_ref().clone()),
54+
Some(i) => Some(i.into_img(resources_table)?.as_ref().clone()),
5555
None => None,
5656
};
5757

@@ -102,7 +102,11 @@ struct SubmenuPayload {
102102
}
103103

104104
impl SubmenuPayload {
105-
pub fn create_item<R: Runtime>(self, webview: &Webview<R>) -> crate::Result<Submenu<R>> {
105+
pub fn create_item<R: Runtime>(
106+
self,
107+
webview: &Webview<R>,
108+
resources_table: &ResourceTable,
109+
) -> crate::Result<Submenu<R>> {
106110
let mut builder = if let Some(id) = self.id {
107111
SubmenuBuilder::with_id(webview, id, self.text)
108112
} else {
@@ -112,7 +116,7 @@ impl SubmenuPayload {
112116
builder = builder.enabled(enabled);
113117
}
114118
for item in self.items {
115-
builder = item.with_item(webview, |i| Ok(builder.item(i)))?;
119+
builder = item.with_item(webview, resources_table, |i| Ok(builder.item(i)))?;
116120
}
117121

118122
builder.build()
@@ -178,7 +182,11 @@ struct IconMenuItemPayload {
178182
}
179183

180184
impl IconMenuItemPayload {
181-
pub fn create_item<R: Runtime>(self, webview: &Webview<R>) -> crate::Result<IconMenuItem<R>> {
185+
pub fn create_item<R: Runtime>(
186+
self,
187+
webview: &Webview<R>,
188+
resources_table: &ResourceTable,
189+
) -> crate::Result<IconMenuItem<R>> {
182190
let mut builder = if let Some(id) = self.id {
183191
IconMenuItemBuilder::with_id(id, self.text)
184192
} else {
@@ -192,7 +200,7 @@ impl IconMenuItemPayload {
192200
}
193201
builder = match self.icon {
194202
Icon::Native(native_icon) => builder.native_icon(native_icon),
195-
Icon::Icon(icon) => builder.icon(icon.into_img(webview)?.as_ref().clone()),
203+
Icon::Icon(icon) => builder.icon(icon.into_img(resources_table)?.as_ref().clone()),
196204
};
197205

198206
let item = builder.build(webview)?;
@@ -260,6 +268,7 @@ impl PredefinedMenuItemPayload {
260268
pub fn create_item<R: Runtime>(
261269
self,
262270
webview: &Webview<R>,
271+
resources_table: &ResourceTable,
263272
) -> crate::Result<PredefinedMenuItem<R>> {
264273
match self.item {
265274
Predefined::Separator => PredefinedMenuItem::separator(webview),
@@ -279,7 +288,7 @@ impl PredefinedMenuItemPayload {
279288
Predefined::Quit => PredefinedMenuItem::quit(webview, self.text.as_deref()),
280289
Predefined::About(metadata) => {
281290
let metadata = match metadata {
282-
Some(m) => Some(m.into_metadata(webview)?),
291+
Some(m) => Some(m.into_metadata(resources_table)?),
283292
None => None,
284293
};
285294
PredefinedMenuItem::about(webview, self.text.as_deref(), metadata)
@@ -304,17 +313,17 @@ impl MenuItemPayloadKind {
304313
pub fn with_item<T, R: Runtime, F: FnOnce(&dyn IsMenuItem<R>) -> crate::Result<T>>(
305314
self,
306315
webview: &Webview<R>,
316+
resources_table: &ResourceTable,
307317
f: F,
308318
) -> crate::Result<T> {
309319
match self {
310320
Self::ExistingItem((rid, kind)) => {
311-
let resources_table = webview.resources_table();
312321
do_menu_item!(resources_table, rid, kind, |i| f(&*i))
313322
}
314-
Self::Submenu(i) => f(&i.create_item(webview)?),
315-
Self::Predefined(i) => f(&i.create_item(webview)?),
323+
Self::Submenu(i) => f(&i.create_item(webview, resources_table)?),
324+
Self::Predefined(i) => f(&i.create_item(webview, resources_table)?),
316325
Self::Check(i) => f(&i.create_item(webview)?),
317-
Self::Icon(i) => f(&i.create_item(webview)?),
326+
Self::Icon(i) => f(&i.create_item(webview, resources_table)?),
318327
Self::MenuItem(i) => f(&i.create_item(webview)?),
319328
}
320329
}
@@ -354,7 +363,7 @@ fn new<R: Runtime>(
354363
}
355364
if let Some(items) = options.items {
356365
for item in items {
357-
builder = item.with_item(&webview, |i| Ok(builder.item(i)))?;
366+
builder = item.with_item(&webview, &resources_table, |i| Ok(builder.item(i)))?;
358367
}
359368
}
360369
let menu = builder.build()?;
@@ -371,7 +380,7 @@ fn new<R: Runtime>(
371380
enabled: options.enabled,
372381
items: options.items.unwrap_or_default(),
373382
}
374-
.create_item(&webview)?;
383+
.create_item(&webview, &resources_table)?;
375384
let id = submenu.id().clone();
376385
let rid = resources_table.add(submenu);
377386

@@ -398,7 +407,7 @@ fn new<R: Runtime>(
398407
item: options.predefined_item.unwrap(),
399408
text: options.text,
400409
}
401-
.create_item(&webview)?;
410+
.create_item(&webview, &resources_table)?;
402411
let id = item.id().clone();
403412
let rid = resources_table.add(item);
404413
(rid, id)
@@ -430,7 +439,7 @@ fn new<R: Runtime>(
430439
enabled: options.enabled,
431440
accelerator: options.accelerator,
432441
}
433-
.create_item(&webview)?;
442+
.create_item(&webview, &resources_table)?;
434443
let id = item.id().clone();
435444
let rid = resources_table.add(item);
436445
(rid, id)
@@ -454,13 +463,13 @@ fn append<R: Runtime>(
454463
ItemKind::Menu => {
455464
let menu = resources_table.get::<Menu<R>>(rid)?;
456465
for item in items {
457-
item.with_item(&webview, |i| menu.append(i))?;
466+
item.with_item(&webview, &resources_table, |i| menu.append(i))?;
458467
}
459468
}
460469
ItemKind::Submenu => {
461470
let submenu = resources_table.get::<Submenu<R>>(rid)?;
462471
for item in items {
463-
item.with_item(&webview, |i| submenu.append(i))?;
472+
item.with_item(&webview, &resources_table, |i| submenu.append(i))?;
464473
}
465474
}
466475
_ => return Err(anyhow::anyhow!("unexpected menu item kind").into()),
@@ -481,13 +490,13 @@ fn prepend<R: Runtime>(
481490
ItemKind::Menu => {
482491
let menu = resources_table.get::<Menu<R>>(rid)?;
483492
for item in items {
484-
item.with_item(&webview, |i| menu.prepend(i))?;
493+
item.with_item(&webview, &resources_table, |i| menu.prepend(i))?;
485494
}
486495
}
487496
ItemKind::Submenu => {
488497
let submenu = resources_table.get::<Submenu<R>>(rid)?;
489498
for item in items {
490-
item.with_item(&webview, |i| submenu.prepend(i))?;
499+
item.with_item(&webview, &resources_table, |i| submenu.prepend(i))?;
491500
}
492501
}
493502
_ => return Err(anyhow::anyhow!("unexpected menu item kind").into()),
@@ -509,14 +518,14 @@ fn insert<R: Runtime>(
509518
ItemKind::Menu => {
510519
let menu = resources_table.get::<Menu<R>>(rid)?;
511520
for item in items {
512-
item.with_item(&webview, |i| menu.insert(i, position))?;
521+
item.with_item(&webview, &resources_table, |i| menu.insert(i, position))?;
513522
position += 1
514523
}
515524
}
516525
ItemKind::Submenu => {
517526
let submenu = resources_table.get::<Submenu<R>>(rid)?;
518527
for item in items {
519-
item.with_item(&webview, |i| submenu.insert(i, position))?;
528+
item.with_item(&webview, &resources_table, |i| submenu.insert(i, position))?;
520529
position += 1
521530
}
522531
}
@@ -846,7 +855,9 @@ fn set_icon<R: Runtime>(
846855

847856
match icon {
848857
Some(Icon::Native(icon)) => icon_item.set_native_icon(Some(icon)),
849-
Some(Icon::Icon(icon)) => icon_item.set_icon(Some(icon.into_img(&webview)?.as_ref().clone())),
858+
Some(Icon::Icon(icon)) => {
859+
icon_item.set_icon(Some(icon.into_img(&resources_table)?.as_ref().clone()))
860+
}
850861
None => {
851862
icon_item.set_icon(None)?;
852863
icon_item.set_native_icon(None)?;

core/tauri/src/tray/plugin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ fn new<R: Runtime>(
6464
};
6565
}
6666
if let Some(icon) = options.icon {
67-
builder = builder.icon(icon.into_img(&webview)?.as_ref().clone());
67+
builder = builder.icon(icon.into_img(&resources_table)?.as_ref().clone());
6868
}
6969
if let Some(tooltip) = options.tooltip {
7070
builder = builder.tooltip(tooltip);
@@ -121,7 +121,7 @@ fn set_icon<R: Runtime>(
121121
let resources_table = webview.resources_table();
122122
let tray = resources_table.get::<TrayIcon<R>>(rid)?;
123123
let icon = match icon {
124-
Some(i) => Some(i.into_img(&webview)?.as_ref().clone()),
124+
Some(i) => Some(i.into_img(&resources_table)?.as_ref().clone()),
125125
None => None,
126126
};
127127
tray.set_icon(icon)

core/tauri/src/window/plugin.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ mod desktop_commands {
1919
sealed::ManagerBase,
2020
utils::config::{WindowConfig, WindowEffectsConfig},
2121
window::{ProgressBarState, WindowBuilder},
22-
AppHandle, CursorIcon, Monitor, PhysicalPosition, PhysicalSize, Position, Size, Theme,
22+
AppHandle, CursorIcon, Manager, Monitor, PhysicalPosition, PhysicalSize, Position, Size, Theme,
2323
UserAttentionType, Webview, Window,
2424
};
2525

@@ -138,8 +138,9 @@ mod desktop_commands {
138138
value: crate::image::JsImage,
139139
) -> crate::Result<()> {
140140
let window = get_window(window, label)?;
141+
let resources_table = webview.resources_table();
141142
window
142-
.set_icon(value.into_img(&webview)?.as_ref().clone())
143+
.set_icon(value.into_img(&resources_table)?.as_ref().clone())
143144
.map_err(Into::into)
144145
}
145146

0 commit comments

Comments
 (0)