desktop_context.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. use crate::controller::DesktopController;
  2. use dioxus_core::ScopeState;
  3. use wry::application::event_loop::ControlFlow;
  4. use wry::application::event_loop::EventLoopProxy;
  5. use wry::application::window::Fullscreen as WryFullscreen;
  6. use UserWindowEvent::*;
  7. pub type ProxyType = EventLoopProxy<UserWindowEvent>;
  8. /// Get an imperative handle to the current window
  9. pub fn use_window(cx: &ScopeState) -> &DesktopContext {
  10. cx.use_hook(|| cx.consume_context::<DesktopContext>())
  11. .as_ref()
  12. .unwrap()
  13. }
  14. /// An imperative interface to the current window.
  15. ///
  16. /// To get a handle to the current window, use the [`use_window`] hook.
  17. ///
  18. ///
  19. /// # Example
  20. ///
  21. /// you can use `cx.consume_context::<DesktopContext>` to get this context
  22. ///
  23. /// ```rust, ignore
  24. /// let desktop = cx.consume_context::<DesktopContext>().unwrap();
  25. /// ```
  26. #[derive(Clone)]
  27. pub struct DesktopContext {
  28. /// The wry/tao proxy to the current window
  29. pub proxy: ProxyType,
  30. }
  31. impl DesktopContext {
  32. pub(crate) fn new(proxy: ProxyType) -> Self {
  33. Self { proxy }
  34. }
  35. /// trigger the drag-window event
  36. ///
  37. /// Moves the window with the left mouse button until the button is released.
  38. ///
  39. /// you need use it in `onmousedown` event:
  40. /// ```rust, ignore
  41. /// onmousedown: move |_| { desktop.drag_window(); }
  42. /// ```
  43. pub fn drag(&self) {
  44. let _ = self.proxy.send_event(DragWindow);
  45. }
  46. /// set window minimize state
  47. pub fn set_minimized(&self, minimized: bool) {
  48. let _ = self.proxy.send_event(Minimize(minimized));
  49. }
  50. /// set window maximize state
  51. pub fn set_maximized(&self, maximized: bool) {
  52. let _ = self.proxy.send_event(Maximize(maximized));
  53. }
  54. /// toggle window maximize state
  55. pub fn toggle_maximized(&self) {
  56. let _ = self.proxy.send_event(MaximizeToggle);
  57. }
  58. /// set window visible or not
  59. pub fn set_visible(&self, visible: bool) {
  60. let _ = self.proxy.send_event(Visible(visible));
  61. }
  62. /// close window
  63. pub fn close(&self) {
  64. let _ = self.proxy.send_event(CloseWindow);
  65. }
  66. /// set window to focus
  67. pub fn focus(&self) {
  68. let _ = self.proxy.send_event(FocusWindow);
  69. }
  70. /// change window to fullscreen
  71. pub fn set_fullscreen(&self, fullscreen: bool) {
  72. let _ = self.proxy.send_event(Fullscreen(fullscreen));
  73. }
  74. /// set resizable state
  75. pub fn set_resizable(&self, resizable: bool) {
  76. let _ = self.proxy.send_event(Resizable(resizable));
  77. }
  78. /// set the window always on top
  79. pub fn set_always_on_top(&self, top: bool) {
  80. let _ = self.proxy.send_event(AlwaysOnTop(top));
  81. }
  82. /// set cursor visible or not
  83. pub fn set_cursor_visible(&self, visible: bool) {
  84. let _ = self.proxy.send_event(CursorVisible(visible));
  85. }
  86. /// set cursor grab
  87. pub fn set_cursor_grab(&self, grab: bool) {
  88. let _ = self.proxy.send_event(CursorGrab(grab));
  89. }
  90. /// set window title
  91. pub fn set_title(&self, title: &str) {
  92. let _ = self.proxy.send_event(SetTitle(String::from(title)));
  93. }
  94. /// change window to borderless
  95. pub fn set_decorations(&self, decoration: bool) {
  96. let _ = self.proxy.send_event(SetDecorations(decoration));
  97. }
  98. /// set window zoom level
  99. pub fn set_zoom_level(&self, scale_factor: f64) {
  100. let _ = self.proxy.send_event(SetZoomLevel(scale_factor));
  101. }
  102. /// launch print modal
  103. pub fn print(&self) {
  104. let _ = self.proxy.send_event(Print);
  105. }
  106. /// opens DevTool window
  107. pub fn devtool(&self) {
  108. let _ = self.proxy.send_event(DevTool);
  109. }
  110. /// run (evaluate) a script in the WebView context
  111. pub fn eval(&self, script: impl std::string::ToString) {
  112. let _ = self.proxy.send_event(Eval(script.to_string()));
  113. }
  114. }
  115. #[derive(Debug)]
  116. pub enum UserWindowEvent {
  117. Update,
  118. CloseWindow,
  119. DragWindow,
  120. FocusWindow,
  121. Visible(bool),
  122. Minimize(bool),
  123. Maximize(bool),
  124. MaximizeToggle,
  125. Resizable(bool),
  126. AlwaysOnTop(bool),
  127. Fullscreen(bool),
  128. CursorVisible(bool),
  129. CursorGrab(bool),
  130. SetTitle(String),
  131. SetDecorations(bool),
  132. SetZoomLevel(f64),
  133. Print,
  134. DevTool,
  135. Eval(String),
  136. }
  137. pub(super) fn handler(
  138. user_event: UserWindowEvent,
  139. desktop: &mut DesktopController,
  140. control_flow: &mut ControlFlow,
  141. ) {
  142. // currently dioxus-desktop supports a single window only,
  143. // so we can grab the only webview from the map;
  144. let webview = desktop.webviews.values().next().unwrap();
  145. let window = webview.window();
  146. match user_event {
  147. Update => desktop.try_load_ready_webviews(),
  148. CloseWindow => *control_flow = ControlFlow::Exit,
  149. DragWindow => {
  150. // if the drag_window has any errors, we don't do anything
  151. window.fullscreen().is_none().then(|| window.drag_window());
  152. }
  153. Visible(state) => window.set_visible(state),
  154. Minimize(state) => window.set_minimized(state),
  155. Maximize(state) => window.set_maximized(state),
  156. MaximizeToggle => window.set_maximized(!window.is_maximized()),
  157. Fullscreen(state) => {
  158. if let Some(handle) = window.current_monitor() {
  159. window.set_fullscreen(state.then(|| WryFullscreen::Borderless(Some(handle))));
  160. }
  161. }
  162. FocusWindow => window.set_focus(),
  163. Resizable(state) => window.set_resizable(state),
  164. AlwaysOnTop(state) => window.set_always_on_top(state),
  165. CursorVisible(state) => window.set_cursor_visible(state),
  166. CursorGrab(state) => {
  167. let _ = window.set_cursor_grab(state);
  168. }
  169. SetTitle(content) => window.set_title(&content),
  170. SetDecorations(state) => window.set_decorations(state),
  171. SetZoomLevel(scale_factor) => webview.zoom(scale_factor),
  172. Print => {
  173. if let Err(e) = webview.print() {
  174. // we can't panic this error.
  175. log::warn!("Open print modal failed: {e}");
  176. }
  177. }
  178. DevTool => {
  179. #[cfg(debug_assertions)]
  180. webview.open_devtools();
  181. #[cfg(not(debug_assertions))]
  182. log::warn!("Devtools are disabled in release builds");
  183. }
  184. Eval(code) => {
  185. if let Err(e) = webview.evaluate_script(code.as_str()) {
  186. // we can't panic this error.
  187. log::warn!("Eval script error: {e}");
  188. }
  189. }
  190. }
  191. }
  192. /// Get a closure that executes any JavaScript in the WebView context.
  193. pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) {
  194. let desktop = use_window(cx).clone();
  195. cx.use_hook(|| move |script| desktop.eval(script))
  196. }