diff --git a/.changes/refactor-listeners-wry.md b/.changes/refactor-listeners-wry.md new file mode 100644 index 000000000..9c0254e52 --- /dev/null +++ b/.changes/refactor-listeners-wry.md @@ -0,0 +1,5 @@ +--- +"tauri-runtime-wry": patch +--- + +Moved the window and menu event listeners to the window struct. diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 181d6f3cf..b7733967d 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -91,6 +91,7 @@ use std::{ HashMap, HashSet, }, fmt, + marker::PhantomData, ops::Deref, path::PathBuf, sync::{ @@ -124,12 +125,10 @@ use clipboard::*; pub type WebContextStore = Arc, WebContext>>>; // window -type WindowEventHandler = Box; -type WindowEventListenersMap = Arc>>; -pub type WindowEventListeners = Arc>>; +pub type WindowEventHandler = Box; +pub type WindowEventListeners = Arc>>; // menu pub type MenuEventHandler = Box; -pub type MenuEventListeners = Arc>>; pub type WindowMenuEventListeners = Arc>>; #[derive(Debug, Clone, Default)] @@ -172,13 +171,12 @@ fn send_user_message(context: &Context, message: Message) -> &context.main_thread.window_target, message, UserMessageContext { + marker: &PhantomData, webview_id_map: context.webview_id_map.clone(), - window_event_listeners: &context.window_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager: context.main_thread.global_shortcut_manager.clone(), #[cfg(feature = "clipboard")] clipboard_manager: context.main_thread.clipboard_manager.clone(), - menu_event_listeners: &context.menu_event_listeners, windows: context.main_thread.windows.clone(), #[cfg(feature = "system-tray")] tray_context: &context.main_thread.tray_context, @@ -199,8 +197,6 @@ pub struct Context { pub webview_id_map: WebviewIdStore, main_thread_id: ThreadId, pub proxy: WryEventLoopProxy>, - pub window_event_listeners: WindowEventListeners, - pub menu_event_listeners: MenuEventListeners, main_thread: DispatcherMainThreadContext, } @@ -218,20 +214,6 @@ impl Context { } impl Context { - fn prepare_window(&self, window_id: WebviewId) { - self - .window_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowEventListenersMap::default()); - - self - .menu_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowMenuEventListeners::default()); - } - fn create_webview(&self, pending: PendingWindow>) -> Result>> { let label = pending.label.clone(); let menu_ids = pending.menu_ids.clone(); @@ -239,8 +221,6 @@ impl Context { let context = self.clone(); let window_id = rand::random(); - self.prepare_window(window_id); - send_user_message( self, Message::CreateWebview( @@ -1017,6 +997,8 @@ unsafe impl Send for RawWindowHandle {} pub enum WindowMessage { WithWebview(Box), + AddEventListener(Uuid, Box), + AddMenuEventListener(Uuid, Box), // Devtools #[cfg(any(debug_assertions, feature = "devtools"))] OpenDevTools, @@ -1176,31 +1158,29 @@ impl Dispatch for WryDispatcher { fn on_window_event(&self, f: F) -> Uuid { let id = Uuid::new_v4(); - self - .context - .window_event_listeners - .lock() - .unwrap() - .get(&self.window_id) - .unwrap() - .lock() - .unwrap() - .insert(id, Box::new(f)); + let _ = self.context.proxy.send_event(Message::Window( + self.window_id, + WindowMessage::AddEventListener(id, Box::new(f)), + )); + /* self + .context + .window_event_listeners + .lock() + .unwrap() + .get(&self.window_id) + .unwrap() + .lock() + .unwrap() + .insert(id, Box::new(f));*/ id } fn on_menu_event(&self, f: F) -> Uuid { let id = Uuid::new_v4(); - self - .context - .menu_event_listeners - .lock() - .unwrap() - .get(&self.window_id) - .unwrap() - .lock() - .unwrap() - .insert(id, Box::new(f)); + let _ = self.context.proxy.send_event(Message::Window( + self.window_id, + WindowMessage::AddMenuEventListener(id, Box::new(f)), + )); id } @@ -1604,11 +1584,22 @@ impl WindowHandle { } } -#[derive(Debug)] pub struct WindowWrapper { label: String, inner: Option, menu_items: Option>, + window_event_listeners: WindowEventListeners, + menu_event_listeners: WindowMenuEventListeners, +} + +impl fmt::Debug for WindowWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("WindowWrapper") + .field("label", &self.label) + .field("inner", &self.inner) + .field("menu_items", &self.menu_items) + .finish() + } } #[derive(Debug, Clone)] @@ -1773,8 +1764,6 @@ impl Wry { let windows = Arc::new(Mutex::new(HashMap::default())); let webview_id_map = WebviewIdStore::default(); - let window_event_listeners = WindowEventListeners::default(); - let menu_event_listeners = MenuEventListeners::default(); #[cfg(feature = "system-tray")] let tray_context = TrayContext::default(); @@ -1783,8 +1772,6 @@ impl Wry { webview_id_map, main_thread_id, proxy: event_loop.create_proxy(), - window_event_listeners: window_event_listeners.clone(), - menu_event_listeners: menu_event_listeners.clone(), main_thread: DispatcherMainThreadContext { window_target: event_loop.deref().clone(), web_context, @@ -1889,8 +1876,6 @@ impl Runtime for Wry { let js_event_listeners = pending.js_event_listeners.clone(); let window_id = rand::random(); - self.context.prepare_window(window_id); - let webview = create_webview( window_id, &self.event_loop, @@ -1983,8 +1968,6 @@ impl Runtime for Wry { let webview_id_map = self.context.webview_id_map.clone(); let web_context = &self.context.main_thread.web_context; let plugins = &mut self.plugins; - let window_event_listeners = self.context.window_event_listeners.clone(); - let menu_event_listeners = self.context.menu_event_listeners.clone(); #[cfg(feature = "system-tray")] let tray_context = self.context.main_thread.tray_context.clone(); @@ -2017,14 +2000,12 @@ impl Runtime for Wry { callback: &mut callback, webview_id_map: webview_id_map.clone(), windows: windows.clone(), - window_event_listeners: &window_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager: global_shortcut_manager.clone(), #[cfg(feature = "global-shortcut")] global_shortcut_manager_handle: &global_shortcut_manager_handle, #[cfg(feature = "clipboard")] clipboard_manager: clipboard_manager.clone(), - menu_event_listeners: &menu_event_listeners, #[cfg(feature = "system-tray")] tray_context: &tray_context, }, @@ -2043,14 +2024,12 @@ impl Runtime for Wry { callback: &mut callback, windows: windows.clone(), webview_id_map: webview_id_map.clone(), - window_event_listeners: &window_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager: global_shortcut_manager.clone(), #[cfg(feature = "global-shortcut")] global_shortcut_manager_handle: &global_shortcut_manager_handle, #[cfg(feature = "clipboard")] clipboard_manager: clipboard_manager.clone(), - menu_event_listeners: &menu_event_listeners, #[cfg(feature = "system-tray")] tray_context: &tray_context, }, @@ -2066,8 +2045,6 @@ impl Runtime for Wry { let webview_id_map = self.context.webview_id_map.clone(); let web_context = self.context.main_thread.web_context; let mut plugins = self.plugins; - let window_event_listeners = self.context.window_event_listeners.clone(); - let menu_event_listeners = self.context.menu_event_listeners.clone(); #[cfg(feature = "system-tray")] let tray_context = self.context.main_thread.tray_context; @@ -2093,14 +2070,12 @@ impl Runtime for Wry { callback: &mut callback, webview_id_map: webview_id_map.clone(), windows: windows.clone(), - window_event_listeners: &window_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager: global_shortcut_manager.clone(), #[cfg(feature = "global-shortcut")] global_shortcut_manager_handle: &global_shortcut_manager_handle, #[cfg(feature = "clipboard")] clipboard_manager: clipboard_manager.clone(), - menu_event_listeners: &menu_event_listeners, #[cfg(feature = "system-tray")] tray_context: &tray_context, }, @@ -2118,14 +2093,12 @@ impl Runtime for Wry { callback: &mut callback, webview_id_map: webview_id_map.clone(), windows: windows.clone(), - window_event_listeners: &window_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager: global_shortcut_manager.clone(), #[cfg(feature = "global-shortcut")] global_shortcut_manager_handle: &global_shortcut_manager_handle, #[cfg(feature = "clipboard")] clipboard_manager: clipboard_manager.clone(), - menu_event_listeners: &menu_event_listeners, #[cfg(feature = "system-tray")] tray_context: &tray_context, }, @@ -2139,26 +2112,24 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> { pub callback: &'a mut (dyn FnMut(RunEvent) + 'static), pub webview_id_map: WebviewIdStore, pub windows: Arc>>, - pub window_event_listeners: &'a WindowEventListeners, #[cfg(feature = "global-shortcut")] pub global_shortcut_manager: Arc>, #[cfg(feature = "global-shortcut")] pub global_shortcut_manager_handle: &'a GlobalShortcutManagerHandle, #[cfg(feature = "clipboard")] pub clipboard_manager: Arc>, - pub menu_event_listeners: &'a MenuEventListeners, #[cfg(feature = "system-tray")] pub tray_context: &'a TrayContext, } struct UserMessageContext<'a> { + #[allow(dead_code)] + marker: &'a PhantomData<()>, webview_id_map: WebviewIdStore, - window_event_listeners: &'a WindowEventListeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager: Arc>, #[cfg(feature = "clipboard")] clipboard_manager: Arc>, - menu_event_listeners: &'a MenuEventListeners, windows: Arc>>, #[cfg(feature = "system-tray")] tray_context: &'a TrayContext, @@ -2171,9 +2142,8 @@ fn handle_user_message( web_context: &WebContextStore, ) -> RunIteration { let UserMessageContext { + marker: _, webview_id_map, - window_event_listeners, - menu_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager, #[cfg(feature = "clipboard")] @@ -2207,7 +2177,15 @@ fn handle_user_message( } } else { let windows_lock = windows.lock().expect("poisoned webview collection"); - if let Some(window) = windows_lock.get(&id).and_then(|w| w.inner.clone()) { + if let Some((Some(window), window_event_listeners, menu_event_listeners)) = + windows_lock.get(&id).map(|w| { + ( + w.inner.clone(), + w.window_event_listeners.clone(), + w.menu_event_listeners.clone(), + ) + }) + { drop(windows_lock); match window_message { WindowMessage::WithWebview(f) => { @@ -2242,6 +2220,14 @@ fn handle_user_message( } } + WindowMessage::AddEventListener(id, listener) => { + window_event_listeners.lock().unwrap().insert(id, listener); + } + + WindowMessage::AddMenuEventListener(id, listener) => { + menu_event_listeners.lock().unwrap().insert(id, listener); + } + #[cfg(any(debug_assertions, feature = "devtools"))] WindowMessage::OpenDevTools => { if let WindowHandle::Webview(w) = &window { @@ -2417,17 +2403,17 @@ fn handle_user_message( } } WebviewMessage::WebviewEvent(event) => { - if let Some(event) = WindowEventWrapper::from(&event).0 { - let shared_listeners = window_event_listeners - .lock() - .unwrap() - .get(&id) - .unwrap() - .clone(); - let listeners = shared_listeners.lock().unwrap(); - let handlers = listeners.values(); - for handler in handlers { - handler(&event); + if let Some(window) = windows + .lock() + .expect("poisoned webview collection") + .get(&id) + { + if let Some(event) = WindowEventWrapper::from(&event).0 { + let listeners = window.window_event_listeners.lock().unwrap(); + let handlers = listeners.values(); + for handler in handlers { + handler(&event); + } } } } @@ -2446,16 +2432,6 @@ fn handle_user_message( Message::CreateWindow(window_id, handler, sender) => { let (label, builder) = handler(); if let Ok(window) = builder.build(event_loop) { - window_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowEventListenersMap::default()); - - menu_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowMenuEventListeners::default()); - webview_id_map.insert(window.id(), window_id); let w = Arc::new(window); @@ -2466,6 +2442,8 @@ fn handle_user_message( label, inner: Some(WindowHandle::Window(w.clone())), menu_items: Default::default(), + window_event_listeners: Default::default(), + menu_event_listeners: Default::default(), }, ); sender.send(Ok(Arc::downgrade(&w))).unwrap(); @@ -2544,14 +2522,12 @@ fn handle_event_loop( callback, webview_id_map, windows, - window_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager, #[cfg(feature = "global-shortcut")] global_shortcut_manager_handle, #[cfg(feature = "clipboard")] clipboard_manager, - menu_event_listeners, #[cfg(feature = "system-tray")] tray_context, } = context; @@ -2612,8 +2588,13 @@ fn handle_event_loop( } else { *webview_id_map.0.lock().unwrap().values().next().unwrap() }; - let listeners = menu_event_listeners.lock().unwrap(); - listeners.get(&window_id).cloned().unwrap_or_default() + windows + .lock() + .unwrap() + .get(&window_id) + .unwrap() + .menu_event_listeners + .clone() }; let listeners = window_menu_event_listeners.lock().unwrap(); let handlers = listeners.values(); @@ -2681,23 +2662,16 @@ fn handle_event_loop( { let windows_lock = windows.lock().expect("poisoned webview collection"); - if let Some((label, window_handle)) = - windows_lock.get(&window_id).map(|w| (&w.label, &w.inner)) - { - if let Some(event) = WindowEventWrapper::parse(window_handle, &event).0 { - let label = label.clone(); + if let Some(window) = windows_lock.get(&window_id) { + if let Some(event) = WindowEventWrapper::parse(&window.inner, &event).0 { + let label = window.label.clone(); + let window_event_listeners = window.window_event_listeners.clone(); drop(windows_lock); callback(RunEvent::WindowEvent { label, event: event.clone(), }); - let shared_listeners = window_event_listeners - .lock() - .unwrap() - .get(&window_id) - .unwrap() - .clone(); - let listeners = shared_listeners.lock().unwrap(); + let listeners = window_event_listeners.lock().unwrap(); let handlers = listeners.values(); for handler in handlers { handler(&event); @@ -2708,13 +2682,10 @@ fn handle_event_loop( match event { WryWindowEvent::CloseRequested => { - on_close_requested(callback, window_id, windows.clone(), window_event_listeners); + on_close_requested(callback, window_id, windows.clone()); } WryWindowEvent::Destroyed => { if windows.lock().unwrap().remove(&window_id).is_some() { - menu_event_listeners.lock().unwrap().remove(&window_id); - window_event_listeners.lock().unwrap().remove(&window_id); - let is_empty = windows.lock().unwrap().is_empty(); if is_empty { let (tx, rx) = channel(); @@ -2754,13 +2725,12 @@ fn handle_event_loop( event_loop, message, UserMessageContext { + marker: &PhantomData, webview_id_map, - window_event_listeners, #[cfg(feature = "global-shortcut")] global_shortcut_manager, #[cfg(feature = "clipboard")] clipboard_manager, - menu_event_listeners, windows, #[cfg(feature = "system-tray")] tray_context, @@ -2782,20 +2752,14 @@ fn on_close_requested<'a, T: UserEvent>( callback: &'a mut (dyn FnMut(RunEvent) + 'static), window_id: WebviewId, windows: Arc>>, - window_event_listeners: &WindowEventListeners, ) { let (tx, rx) = channel(); let windows_guard = windows.lock().expect("poisoned webview collection"); if let Some(w) = windows_guard.get(&window_id) { let label = w.label.clone(); + let window_event_listeners = w.window_event_listeners.clone(); drop(windows_guard); - let shared_listeners = window_event_listeners - .lock() - .unwrap() - .get(&window_id) - .unwrap() - .clone(); - let listeners = shared_listeners.lock().unwrap(); + let listeners = window_event_listeners.lock().unwrap(); let handlers = listeners.values(); for handler in handlers { handler(&WindowEvent::CloseRequested { @@ -3024,6 +2988,8 @@ fn create_webview( label, inner: Some(WindowHandle::Webview(Arc::new(webview))), menu_items, + window_event_listeners: Default::default(), + menu_event_listeners: Default::default(), }) } @@ -3054,14 +3020,14 @@ fn create_ipc_handler( /// Create a wry file drop handler. fn create_file_drop_handler(context: &Context) -> Box { - let window_event_listeners = context.window_event_listeners.clone(); + let windows = context.main_thread.windows.clone(); let webview_id_map = context.webview_id_map.clone(); Box::new(move |window, event| { let event: FileDropEvent = FileDropEventWrapper(event).into(); let window_event = WindowEvent::FileDrop(event); - let listeners = window_event_listeners.lock().unwrap(); - if let Some(window_listeners) = listeners.get(&webview_id_map.get(&window.id())) { - let listeners_map = window_listeners.lock().unwrap(); + let windows = windows.lock().unwrap(); + if let Some(window) = windows.get(&webview_id_map.get(&window.id())) { + let listeners_map = window.window_event_listeners.lock().unwrap(); let has_listener = !listeners_map.is_empty(); let handlers = listeners_map.values(); for listener in handlers {