fix desktop to poll without budget

This commit is contained in:
Jonathan Kelley committed 2022-12-29 20:39:22 -05:00
1 parent bd720e2268
commit 7bc8150da7
5 files changed
+48 -75

No files matched your search

+2 -10
View File
@@ -5,16 +5,8 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use futures_util::Future; use futures_util::Future;
#[tokio::main] fn main() {
async fn main() { dioxus_desktop::launch(app);
let mut dom = VirtualDom::new(app);
dom.rebuild();
loop {
dom.wait_for_work().await;
}
// dioxus_desktop::launch(app).await;
} }
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
+2 -3
View File
@@ -3,9 +3,8 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_elements::input_data::keyboard_types::Key; use dioxus_elements::input_data::keyboard_types::Key;
#[tokio::main] fn main() {
async fn main() { dioxus_desktop::launch(app);
dioxus_desktop::launch(app).await;
} }
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
+13 -21
View File
@@ -13,21 +13,10 @@ use crate::{
scopes::{ScopeId, ScopeState}, scopes::{ScopeId, ScopeState},
AttributeValue, Element, Event, Scope, SuspenseContext, AttributeValue, Element, Event, Scope, SuspenseContext,
}; };
use futures_util::{ use futures_util::{pin_mut, StreamExt};
pin_mut,
stream::{futures_unordered, FuturesUnordered},
StreamExt,
};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use slab::Slab; use slab::Slab;
use std::{ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future::Future, rc::Rc};
any::Any,
borrow::BorrowMut,
cell::Cell,
collections::{BTreeSet, HashSet},
future::Future,
rc::Rc,
};
/// A virtual node system that progresses user events and diffs UI trees. /// A virtual node system that progresses user events and diffs UI trees.
/// ///
@@ -431,7 +420,7 @@ impl VirtualDom {
loop { loop {
match some_msg.take() { match some_msg.take() {
// If a bunch of messages are ready in a sequence, try to pop them off synchronously // 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::Immediate(id) => self.mark_dirty(id),
SchedulerMsg::TaskNotified(task) => self.handle_task_wakeup(task), SchedulerMsg::TaskNotified(task) => self.handle_task_wakeup(task),
SchedulerMsg::SuspenseNotified(id) => self.handle_suspense_wakeup(id), SchedulerMsg::SuspenseNotified(id) => self.handle_suspense_wakeup(id),
@@ -441,20 +430,23 @@ impl VirtualDom {
None => { None => {
match self.rx.try_next() { match self.rx.try_next() {
Ok(Some(val)) => some_msg = Some(val), Ok(Some(val)) => some_msg = Some(val),
Ok(None) => panic!("Scheduler channel closed"), Ok(None) => return,
Err(_) => { Err(_) => {
// If we have any dirty scopes, or finished fiber trees then we should exit // 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() { if !self.dirty_scopes.is_empty() || !self.finished_fibers.is_empty() {
return; return;
} }
println!("Waiting for next message..."); let res = (&mut *self.scheduler.tasks.borrow_mut()).next().await;
let mut tasks = self.scheduler.tasks.borrow_mut();
let takss = &mut *tasks; if res.is_none() {
// If we have no tasks, then we should wait for a message
use futures_util::StreamExt; if let Some(msg) = self.rx.next().await {
takss.next().await; some_msg = Some(msg);
} else {
return;
}
}
} }
} }
} }
+2 -3
View File
@@ -82,7 +82,7 @@ impl DesktopContext {
/// onmousedown: move |_| { desktop.drag_window(); } /// onmousedown: move |_| { desktop.drag_window(); }
/// ``` /// ```
pub fn drag(&self) { pub fn drag(&self) {
let _ = self.proxy.send_event(DragWindow); let _ = self.webview.window().drag_window();
} }
/// toggle window maximize state /// toggle window maximize state
pub fn toggle_maximized(&self) { pub fn toggle_maximized(&self) {
@@ -129,7 +129,6 @@ impl DesktopContext {
#[derive(Debug)] #[derive(Debug)]
pub enum UserWindowEvent { pub enum UserWindowEvent {
EditsReady,
Initialize, Initialize,
Poll, Poll,
@@ -174,7 +173,7 @@ impl DesktopController {
let window = webview.window(); let window = webview.window();
match user_event { match user_event {
Initialize | EditsReady => { EditsReady => {
// self.try_load_ready_webviews(); // self.try_load_ready_webviews();
} }
CloseWindow => *control_flow = ControlFlow::Exit, CloseWindow => *control_flow = ControlFlow::Exit,
+29 -38
View File
@@ -13,28 +13,17 @@ mod protocol;
#[cfg(all(feature = "hot-reload", debug_assertions))] #[cfg(all(feature = "hot-reload", debug_assertions))]
mod hot_reload; mod hot_reload;
use dioxus_html::{a, HtmlEvent}; pub use cfg::Config;
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;
use desktop_context::UserWindowEvent; use desktop_context::UserWindowEvent;
pub use desktop_context::{use_eval, use_window, DesktopContext, EvalResult}; 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_core::*;
use dioxus_html::HtmlEvent;
use events::parse_ipc_message; 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::dpi::{LogicalSize, PhysicalSize};
pub use tao::window::WindowBuilder; pub use tao::window::WindowBuilder;
use tao::{ use tao::{
@@ -42,8 +31,9 @@ use tao::{
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
window::Window, window::Window,
}; };
pub use wry;
pub use wry::application as tao;
use wry::application::event_loop::EventLoopProxy; use wry::application::event_loop::EventLoopProxy;
use wry::application::platform::run_return::EventLoopExtRunReturn;
use wry::webview::WebViewBuilder; use wry::webview::WebViewBuilder;
/// Launch the WebView and run the event loop. /// Launch the WebView and run the event loop.
@@ -63,8 +53,8 @@ use wry::webview::WebViewBuilder;
/// }) /// })
/// } /// }
/// ``` /// ```
pub async fn launch(root: Component) { pub fn launch(root: Component) {
launch_with_props(root, (), Config::default()).await launch_with_props(root, (), Config::default())
} }
/// Launch the WebView and run the event loop, with configuration. /// 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) { pub fn launch_cfg(root: Component, config_builder: Config) {
launch_with_props(root, (), config_builder).await launch_with_props(root, (), config_builder)
} }
/// Launch the WebView and run the event loop, with configuration and root props. /// 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 event_loop = EventLoop::with_user_event();
let mut dom = VirtualDom::new_with_props(root, props); let mut dom = VirtualDom::new_with_props(root, props);
let proxy = event_loop.create_proxy(); 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 // We want to poll the virtualdom and the event loop at the same time
// So the waker will be connected to both // So the waker will be connected to both
let waker = futures_util::task::waker(Arc::new(DomHandle { let waker = futures_util::task::waker(Arc::new(DomHandle {
proxy: proxy.clone(), proxy: proxy.clone(),
})); }));
let mut webviews = HashMap::new();
event_loop.run(move |window_event, event_loop, control_flow| { event_loop.run(move |window_event, event_loop, control_flow| {
*control_flow = ControlFlow::Wait; *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::LoopDestroyed => {}
Event::RedrawRequested(_id) => {} Event::RedrawRequested(_id) => {}
Event::NewEvents(cause) => {}
Event::WindowEvent { event, .. } => match event { Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::Destroyed { .. } => { WindowEvent::Destroyed { .. } => {
@@ -159,8 +157,6 @@ pub async fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P,
}, },
Event::UserEvent(user_event) => { Event::UserEvent(user_event) => {
println!("user event: {:?}", user_event);
match user_event { match user_event {
UserWindowEvent::UserEvent(json_value) => { UserWindowEvent::UserEvent(json_value) => {
if let Ok(value) = serde_json::from_value::<HtmlEvent>(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 => { UserWindowEvent::Poll => {
let mut cx = std::task::Context::from_waker(&waker); 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 { loop {
{ {
println!("wait for next work");
let fut = dom.wait_for_work(); let fut = dom.wait_for_work();
pin_mut!(fut); pin_mut!(fut);
match fut.poll_unpin(&mut cx) { match fut.poll_unpin(&mut cx) {
std::task::Poll::Ready(_) => { std::task::Poll::Ready(_) => {}
println!("work ready");
}
std::task::Poll::Pending => break, std::task::Poll::Pending => break,
} }
} }
println!("rendering..");
let edits = dom.render_immediate(); let edits = dom.render_immediate();
// apply the edits // 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 edits = dom.rebuild();
let (_id, view) = webviews.iter_mut().next().unwrap(); let (_id, view) = webviews.iter_mut().next().unwrap();
@@ -306,7 +297,7 @@ fn build_webview(
let _ = proxy.send_event(UserWindowEvent::UserEvent(message.params())); let _ = proxy.send_event(UserWindowEvent::UserEvent(message.params()));
} }
"initialize" => { "initialize" => {
let _ = proxy.send_event(UserWindowEvent::EditsReady); let _ = proxy.send_event(UserWindowEvent::Initialize);
} }
"browser_open" => match message.params().as_object() { "browser_open" => match message.params().as_object() {
Some(temp) if temp.contains_key("href") => { Some(temp) if temp.contains_key("href") => {