From b5a125b96365b3b7238694c967ed662831bf22a6 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 4 Jan 2024 20:27:04 -0800 Subject: [PATCH] Refactor IPC a bit --- packages/desktop/src/app.rs | 32 +++--------- packages/desktop/src/desktop_context.rs | 66 +++++++------------------ packages/desktop/src/hooks.rs | 6 ++- packages/desktop/src/ipc.rs | 18 +++++++ packages/desktop/src/launch.rs | 3 +- packages/desktop/src/waker.rs | 2 +- packages/desktop/src/webview.rs | 24 ++++++++- 7 files changed, 74 insertions(+), 77 deletions(-) diff --git a/packages/desktop/src/app.rs b/packages/desktop/src/app.rs index c40029b34..e4d758b7d 100644 --- a/packages/desktop/src/app.rs +++ b/packages/desktop/src/app.rs @@ -1,10 +1,11 @@ use crate::{ cfg::{Config, WindowCloseBehaviour}, - desktop_context::{EventData, UserWindowEvent, WindowEventHandlers}, + desktop_context::WindowEventHandlers, edits::WebviewQueue, element::DesktopElement, file_upload::FileDialogRequest, ipc::IpcMessage, + ipc::{EventData, UserWindowEvent}, query::QueryResult, shortcut::{GlobalHotKeyEvent, ShortcutRegistry}, webview::WebviewInstance, @@ -12,7 +13,6 @@ use crate::{ use crossbeam_channel::Receiver; use dioxus_core::{Component, ElementId, VirtualDom}; use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent, MountedData}; -use futures_util::{pin_mut, FutureExt}; use std::{cell::Cell, collections::HashMap, rc::Rc, sync::Arc}; use tao::{ event::Event, @@ -33,6 +33,10 @@ 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, } @@ -249,10 +253,7 @@ impl App

{ dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { for webview in self.webviews.values_mut() { webview.dom.replace_template(template); - } - - for id in self.webviews.keys().copied().collect::>() { - self.poll_vdom(id); + webview.poll_vdom(); } } dioxus_hot_reload::HotReloadMsg::Shutdown => { @@ -300,24 +301,7 @@ impl App

{ return; }; - let mut cx = std::task::Context::from_waker(&view.waker); - - // Continously poll the virtualdom until it's pending - // Wait for work will return Ready when it has edits to be sent to the webview - // It will return Pending when it needs to be polled again - nothing is ready - loop { - { - let fut = view.dom.wait_for_work(); - pin_mut!(fut); - - match fut.poll_unpin(&mut cx) { - std::task::Poll::Ready(_) => {} - std::task::Poll::Pending => return, - } - } - - view.desktop_context.send_edits(view.dom.render_immediate()); - } + view.poll_vdom(); } } diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 3988bbbce..b02eca60e 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -1,19 +1,21 @@ -use crate::shortcut::{HotKey, ShortcutId, ShortcutRegistry, ShortcutRegistryError}; -use crate::AssetHandler; -use crate::Config; -use crate::{app::SharedContext, ipc::IpcMessage}; -use crate::{assets::AssetFuture, edits::WebviewQueue}; -use crate::{assets::AssetHandlerRegistry, edits::EditQueue}; -use crate::{query::QueryEngine, webview::WebviewInstance}; -use dioxus_core::Mutations; -use dioxus_core::VirtualDom; +use crate::{ + app::SharedContext, + assets::{AssetFuture, AssetHandlerRegistry}, + edits::EditQueue, + ipc::{EventData, UserWindowEvent}, + query::QueryEngine, + shortcut::{HotKey, ShortcutId, ShortcutRegistryError}, + webview::WebviewInstance, + AssetHandler, Config, +}; +use dioxus_core::{Mutations, VirtualDom}; use dioxus_interpreter_js::binary_protocol::Channel; use rustc_hash::FxHashMap; use slab::Slab; use std::{cell::RefCell, fmt::Debug, rc::Rc, rc::Weak, sync::atomic::AtomicU16}; use tao::{ event::Event, - event_loop::{EventLoopProxy, EventLoopWindowTarget}, + event_loop::EventLoopWindowTarget, window::{Fullscreen as WryFullscreen, Window, WindowId}, }; use wry::WebView; @@ -52,21 +54,13 @@ pub struct DesktopService { /// The tao window itself pub window: Window, - /// The receiver for queries about the current window - pub(super) query: QueryEngine, - pub(crate) shared: SharedContext, - // pub(crate) event_handlers: WindowEventHandlers, - // pub(super) pending_windows: WebviewQueue, - // pub(crate) shortcut_manager: ShortcutRegistry, - - // pub(crate) event_loop: EventLoopWindowTarget, + /// The receiver for queries about the current window + pub(super) query: QueryEngine, pub(crate) edit_queue: EditQueue, - pub(crate) templates: RefCell>, pub(crate) max_template_count: AtomicU16, - pub(crate) channel: RefCell, pub(crate) asset_handlers: AssetHandlerRegistry, @@ -153,22 +147,17 @@ impl DesktopService { /// onmousedown: move |_| { desktop.drag_window(); } /// ``` pub fn drag(&self) { - let window = &self.window; - - // if the drag_window has any errors, we don't do anything - if window.fullscreen().is_none() { - window.drag_window().unwrap(); + if self.window.fullscreen().is_none() { + _ = self.window.drag_window(); } } /// Toggle whether the window is maximized or not pub fn toggle_maximized(&self) { - let window = &self.window; - - window.set_maximized(!window.is_maximized()) + self.window.set_maximized(!self.window.is_maximized()) } - /// close window + /// Close this window pub fn close(&self) { let _ = self .shared @@ -176,7 +165,7 @@ impl DesktopService { .send_event(UserWindowEvent(EventData::CloseWindow, self.id())); } - /// close window + /// Close a particular window, given its ID pub fn close_window(&self, id: WindowId) { let _ = self .shared @@ -304,23 +293,6 @@ impl DesktopService { } } -#[derive(Debug, Clone)] -pub struct UserWindowEvent(pub EventData, pub WindowId); - -#[derive(Debug, Clone)] -pub enum EventData { - Poll, - - Ipc(IpcMessage), - - #[cfg(all(feature = "hot-reload", debug_assertions))] - HotReloadEvent(dioxus_hot_reload::HotReloadMsg), - - NewWindow, - - CloseWindow, -} - #[cfg(target_os = "ios")] fn is_main_thread() -> bool { use objc::runtime::{Class, BOOL, NO}; diff --git a/packages/desktop/src/hooks.rs b/packages/desktop/src/hooks.rs index 0f53f7ee6..d57d1bc5b 100644 --- a/packages/desktop/src/hooks.rs +++ b/packages/desktop/src/hooks.rs @@ -1,7 +1,9 @@ use std::rc::Rc; -use crate::{assets::*, shortcut::IntoAccelerator, ShortcutHandle, ShortcutRegistryError}; -use crate::{desktop_context::UserWindowEvent, window, DesktopContext, WryEventHandler}; +use crate::{ + assets::*, ipc::UserWindowEvent, shortcut::IntoAccelerator, window, DesktopContext, + ShortcutHandle, ShortcutRegistryError, WryEventHandler, +}; use dioxus_core::ScopeState; use tao::{event::Event, event_loop::EventLoopWindowTarget}; diff --git a/packages/desktop/src/ipc.rs b/packages/desktop/src/ipc.rs index 54c6d0eb0..5d939e808 100644 --- a/packages/desktop/src/ipc.rs +++ b/packages/desktop/src/ipc.rs @@ -1,4 +1,22 @@ use serde::{Deserialize, Serialize}; +use tao::window::WindowId; + +#[derive(Debug, Clone)] +pub struct UserWindowEvent(pub EventData, pub WindowId); + +#[derive(Debug, Clone)] +pub enum EventData { + Poll, + + Ipc(IpcMessage), + + #[cfg(all(feature = "hot-reload", debug_assertions))] + HotReloadEvent(dioxus_hot_reload::HotReloadMsg), + + NewWindow, + + CloseWindow, +} /// A message struct that manages the communication between the webview and the eventloop code /// diff --git a/packages/desktop/src/launch.rs b/packages/desktop/src/launch.rs index 8cdcec9b4..c8676c507 100644 --- a/packages/desktop/src/launch.rs +++ b/packages/desktop/src/launch.rs @@ -1,7 +1,6 @@ use crate::{ app::App, - desktop_context::{EventData, UserWindowEvent}, - ipc::IpcMethod, + ipc::{EventData, IpcMethod, UserWindowEvent}, Config, }; use dioxus_core::*; diff --git a/packages/desktop/src/waker.rs b/packages/desktop/src/waker.rs index 488c8f677..de59d81c9 100644 --- a/packages/desktop/src/waker.rs +++ b/packages/desktop/src/waker.rs @@ -1,4 +1,4 @@ -use crate::desktop_context::{EventData, UserWindowEvent}; +use crate::ipc::{EventData, UserWindowEvent}; use futures_util::task::ArcWake; use std::sync::Arc; use tao::{event_loop::EventLoopProxy, window::WindowId}; diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index 3ffee1a3a..286109e13 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -1,14 +1,15 @@ use crate::{ app::SharedContext, assets::AssetHandlerRegistry, - desktop_context::{EventData, UserWindowEvent}, edits::EditQueue, eval::DesktopEvalProvider, + ipc::{EventData, UserWindowEvent}, protocol::{self}, waker::tao_waker, Config, DesktopContext, DesktopService, }; use dioxus_core::VirtualDom; +use futures_util::{pin_mut, FutureExt}; use std::{rc::Rc, task::Waker}; use wry::{WebContext, WebViewBuilder}; @@ -160,4 +161,25 @@ impl WebviewInstance { _web_context: web_context, } } + + pub fn poll_vdom(&mut self) { + let mut cx = std::task::Context::from_waker(&self.waker); + + // Continously poll the virtualdom until it's pending + // Wait for work will return Ready when it has edits to be sent to the webview + // It will return Pending when it needs to be polled again - nothing is ready + loop { + { + let fut = self.dom.wait_for_work(); + pin_mut!(fut); + + match fut.poll_unpin(&mut cx) { + std::task::Poll::Ready(_) => {} + std::task::Poll::Pending => return, + } + } + + self.desktop_context.send_edits(self.dom.render_immediate()); + } + } }