mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-25 03:33:36 +03:00
fix(core): menu id map not reflecting the current window menu (#2726)
This commit is contained in:
parent
b5ee03a13a
commit
ac37b56ef4
5
.changes/fix-menu-ids.md
Normal file
5
.changes/fix-menu-ids.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch
|
||||
---
|
||||
|
||||
Fixes the menu id mapping not reflecting the current window.
|
6
.changes/get-menu.md
Normal file
6
.changes/get-menu.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri-runtime": minor
|
||||
"tauri-runtime-wry": minor
|
||||
---
|
||||
|
||||
Replace `WindowBuilder`'s `has_menu` with `get_menu`.
|
@ -9,7 +9,7 @@ use tauri_runtime::{
|
||||
Request as HttpRequest, RequestParts as HttpRequestParts, Response as HttpResponse,
|
||||
ResponseParts as HttpResponseParts,
|
||||
},
|
||||
menu::{CustomMenuItem, Menu, MenuEntry, MenuHash, MenuItem, MenuUpdate, Submenu},
|
||||
menu::{CustomMenuItem, Menu, MenuEntry, MenuHash, MenuId, MenuItem, MenuUpdate},
|
||||
monitor::Monitor,
|
||||
webview::{
|
||||
FileDropEvent, FileDropHandler, RpcRequest, WebviewRpcHandler, WindowBuilder, WindowBuilderBase,
|
||||
@ -693,7 +693,7 @@ impl From<UserAttentionType> for UserAttentionTypeWrapper {
|
||||
pub struct WindowBuilderWrapper {
|
||||
inner: WryWindowBuilder,
|
||||
center: bool,
|
||||
menu: Menu,
|
||||
menu: Option<Menu>,
|
||||
}
|
||||
|
||||
// safe since `menu_items` are read only here
|
||||
@ -736,7 +736,7 @@ impl WindowBuilder for WindowBuilderWrapper {
|
||||
}
|
||||
|
||||
fn menu(mut self, menu: Menu) -> Self {
|
||||
self.menu = convert_menu_id(Menu::new(), menu);
|
||||
self.menu.replace(menu);
|
||||
self
|
||||
}
|
||||
|
||||
@ -857,8 +857,8 @@ impl WindowBuilder for WindowBuilderWrapper {
|
||||
self.inner.window.window_icon.is_some()
|
||||
}
|
||||
|
||||
fn has_menu(&self) -> bool {
|
||||
self.inner.window.window_menu.is_some()
|
||||
fn get_menu(&self) -> Option<&Menu> {
|
||||
self.menu.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1206,6 +1206,7 @@ impl Dispatch for WryDispatcher {
|
||||
) -> Result<DetachedWindow<Self::Runtime>> {
|
||||
let (tx, rx) = channel();
|
||||
let label = pending.label.clone();
|
||||
let menu_ids = pending.menu_ids.clone();
|
||||
let context = self.context.clone();
|
||||
|
||||
send_user_message(
|
||||
@ -1223,7 +1224,11 @@ impl Dispatch for WryDispatcher {
|
||||
window_id,
|
||||
context: self.context.clone(),
|
||||
};
|
||||
Ok(DetachedWindow { label, dispatcher })
|
||||
Ok(DetachedWindow {
|
||||
label,
|
||||
dispatcher,
|
||||
menu_ids,
|
||||
})
|
||||
}
|
||||
|
||||
fn set_resizable(&self, resizable: bool) -> Result<()> {
|
||||
@ -1451,7 +1456,7 @@ impl WindowHandle {
|
||||
pub struct WindowWrapper {
|
||||
label: String,
|
||||
inner: WindowHandle,
|
||||
menu_items: HashMap<u16, WryCustomMenuItem>,
|
||||
menu_items: Option<HashMap<u16, WryCustomMenuItem>>,
|
||||
}
|
||||
|
||||
/// A Tauri [`Runtime`] wrapper around wry.
|
||||
@ -1509,6 +1514,7 @@ impl RuntimeHandle for WryHandle {
|
||||
) -> Result<DetachedWindow<Self::Runtime>> {
|
||||
let (tx, rx) = channel();
|
||||
let label = pending.label.clone();
|
||||
let menu_ids = pending.menu_ids.clone();
|
||||
let context = self.context.clone();
|
||||
send_user_message(
|
||||
&self.context,
|
||||
@ -1525,7 +1531,11 @@ impl RuntimeHandle for WryHandle {
|
||||
window_id,
|
||||
context: self.context.clone(),
|
||||
};
|
||||
Ok(DetachedWindow { label, dispatcher })
|
||||
Ok(DetachedWindow {
|
||||
label,
|
||||
dispatcher,
|
||||
menu_ids,
|
||||
})
|
||||
}
|
||||
|
||||
fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
|
||||
@ -1632,6 +1642,7 @@ impl Runtime for Wry {
|
||||
|
||||
fn create_window(&self, pending: PendingWindow<Self>) -> Result<DetachedWindow<Self>> {
|
||||
let label = pending.label.clone();
|
||||
let menu_ids = pending.menu_ids.clone();
|
||||
let proxy = self.event_loop.create_proxy();
|
||||
let webview = create_webview(
|
||||
&self.event_loop,
|
||||
@ -1717,7 +1728,11 @@ impl Runtime for Wry {
|
||||
.unwrap()
|
||||
.insert(webview.inner.window().id(), webview);
|
||||
|
||||
Ok(DetachedWindow { label, dispatcher })
|
||||
Ok(DetachedWindow {
|
||||
label,
|
||||
dispatcher,
|
||||
menu_ids,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "system-tray")]
|
||||
@ -2006,17 +2021,16 @@ fn handle_user_message(
|
||||
let _ = window.drag_window();
|
||||
}
|
||||
WindowMessage::UpdateMenuItem(id, update) => {
|
||||
let item = webview
|
||||
.menu_items
|
||||
.get_mut(&id)
|
||||
.expect("menu item not found");
|
||||
match update {
|
||||
MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled),
|
||||
MenuUpdate::SetTitle(title) => item.set_title(&title),
|
||||
MenuUpdate::SetSelected(selected) => item.set_selected(selected),
|
||||
#[cfg(target_os = "macos")]
|
||||
MenuUpdate::SetNativeImage(image) => {
|
||||
item.set_native_image(NativeImageWrapper::from(image).0)
|
||||
if let Some(menu_items) = webview.menu_items.as_mut() {
|
||||
let item = menu_items.get_mut(&id).expect("menu item not found");
|
||||
match update {
|
||||
MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled),
|
||||
MenuUpdate::SetTitle(title) => item.set_title(&title),
|
||||
MenuUpdate::SetSelected(selected) => item.set_selected(selected),
|
||||
#[cfg(target_os = "macos")]
|
||||
MenuUpdate::SetNativeImage(image) => {
|
||||
item.set_native_image(NativeImageWrapper::from(image).0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2464,38 +2478,6 @@ fn center_window(window: &Window, window_size: WryPhysicalSize<u32>) -> Result<(
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_menu_id(mut new_menu: Menu, menu: Menu) -> Menu {
|
||||
for item in menu.items {
|
||||
match item {
|
||||
MenuEntry::CustomItem(c) => {
|
||||
let mut item = CustomMenuItem::new(c.id_str, c.title);
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Some(native_image) = c.native_image {
|
||||
item = item.native_image(native_image);
|
||||
}
|
||||
if let Some(accelerator) = c.keyboard_accelerator {
|
||||
item = item.accelerator(accelerator);
|
||||
}
|
||||
if !c.enabled {
|
||||
item = item.disabled();
|
||||
}
|
||||
if c.selected {
|
||||
item = item.selected();
|
||||
}
|
||||
new_menu = new_menu.add_item(item);
|
||||
}
|
||||
MenuEntry::NativeItem(i) => {
|
||||
new_menu = new_menu.add_native_item(i);
|
||||
}
|
||||
MenuEntry::Submenu(submenu) => {
|
||||
let new_submenu = convert_menu_id(Menu::new(), submenu.inner);
|
||||
new_menu = new_menu.add_submenu(Submenu::new(submenu.title, new_submenu));
|
||||
}
|
||||
}
|
||||
}
|
||||
new_menu
|
||||
}
|
||||
|
||||
fn to_wry_menu(
|
||||
custom_menu_items: &mut HashMap<MenuHash, WryCustomMenuItem>,
|
||||
menu: Menu,
|
||||
@ -2544,15 +2526,18 @@ fn create_webview(
|
||||
file_drop_handler,
|
||||
label,
|
||||
url,
|
||||
menu_ids,
|
||||
..
|
||||
} = pending;
|
||||
|
||||
let is_window_transparent = window_builder.inner.window.transparent;
|
||||
let menu_items = {
|
||||
let menu_items = if let Some(menu) = window_builder.menu {
|
||||
let mut menu_items = HashMap::new();
|
||||
let menu = to_wry_menu(&mut menu_items, window_builder.menu);
|
||||
let menu = to_wry_menu(&mut menu_items, menu);
|
||||
window_builder.inner = window_builder.inner.with_menu(menu);
|
||||
menu_items
|
||||
Some(menu_items)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let window = window_builder.inner.build(event_loop).unwrap();
|
||||
|
||||
@ -2577,13 +2562,18 @@ fn create_webview(
|
||||
.unwrap() // safe to unwrap because we validate the URL beforehand
|
||||
.with_transparent(is_window_transparent);
|
||||
if let Some(handler) = rpc_handler {
|
||||
webview_builder =
|
||||
webview_builder.with_rpc_handler(create_rpc_handler(context.clone(), label.clone(), handler));
|
||||
webview_builder = webview_builder.with_rpc_handler(create_rpc_handler(
|
||||
context.clone(),
|
||||
label.clone(),
|
||||
menu_ids.clone(),
|
||||
handler,
|
||||
));
|
||||
}
|
||||
if let Some(handler) = file_drop_handler {
|
||||
webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler(
|
||||
context,
|
||||
label.clone(),
|
||||
menu_ids,
|
||||
handler,
|
||||
));
|
||||
}
|
||||
@ -2639,6 +2629,7 @@ fn create_webview(
|
||||
fn create_rpc_handler(
|
||||
context: Context,
|
||||
label: String,
|
||||
menu_ids: HashMap<MenuHash, MenuId>,
|
||||
handler: WebviewRpcHandler<Wry>,
|
||||
) -> Box<dyn Fn(&Window, WryRpcRequest) -> Option<RpcResponse> + 'static> {
|
||||
Box::new(move |window, request| {
|
||||
@ -2649,6 +2640,7 @@ fn create_rpc_handler(
|
||||
context: context.clone(),
|
||||
},
|
||||
label: label.clone(),
|
||||
menu_ids: menu_ids.clone(),
|
||||
},
|
||||
RpcRequestWrapper(request).into(),
|
||||
);
|
||||
@ -2660,6 +2652,7 @@ fn create_rpc_handler(
|
||||
fn create_file_drop_handler(
|
||||
context: Context,
|
||||
label: String,
|
||||
menu_ids: HashMap<MenuHash, MenuId>,
|
||||
handler: FileDropHandler<Wry>,
|
||||
) -> Box<dyn Fn(&Window, WryFileDropEvent) -> bool + 'static> {
|
||||
Box::new(move |window, event| {
|
||||
@ -2671,6 +2664,7 @@ fn create_file_drop_handler(
|
||||
context: context.clone(),
|
||||
},
|
||||
label: label.clone(),
|
||||
menu_ids: menu_ids.clone(),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
@ -156,8 +156,8 @@ pub trait WindowBuilder: WindowBuilderBase {
|
||||
/// Whether the icon was set or not.
|
||||
fn has_icon(&self) -> bool;
|
||||
|
||||
/// Whether the menu was set or not.
|
||||
fn has_menu(&self) -> bool;
|
||||
/// Gets the window menu.
|
||||
fn get_menu(&self) -> Option<&Menu>;
|
||||
}
|
||||
|
||||
/// Rpc request.
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
use crate::{
|
||||
http::{Request as HttpRequest, Response as HttpResponse},
|
||||
menu::{Menu, MenuEntry, MenuHash, MenuId},
|
||||
webview::{FileDropHandler, WebviewAttributes, WebviewRpcHandler},
|
||||
Dispatch, Runtime, WindowBuilder,
|
||||
};
|
||||
@ -61,6 +62,18 @@ pub struct MenuEvent {
|
||||
pub menu_item_id: u16,
|
||||
}
|
||||
|
||||
fn get_menu_ids(map: &mut HashMap<MenuHash, MenuId>, menu: &Menu) {
|
||||
for item in &menu.items {
|
||||
match item {
|
||||
MenuEntry::CustomItem(c) => {
|
||||
map.insert(c.id, c.id_str.clone());
|
||||
}
|
||||
MenuEntry::Submenu(s) => get_menu_ids(map, &s.inner),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A webview window that has yet to be built.
|
||||
pub struct PendingWindow<R: Runtime> {
|
||||
/// The label that the window will be named.
|
||||
@ -82,6 +95,9 @@ pub struct PendingWindow<R: Runtime> {
|
||||
|
||||
/// The resolved URL to load on the webview.
|
||||
pub url: String,
|
||||
|
||||
/// Maps runtime id to a string menu id.
|
||||
pub menu_ids: HashMap<MenuHash, MenuId>,
|
||||
}
|
||||
|
||||
impl<R: Runtime> PendingWindow<R> {
|
||||
@ -91,6 +107,10 @@ impl<R: Runtime> PendingWindow<R> {
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: impl Into<String>,
|
||||
) -> Self {
|
||||
let mut menu_ids = HashMap::new();
|
||||
if let Some(menu) = window_builder.get_menu() {
|
||||
get_menu_ids(&mut menu_ids, menu);
|
||||
}
|
||||
Self {
|
||||
window_builder,
|
||||
webview_attributes,
|
||||
@ -99,6 +119,7 @@ impl<R: Runtime> PendingWindow<R> {
|
||||
rpc_handler: None,
|
||||
file_drop_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
menu_ids,
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,14 +129,20 @@ impl<R: Runtime> PendingWindow<R> {
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: impl Into<String>,
|
||||
) -> Self {
|
||||
let window_builder = <<R::Dispatcher as Dispatch>::WindowBuilder>::with_config(window_config);
|
||||
let mut menu_ids = HashMap::new();
|
||||
if let Some(menu) = window_builder.get_menu() {
|
||||
get_menu_ids(&mut menu_ids, menu);
|
||||
}
|
||||
Self {
|
||||
window_builder: <<R::Dispatcher as Dispatch>::WindowBuilder>::with_config(window_config),
|
||||
window_builder,
|
||||
webview_attributes,
|
||||
uri_scheme_protocols: Default::default(),
|
||||
label: label.into(),
|
||||
rpc_handler: None,
|
||||
file_drop_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
menu_ids,
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,6 +169,9 @@ pub struct DetachedWindow<R: Runtime> {
|
||||
|
||||
/// The [`Dispatch`](crate::Dispatch) associated with the window.
|
||||
pub dispatcher: R::Dispatcher,
|
||||
|
||||
/// Maps runtime id to a string menu id.
|
||||
pub menu_ids: HashMap<MenuHash, MenuId>,
|
||||
}
|
||||
|
||||
impl<R: Runtime> Clone for DetachedWindow<R> {
|
||||
@ -149,6 +179,7 @@ impl<R: Runtime> Clone for DetachedWindow<R> {
|
||||
Self {
|
||||
label: self.label.clone(),
|
||||
dispatcher: self.dispatcher.clone(),
|
||||
menu_ids: self.menu_ids.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ pub enum WindowManagerCmd {
|
||||
#[serde(tag = "cmd", content = "data", rename_all = "camelCase")]
|
||||
pub enum Cmd {
|
||||
CreateWebview {
|
||||
options: WindowConfig,
|
||||
options: Box<WindowConfig>,
|
||||
},
|
||||
Manage {
|
||||
label: Option<String>,
|
||||
@ -123,7 +123,7 @@ impl Cmd {
|
||||
window
|
||||
.create_window(label.clone(), url, |_, webview_attributes| {
|
||||
(
|
||||
<<R::Dispatcher as Dispatch>::WindowBuilder>::with_config(options),
|
||||
<<R::Dispatcher as Dispatch>::WindowBuilder>::with_config(*options),
|
||||
webview_attributes,
|
||||
)
|
||||
})?
|
||||
|
@ -29,10 +29,7 @@ use crate::api::path::{resolve_path, BaseDirectory};
|
||||
|
||||
use crate::app::{GlobalMenuEventListener, WindowMenuEvent};
|
||||
|
||||
use crate::{
|
||||
runtime::menu::{Menu, MenuEntry, MenuHash, MenuId},
|
||||
MenuEvent,
|
||||
};
|
||||
use crate::{runtime::menu::Menu, MenuEvent};
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
@ -79,8 +76,6 @@ pub struct InnerWindowManager<R: Runtime> {
|
||||
uri_scheme_protocols: HashMap<String, Arc<CustomProtocol<R>>>,
|
||||
/// The menu set to all windows.
|
||||
menu: Option<Menu>,
|
||||
/// Maps runtime id to a strongly typed menu id.
|
||||
menu_ids: HashMap<MenuHash, MenuId>,
|
||||
/// Menu event listeners to all windows.
|
||||
menu_event_listeners: Arc<Vec<GlobalMenuEventListener<R>>>,
|
||||
/// Window event listeners to all windows.
|
||||
@ -89,20 +84,14 @@ pub struct InnerWindowManager<R: Runtime> {
|
||||
|
||||
impl<R: Runtime> fmt::Debug for InnerWindowManager<R> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut s = f.debug_struct("InnerWindowManager");
|
||||
#[allow(unused_mut)]
|
||||
let mut w = s
|
||||
f.debug_struct("InnerWindowManager")
|
||||
.field("plugins", &self.plugins)
|
||||
.field("state", &self.state)
|
||||
.field("config", &self.config)
|
||||
.field("default_window_icon", &self.default_window_icon)
|
||||
.field("package_info", &self.package_info);
|
||||
{
|
||||
w = w
|
||||
.field("menu", &self.menu)
|
||||
.field("menu_ids", &self.menu_ids);
|
||||
}
|
||||
w.finish()
|
||||
.field("package_info", &self.package_info)
|
||||
.field("menu", &self.menu)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,18 +122,6 @@ impl<R: Runtime> Clone for WindowManager<R> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_menu_ids(map: &mut HashMap<MenuHash, MenuId>, menu: &Menu) {
|
||||
for item in &menu.items {
|
||||
match item {
|
||||
MenuEntry::CustomItem(c) => {
|
||||
map.insert(c.id, c.id_str.clone());
|
||||
}
|
||||
MenuEntry::Submenu(s) => get_menu_ids(map, &s.inner),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Runtime> WindowManager<R> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn with_handlers(
|
||||
@ -170,13 +147,6 @@ impl<R: Runtime> WindowManager<R> {
|
||||
default_window_icon: context.default_window_icon,
|
||||
package_info: context.package_info,
|
||||
uri_scheme_protocols,
|
||||
menu_ids: {
|
||||
let mut map = HashMap::new();
|
||||
if let Some(menu) = &menu {
|
||||
get_menu_ids(&mut map, menu)
|
||||
}
|
||||
map
|
||||
},
|
||||
menu,
|
||||
menu_event_listeners: Arc::new(menu_event_listeners),
|
||||
window_event_listeners: Arc::new(window_event_listeners),
|
||||
@ -195,11 +165,6 @@ impl<R: Runtime> WindowManager<R> {
|
||||
self.inner.state.clone()
|
||||
}
|
||||
|
||||
/// Get the menu ids mapper.
|
||||
pub(crate) fn menu_ids(&self) -> HashMap<MenuHash, MenuId> {
|
||||
self.inner.menu_ids.clone()
|
||||
}
|
||||
|
||||
/// Get the base path to serve data from.
|
||||
///
|
||||
/// * In dev mode, this will be based on the `devPath` configuration value.
|
||||
@ -281,7 +246,7 @@ impl<R: Runtime> WindowManager<R> {
|
||||
}
|
||||
}
|
||||
|
||||
if !pending.window_builder.has_menu() {
|
||||
if pending.window_builder.get_menu().is_none() {
|
||||
if let Some(menu) = &self.inner.menu {
|
||||
pending.window_builder = pending.window_builder.menu(menu.clone());
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ impl<R: Runtime> Window<R> {
|
||||
|
||||
/// Registers a menu event listener.
|
||||
pub fn on_menu_event<F: Fn(MenuEvent) + Send + 'static>(&self, f: F) -> uuid::Uuid {
|
||||
let menu_ids = self.manager.menu_ids();
|
||||
let menu_ids = self.window.menu_ids.clone();
|
||||
self.window.dispatcher.on_menu_event(move |event| {
|
||||
f(MenuEvent {
|
||||
menu_item_id: menu_ids.get(&event.menu_item_id).unwrap().clone(),
|
||||
@ -329,7 +329,7 @@ impl<R: Runtime> Window<R> {
|
||||
/// Gets a handle to the window menu.
|
||||
pub fn menu_handle(&self) -> MenuHandle<R> {
|
||||
MenuHandle {
|
||||
ids: self.manager.menu_ids(),
|
||||
ids: self.window.menu_ids.clone(),
|
||||
dispatcher: self.dispatcher(),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user