use std::{
collections::HashMap,
sync::{Arc, Mutex, MutexGuard},
};
use crate::{
AppHandle, Runtime, Window,
menu::{Menu, MenuEvent, MenuId},
};
pub struct MenuManager<R: Runtime> {
pub menus: Arc<Mutex<HashMap<MenuId, Menu<R>>>>,
pub menu: Mutex<Option<Menu<R>>>,
pub global_event_listeners: Mutex<Vec<crate::app::GlobalMenuEventListener<AppHandle<R>>>>,
pub event_listeners: Mutex<HashMap<String, crate::app::GlobalMenuEventListener<Window<R>>>>,
}
impl<R: Runtime> MenuManager<R> {
pub fn menu_lock(&self) -> MutexGuard<'_, Option<Menu<R>>> {
self.menu.lock().expect("poisoned menu mutex")
}
pub fn menus_stash_lock(&self) -> MutexGuard<'_, HashMap<MenuId, Menu<R>>> {
self.menus.lock().expect("poisoned menu mutex")
}
pub fn is_menu_in_use<I: PartialEq<MenuId>>(&self, id: &I) -> bool {
self
.menu_lock()
.as_ref()
.map(|m| id.eq(m.id()))
.unwrap_or(false)
}
pub fn insert_menu_into_stash(&self, menu: &Menu<R>) {
self
.menus_stash_lock()
.insert(menu.id().clone(), menu.clone());
}
pub(crate) fn prepare_window_menu_creation_handler(
&self,
window_menu: Option<&crate::window::WindowMenu<R>>,
#[allow(unused)] theme: Option<tauri_utils::Theme>,
) -> Option<impl Fn(tauri_runtime::window::RawWindow<'_>) + use<R>> {
let window_menu = window_menu?;
self
.menus_stash_lock()
.insert(window_menu.menu.id().clone(), window_menu.menu.clone());
#[cfg(target_os = "macos")]
return None;
#[cfg_attr(target_os = "macos", allow(unused_variables, unreachable_code))]
#[cfg_attr(all(not(windows), not(gtk)), allow(unused_variables))]
{
let menu = window_menu.menu.clone();
Some(move |raw: tauri_runtime::window::RawWindow<'_>| {
#[cfg(target_os = "windows")]
{
let theme = theme
.map(crate::menu::map_to_menu_theme)
.unwrap_or(muda::MenuTheme::Auto);
let _ = unsafe { menu.inner().init_for_hwnd_with_theme(raw.hwnd as _, theme) };
}
#[cfg(gtk)]
if crate::gtk_version::check().is_ok() {
use gtk::glib::translate::FromGlibPtrNone;
let gtk_window = unsafe {
gtk::ApplicationWindow::from_glib_none(
raw.gtk_window as *mut gtk::ffi::GtkApplicationWindow,
)
};
let default_vbox = raw
.default_vbox
.map(|vbox| unsafe { gtk::Box::from_glib_none(vbox as *mut gtk::ffi::GtkBox) });
let _ = menu
.inner()
.init_for_gtk_window(>k_window, default_vbox.as_ref());
}
})
}
}
pub fn on_menu_event<F: Fn(&AppHandle<R>, MenuEvent) + Send + Sync + 'static>(&self, handler: F) {
self
.global_event_listeners
.lock()
.unwrap()
.push(Box::new(handler));
}
}