From 7bc8150da738176bf910999a62bf5bb49de95628 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 29 Dec 2022 20:39:22 -0500 Subject: [PATCH] fix desktop to poll without budget --- examples/clock.rs | 12 +---- examples/todomvc.rs | 5 +- packages/core/src/virtual_dom.rs | 34 +++++-------- packages/desktop/src/desktop_context.rs | 5 +- packages/desktop/src/lib.rs | 67 +++++++++++-------------- 5 files changed, 48 insertions(+), 75 deletions(-) diff --git a/examples/clock.rs b/examples/clock.rs index 5df326c1d..c76c49faf 100644 --- a/examples/clock.rs +++ b/examples/clock.rs @@ -5,16 +5,8 @@ use dioxus::prelude::*; use futures_util::Future; -#[tokio::main] -async fn main() { - let mut dom = VirtualDom::new(app); - dom.rebuild(); - - loop { - dom.wait_for_work().await; - } - - // dioxus_desktop::launch(app).await; +fn main() { + dioxus_desktop::launch(app); } fn app(cx: Scope) -> Element { diff --git a/examples/todomvc.rs b/examples/todomvc.rs index afd1f36b3..b5277133e 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -3,9 +3,8 @@ use dioxus::prelude::*; use dioxus_elements::input_data::keyboard_types::Key; -#[tokio::main] -async fn main() { - dioxus_desktop::launch(app).await; +fn main() { + dioxus_desktop::launch(app); } #[derive(PartialEq, Eq)] diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 2306073cf..435ccea3d 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -13,21 +13,10 @@ use crate::{ scopes::{ScopeId, ScopeState}, AttributeValue, Element, Event, Scope, SuspenseContext, }; -use futures_util::{ - pin_mut, - stream::{futures_unordered, FuturesUnordered}, - StreamExt, -}; +use futures_util::{pin_mut, StreamExt}; use rustc_hash::FxHashMap; use slab::Slab; -use std::{ - any::Any, - borrow::BorrowMut, - cell::Cell, - collections::{BTreeSet, HashSet}, - future::Future, - rc::Rc, -}; +use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future::Future, rc::Rc}; /// A virtual node system that progresses user events and diffs UI trees. /// @@ -431,7 +420,7 @@ impl VirtualDom { loop { match some_msg.take() { // If a bunch of messages are ready in a sequence, try to pop them off synchronously - Some(msg) => match dbg!(msg) { + Some(msg) => match msg { SchedulerMsg::Immediate(id) => self.mark_dirty(id), SchedulerMsg::TaskNotified(task) => self.handle_task_wakeup(task), SchedulerMsg::SuspenseNotified(id) => self.handle_suspense_wakeup(id), @@ -441,20 +430,23 @@ impl VirtualDom { None => { match self.rx.try_next() { Ok(Some(val)) => some_msg = Some(val), - Ok(None) => panic!("Scheduler channel closed"), + Ok(None) => return, Err(_) => { // If we have any dirty scopes, or finished fiber trees then we should exit if !self.dirty_scopes.is_empty() || !self.finished_fibers.is_empty() { return; } - println!("Waiting for next message..."); - let mut tasks = self.scheduler.tasks.borrow_mut(); + let res = (&mut *self.scheduler.tasks.borrow_mut()).next().await; - let takss = &mut *tasks; - - use futures_util::StreamExt; - takss.next().await; + if res.is_none() { + // If we have no tasks, then we should wait for a message + if let Some(msg) = self.rx.next().await { + some_msg = Some(msg); + } else { + return; + } + } } } } diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index fdc38db3a..f6f7df32d 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -82,7 +82,7 @@ impl DesktopContext { /// onmousedown: move |_| { desktop.drag_window(); } /// ``` pub fn drag(&self) { - let _ = self.proxy.send_event(DragWindow); + let _ = self.webview.window().drag_window(); } /// toggle window maximize state pub fn toggle_maximized(&self) { @@ -129,7 +129,6 @@ impl DesktopContext { #[derive(Debug)] pub enum UserWindowEvent { - EditsReady, Initialize, Poll, @@ -174,7 +173,7 @@ impl DesktopController { let window = webview.window(); match user_event { - Initialize | EditsReady => { + EditsReady => { // self.try_load_ready_webviews(); } CloseWindow => *control_flow = ControlFlow::Exit, diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index b620e7857..a7b47109b 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -13,28 +13,17 @@ mod protocol; #[cfg(all(feature = "hot-reload", debug_assertions))] mod hot_reload; -use dioxus_html::{a, HtmlEvent}; -use futures_util::task::ArcWake; -use serde_json::Value; -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; -use std::task::Waker; - +pub use cfg::Config; use desktop_context::UserWindowEvent; pub use desktop_context::{use_eval, use_window, DesktopContext, EvalResult}; -use futures_channel::mpsc::UnboundedSender; -use futures_util::future::poll_fn; -use futures_util::{pin_mut, FutureExt}; -pub use wry; -pub use wry::application as tao; - -pub use cfg::Config; -use controller::DesktopController; use dioxus_core::*; +use dioxus_html::HtmlEvent; use events::parse_ipc_message; +use futures_util::task::ArcWake; +use futures_util::{pin_mut, FutureExt}; +use std::collections::HashMap; +use std::rc::Rc; +use std::sync::Arc; pub use tao::dpi::{LogicalSize, PhysicalSize}; pub use tao::window::WindowBuilder; use tao::{ @@ -42,8 +31,9 @@ use tao::{ event_loop::{ControlFlow, EventLoop}, window::Window, }; +pub use wry; +pub use wry::application as tao; use wry::application::event_loop::EventLoopProxy; -use wry::application::platform::run_return::EventLoopExtRunReturn; use wry::webview::WebViewBuilder; /// Launch the WebView and run the event loop. @@ -63,8 +53,8 @@ use wry::webview::WebViewBuilder; /// }) /// } /// ``` -pub async fn launch(root: Component) { - launch_with_props(root, (), Config::default()).await +pub fn launch(root: Component) { + launch_with_props(root, (), Config::default()) } /// Launch the WebView and run the event loop, with configuration. @@ -86,8 +76,8 @@ pub async fn launch(root: Component) { /// }) /// } /// ``` -pub async fn launch_cfg(root: Component, config_builder: Config) { - launch_with_props(root, (), config_builder).await +pub fn launch_cfg(root: Component, config_builder: Config) { + launch_with_props(root, (), config_builder) } /// Launch the WebView and run the event loop, with configuration and root props. @@ -115,21 +105,27 @@ pub async fn launch_cfg(root: Component, config_builder: Config) { /// }) /// } /// ``` -pub async fn launch_with_props(root: Component

, props: P, mut cfg: Config) { +pub fn launch_with_props(root: Component

, props: P, mut cfg: Config) { let event_loop = EventLoop::with_user_event(); let mut dom = VirtualDom::new_with_props(root, props); let proxy = event_loop.create_proxy(); + let mut webviews = HashMap::new(); + + // todo: make this configurable + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + // We want to poll the virtualdom and the event loop at the same time // So the waker will be connected to both let waker = futures_util::task::waker(Arc::new(DomHandle { proxy: proxy.clone(), })); - let mut webviews = HashMap::new(); - event_loop.run(move |window_event, event_loop, control_flow| { *control_flow = ControlFlow::Wait; @@ -150,6 +146,8 @@ pub async fn launch_with_props(root: Component

, props: P, Event::LoopDestroyed => {} Event::RedrawRequested(_id) => {} + Event::NewEvents(cause) => {} + Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::Destroyed { .. } => { @@ -159,8 +157,6 @@ pub async fn launch_with_props(root: Component

, props: P, }, Event::UserEvent(user_event) => { - println!("user event: {:?}", user_event); - match user_event { UserWindowEvent::UserEvent(json_value) => { if let Ok(value) = serde_json::from_value::(json_value) { @@ -190,25 +186,20 @@ pub async fn launch_with_props(root: Component

, props: P, UserWindowEvent::Poll => { let mut cx = std::task::Context::from_waker(&waker); - println!("polling.."); + // using this will reset the budget for the task that we're blocking the main thread with + let _guard = rt.enter(); loop { { - println!("wait for next work"); - let fut = dom.wait_for_work(); pin_mut!(fut); match fut.poll_unpin(&mut cx) { - std::task::Poll::Ready(_) => { - println!("work ready"); - } + std::task::Poll::Ready(_) => {} std::task::Poll::Pending => break, } } - println!("rendering.."); - let edits = dom.render_immediate(); // apply the edits @@ -224,7 +215,7 @@ pub async fn launch_with_props(root: Component

, props: P, } } - UserWindowEvent::EditsReady => { + UserWindowEvent::Initialize => { let edits = dom.rebuild(); let (_id, view) = webviews.iter_mut().next().unwrap(); @@ -306,7 +297,7 @@ fn build_webview( let _ = proxy.send_event(UserWindowEvent::UserEvent(message.params())); } "initialize" => { - let _ = proxy.send_event(UserWindowEvent::EditsReady); + let _ = proxy.send_event(UserWindowEvent::Initialize); } "browser_open" => match message.params().as_object() { Some(temp) if temp.contains_key("href") => {