dioxus_desktop/
launch.rs

1use crate::Config;
2use crate::{
3    app::App,
4    ipc::{IpcMethod, UserWindowEvent},
5};
6use dioxus_core::*;
7use dioxus_document::eval;
8use std::any::Any;
9use tao::event::{Event, StartCause, WindowEvent};
10
11/// Launch the WebView and run the event loop, with configuration and root props.
12///
13/// This will block the main thread, and *must* be spawned on the main thread. This function does not assume any runtime
14/// and is equivalent to calling launch_with_props with the tokio feature disabled.
15pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, mut desktop_config: Config) -> ! {
16    let mut custom_event_handler = desktop_config.custom_event_handler.take();
17    let (event_loop, mut app) = App::new(desktop_config, virtual_dom);
18
19    event_loop.run(move |window_event, event_loop, control_flow| {
20        // Set the control flow and check if any events need to be handled in the app itself
21        app.tick(&window_event);
22
23        if let Some(ref mut f) = custom_event_handler {
24            f(&window_event, event_loop)
25        }
26
27        match window_event {
28            Event::NewEvents(StartCause::Init) => app.handle_start_cause_init(),
29            Event::LoopDestroyed => app.handle_loop_destroyed(),
30            Event::WindowEvent {
31                event, window_id, ..
32            } => match event {
33                WindowEvent::CloseRequested => app.handle_close_requested(window_id),
34                WindowEvent::Destroyed { .. } => app.window_destroyed(window_id),
35                WindowEvent::Resized(new_size) => app.resize_window(window_id, new_size),
36                _ => {}
37            },
38
39            Event::UserEvent(event) => match event {
40                UserWindowEvent::Poll(id) => app.poll_vdom(id),
41                UserWindowEvent::NewWindow => app.handle_new_window(),
42                UserWindowEvent::CloseWindow(id) => app.handle_close_msg(id),
43                UserWindowEvent::Shutdown => app.control_flow = tao::event_loop::ControlFlow::Exit,
44
45                #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
46                UserWindowEvent::GlobalHotKeyEvent(evnt) => app.handle_global_hotkey(evnt),
47
48                #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
49                UserWindowEvent::MudaMenuEvent(evnt) => app.handle_menu_event(evnt),
50
51                #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
52                UserWindowEvent::TrayMenuEvent(evnt) => app.handle_tray_menu_event(evnt),
53
54                #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
55                UserWindowEvent::TrayIconEvent(evnt) => app.handle_tray_icon_event(evnt),
56
57                #[cfg(all(feature = "devtools", debug_assertions))]
58                UserWindowEvent::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
59
60                // Windows-only drag-n-drop fix events. We need to call the interpreter drag-n-drop code.
61                UserWindowEvent::WindowsDragDrop(id) => {
62                    if let Some(webview) = app.webviews.get(&id) {
63                        webview.dom.in_runtime(|| {
64                            ScopeId::ROOT.in_runtime(|| {
65                                eval("window.interpreter.handleWindowsDragDrop();");
66                            });
67                        });
68                    }
69                }
70                UserWindowEvent::WindowsDragLeave(id) => {
71                    if let Some(webview) = app.webviews.get(&id) {
72                        webview.dom.in_runtime(|| {
73                            ScopeId::ROOT.in_runtime(|| {
74                                eval("window.interpreter.handleWindowsDragLeave();");
75                            });
76                        });
77                    }
78                }
79                UserWindowEvent::WindowsDragOver(id, x_pos, y_pos) => {
80                    if let Some(webview) = app.webviews.get(&id) {
81                        webview.dom.in_runtime(|| {
82                            ScopeId::ROOT.in_runtime(|| {
83                                let e = eval(
84                                    r#"
85                                    const xPos = await dioxus.recv();
86                                    const yPos = await dioxus.recv();
87                                    window.interpreter.handleWindowsDragOver(xPos, yPos)
88                                    "#,
89                                );
90
91                                _ = e.send(x_pos);
92                                _ = e.send(y_pos);
93                            });
94                        });
95                    }
96                }
97
98                UserWindowEvent::Ipc { id, msg } => match msg.method() {
99                    IpcMethod::Initialize => app.handle_initialize_msg(id),
100                    IpcMethod::FileDialog => app.handle_file_dialog_msg(msg, id),
101                    IpcMethod::UserEvent => {}
102                    IpcMethod::Query => app.handle_query_msg(msg, id),
103                    IpcMethod::BrowserOpen => app.handle_browser_open(msg),
104                    IpcMethod::Other(_) => {}
105                },
106            },
107            _ => {}
108        }
109
110        *control_flow = app.control_flow;
111    })
112}
113
114/// Launches the WebView and runs the event loop, with configuration and root props.
115pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) -> ! {
116    #[cfg(feature = "tokio_runtime")]
117    {
118        tokio::runtime::Builder::new_multi_thread()
119            .enable_all()
120            .build()
121            .unwrap()
122            .block_on(tokio::task::unconstrained(async move {
123                launch_virtual_dom_blocking(virtual_dom, desktop_config)
124            }));
125
126        unreachable!("The desktop launch function will never exit")
127    }
128
129    #[cfg(not(feature = "tokio_runtime"))]
130    {
131        launch_virtual_dom_blocking(virtual_dom, desktop_config);
132    }
133}
134
135/// Launches the WebView and runs the event loop, with configuration and root props.
136pub fn launch(
137    root: fn() -> Element,
138    contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
139    platform_config: Vec<Box<dyn Any>>,
140) -> ! {
141    let mut virtual_dom = VirtualDom::new(root);
142
143    for context in contexts {
144        virtual_dom.insert_any_root_context(context());
145    }
146
147    let platform_config = *platform_config
148        .into_iter()
149        .find_map(|cfg| cfg.downcast::<Config>().ok())
150        .unwrap_or_default();
151
152    launch_virtual_dom(virtual_dom, platform_config)
153}