Browse Source

fix desktop to poll without budget

Jonathan Kelley 2 years ago
parent
commit
7bc8150da7

+ 2 - 10
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 {

+ 2 - 3
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)]

+ 13 - 21
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;
+                                }
+                            }
                         }
                     }
                 }

+ 2 - 3
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,

+ 29 - 38
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<P: 'static + Send>(root: Component<P>, props: P, mut cfg: Config) {
+pub fn launch_with_props<P: 'static + Send>(root: Component<P>, 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<P: 'static + Send>(root: Component<P>, 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<P: 'static + Send>(root: Component<P>, 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::<HtmlEvent>(json_value) {
@@ -190,25 +186,20 @@ pub async fn launch_with_props<P: 'static + Send>(root: Component<P>, 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<P: 'static + Send>(root: Component<P>, 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") => {