Native menu bar (macOS): the shell describes it (menu_set, shell-only), host validates and builds it, a chosen id goes back to the shell (native-menu); App/File/Edit/View/Account/Plugins/Window/Help from the in-app menu's state, words wb.menu.*

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CRTkafa 2026-10-02 02:00:15 +07:00
parent aa5f50c4a9
commit 788be02a26
12 changed files with 813 additions and 1 deletions

View file

@ -729,6 +729,24 @@ async fn tab_find(webview: Webview, app: AppHandle, id: String, action: String,
host::tab_find(&app, &id, &action, query.as_deref())
}
/// Sets the native menu bar (macOS) from the shell's description ([`crate::menu`]); other platforms keep the
/// in-app menu and answer false. Choosing an item sends its id to the shell (`native-menu`).
#[tauri::command]
async fn menu_set(webview: Webview, app: AppHandle, spec: serde_json::Value) -> Result<bool, String> {
shell_only(&webview)?;
let spec = crate::menu::parse(spec)?;
#[cfg(target_os = "macos")]
{
crate::menu::set(&app, &spec)?;
Ok(true)
}
#[cfg(not(target_os = "macos"))]
{
let _ = (app, spec);
Ok(false)
}
}
/// Whether safe mode is on ([`crate::safe`]): the shell shows it in the titlebar and drops its chrome theme.
#[tauri::command]
async fn safe_mode_get(webview: Webview) -> Result<crate::safe::SafeState, String> {
@ -1236,6 +1254,7 @@ fn host_handler() -> impl Fn(tauri::ipc::Invoke<Wry>) -> bool + Send + Sync + 's
tab_action,
tab_zoom,
tab_find,
menu_set,
safe_mode_get,
safe_mode_set,
diag_get,
@ -1380,6 +1399,15 @@ impl App {
let vault_handler = vault_handler();
let backup_handler = backup_handler();
let builder = tauri::Builder::<Wry>::default()
// The native menu bar's choices go to the shell, which runs them ([`crate::menu`]).
.on_menu_event(|app, event| {
#[cfg(target_os = "macos")]
if let Some(id) = crate::menu::chosen(event.id().as_ref()) {
emit_shell(app, crate::menu::EVENT_NATIVE_MENU, id.to_owned());
}
#[cfg(not(target_os = "macos"))]
let _ = (app, event);
})
// Must be first: a second launch focuses the running window instead of fighting over
// the app's data and WebView profile (and hands over its link).
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {