diff --git a/packages/desktop/src/app.rs b/packages/desktop/src/app.rs index e4d758b7d..8fb87a2cf 100644 --- a/packages/desktop/src/app.rs +++ b/packages/desktop/src/app.rs @@ -1,7 +1,6 @@ use crate::{ cfg::{Config, WindowCloseBehaviour}, desktop_context::WindowEventHandlers, - edits::WebviewQueue, element::DesktopElement, file_upload::FileDialogRequest, ipc::IpcMessage, @@ -13,13 +12,19 @@ use crate::{ use crossbeam_channel::Receiver; use dioxus_core::{Component, ElementId, VirtualDom}; use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent, MountedData}; -use std::{cell::Cell, collections::HashMap, rc::Rc, sync::Arc}; +use std::{ + cell::{Cell, RefCell}, + collections::HashMap, + rc::Rc, + sync::Arc, +}; use tao::{ event::Event, event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget}, window::WindowId, }; +/// The single top-level object that manages all the running windows, assets, shortcuts, etc pub(crate) struct App

{ // move the props into a cell so we can pop it out later to create the first window // iOS panics if we create a window before the event loop is started, so we toss them into a cell @@ -33,17 +38,16 @@ pub(crate) struct App

{ pub(crate) webviews: HashMap, pub(crate) window_behavior: WindowCloseBehaviour, - /// This bit of state is shared between all the windows, providing a way for us to communicate with - /// running instances. - /// - /// Todo: everything in this struct is wrapped in Rc<>, but we really only need the one top-level refcell pub(crate) shared: SharedContext, } +/// A bundle of state shared between all the windows, providing a way for us to communicate with running webview. +/// +/// Todo: everything in this struct is wrapped in Rc<>, but we really only need the one top-level refcell #[derive(Clone)] pub struct SharedContext { pub(crate) event_handlers: WindowEventHandlers, - pub(crate) pending_webviews: WebviewQueue, + pub(crate) pending_webviews: Rc>>, pub(crate) shortcut_manager: ShortcutRegistry, pub(crate) global_hotkey_channel: Receiver, pub(crate) proxy: EventLoopProxy, @@ -64,7 +68,7 @@ impl App

{ cfg: Cell::new(Some(cfg)), shared: SharedContext { event_handlers: WindowEventHandlers::default(), - pending_webviews: WebviewQueue::default(), + pending_webviews: Default::default(), shortcut_manager: ShortcutRegistry::new(), global_hotkey_channel: GlobalHotKeyEvent::receiver().clone(), proxy: event_loop.create_proxy(), @@ -78,22 +82,16 @@ impl App

{ (event_loop, app) } - pub fn tick( - &mut self, - window_event: &Event<'_, UserWindowEvent>, - event_loop: &EventLoopWindowTarget, - ) { + pub fn tick(&mut self, window_event: &Event<'_, UserWindowEvent>) { self.control_flow = ControlFlow::Wait; self.shared .event_handlers - .apply_event(window_event, event_loop); + .apply_event(window_event, &self.shared.target); - _ = self - .shared - .global_hotkey_channel - .try_recv() - .map(|event| self.shared.shortcut_manager.call_handlers(event)); + if let Ok(event) = self.shared.global_hotkey_channel.try_recv() { + self.shared.shortcut_manager.call_handlers(event); + } } #[cfg(all(feature = "hot-reload", debug_assertions))] @@ -136,7 +134,6 @@ impl App

{ let Some(webview) = self.webviews.get(&id) else { return; }; - hide_app_window(&webview.desktop_context.webview); } @@ -164,14 +161,14 @@ impl App

{ self.is_visible_before_start = cfg.window.window.visible; - let handler = WebviewInstance::new( + let webview = WebviewInstance::new( cfg, VirtualDom::new_with_props(self.root, props), self.shared.clone(), ); - let id = handler.desktop_context.window.id(); - self.webviews.insert(id, handler); + let id = webview.desktop_context.window.id(); + self.webviews.insert(id, webview); _ = self .shared diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index a5d17b541..b7567030c 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -8,8 +8,6 @@ use wry::{ FileDropEvent, }; -// pub(crate) type DynEventHandlerFn = dyn Fn(&mut EventLoop<()>, &mut WebView); - /// The behaviour of the application when the last window is closed. #[derive(Copy, Clone, Eq, PartialEq)] pub enum WindowCloseBehaviour { diff --git a/packages/desktop/src/edits.rs b/packages/desktop/src/edits.rs index 6fd4e6759..4562f2ebf 100644 --- a/packages/desktop/src/edits.rs +++ b/packages/desktop/src/edits.rs @@ -1,12 +1,8 @@ -use crate::webview::WebviewInstance; -use dioxus_core::Mutations; -use dioxus_core::{BorrowedAttributeValue, Template, TemplateAttribute, TemplateNode}; +use dioxus_core::{BorrowedAttributeValue, Mutations, Template, TemplateAttribute, TemplateNode}; use dioxus_html::event_bubbles; use dioxus_interpreter_js::binary_protocol::Channel; use rustc_hash::FxHashMap; use std::{ - cell::RefCell, - rc::Rc, sync::atomic::AtomicU16, sync::Arc, sync::{atomic::Ordering, Mutex}, @@ -14,8 +10,6 @@ use std::{ use wry::RequestAsyncResponder; -pub(crate) type WebviewQueue = Rc>>; - /// This handles communication between the requests that the webview makes and the interpreter. The interpreter /// constantly makes long running requests to the webview to get any edits that should be made to the DOM almost like /// server side events. diff --git a/packages/desktop/src/hooks.rs b/packages/desktop/src/hooks.rs index d57d1bc5b..24662872e 100644 --- a/packages/desktop/src/hooks.rs +++ b/packages/desktop/src/hooks.rs @@ -1,10 +1,9 @@ -use std::rc::Rc; - use crate::{ assets::*, ipc::UserWindowEvent, shortcut::IntoAccelerator, window, DesktopContext, ShortcutHandle, ShortcutRegistryError, WryEventHandler, }; use dioxus_core::ScopeState; +use std::rc::Rc; use tao::{event::Event, event_loop::EventLoopWindowTarget}; /// Get an imperative handle to the current window diff --git a/packages/desktop/src/launch.rs b/packages/desktop/src/launch.rs index c8676c507..e53a5ea77 100644 --- a/packages/desktop/src/launch.rs +++ b/packages/desktop/src/launch.rs @@ -97,8 +97,8 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) pub fn launch_with_props_blocking(root: Component

, props: P, cfg: Config) { let (event_loop, mut app) = App::new(cfg, props, root); - event_loop.run(move |window_event, event_loop, control_flow| { - app.tick(&window_event, event_loop); + event_loop.run(move |window_event, _, control_flow| { + app.tick(&window_event); match window_event { Event::NewEvents(StartCause::Init) => app.handle_start_cause_init(), diff --git a/packages/desktop/src/waker.rs b/packages/desktop/src/waker.rs index de59d81c9..5c3e915e3 100644 --- a/packages/desktop/src/waker.rs +++ b/packages/desktop/src/waker.rs @@ -7,7 +7,8 @@ use tao::{event_loop::EventLoopProxy, window::WindowId}; /// /// This lets the VirtualDom "come up for air" and process events while the main thread is blocked by the WebView. /// -/// All other IO lives in the Tokio runtime, +/// All IO and multithreading lives on other threads. Thanks to tokio's work stealing approach, the main thread can never +/// claim a task while it's blocked by the event loop. pub fn tao_waker(proxy: EventLoopProxy, id: WindowId) -> std::task::Waker { struct DomHandle { proxy: EventLoopProxy,