diff --git a/packages/desktop/src/app.rs b/packages/desktop/src/app.rs
index 4e954d496..9a45e6c19 100644
--- a/packages/desktop/src/app.rs
+++ b/packages/desktop/src/app.rs
@@ -1,48 +1,25 @@
-pub use crate::assets::{AssetFuture, AssetHandler, AssetRequest, AssetResponse};
-pub use crate::cfg::{Config, WindowCloseBehaviour};
-pub use crate::desktop_context::DesktopContext;
-pub use crate::desktop_context::{window, DesktopService, WryEventHandler, WryEventHandlerId};
-use crate::edits::{EditQueue, WebviewQueue};
-use crate::element::DesktopElement;
-use crate::eval::init_eval;
-use crate::events::{IpcMessage, IpcMethod};
-use crate::file_upload;
-use crate::hooks::*;
-use crate::query::QueryResult;
-use crate::shortcut::GlobalHotKeyEvent;
-use crate::shortcut::ShortcutRegistry;
-pub use crate::shortcut::{ShortcutHandle, ShortcutId, ShortcutRegistryError};
use crate::{
+ cfg::{Config, WindowCloseBehaviour},
desktop_context::{EventData, UserWindowEvent, WindowEventHandlers},
+ edits::WebviewQueue,
+ element::DesktopElement,
+ events::IpcMessage,
+ file_upload::FileDialogRequest,
+ query::QueryResult,
+ shortcut::{GlobalHotKeyEvent, ShortcutRegistry},
webview::WebviewHandler,
};
-use dioxus_core::*;
-use dioxus_html::{event_bubbles, MountedData};
+use dioxus_core::{Component, ElementId, VirtualDom};
+use dioxus_html::MountedData;
use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent};
-use dioxus_interpreter_js::binary_protocol::Channel;
use futures_util::{pin_mut, FutureExt};
-use global_hotkey::{
- hotkey::{Code, HotKey, Modifiers},
- GlobalHotKeyManager,
-};
-use rustc_hash::FxHashMap;
+use std::cell::Cell;
use std::rc::Rc;
-use std::sync::atomic::AtomicU16;
-use std::task::Waker;
-use std::{borrow::Borrow, cell::Cell};
use std::{collections::HashMap, sync::Arc};
-pub use tao::dpi::{LogicalSize, PhysicalSize};
+use tao::event_loop::EventLoopBuilder;
use tao::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
-pub use tao::window::WindowBuilder;
use tao::window::WindowId;
-use tao::{
- event::{Event, StartCause, WindowEvent},
- event_loop::ControlFlow,
-};
-use tao::{event_loop::EventLoopBuilder, window::Window};
-use tokio::runtime::Builder;
-pub use wry;
-use wry::WebContext;
+use tao::{event::Event, event_loop::ControlFlow};
use wry::WebView;
pub struct App
{
@@ -221,24 +198,14 @@ impl App {
return;
};
- view.dom
- .base_scope()
- .consume_context::()
- .unwrap()
- .query
- .send(result);
+ view.desktop_context.query.send(result);
}
pub fn handle_user_event_msg(&mut self, msg: IpcMessage, id: WindowId) {
- let params = msg.params();
+ let parsed_params = serde_json::from_value(msg.params())
+ .map_err(|err| tracing::error!("Error parsing user_event: {:?}", err));
- let evt = match serde_json::from_value::(params) {
- Ok(value) => value,
- Err(err) => {
- tracing::error!("Error parsing user_event: {:?}", err);
- return;
- }
- };
+ let Ok(evt) = parsed_params else { return };
let HtmlEvent {
element,
@@ -250,20 +217,13 @@ impl App {
let view = self.webviews.get_mut(&id).unwrap();
// check for a mounted event placeholder and replace it with a desktop specific element
- let as_any = if let dioxus_html::EventData::Mounted = &data {
- let query = view
- .dom
- .base_scope()
- .consume_context::()
- .unwrap()
- .query
- .clone();
-
- let element = DesktopElement::new(element, view.desktop_context.clone(), query);
-
- Rc::new(MountedData::new(element))
- } else {
- data.into_any()
+ let as_any = match data {
+ dioxus_html::EventData::Mounted => Rc::new(MountedData::new(DesktopElement::new(
+ element,
+ view.desktop_context.clone(),
+ view.desktop_context.query.clone(),
+ ))),
+ _ => data.into_any(),
};
view.dom.handle_event(&name, as_any, element, bubbles);
@@ -278,9 +238,7 @@ impl App {
webview.dom.replace_template(template);
}
- let ids = self.webviews.keys().copied().collect::>();
-
- for id in ids {
+ for id in self.webviews.keys().copied().collect::>() {
self.poll_vdom(id);
}
}
@@ -291,31 +249,32 @@ impl App {
}
pub fn handle_file_dialog_msg(&mut self, msg: IpcMessage, window: WindowId) {
- if let Ok(file_diolog) =
- serde_json::from_value::(msg.params())
- {
- let id = ElementId(file_diolog.target);
- let event_name = &file_diolog.event;
- let event_bubbles = file_diolog.bubbles;
- let files = file_upload::get_file_event(&file_diolog);
- let data = Rc::new(FormData {
- value: Default::default(),
- values: Default::default(),
- files: Some(Arc::new(NativeFileEngine::new(files))),
- });
+ let Ok(file_dialog) = serde_json::from_value::(msg.params()) else {
+ return;
+ };
- let view = self.webviews.get_mut(&window).unwrap();
+ let id = ElementId(file_dialog.target);
+ let event_name = &file_dialog.event;
+ let event_bubbles = file_dialog.bubbles;
+ let files = file_dialog.get_file_event();
- if event_name == "change&input" {
- view.dom
- .handle_event("input", data.clone(), id, event_bubbles);
- view.dom.handle_event("change", data, id, event_bubbles);
- } else {
- view.dom.handle_event(event_name, data, id, event_bubbles);
- }
+ let data = Rc::new(FormData {
+ value: Default::default(),
+ values: Default::default(),
+ files: Some(Arc::new(NativeFileEngine::new(files))),
+ });
- view.desktop_context.send_edits(view.dom.render_immediate());
+ let view = self.webviews.get_mut(&window).unwrap();
+
+ if event_name == "change&input" {
+ view.dom
+ .handle_event("input", data.clone(), id, event_bubbles);
+ view.dom.handle_event("change", data, id, event_bubbles);
+ } else {
+ view.dom.handle_event(event_name, data, id, event_bubbles);
}
+
+ view.desktop_context.send_edits(view.dom.render_immediate());
}
/// Poll the virtualdom until it's pending
@@ -324,10 +283,15 @@ impl App {
///
/// All IO is done on the tokio runtime we started earlier
pub fn poll_vdom(&mut self, id: WindowId) {
- let view = self.webviews.get_mut(&id).unwrap();
+ let Some(view) = self.webviews.get_mut(&id) else {
+ 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();
@@ -335,7 +299,7 @@ impl App {
match fut.poll_unpin(&mut cx) {
std::task::Poll::Ready(_) => {}
- std::task::Poll::Pending => break,
+ std::task::Poll::Pending => return,
}
}
diff --git a/packages/desktop/src/assets.rs b/packages/desktop/src/assets.rs
index f80c7542a..7f86b6184 100644
--- a/packages/desktop/src/assets.rs
+++ b/packages/desktop/src/assets.rs
@@ -1,6 +1,4 @@
-use crate::edits::EditQueue;
use crate::DesktopContext;
-use dioxus_core::ScopeState;
use slab::Slab;
use std::{
borrow::Cow,
@@ -15,10 +13,7 @@ use tokio::{
runtime::Handle,
sync::{OnceCell, RwLock},
};
-use wry::{
- http::{status::StatusCode, Request, Response},
- Result,
-};
+use wry::http::{Request, Response};
/// An arbitrary asset is an HTTP response containing a binary body.
pub type AssetResponse = Response>;
diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs
index 240f8ec24..ef2f671b2 100644
--- a/packages/desktop/src/desktop_context.rs
+++ b/packages/desktop/src/desktop_context.rs
@@ -146,25 +146,19 @@ impl DesktopService {
self.shortcut_manager.clone(),
);
- let desktop_context = window
- .dom
- .base_scope()
- .consume_context::>()
- .unwrap();
-
- let id = window.desktop_context.window.id();
+ let cx = window.desktop_context.clone();
self.proxy
- .send_event(UserWindowEvent(EventData::NewWindow, id))
+ .send_event(UserWindowEvent(EventData::NewWindow, cx.id()))
.unwrap();
self.proxy
- .send_event(UserWindowEvent(EventData::Poll, id))
+ .send_event(UserWindowEvent(EventData::Poll, cx.id()))
.unwrap();
self.pending_windows.borrow_mut().push(window);
- Rc::downgrade(&desktop_context)
+ Rc::downgrade(&cx)
}
/// trigger the drag-window event
diff --git a/packages/desktop/src/eval.rs b/packages/desktop/src/eval.rs
index e187be450..e9b0f036b 100644
--- a/packages/desktop/src/eval.rs
+++ b/packages/desktop/src/eval.rs
@@ -1,21 +1,19 @@
#![allow(clippy::await_holding_refcell_ref)]
use async_trait::async_trait;
-use dioxus_core::ScopeState;
use dioxus_html::prelude::{EvalError, EvalProvider, Evaluator};
use std::{cell::RefCell, rc::Rc};
use crate::{query::Query, DesktopContext};
-/// Provides the DesktopEvalProvider through [`cx.provide_context`].
-pub fn init_eval(cx: &ScopeState) {
- let desktop_ctx = cx.consume_context::().unwrap();
- let provider: Rc = Rc::new(DesktopEvalProvider { desktop_ctx });
- cx.provide_context(provider);
-}
-
/// Reprents the desktop-target's provider of evaluators.
pub struct DesktopEvalProvider {
- desktop_ctx: DesktopContext,
+ pub(crate) desktop_ctx: DesktopContext,
+}
+
+impl DesktopEvalProvider {
+ pub fn new(desktop_ctx: DesktopContext) -> Self {
+ Self { desktop_ctx }
+ }
}
impl EvalProvider for DesktopEvalProvider {
diff --git a/packages/desktop/src/file_upload.rs b/packages/desktop/src/file_upload.rs
index 7b5f08fc3..98dbec437 100644
--- a/packages/desktop/src/file_upload.rs
+++ b/packages/desktop/src/file_upload.rs
@@ -14,74 +14,77 @@ pub(crate) struct FileDialogRequest {
pub bubbles: bool,
}
-#[cfg(not(any(
- target_os = "windows",
- target_os = "macos",
- target_os = "linux",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "netbsd",
- target_os = "openbsd"
-)))]
-pub(crate) fn get_file_event(_request: &FileDialogRequest) -> Vec {
- vec![]
-}
+#[allow(unused)]
+impl FileDialogRequest {
+ #[cfg(not(any(
+ target_os = "windows",
+ target_os = "macos",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ )))]
+ pub(crate) fn get_file_event(&self) -> Vec {
+ vec![]
+ }
-#[cfg(any(
- target_os = "windows",
- target_os = "macos",
- target_os = "linux",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "netbsd",
- target_os = "openbsd"
-))]
-pub(crate) fn get_file_event(request: &FileDialogRequest) -> Vec {
- fn get_file_event_for_folder(
- request: &FileDialogRequest,
- dialog: rfd::FileDialog,
- ) -> Vec {
- if request.multiple {
- dialog.pick_folders().into_iter().flatten().collect()
- } else {
- dialog.pick_folder().into_iter().collect()
+ #[cfg(any(
+ target_os = "windows",
+ target_os = "macos",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ pub(crate) fn get_file_event(&self) -> Vec {
+ fn get_file_event_for_folder(
+ request: &FileDialogRequest,
+ dialog: rfd::FileDialog,
+ ) -> Vec {
+ if request.multiple {
+ dialog.pick_folders().into_iter().flatten().collect()
+ } else {
+ dialog.pick_folder().into_iter().collect()
+ }
}
- }
- fn get_file_event_for_file(
- request: &FileDialogRequest,
- mut dialog: rfd::FileDialog,
- ) -> Vec {
- let filters: Vec<_> = request
- .accept
- .as_deref()
- .unwrap_or_default()
- .split(',')
- .filter_map(|s| Filters::from_str(s).ok())
- .collect();
+ fn get_file_event_for_file(
+ request: &FileDialogRequest,
+ mut dialog: rfd::FileDialog,
+ ) -> Vec {
+ let filters: Vec<_> = request
+ .accept
+ .as_deref()
+ .unwrap_or_default()
+ .split(',')
+ .filter_map(|s| Filters::from_str(s).ok())
+ .collect();
- let file_extensions: Vec<_> = filters
- .iter()
- .flat_map(|f| f.as_extensions().into_iter())
- .collect();
+ let file_extensions: Vec<_> = filters
+ .iter()
+ .flat_map(|f| f.as_extensions().into_iter())
+ .collect();
- dialog = dialog.add_filter("name", file_extensions.as_slice());
+ dialog = dialog.add_filter("name", file_extensions.as_slice());
- let files: Vec<_> = if request.multiple {
- dialog.pick_files().into_iter().flatten().collect()
+ let files: Vec<_> = if request.multiple {
+ dialog.pick_files().into_iter().flatten().collect()
+ } else {
+ dialog.pick_file().into_iter().collect()
+ };
+
+ files
+ }
+
+ let dialog = rfd::FileDialog::new();
+
+ if self.directory {
+ get_file_event_for_folder(self, dialog)
} else {
- dialog.pick_file().into_iter().collect()
- };
-
- files
- }
-
- let dialog = rfd::FileDialog::new();
-
- if request.directory {
- get_file_event_for_folder(request, dialog)
- } else {
- get_file_event_for_file(request, dialog)
+ get_file_event_for_file(self, dialog)
+ }
}
}
diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs
index cd83362b5..6eac25b62 100644
--- a/packages/desktop/src/webview.rs
+++ b/packages/desktop/src/webview.rs
@@ -1,15 +1,17 @@
use std::{rc::Rc, task::Waker};
-use crate::edits::{EditQueue, WebviewQueue};
use crate::{
assets::AssetHandlerRegistry, desktop_context::UserWindowEvent, waker::tao_waker, Config,
DesktopContext,
};
use crate::{
desktop_context::{EventData, WindowEventHandlers},
- eval::init_eval,
shortcut::ShortcutRegistry,
};
+use crate::{
+ edits::{EditQueue, WebviewQueue},
+ eval::DesktopEvalProvider,
+};
use crate::{
protocol::{self},
DesktopService,
@@ -162,9 +164,12 @@ pub fn create_new_window(
asset_handlers,
));
+ // Provide the desktop context to the virtualdom
dom.base_scope().provide_context(desktop_context.clone());
- init_eval(dom.base_scope());
+ // Also set up its eval provider
+ dom.base_scope()
+ .provide_context(Rc::new(DesktopEvalProvider::new(desktop_context.clone())));
WebviewHandler {
// We want to poll the virtualdom and the event loop at the same time, so the waker will be connected to both