// Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT #![allow(unused)] use std::rc::Rc; use muda::{ accelerator::{Accelerator, Code, Modifiers}, dpi::Position, AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, PredefinedMenuItem, Submenu, }; #[cfg(target_os = "macos")] use tao::platform::macos::WindowExtMacOS; #[cfg(target_os = "linux")] use tao::platform::unix::WindowExtUnix; #[cfg(target_os = "windows")] use tao::platform::windows::{EventLoopBuilderExtWindows, WindowExtWindows}; use tao::{ event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoopBuilder}, window::{Window, WindowBuilder}, }; #[cfg(target_os = "linux")] use wry::WebViewBuilderExtUnix; use wry::{http::Request, WebViewBuilder}; fn main() -> wry::Result<()> { let mut event_loop_builder = EventLoopBuilder::new(); let menu_bar = Menu::new(); #[cfg(target_os = "windows")] { let menu_bar = menu_bar.clone(); event_loop_builder.with_msg_hook(move |msg| { use windows_sys::Win32::UI::WindowsAndMessaging::{TranslateAcceleratorW, MSG}; unsafe { let msg = msg as *const MSG; let translated = TranslateAcceleratorW((*msg).hwnd, menu_bar.haccel() as _, msg); translated == 1 } }); } let event_loop = event_loop_builder.build(); let window = WindowBuilder::new() .with_title("Window 1") .build(&event_loop) .unwrap(); let window2 = WindowBuilder::new() .with_title("Window 2") .build(&event_loop) .unwrap(); #[cfg(target_os = "macos")] { let app_m = Submenu::new("App", true); menu_bar.append(&app_m).unwrap(); app_m .append_items(&[ &PredefinedMenuItem::about(None, None), &PredefinedMenuItem::separator(), &PredefinedMenuItem::services(None), &PredefinedMenuItem::separator(), &PredefinedMenuItem::hide(None), &PredefinedMenuItem::hide_others(None), &PredefinedMenuItem::show_all(None), &PredefinedMenuItem::separator(), &PredefinedMenuItem::quit(None), ]) .unwrap(); } let file_m = Submenu::new("&File", true); let edit_m = Submenu::new("&Edit", true); let window_m = Submenu::new("&Window", true); menu_bar .append_items(&[&file_m, &edit_m, &window_m]) .unwrap(); let custom_i_1 = MenuItem::new( "C&ustom 1", true, Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), ); let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); let icon = load_icon(std::path::Path::new(path)); let image_item = IconMenuItem::new( "Image custom 1", true, Some(icon), Some(Accelerator::new(Some(Modifiers::CONTROL), Code::KeyC)), ); let check_custom_i_1 = CheckMenuItem::new("Check Custom 1", true, true, None); let check_custom_i_2 = CheckMenuItem::new("Check Custom 2", false, true, None); let check_custom_i_3 = CheckMenuItem::new( "Check Custom 3", true, true, Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyD)), ); let copy_i = PredefinedMenuItem::copy(None); let cut_i = PredefinedMenuItem::cut(None); let paste_i = PredefinedMenuItem::paste(None); file_m .append_items(&[ &custom_i_1, &image_item, &window_m, &PredefinedMenuItem::separator(), &check_custom_i_1, &check_custom_i_2, ]) .unwrap(); window_m .append_items(&[ &PredefinedMenuItem::minimize(None), &PredefinedMenuItem::maximize(None), &PredefinedMenuItem::close_window(Some("Close")), &PredefinedMenuItem::fullscreen(None), &PredefinedMenuItem::bring_all_to_front(None), &PredefinedMenuItem::about( None, Some(AboutMetadata { name: Some("tao".to_string()), version: Some("1.2.3".to_string()), copyright: Some("Copyright tao".to_string()), ..Default::default() }), ), &check_custom_i_3, &image_item, &custom_i_1, ]) .unwrap(); edit_m .append_items(&[ ©_i, &PredefinedMenuItem::separator(), &cut_i, &PredefinedMenuItem::separator(), &paste_i, ]) .unwrap(); #[cfg(target_os = "windows")] unsafe { menu_bar.init_for_hwnd(window.hwnd() as _).unwrap(); menu_bar.init_for_hwnd(window2.hwnd() as _).unwrap(); } #[cfg(target_os = "linux")] { menu_bar .init_for_gtk_window(window.gtk_window(), window.default_vbox()) .unwrap(); menu_bar .init_for_gtk_window(window2.gtk_window(), window2.default_vbox()) .unwrap(); } #[cfg(target_os = "macos")] { menu_bar.init_for_nsapp(); window_m.set_as_windows_menu_for_nsapp(); } #[cfg(windows)] let condition = "e.button !== 2"; #[cfg(not(windows))] let condition = "e.button == 2 && e.buttons === 0"; let html: String = format!( r#"

WRYYYYYYYYYYYYYYYYYYYYYY!

"#, ); let window = Rc::new(window); let window2 = Rc::new(window2); let create_ipc_handler = |window: &Rc| { let window = window.clone(); let file_m_c = file_m.clone(); let menu_bar = menu_bar.clone(); move |req: Request| { let req = req.body(); if req == "showContextMenu" { show_context_menu(&window, &file_m_c, None) } else if let Some(rest) = req.strip_prefix("showContextMenuPos:") { let (x, mut y) = rest .split_once(',') .map(|(x, y)| (x.parse::().unwrap(), y.parse::().unwrap())) .unwrap(); #[cfg(target_os = "linux")] if let Some(menu_bar) = menu_bar .clone() .gtk_menubar_for_gtk_window(window.gtk_window()) { use gtk::prelude::*; y += menu_bar.allocated_height(); } show_context_menu(&window, &file_m_c, Some(Position::Logical((x, y).into()))) } } }; fn create_webview(window: &Rc) -> WebViewBuilder<'_> { #[cfg(not(target_os = "linux"))] return WebViewBuilder::new(window); #[cfg(target_os = "linux")] WebViewBuilder::new_gtk(window.default_vbox().unwrap()) }; let webview = create_webview(&window) .with_html(&html) .with_ipc_handler(create_ipc_handler(&window)) .build()?; let webview2 = create_webview(&window2) .with_html(html) .with_ipc_handler(create_ipc_handler(&window2)) .build()?; let menu_channel = MenuEvent::receiver(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = event { *control_flow = ControlFlow::Exit; } if let Ok(event) = menu_channel.try_recv() { if event.id == custom_i_1.id() { custom_i_1 .set_accelerator(Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyF))) .unwrap(); file_m .insert(&MenuItem::new("New Menu Item", true, None), 2) .unwrap(); } println!("{event:?}"); } }) } fn show_context_menu(window: &Window, menu: &dyn ContextMenu, position: Option) { println!("Show context menu at position {position:?}"); #[cfg(target_os = "windows")] unsafe { menu.show_context_menu_for_hwnd(window.hwnd() as _, position); } #[cfg(target_os = "linux")] menu.show_context_menu_for_gtk_window(window.gtk_window().as_ref(), position); #[cfg(target_os = "macos")] unsafe { menu.show_context_menu_for_nsview(window.ns_view() as _, position); } } fn load_icon(path: &std::path::Path) -> muda::Icon { let (icon_rgba, icon_width, icon_height) = { let image = image::open(path) .expect("Failed to open icon path") .into_rgba8(); let (width, height) = image.dimensions(); let rgba = image.into_raw(); (rgba, width, height) }; muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") }