Skip to content

Commit d47ee24

Browse files
committed
fix(macos): enable native Help menu search field
Workaround for muda's broken set_as_help_menu_for_nsapp(). Directly calls NSApplication.setHelpMenu() after menu creation to enable the native macOS Help menu search functionality. See: tauri-apps/muda#322
1 parent 0d6f46a commit d47ee24

5 files changed

Lines changed: 101 additions & 0 deletions

File tree

src-tauri/Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,10 @@ dirs = "5"
3636
chrono = "0.4"
3737
tauri-plugin-window-state = "2"
3838

39+
[target.'cfg(target_os = "macos")'.dependencies]
40+
objc2 = "0.6"
41+
objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSMenu", "NSMenuItem", "NSResponder"] }
42+
objc2-foundation = { version = "0.3", features = ["NSString"] }
43+
3944
[dev-dependencies]
4045
tempfile = "3"

src-tauri/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ mod window_manager;
99
mod workspace;
1010
mod file_tree;
1111

12+
#[cfg(target_os = "macos")]
13+
mod macos_menu;
14+
1215
use std::sync::atomic::{AtomicBool, Ordering};
1316
use std::sync::Mutex;
1417
use tauri::{Listener, Manager};
@@ -113,6 +116,10 @@ pub fn run() {
113116
let menu = menu::create_menu(app.handle())?;
114117
app.set_menu(menu)?;
115118

119+
// Fix macOS Help/Window menus (workaround for muda bug)
120+
#[cfg(target_os = "macos")]
121+
macos_menu::apply_menu_fixes();
122+
116123
// Listen for "ready" events from frontend windows
117124
// This is used by menu_events to know when it's safe to emit events
118125
// The payload contains the window label as a string

src-tauri/src/macos_menu.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//! macOS-specific menu fixes.
2+
//!
3+
//! Workaround for muda's broken `set_as_help_menu_for_nsapp()`.
4+
//! See: https://github.com/tauri-apps/muda/pull/322
5+
6+
use objc2::MainThreadMarker;
7+
use objc2_app_kit::NSApplication;
8+
use objc2_foundation::NSString;
9+
10+
/// Fix the Help menu on macOS.
11+
///
12+
/// This finds the "Help" submenu in the app's main menu and properly registers it
13+
/// with NSApplication so macOS shows the native search field.
14+
///
15+
/// Must be called after `app.set_menu()`.
16+
pub fn fix_help_menu() {
17+
let Some(mtm) = MainThreadMarker::new() else {
18+
eprintln!("[macos_menu] Not on main thread, cannot fix Help menu");
19+
return;
20+
};
21+
22+
let app = NSApplication::sharedApplication(mtm);
23+
let Some(main_menu) = app.mainMenu() else {
24+
eprintln!("[macos_menu] No main menu found");
25+
return;
26+
};
27+
28+
// Find the Help menu by title
29+
let help_title = NSString::from_str("Help");
30+
let Some(help_item) = main_menu.itemWithTitle(&help_title) else {
31+
eprintln!("[macos_menu] No 'Help' menu item found");
32+
return;
33+
};
34+
35+
let Some(help_submenu) = help_item.submenu() else {
36+
eprintln!("[macos_menu] Help item has no submenu");
37+
return;
38+
};
39+
40+
// Register as the Help menu — this enables the native search field
41+
app.setHelpMenu(Some(&help_submenu));
42+
43+
#[cfg(debug_assertions)]
44+
eprintln!("[macos_menu] Help menu registered with search field");
45+
}
46+
47+
/// Fix the Window menu on macOS.
48+
///
49+
/// This finds the "Window" submenu and registers it with NSApplication
50+
/// so macOS adds native window management items.
51+
pub fn fix_window_menu() {
52+
let Some(mtm) = MainThreadMarker::new() else {
53+
return;
54+
};
55+
56+
let app = NSApplication::sharedApplication(mtm);
57+
let Some(main_menu) = app.mainMenu() else {
58+
return;
59+
};
60+
61+
let window_title = NSString::from_str("Window");
62+
let Some(window_item) = main_menu.itemWithTitle(&window_title) else {
63+
// Window menu is optional
64+
return;
65+
};
66+
67+
let Some(window_submenu) = window_item.submenu() else {
68+
return;
69+
};
70+
71+
app.setWindowsMenu(Some(&window_submenu));
72+
73+
#[cfg(debug_assertions)]
74+
eprintln!("[macos_menu] Window menu registered");
75+
}
76+
77+
/// Apply all macOS menu fixes.
78+
pub fn apply_menu_fixes() {
79+
fix_help_menu();
80+
fix_window_menu();
81+
}

src-tauri/src/menu.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,11 @@ pub fn update_recent_workspaces(app: AppHandle, workspaces: Vec<String>) -> Resu
798798
pub fn rebuild_menu(app: AppHandle, shortcuts: HashMap<String, String>) -> Result<(), String> {
799799
let menu = create_menu_with_shortcuts(&app, &shortcuts).map_err(|e| e.to_string())?;
800800
app.set_menu(menu).map_err(|e| e.to_string())?;
801+
802+
// Fix macOS Help/Window menus (workaround for muda bug)
803+
#[cfg(target_os = "macos")]
804+
crate::macos_menu::apply_menu_fixes();
805+
801806
Ok(())
802807
}
803808

0 commit comments

Comments
 (0)