(root: Component, 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());
#[cfg(debug_assertions)]
hot_reload::init(desktop.templates_tx.clone());
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,
) {
let webview = build_webview(
cfg,
event_loop,
self.is_ready.clone(),
self.proxy.clone(),
self.eval_sender.clone(),
self.event_tx.clone(),
);
self.webviews.insert(webview.window().id(), webview);
}
}
fn build_webview(
cfg: &mut Config,
event_loop: &tao::event_loop::EventLoopWindowTarget,
is_ready: Arc,
proxy: tao::event_loop::EventLoopProxy,
eval_sender: tokio::sync::mpsc::UnboundedSender,
event_tx: UnboundedSender,
) -> 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();
let root_name = cfg.root_name.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() {
window.set_window_icon(Some(
tao::window::Icon::from_rgba(
include_bytes!("./assets/default_icon.bin").to_vec(),
460,
460,
)
.expect("image parse failed"),
));
}
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| {
let message = match parse_ipc_message(&payload) {
Some(message) => message,
None => {
log::error!("Failed to parse IPC message: {}", payload);
return;
}
};
match message.method() {
"eval_result" => {
let result = message.params();
eval_sender.send(result).unwrap();
}
"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);
}
}
}
}
_ => (),
}
})
.with_custom_protocol(String::from("dioxus"), move |r| {
protocol::desktop_handler(
r,
resource_dir.clone(),
custom_head.clone(),
index_file.clone(),
&root_name,
)
})
.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();
}, false);
} else {
document.attachEvent('oncontextmenu', function() {
window.event.returnValue = false;
});
}
"#,
)
} else {
// in debug, we are okay with the reload menu showing and dev tool
webview = webview.with_devtools(true);
}
webview.build().unwrap()
}