webview.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. use crate::desktop_context::EventData;
  2. use crate::protocol;
  3. use crate::{desktop_context::UserWindowEvent, Config};
  4. use tao::event_loop::{EventLoopProxy, EventLoopWindowTarget};
  5. pub use wry;
  6. pub use wry::application as tao;
  7. use wry::application::window::Window;
  8. use wry::webview::{WebContext, WebView, WebViewBuilder};
  9. pub fn build(
  10. cfg: &mut Config,
  11. event_loop: &EventLoopWindowTarget<UserWindowEvent>,
  12. proxy: EventLoopProxy<UserWindowEvent>,
  13. ) -> (WebView, WebContext) {
  14. let builder = cfg.window.clone();
  15. let window = builder.build(event_loop).unwrap();
  16. let file_handler = cfg.file_drop_handler.take();
  17. let custom_head = cfg.custom_head.clone();
  18. let index_file = cfg.custom_index.clone();
  19. let root_name = cfg.root_name.clone();
  20. let assets_head = {
  21. #[cfg(all(
  22. debug_assertions,
  23. any(
  24. target_os = "windows",
  25. target_os = "macos",
  26. target_os = "linux",
  27. target_os = "dragonfly",
  28. target_os = "freebsd",
  29. target_os = "netbsd",
  30. target_os = "openbsd"
  31. )
  32. ))]
  33. {
  34. None
  35. }
  36. #[cfg(not(all(
  37. debug_assertions,
  38. any(
  39. target_os = "windows",
  40. target_os = "macos",
  41. target_os = "linux",
  42. target_os = "dragonfly",
  43. target_os = "freebsd",
  44. target_os = "netbsd",
  45. target_os = "openbsd"
  46. )
  47. )))]
  48. {
  49. let head = crate::protocol::get_asset_root_or_default();
  50. let head = head.join("dist/__assets_head.html");
  51. match std::fs::read_to_string(&head) {
  52. Ok(s) => Some(s),
  53. Err(err) => {
  54. tracing::error!("Failed to read {head:?}: {err}");
  55. None
  56. }
  57. }
  58. }
  59. };
  60. // We assume that if the icon is None in cfg, then the user just didnt set it
  61. if cfg.window.window.window_icon.is_none() {
  62. window.set_window_icon(Some(
  63. tao::window::Icon::from_rgba(
  64. include_bytes!("./assets/default_icon.bin").to_vec(),
  65. 460,
  66. 460,
  67. )
  68. .expect("image parse failed"),
  69. ));
  70. }
  71. let mut web_context = WebContext::new(cfg.data_dir.clone());
  72. let mut webview = WebViewBuilder::new(window)
  73. .unwrap()
  74. .with_transparent(cfg.window.window.transparent)
  75. .with_url("dioxus://index.html/")
  76. .unwrap()
  77. .with_ipc_handler(move |window: &Window, payload: String| {
  78. // defer the event to the main thread
  79. if let Ok(message) = serde_json::from_str(&payload) {
  80. _ = proxy.send_event(UserWindowEvent(EventData::Ipc(message), window.id()));
  81. }
  82. })
  83. .with_custom_protocol(String::from("dioxus"), move |r| {
  84. protocol::desktop_handler(
  85. r,
  86. custom_head.clone(),
  87. index_file.clone(),
  88. assets_head.clone(),
  89. &root_name,
  90. )
  91. })
  92. .with_file_drop_handler(move |window, evet| {
  93. file_handler
  94. .as_ref()
  95. .map(|handler| handler(window, evet))
  96. .unwrap_or_default()
  97. })
  98. .with_web_context(&mut web_context);
  99. #[cfg(windows)]
  100. {
  101. // Windows has a platform specific settings to disable the browser shortcut keys
  102. use wry::webview::WebViewBuilderExtWindows;
  103. webview = webview.with_browser_accelerator_keys(false);
  104. }
  105. if let Some(color) = cfg.background_color {
  106. webview = webview.with_background_color(color);
  107. }
  108. // These are commented out because wry is currently broken in wry
  109. // let mut web_context = WebContext::new(cfg.data_dir.clone());
  110. // .with_web_context(&mut web_context);
  111. for (name, handler) in cfg.protocols.drain(..) {
  112. webview = webview.with_custom_protocol(name, handler)
  113. }
  114. if cfg.disable_context_menu {
  115. // in release mode, we don't want to show the dev tool or reload menus
  116. webview = webview.with_initialization_script(
  117. r#"
  118. if (document.addEventListener) {
  119. document.addEventListener('contextmenu', function(e) {
  120. e.preventDefault();
  121. }, false);
  122. } else {
  123. document.attachEvent('oncontextmenu', function() {
  124. window.event.returnValue = false;
  125. });
  126. }
  127. "#,
  128. )
  129. } else {
  130. // in debug, we are okay with the reload menu showing and dev tool
  131. webview = webview.with_devtools(true);
  132. }
  133. (webview.build().unwrap(), web_context)
  134. }