implement launch builder for the desktop and web platforms

This commit is contained in:
Evan Almloff committed 2024-01-16 08:42:16 -06:00
1 parent ef553a2cb2
commit 7e4d2debe0
70 files changed
+448 -431

No files matched your search

+24 -14
View File
@@ -10,7 +10,7 @@ use crate::{
webview::WebviewInstance,
};
use crossbeam_channel::Receiver;
use dioxus_core::{Component, ElementId, VirtualDom};
use dioxus_core::{ComponentFunction, CrossPlatformConfig, ElementId};
use dioxus_html::{
native_bind::NativeFileEngine, FileEngine, HasFileData, HasFormData, HtmlEvent,
PlatformEventData,
@@ -18,6 +18,7 @@ use dioxus_html::{
use std::{
cell::{Cell, RefCell},
collections::HashMap,
marker::PhantomData,
rc::Rc,
sync::Arc,
};
@@ -28,14 +29,17 @@ use tao::{
};
/// The single top-level object that manages all the running windows, assets, shortcuts, etc
pub(crate) struct App<P> {
pub(crate) struct App<
Component: ComponentFunction<Phantom, Props = Props>,
Props: Clone + 'static,
Phantom: 'static,
> {
// 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, so we toss them into a cell
pub(crate) props: Cell<Option<P>>,
pub(crate) dioxus_config: Cell<Option<CrossPlatformConfig<Component, Props, Phantom>>>,
pub(crate) cfg: Cell<Option<Config>>,
// Stuff we need mutable access to
pub(crate) root: Component<P>,
pub(crate) control_flow: ControlFlow,
pub(crate) is_visible_before_start: bool,
pub(crate) window_behavior: WindowCloseBehaviour,
@@ -45,6 +49,8 @@ pub(crate) struct App<P> {
///
/// This includes stuff like the event handlers, shortcuts, etc as well as ways to modify *other* windows
pub(crate) shared: Rc<SharedContext>,
phantom: PhantomData<Phantom>,
}
/// A bundle of state shared between all the windows, providing a way for us to communicate with running webview.
@@ -59,17 +65,24 @@ pub struct SharedContext {
pub(crate) target: EventLoopWindowTarget<UserWindowEvent>,
}
impl<P: 'static + Clone> App<P> {
pub fn new(cfg: Config, props: P, root: Component<P>) -> (EventLoop<UserWindowEvent>, Self) {
impl<
Component: ComponentFunction<Phantom, Props = Props>,
Props: Clone + 'static,
Phantom: 'static,
> App<Component, Props, Phantom>
{
pub fn new(
cfg: Config,
dioxus_config: CrossPlatformConfig<Component, Props, Phantom>,
) -> (EventLoop<UserWindowEvent>, Self) {
let event_loop = EventLoopBuilder::<UserWindowEvent>::with_user_event().build();
let app = Self {
root,
window_behavior: cfg.last_window_close_behaviour,
is_visible_before_start: true,
webviews: HashMap::new(),
control_flow: ControlFlow::Wait,
props: Cell::new(Some(props)),
dioxus_config: Cell::new(Some(dioxus_config)),
cfg: Cell::new(Some(cfg)),
shared: Rc::new(SharedContext {
event_handlers: WindowEventHandlers::default(),
@@ -79,6 +92,7 @@ impl<P: 'static + Clone> App<P> {
proxy: event_loop.create_proxy(),
target: event_loop.clone(),
}),
phantom: PhantomData,
};
// Set the event converter
@@ -164,16 +178,12 @@ impl<P: 'static + Clone> App<P> {
}
pub fn handle_start_cause_init(&mut self) {
let props = self.props.take().unwrap();
let dioxus_config = self.dioxus_config.take().unwrap();
let cfg = self.cfg.take().unwrap();
self.is_visible_before_start = cfg.window.window.visible;
let webview = WebviewInstance::new(
cfg,
VirtualDom::new_with_props(self.root, props),
self.shared.clone(),
);
let webview = WebviewInstance::new(cfg, dioxus_config.build_vdom(), self.shared.clone());
let id = webview.desktop_context.window.id();
self.webviews.insert(id, webview);
-14
View File
@@ -71,20 +71,6 @@ 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, app: fn() -> Element) {
self.launch_with_props(|props| props(), app)
}
/// 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<P: 'static + Clone>(self, root: Component<P>, 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`.
+33 -86
View File
@@ -6,96 +6,19 @@ use crate::{
use dioxus_core::*;
use tao::event::{Event, StartCause, WindowEvent};
/// Launch the WebView and run the event loop.
///
/// This function will start a multithreaded Tokio runtime as well the WebView event loop.
///
/// ```rust, no_run
/// use dioxus::prelude::*;
///
/// fn main() {
/// dioxus_desktop::launch(app);
/// }
///
/// fn app() -> Element {
/// rsx!{
/// h1 {"hello world!"}
/// })
/// }
/// ```
pub fn launch(app: fn() -> Element) {
launch_with_props(|root| root(), app, Config::default())
}
/// Launch the WebView and run the event loop, with configuration.
///
/// This function will start a multithreaded Tokio runtime as well the WebView event loop.
///
/// You can configure the WebView window with a configuration closure
///
/// ```rust, no_run
/// use dioxus::prelude::*;
/// use dioxus_desktop::*;
///
/// fn main() {
/// dioxus_desktop::launch_cfg(app, Config::default().with_window(WindowBuilder::new().with_title("My App")));
/// }
///
/// fn app() -> Element {
/// rsx!{
/// h1 {"hello world!"}
/// })
/// }
/// ```
pub fn launch_cfg(app: fn() -> Element, config_builder: Config) {
launch_with_props(|props| props(), app, config_builder)
}
/// 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
///
/// ```rust, no_run
/// use dioxus::prelude::*;
/// use dioxus_desktop::Config;
///
/// fn main() {
/// dioxus_desktop::launch_with_props(app, AppProps { name: "asd" }, Config::default());
/// }
///
/// struct AppProps {
/// name: &'static str
/// }
///
/// fn app(cx: Scope<AppProps>) -> Element {
/// rsx!{
/// h1 {"hello {cx.props.name}!"}
/// })
/// }
/// ```
pub fn launch_with_props<P: 'static + Clone>(root: Component<P>, props: P, cfg: Config) {
#[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<P: 'static + Clone>(root: Component<P>, props: P, cfg: Config) {
let (event_loop, mut app) = App::new(cfg, props, root);
pub fn launch_with_props_blocking<
Component: ComponentFunction<Phantom, Props = Props>,
Props: Clone + 'static,
Phantom: 'static,
>(
dioxus_cfg: CrossPlatformConfig<Component, Props, Phantom>,
desktop_config: Config,
) {
let (event_loop, mut app) = App::new(desktop_config, dioxus_cfg);
event_loop.run(move |window_event, _, control_flow| {
app.tick(&window_event);
@@ -130,3 +53,27 @@ pub fn launch_with_props_blocking<P: 'static + Clone>(root: Component<P>, props:
*control_flow = app.control_flow;
})
}
/// The desktop renderer platform
pub struct DesktopPlatform;
impl<Props: Clone + 'static> PlatformBuilder<Props> for DesktopPlatform {
type Config = Config;
fn launch<Component: ComponentFunction<Phantom, Props = Props>, Phantom: 'static>(
config: dioxus_core::CrossPlatformConfig<Component, Props, Phantom>,
platform_config: Self::Config,
) {
#[cfg(feature = "tokio")]
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(tokio::task::unconstrained(async move {
launch_with_props_blocking(config, platform_config)
}));
#[cfg(not(feature = "tokio"))]
launch_with_props_blocking(config, platform_config)
}
}