Menu Utilities library for Desktop Applications.
- Windows
- macOS
- Linux/BSD with GTK 3 or GTK 4
- On Windows, accelerators don't work unless the win32 message loop calls
TranslateAcceleratorW. SeeMenu::init_for_hwndfor more details
The Win32 and AppKit backends are always enabled on Windows and macOS, respectively.
gtk3: Enables the GTK 3 backend on Linux or BSD platforms. This is enabled by default.gtk4: Enables the GTK 4 backend on Linux or BSD platforms. Usedefault-features = falsewhen enabling this feature because the default features includegtk3.common-controls-v6: UseTaskDialogIndirectAPI fromComCtl32.dllv6 on Windows for showing the predefinedAboutmenu item dialog.snapshot: Enables thread-safe menu snapshot types and methods, switching shared menu state to thread-safe synchronization.serde: Enables de/serializing the dpi types.
When both gtk3 and gtk4 are enabled, Muda uses the GTK 4 backend and emits a Cargo warning.
The gtk3 feature uses GTK 3 for menus. The gtk4 feature uses GTK 4 for menus.
Be sure to install the packages for the GTK backend you enabled before building:
# GTK 3 backend
pacman -S gtk3
# GTK 4 backend
pacman -S gtk4# GTK 3 backend
sudo apt install libgtk-3-dev
# GTK 4 backend
sudo apt install libgtk-4-devInstall these dependencies in order to compile muda. Instructions using pkg:
# GTK 3 backend
pkg install -y rust glib pkgconf gtk3
# GTK 4 backend
pkg install -y rust glib pkgconf gtk4Create the menu and add your items
use muda::{Menu, Submenu, MenuItem, accelerator::{Code, Modifiers, Accelerator}, PredefinedMenuItem};
let menu = Menu::new();
let menu_item2 = MenuItem::new("Menu item #2", false, None);
let submenu = Submenu::with_items(
"Submenu Outer",
true,
&[
&MenuItem::new(
"Menu item #1",
true,
Some(Accelerator::new(Modifiers::ALT, Code::KeyD)),
),
&PredefinedMenuItem::separator(),
&menu_item2,
&MenuItem::new("Menu item #3", true, None),
&PredefinedMenuItem::separator(),
&Submenu::with_items(
"Submenu Inner",
true,
&[
&MenuItem::new("Submenu item #1", true, None),
&PredefinedMenuItem::separator(),
&menu_item2,
],
).unwrap(),
],
).unwrap();
menu.append(&submenu).unwrap();Then add your root menu to a window on Windows, GTK 3, or GTK 4 or use it as your global app menu on macOS
The window handles and GTK widgets below come from your application's window setup. For GTK, use the same GTK version as the enabled Muda backend.
#[cfg(target_os = "windows")]
unsafe { menu.init_for_hwnd(window_hwnd) }.unwrap();
#[cfg(target_os = "linux")]
menu.init_for_gtk_window(>k_window, Some(&vertical_gtk_box)).unwrap();
#[cfg(target_os = "macos")]
menu.init_for_nsapp();You can also use a Menu or a Submenu to show a context menu.
Use a valid window handle, GTK window, or NSView from your application.
use muda::ContextMenu;
let position = muda::dpi::PhysicalPosition { x: 100., y: 120. };
#[cfg(target_os = "windows")]
unsafe { menu.show_context_menu_for_hwnd(window_hwnd, Some(position.into())) };
#[cfg(target_os = "linux")]
menu.show_context_menu_for_gtk_window(>k_window, Some(position.into()));
#[cfg(target_os = "macos")]
unsafe { menu.show_context_menu_for_nsview(nsview, Some(position.into())) };You can use MenuEvent::receiver to get a reference to the MenuEventReceiver
which you can use to listen to events when a menu item is activated
if let Ok(event) = MenuEvent::receiver().try_recv() {
match event.id {
_ if event.id == save_item.id() => {
println!("Save menu item activated");
},
_ => {}
}
}You should use [MenuEvent::set_event_handler] and forward
the menu events to the event loop by using EventLoopProxy
so that the event loop is awakened on each menu event.
enum UserEvent {
MenuEvent(muda::MenuEvent)
}
let event_loop = EventLoop::<UserEvent>::with_user_event().build().unwrap();
let proxy = event_loop.create_proxy();
muda::MenuEvent::set_event_handler(Some(Arc::new(move |event| {
proxy.send_event(UserEvent::MenuEvent(event));
})));Only one handler can be set at a time, for the whole process, so MenuEvent::set_event_handler
replaces the current handler and returns it. While a handler is set, the MenuEventReceiver
doesn't receive any events.
Each SemVer-incompatible version of muda has its own handler and receiver, and a menu only sends
its events to those of the version that created it. So if your dependency tree has two versions,
for example because tray-icon depends on another one, the menus created through one of them
never send events to the handler or receiver of the other. Run cargo tree --duplicates to check.
Apache-2.0/MIT