diff --git a/examples/clock.rs b/examples/clock.rs index f9c1892d9..4b7be3d3b 100644 --- a/examples/clock.rs +++ b/examples/clock.rs @@ -1,7 +1,8 @@ use dioxus::prelude::*; use dioxus_signals::use_signal; -fn main() { +#[tokio::main] +async fn main() { dioxus_desktop::launch(app); } @@ -10,7 +11,7 @@ fn app(cx: Scope) -> Element { use_future!(cx, || async move { loop { - tokio::time::sleep(std::time::Duration::from_millis(100)).await; + tokio::time::sleep(std::time::Duration::from_millis(10)).await; count += 1; println!("current: {count}"); } diff --git a/packages/desktop/src/app.rs b/packages/desktop/src/app.rs index 9a45e6c19..c8ca8a92a 100644 --- a/packages/desktop/src/app.rs +++ b/packages/desktop/src/app.rs @@ -3,30 +3,28 @@ use crate::{ desktop_context::{EventData, UserWindowEvent, WindowEventHandlers}, edits::WebviewQueue, element::DesktopElement, - events::IpcMessage, file_upload::FileDialogRequest, + ipc::IpcMessage, query::QueryResult, shortcut::{GlobalHotKeyEvent, ShortcutRegistry}, webview::WebviewHandler, }; use dioxus_core::{Component, ElementId, VirtualDom}; -use dioxus_html::MountedData; -use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent}; +use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent, MountedData}; use futures_util::{pin_mut, FutureExt}; -use std::cell::Cell; -use std::rc::Rc; -use std::{collections::HashMap, sync::Arc}; -use tao::event_loop::EventLoopBuilder; -use tao::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; -use tao::window::WindowId; -use tao::{event::Event, event_loop::ControlFlow}; -use wry::WebView; +use std::{cell::Cell, collections::HashMap, rc::Rc, sync::Arc}; +use tao::{ + event::Event, + event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget}, + window::WindowId, +}; -pub struct App
{ +pub(crate) struct App
{
// move the props into a cell so we can pop it out later to create the first window
// iOS panics if we create a window before the event loop is started
pub(crate) props: Rc ,
pub(crate) webviews: HashMap {
/// Different hide implementations per platform
#[allow(unused)]
-pub fn hide_app_window(webview: &WebView) {
+pub fn hide_app_window(webview: &wry::WebView) {
#[cfg(target_os = "windows")]
{
use wry::application::platform::windows::WindowExtWindows;
diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs
index 4fb7f6ecb..a5d17b541 100644
--- a/packages/desktop/src/cfg.rs
+++ b/packages/desktop/src/cfg.rs
@@ -1,6 +1,7 @@
use std::borrow::Cow;
use std::path::PathBuf;
+use dioxus_core::prelude::Component;
use tao::window::{Icon, WindowBuilder, WindowId};
use wry::{
http::{Request as HttpRequest, Response as HttpResponse},
@@ -68,6 +69,20 @@ impl Config {
}
}
+ /// Launch a Dioxus app using the given component and config
+ ///
+ /// See the [`crate::launch::launch`] function for more details.
+ pub fn launch(self, root: Component<()>) {
+ crate::launch::launch_cfg(root, self)
+ }
+
+ /// Launch a Dioxus app using the given component, config, and props
+ ///
+ /// See the [`crate::launch::launch_with_props`] function for more details.
+ pub fn launch_with_props , props: P) {
+ crate::launch::launch_with_props(root, props, self)
+ }
+
/// Set whether the default menu bar should be enabled.
///
/// > Note: `enable` is `true` by default. To disable the default menu bar pass `false`.
diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs
index ef2f671b2..e1ed1f07a 100644
--- a/packages/desktop/src/desktop_context.rs
+++ b/packages/desktop/src/desktop_context.rs
@@ -1,4 +1,4 @@
-use crate::events::IpcMessage;
+use crate::ipc::IpcMessage;
use crate::query::QueryEngine;
use crate::shortcut::{HotKey, ShortcutId, ShortcutRegistry, ShortcutRegistryError};
use crate::AssetHandler;
diff --git a/packages/desktop/src/events.rs b/packages/desktop/src/ipc.rs
similarity index 100%
rename from packages/desktop/src/events.rs
rename to packages/desktop/src/ipc.rs
diff --git a/packages/desktop/src/launch.rs b/packages/desktop/src/launch.rs
index 8af51e137..8ee939494 100644
--- a/packages/desktop/src/launch.rs
+++ b/packages/desktop/src/launch.rs
@@ -1,12 +1,11 @@
use crate::{
app::App,
desktop_context::{EventData, UserWindowEvent},
- events::IpcMethod,
+ ipc::IpcMethod,
Config,
};
use dioxus_core::*;
use tao::event::{Event, StartCause, WindowEvent};
-use tokio::runtime::Builder;
/// Launch the WebView and run the event loop.
///
@@ -55,6 +54,7 @@ pub fn launch_cfg(root: Component, config_builder: Config) {
/// Launch the WebView and run the event loop, with configuration and root props.
///
+/// If the [`tokio`] feature is enabled, this will also startup and block a tokio runtime using the unconstrained task.
/// This function will start a multithreaded Tokio runtime as well the WebView event loop. This will block the current thread.
///
/// You can configure the WebView window with a configuration closure
@@ -78,12 +78,24 @@ pub fn launch_cfg(root: Component, config_builder: Config) {
/// }
/// ```
pub fn launch_with_props , props: P, cfg: Config) {
- // We start the tokio runtime *on this thread*
- // Any future we poll later will use this runtime to spawn tasks and for IO
- // I would love to just allow dioxus to work with any runtime... but tokio is weird
- let rt = Builder::new_multi_thread().enable_all().build().unwrap();
- let _guard = rt.enter();
+ #[cfg(feature = "tokio")]
+ tokio::runtime::Builder::new_multi_thread()
+ .enable_all()
+ .build()
+ .unwrap()
+ .block_on(tokio::task::unconstrained(async move {
+ launch_with_props_blocking(root, props, cfg);
+ }));
+ #[cfg(not(feature = "tokio"))]
+ launch_with_props_blocking(root, props, cfg);
+}
+
+/// Launch the WebView and run the event loop, with configuration and root props.
+///
+/// This will block the main thread, and *must* be spawned on the main thread. This function does not assume any runtime
+/// and is equivalent to calling launch_with_props with the tokio feature disabled.
+pub fn launch_with_props_blocking , props: P, cfg: Config) {
let (event_loop, mut app) = App::new(cfg, props, root);
event_loop.run(move |window_event, event_loop, control_flow| {
diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs
index 818605dc5..3f8d9d3ce 100644
--- a/packages/desktop/src/lib.rs
+++ b/packages/desktop/src/lib.rs
@@ -11,18 +11,19 @@ mod edits;
mod element;
mod escape;
mod eval;
-mod events;
mod file_upload;
mod hooks;
+mod ipc;
mod menubar;
-#[cfg(any(target_os = "ios", target_os = "android"))]
-mod mobile_shortcut;
mod protocol;
mod query;
mod shortcut;
mod waker;
mod webview;
+#[cfg(any(target_os = "ios", target_os = "android"))]
+mod mobile_shortcut;
+
// The main entrypoint for this crate
pub use launch::*;
mod launch;
diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs
index 77acebad6..bdcefa473 100644
--- a/packages/desktop/src/protocol.rs
+++ b/packages/desktop/src/protocol.rs
@@ -57,7 +57,8 @@ pub(super) async fn desktop_handler(
.body(Cow::from(body))
{
Ok(response) => {
- return responder.respond(response);
+ responder.respond(response);
+ return;
}
Err(err) => tracing::error!("error building response: {}", err),
}
@@ -103,7 +104,10 @@ pub(super) async fn desktop_handler(
.header("Content-Type", content_type)
.body(Cow::from(asset))
{
- Ok(response) => return responder.respond(response),
+ Ok(response) => {
+ responder.respond(response);
+ return;
+ }
Err(err) => tracing::error!("error building response: {}", err),
}
}
@@ -114,6 +118,7 @@ pub(super) async fn desktop_handler(
{
Ok(response) => {
responder.respond(response);
+ return;
}
Err(err) => tracing::error!("error building response: {}", err),
}