launch.rs 6.4 KB

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