fix desktop to poll without budget
This commit is contained in:
1 parent
bd720e2268
commit
7bc8150da7
5 files changed
+48
-75
No files matched your search
+2
-10
@@ -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
@@ -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 +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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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") => {
|
||||||
|
|||||||
Reference in new issue
Block a user