|
@@ -8,13 +8,17 @@ mod controller;
|
|
|
mod desktop_context;
|
|
|
mod escape;
|
|
|
mod events;
|
|
|
-#[cfg(any(feature = "hot-reload", debug_assertions))]
|
|
|
-mod hot_reload;
|
|
|
mod protocol;
|
|
|
|
|
|
+#[cfg(all(feature = "hot-reload", debug_assertions))]
|
|
|
+mod hot_reload;
|
|
|
+
|
|
|
+use std::sync::atomic::AtomicBool;
|
|
|
+use std::sync::Arc;
|
|
|
+
|
|
|
use desktop_context::UserWindowEvent;
|
|
|
pub use desktop_context::{use_eval, use_window, DesktopContext};
|
|
|
-use futures_channel::mpsc::unbounded;
|
|
|
+use futures_channel::mpsc::UnboundedSender;
|
|
|
pub use wry;
|
|
|
pub use wry::application as tao;
|
|
|
|
|
@@ -100,15 +104,68 @@ pub fn launch_cfg(root: Component, config_builder: Config) {
|
|
|
/// ```
|
|
|
pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cfg: Config) {
|
|
|
let event_loop = EventLoop::with_user_event();
|
|
|
+ let mut desktop = DesktopController::new_on_tokio(root, props, event_loop.create_proxy());
|
|
|
|
|
|
- let (event_tx, event_rx) = unbounded();
|
|
|
- let mut desktop =
|
|
|
- DesktopController::new_on_tokio(root, props, event_loop.create_proxy(), event_rx);
|
|
|
- let proxy = event_loop.create_proxy();
|
|
|
+ event_loop.run(move |window_event, event_loop, control_flow| {
|
|
|
+ *control_flow = ControlFlow::Wait;
|
|
|
+
|
|
|
+ match window_event {
|
|
|
+ Event::NewEvents(StartCause::Init) => desktop.start(&mut cfg, event_loop),
|
|
|
+
|
|
|
+ Event::WindowEvent {
|
|
|
+ event, window_id, ..
|
|
|
+ } => match event {
|
|
|
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
|
|
+ WindowEvent::Destroyed { .. } => desktop.close_window(window_id, control_flow),
|
|
|
+ _ => {}
|
|
|
+ },
|
|
|
+
|
|
|
+ Event::UserEvent(user_event) => desktop.handle_event(user_event, control_flow),
|
|
|
+ Event::MainEventsCleared => {}
|
|
|
+ Event::Resumed => {}
|
|
|
+ Event::Suspended => {}
|
|
|
+ Event::LoopDestroyed => {}
|
|
|
+ Event::RedrawRequested(_id) => {}
|
|
|
+ _ => {}
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+impl DesktopController {
|
|
|
+ fn start(
|
|
|
+ &mut self,
|
|
|
+ cfg: &mut Config,
|
|
|
+ event_loop: &tao::event_loop::EventLoopWindowTarget<UserWindowEvent>,
|
|
|
+ ) {
|
|
|
+ let webview = build_webview(
|
|
|
+ cfg,
|
|
|
+ event_loop,
|
|
|
+ self.is_ready.clone(),
|
|
|
+ self.proxy.clone(),
|
|
|
+ self.event_tx.clone(),
|
|
|
+ );
|
|
|
+
|
|
|
+ self.webviews.insert(webview.window().id(), webview);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- // We assume that if the icon is None, then the user just didnt set it
|
|
|
+fn build_webview(
|
|
|
+ cfg: &mut Config,
|
|
|
+ event_loop: &tao::event_loop::EventLoopWindowTarget<UserWindowEvent>,
|
|
|
+ is_ready: Arc<AtomicBool>,
|
|
|
+ proxy: tao::event_loop::EventLoopProxy<UserWindowEvent>,
|
|
|
+ event_tx: UnboundedSender<serde_json::Value>,
|
|
|
+) -> wry::webview::WebView {
|
|
|
+ let builder = cfg.window.clone();
|
|
|
+ let window = builder.build(event_loop).unwrap();
|
|
|
+ let file_handler = cfg.file_drop_handler.take();
|
|
|
+ let custom_head = cfg.custom_head.clone();
|
|
|
+ let resource_dir = cfg.resource_dir.clone();
|
|
|
+ let index_file = cfg.custom_index.clone();
|
|
|
+
|
|
|
+ // We assume that if the icon is None in cfg, then the user just didnt set it
|
|
|
if cfg.window.window.window_icon.is_none() {
|
|
|
- cfg.window = cfg.window.with_window_icon(Some(
|
|
|
+ window.set_window_icon(Some(
|
|
|
tao::window::Icon::from_rgba(
|
|
|
include_bytes!("./assets/default_icon.bin").to_vec(),
|
|
|
460,
|
|
@@ -118,84 +175,62 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
|
|
|
));
|
|
|
}
|
|
|
|
|
|
- event_loop.run(move |window_event, event_loop, control_flow| {
|
|
|
- *control_flow = ControlFlow::Wait;
|
|
|
-
|
|
|
- // println!("window event: {:?}", window_event);
|
|
|
- match window_event {
|
|
|
- Event::NewEvents(StartCause::Init) => {
|
|
|
- let builder = cfg.window.clone();
|
|
|
-
|
|
|
- let window = builder.build(event_loop).unwrap();
|
|
|
- let window_id = window.id();
|
|
|
-
|
|
|
- let (is_ready, _) = (desktop.is_ready.clone(), ());
|
|
|
- // let (is_ready, sender) = (desktop.is_ready.clone(), desktop.sender.clone());
|
|
|
-
|
|
|
- let proxy = proxy.clone();
|
|
|
-
|
|
|
- let file_handler = cfg.file_drop_handler.take();
|
|
|
- let custom_head = cfg.custom_head.clone();
|
|
|
- let resource_dir = cfg.resource_dir.clone();
|
|
|
- let index_file = cfg.custom_index.clone();
|
|
|
- let event_tx = event_tx.clone();
|
|
|
-
|
|
|
- let mut webview = WebViewBuilder::new(window)
|
|
|
- .unwrap()
|
|
|
- .with_transparent(cfg.window.window.transparent)
|
|
|
- .with_url("dioxus://index.html/")
|
|
|
- .unwrap()
|
|
|
- .with_ipc_handler(move |_window: &Window, payload: String| {
|
|
|
- parse_ipc_message(&payload)
|
|
|
- .map(|message| match message.method() {
|
|
|
- "user_event" => {
|
|
|
- _ = event_tx.unbounded_send(message.params());
|
|
|
+ let mut webview = WebViewBuilder::new(window)
|
|
|
+ .unwrap()
|
|
|
+ .with_transparent(cfg.window.window.transparent)
|
|
|
+ .with_url("dioxus://index.html/")
|
|
|
+ .unwrap()
|
|
|
+ .with_ipc_handler(move |_window: &Window, payload: String| {
|
|
|
+ parse_ipc_message(&payload)
|
|
|
+ .map(|message| match message.method() {
|
|
|
+ "user_event" => {
|
|
|
+ _ = event_tx.unbounded_send(message.params());
|
|
|
+ }
|
|
|
+ "initialize" => {
|
|
|
+ is_ready.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
|
+ let _ = proxy.send_event(UserWindowEvent::EditsReady);
|
|
|
+ }
|
|
|
+ "browser_open" => {
|
|
|
+ let data = message.params();
|
|
|
+ log::trace!("Open browser: {:?}", data);
|
|
|
+ if let Some(temp) = data.as_object() {
|
|
|
+ if temp.contains_key("href") {
|
|
|
+ let url = temp.get("href").unwrap().as_str().unwrap();
|
|
|
+ if let Err(e) = webbrowser::open(url) {
|
|
|
+ log::error!("Open Browser error: {:?}", e);
|
|
|
}
|
|
|
- "initialize" => {
|
|
|
- is_ready.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
|
- let _ = proxy.send_event(UserWindowEvent::EditsReady);
|
|
|
- }
|
|
|
- "browser_open" => {
|
|
|
- let data = message.params();
|
|
|
- log::trace!("Open browser: {:?}", data);
|
|
|
- if let Some(temp) = data.as_object() {
|
|
|
- if temp.contains_key("href") {
|
|
|
- let url = temp.get("href").unwrap().as_str().unwrap();
|
|
|
- if let Err(e) = webbrowser::open(url) {
|
|
|
- log::error!("Open Browser error: {:?}", e);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- _ => (),
|
|
|
- })
|
|
|
- .unwrap_or_else(|| {
|
|
|
- log::warn!("invalid IPC message received");
|
|
|
- });
|
|
|
- })
|
|
|
- .with_custom_protocol(String::from("dioxus"), move |r| {
|
|
|
- protocol::desktop_handler(
|
|
|
- r,
|
|
|
- resource_dir.clone(),
|
|
|
- custom_head.clone(),
|
|
|
- index_file.clone(),
|
|
|
- )
|
|
|
- })
|
|
|
- .with_file_drop_handler(move |window, evet| {
|
|
|
- file_handler
|
|
|
- .as_ref()
|
|
|
- .map(|handler| handler(window, evet))
|
|
|
- .unwrap_or_default()
|
|
|
- });
|
|
|
-
|
|
|
- for (name, handler) in cfg.protocols.drain(..) {
|
|
|
- webview = webview.with_custom_protocol(name, handler)
|
|
|
- }
|
|
|
-
|
|
|
- if cfg.disable_context_menu {
|
|
|
- // in release mode, we don't want to show the dev tool or reload menus
|
|
|
- webview = webview.with_initialization_script(
|
|
|
- r#"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _ => (),
|
|
|
+ })
|
|
|
+ .unwrap_or_else(|| {
|
|
|
+ log::warn!("invalid IPC message received");
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .with_custom_protocol(String::from("dioxus"), move |r| {
|
|
|
+ protocol::desktop_handler(
|
|
|
+ r,
|
|
|
+ resource_dir.clone(),
|
|
|
+ custom_head.clone(),
|
|
|
+ index_file.clone(),
|
|
|
+ )
|
|
|
+ })
|
|
|
+ .with_file_drop_handler(move |window, evet| {
|
|
|
+ file_handler
|
|
|
+ .as_ref()
|
|
|
+ .map(|handler| handler(window, evet))
|
|
|
+ .unwrap_or_default()
|
|
|
+ });
|
|
|
+
|
|
|
+ for (name, handler) in cfg.protocols.drain(..) {
|
|
|
+ webview = webview.with_custom_protocol(name, handler)
|
|
|
+ }
|
|
|
+
|
|
|
+ if cfg.disable_context_menu {
|
|
|
+ // in release mode, we don't want to show the dev tool or reload menus
|
|
|
+ webview = webview.with_initialization_script(
|
|
|
+ r#"
|
|
|
if (document.addEventListener) {
|
|
|
document.addEventListener('contextmenu', function(e) {
|
|
|
e.preventDefault();
|
|
@@ -206,32 +241,11 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
|
|
|
});
|
|
|
}
|
|
|
"#,
|
|
|
- )
|
|
|
- } else {
|
|
|
- // in debug, we are okay with the reload menu showing and dev tool
|
|
|
- webview = webview.with_devtools(true);
|
|
|
- }
|
|
|
-
|
|
|
- desktop.webviews.insert(window_id, webview.build().unwrap());
|
|
|
- }
|
|
|
-
|
|
|
- Event::WindowEvent {
|
|
|
- event, window_id, ..
|
|
|
- } => match event {
|
|
|
- WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
|
|
- WindowEvent::Destroyed { .. } => desktop.close_window(window_id, control_flow),
|
|
|
- _ => {}
|
|
|
- },
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ // in debug, we are okay with the reload menu showing and dev tool
|
|
|
+ webview = webview.with_devtools(true);
|
|
|
+ }
|
|
|
|
|
|
- Event::UserEvent(user_event) => {
|
|
|
- desktop_context::handler(user_event, &mut desktop, control_flow)
|
|
|
- }
|
|
|
- Event::MainEventsCleared => {}
|
|
|
- Event::Resumed => {}
|
|
|
- Event::Suspended => {}
|
|
|
- Event::LoopDestroyed => {}
|
|
|
- Event::RedrawRequested(_id) => {}
|
|
|
- _ => {}
|
|
|
- }
|
|
|
- })
|
|
|
+ webview.build().unwrap()
|
|
|
}
|