window.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. #[cfg(feature = "menu")]
  5. use crate::runtime::MenuId;
  6. use crate::{
  7. api::config::WindowUrl,
  8. command::{CommandArg, CommandItem},
  9. event::{Event, EventHandler},
  10. manager::WindowManager,
  11. runtime::{
  12. monitor::Monitor as RuntimeMonitor,
  13. tag::{TagRef, ToJsString},
  14. webview::{InvokePayload, WebviewAttributes, WindowBuilder},
  15. window::{
  16. dpi::{PhysicalPosition, PhysicalSize, Position, Size},
  17. DetachedWindow, PendingWindow, WindowEvent,
  18. },
  19. Dispatch, Icon, Params, Runtime,
  20. },
  21. sealed::ManagerBase,
  22. sealed::RuntimeOrDispatch,
  23. Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager, PageLoadPayload,
  24. };
  25. use serde::Serialize;
  26. use std::{
  27. borrow::Borrow,
  28. hash::{Hash, Hasher},
  29. };
  30. /// The window menu event.
  31. #[cfg(feature = "menu")]
  32. #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))]
  33. #[derive(Debug, Clone)]
  34. pub struct MenuEvent<I: MenuId> {
  35. pub(crate) menu_item_id: I,
  36. }
  37. #[cfg(feature = "menu")]
  38. impl<I: MenuId> MenuEvent<I> {
  39. /// The menu item id.
  40. pub fn menu_item_id(&self) -> &I {
  41. &self.menu_item_id
  42. }
  43. }
  44. /// Monitor descriptor.
  45. #[derive(Debug, Clone, Serialize)]
  46. #[serde(rename_all = "camelCase")]
  47. pub struct Monitor {
  48. pub(crate) name: Option<String>,
  49. pub(crate) size: PhysicalSize<u32>,
  50. pub(crate) position: PhysicalPosition<i32>,
  51. pub(crate) scale_factor: f64,
  52. }
  53. impl From<RuntimeMonitor> for Monitor {
  54. fn from(monitor: RuntimeMonitor) -> Self {
  55. Self {
  56. name: monitor.name,
  57. size: monitor.size,
  58. position: monitor.position,
  59. scale_factor: monitor.scale_factor,
  60. }
  61. }
  62. }
  63. impl Monitor {
  64. /// Returns a human-readable name of the monitor.
  65. /// Returns None if the monitor doesn't exist anymore.
  66. pub fn name(&self) -> Option<&String> {
  67. self.name.as_ref()
  68. }
  69. /// Returns the monitor's resolution.
  70. pub fn size(&self) -> &PhysicalSize<u32> {
  71. &self.size
  72. }
  73. /// Returns the top-left corner position of the monitor relative to the larger full screen area.
  74. pub fn position(&self) -> &PhysicalPosition<i32> {
  75. &self.position
  76. }
  77. /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
  78. pub fn scale_factor(&self) -> f64 {
  79. self.scale_factor
  80. }
  81. }
  82. // TODO: expand these docs since this is a pretty important type
  83. crate::manager::default_args! {
  84. /// A webview window managed by Tauri.
  85. ///
  86. /// This type also implements [`Manager`] which allows you to manage other windows attached to
  87. /// the same application.
  88. pub struct Window<P: Params> {
  89. /// The webview window created by the runtime.
  90. /// ok
  91. window: DetachedWindow<P>,
  92. /// The manager to associate this webview window with.
  93. manager: WindowManager<P>,
  94. }
  95. }
  96. impl<P: Params> Clone for Window<P> {
  97. fn clone(&self) -> Self {
  98. Self {
  99. window: self.window.clone(),
  100. manager: self.manager.clone(),
  101. }
  102. }
  103. }
  104. impl<P: Params> Hash for Window<P> {
  105. /// Only use the [`Window`]'s label to represent its hash.
  106. fn hash<H: Hasher>(&self, state: &mut H) {
  107. self.window.label.hash(state)
  108. }
  109. }
  110. impl<P: Params> Eq for Window<P> {}
  111. impl<P: Params> PartialEq for Window<P> {
  112. /// Only use the [`Window`]'s label to compare equality.
  113. fn eq(&self, other: &Self) -> bool {
  114. self.window.label.eq(&other.window.label)
  115. }
  116. }
  117. impl<P: Params> Manager<P> for Window<P> {}
  118. impl<P: Params> ManagerBase<P> for Window<P> {
  119. fn manager(&self) -> &WindowManager<P> {
  120. &self.manager
  121. }
  122. fn runtime(&self) -> RuntimeOrDispatch<'_, P> {
  123. RuntimeOrDispatch::Dispatch(self.dispatcher())
  124. }
  125. }
  126. impl<'de, P: Params> CommandArg<'de, P> for Window<P> {
  127. /// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
  128. fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
  129. Ok(command.message.window())
  130. }
  131. }
  132. impl<P: Params> Window<P> {
  133. /// Create a new window that is attached to the manager.
  134. pub(crate) fn new(manager: WindowManager<P>, window: DetachedWindow<P>) -> Self {
  135. Self { window, manager }
  136. }
  137. /// Creates a new webview window.
  138. pub fn create_window<F>(
  139. &mut self,
  140. label: P::Label,
  141. url: WindowUrl,
  142. setup: F,
  143. ) -> crate::Result<Window<P>>
  144. where
  145. F: FnOnce(
  146. <<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
  147. WebviewAttributes,
  148. ) -> (
  149. <<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
  150. WebviewAttributes,
  151. ),
  152. {
  153. let (window_builder, webview_attributes) = setup(
  154. <<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder::new(),
  155. WebviewAttributes::new(url),
  156. );
  157. self.create_new_window(PendingWindow::new(
  158. window_builder,
  159. webview_attributes,
  160. label,
  161. ))
  162. }
  163. /// The current window's dispatcher.
  164. pub(crate) fn dispatcher(&self) -> <P::Runtime as Runtime>::Dispatcher {
  165. self.window.dispatcher.clone()
  166. }
  167. #[allow(dead_code)]
  168. pub(crate) fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
  169. self
  170. .window
  171. .dispatcher
  172. .run_on_main_thread(f)
  173. .map_err(Into::into)
  174. }
  175. /// How to handle this window receiving an [`InvokeMessage`].
  176. pub(crate) fn on_message(self, command: String, payload: InvokePayload) -> crate::Result<()> {
  177. let manager = self.manager.clone();
  178. match command.as_str() {
  179. "__initialized" => {
  180. let payload: PageLoadPayload = serde_json::from_value(payload.inner)?;
  181. manager.run_on_page_load(self, payload);
  182. }
  183. _ => {
  184. let message = InvokeMessage::new(
  185. self.clone(),
  186. manager.state(),
  187. command.to_string(),
  188. payload.inner,
  189. );
  190. let resolver = InvokeResolver::new(self, payload.callback, payload.error);
  191. let invoke = Invoke { message, resolver };
  192. if let Some(module) = &payload.tauri_module {
  193. let module = module.to_string();
  194. crate::endpoints::handle(module, invoke, manager.config(), manager.package_info());
  195. } else if command.starts_with("plugin:") {
  196. manager.extend_api(invoke);
  197. } else {
  198. manager.run_invoke_handler(invoke);
  199. }
  200. }
  201. }
  202. Ok(())
  203. }
  204. /// The label of this window.
  205. pub fn label(&self) -> &P::Label {
  206. &self.window.label
  207. }
  208. /// Emits an event to the current window.
  209. pub fn emit<E: ?Sized, S>(&self, event: &E, payload: S) -> crate::Result<()>
  210. where
  211. P::Event: Borrow<E>,
  212. E: TagRef<P::Event>,
  213. S: Serialize,
  214. {
  215. self.eval(&format!(
  216. "window['{}']({{event: {}, payload: {}}}, '{}')",
  217. self.manager.event_emit_function_name(),
  218. event.to_js_string()?,
  219. serde_json::to_value(payload)?,
  220. self.manager.generate_salt(),
  221. ))?;
  222. Ok(())
  223. }
  224. /// Emits an event on all windows except this one.
  225. pub fn emit_others<E: ?Sized, S>(&self, event: &E, payload: S) -> crate::Result<()>
  226. where
  227. P::Event: Borrow<E>,
  228. E: TagRef<P::Event>,
  229. S: Serialize + Clone,
  230. {
  231. self.manager.emit_filter(event, payload, |w| w != self)
  232. }
  233. /// Listen to an event on this window.
  234. pub fn listen<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
  235. where
  236. F: Fn(Event) + Send + 'static,
  237. {
  238. let label = self.window.label.clone();
  239. self.manager.listen(event.into(), Some(label), handler)
  240. }
  241. /// Listen to a an event on this window a single time.
  242. pub fn once<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
  243. where
  244. F: Fn(Event) + Send + 'static,
  245. {
  246. let label = self.window.label.clone();
  247. self.manager.once(event.into(), Some(label), handler)
  248. }
  249. /// Triggers an event on this window.
  250. pub fn trigger<E: ?Sized>(&self, event: &E, data: Option<String>)
  251. where
  252. P::Event: Borrow<E>,
  253. E: TagRef<P::Event>,
  254. {
  255. let label = self.window.label.clone();
  256. self.manager.trigger(event, Some(label), data)
  257. }
  258. /// Evaluates JavaScript on this window.
  259. pub fn eval(&self, js: &str) -> crate::Result<()> {
  260. self.window.dispatcher.eval_script(js).map_err(Into::into)
  261. }
  262. /// Registers a window event listener.
  263. pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
  264. self.window.dispatcher.on_window_event(f);
  265. }
  266. /// Registers a menu event listener.
  267. #[cfg(feature = "menu")]
  268. #[cfg_attr(doc_cfg, doc(cfg(feature = "menu")))]
  269. pub fn on_menu_event<F: Fn(MenuEvent<P::MenuId>) + Send + 'static>(&self, f: F) {
  270. let menu_ids = self.manager.menu_ids();
  271. self.window.dispatcher.on_menu_event(move |event| {
  272. f(MenuEvent {
  273. menu_item_id: menu_ids.get(&event.menu_item_id).unwrap().clone(),
  274. })
  275. });
  276. }
  277. // Getters
  278. /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
  279. pub fn scale_factor(&self) -> crate::Result<f64> {
  280. self.window.dispatcher.scale_factor().map_err(Into::into)
  281. }
  282. /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
  283. pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
  284. self.window.dispatcher.inner_position().map_err(Into::into)
  285. }
  286. /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
  287. pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
  288. self.window.dispatcher.outer_position().map_err(Into::into)
  289. }
  290. /// Returns the physical size of the window's client area.
  291. ///
  292. /// The client area is the content of the window, excluding the title bar and borders.
  293. pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
  294. self.window.dispatcher.inner_size().map_err(Into::into)
  295. }
  296. /// Returns the physical size of the entire window.
  297. ///
  298. /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
  299. pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
  300. self.window.dispatcher.outer_size().map_err(Into::into)
  301. }
  302. /// Gets the window's current fullscreen state.
  303. pub fn is_fullscreen(&self) -> crate::Result<bool> {
  304. self.window.dispatcher.is_fullscreen().map_err(Into::into)
  305. }
  306. /// Gets the window's current maximized state.
  307. pub fn is_maximized(&self) -> crate::Result<bool> {
  308. self.window.dispatcher.is_maximized().map_err(Into::into)
  309. }
  310. /// Gets the window’s current decoration state.
  311. pub fn is_decorated(&self) -> crate::Result<bool> {
  312. self.window.dispatcher.is_decorated().map_err(Into::into)
  313. }
  314. /// Gets the window’s current resizable state.
  315. pub fn is_resizable(&self) -> crate::Result<bool> {
  316. self.window.dispatcher.is_resizable().map_err(Into::into)
  317. }
  318. /// Returns the monitor on which the window currently resides.
  319. ///
  320. /// Returns None if current monitor can't be detected.
  321. pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
  322. self
  323. .window
  324. .dispatcher
  325. .current_monitor()
  326. .map(|m| m.map(Into::into))
  327. .map_err(Into::into)
  328. }
  329. /// Returns the primary monitor of the system.
  330. ///
  331. /// Returns None if it can't identify any monitor as a primary one.
  332. pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
  333. self
  334. .window
  335. .dispatcher
  336. .primary_monitor()
  337. .map(|m| m.map(Into::into))
  338. .map_err(Into::into)
  339. }
  340. /// Returns the list of all the monitors available on the system.
  341. pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
  342. self
  343. .window
  344. .dispatcher
  345. .available_monitors()
  346. .map(|m| m.into_iter().map(Into::into).collect())
  347. .map_err(Into::into)
  348. }
  349. /// Returns the native handle that is used by this window.
  350. #[cfg(windows)]
  351. pub fn hwnd(&self) -> crate::Result<*mut std::ffi::c_void> {
  352. self.window.dispatcher.hwnd().map_err(Into::into)
  353. }
  354. // Setters
  355. /// Opens the dialog to prints the contents of the webview.
  356. /// Currently only supported on macOS on `wry`.
  357. /// `window.print()` works on all platforms.
  358. pub fn print(&self) -> crate::Result<()> {
  359. self.window.dispatcher.print().map_err(Into::into)
  360. }
  361. /// Determines if this window should be resizable.
  362. pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
  363. self
  364. .window
  365. .dispatcher
  366. .set_resizable(resizable)
  367. .map_err(Into::into)
  368. }
  369. /// Set this window's title.
  370. pub fn set_title(&self, title: &str) -> crate::Result<()> {
  371. self
  372. .window
  373. .dispatcher
  374. .set_title(title.to_string())
  375. .map_err(Into::into)
  376. }
  377. /// Maximizes this window.
  378. pub fn maximize(&self) -> crate::Result<()> {
  379. self.window.dispatcher.maximize().map_err(Into::into)
  380. }
  381. /// Un-maximizes this window.
  382. pub fn unmaximize(&self) -> crate::Result<()> {
  383. self.window.dispatcher.unmaximize().map_err(Into::into)
  384. }
  385. /// Minimizes this window.
  386. pub fn minimize(&self) -> crate::Result<()> {
  387. self.window.dispatcher.minimize().map_err(Into::into)
  388. }
  389. /// Un-minimizes this window.
  390. pub fn unminimize(&self) -> crate::Result<()> {
  391. self.window.dispatcher.unminimize().map_err(Into::into)
  392. }
  393. /// Show this window.
  394. pub fn show(&self) -> crate::Result<()> {
  395. self.window.dispatcher.show().map_err(Into::into)
  396. }
  397. /// Hide this window.
  398. pub fn hide(&self) -> crate::Result<()> {
  399. self.window.dispatcher.hide().map_err(Into::into)
  400. }
  401. /// Closes this window.
  402. pub fn close(&self) -> crate::Result<()> {
  403. self.window.dispatcher.close().map_err(Into::into)
  404. }
  405. /// Determines if this window should be [decorated].
  406. ///
  407. /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
  408. pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
  409. self
  410. .window
  411. .dispatcher
  412. .set_decorations(decorations)
  413. .map_err(Into::into)
  414. }
  415. /// Determines if this window should always be on top of other windows.
  416. pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
  417. self
  418. .window
  419. .dispatcher
  420. .set_always_on_top(always_on_top)
  421. .map_err(Into::into)
  422. }
  423. /// Resizes this window.
  424. pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
  425. self
  426. .window
  427. .dispatcher
  428. .set_size(size.into())
  429. .map_err(Into::into)
  430. }
  431. /// Sets this window's minimum size.
  432. pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
  433. self
  434. .window
  435. .dispatcher
  436. .set_min_size(size.map(|s| s.into()))
  437. .map_err(Into::into)
  438. }
  439. /// Sets this window's maximum size.
  440. pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
  441. self
  442. .window
  443. .dispatcher
  444. .set_max_size(size.map(|s| s.into()))
  445. .map_err(Into::into)
  446. }
  447. /// Sets this window's position.
  448. pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
  449. self
  450. .window
  451. .dispatcher
  452. .set_position(position.into())
  453. .map_err(Into::into)
  454. }
  455. /// Determines if this window should be fullscreen.
  456. pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
  457. self
  458. .window
  459. .dispatcher
  460. .set_fullscreen(fullscreen)
  461. .map_err(Into::into)
  462. }
  463. /// Bring the window to front and focus.
  464. pub fn set_focus(&self) -> crate::Result<()> {
  465. self.window.dispatcher.set_focus().map_err(Into::into)
  466. }
  467. /// Sets this window' icon.
  468. pub fn set_icon(&self, icon: Icon) -> crate::Result<()> {
  469. self.window.dispatcher.set_icon(icon).map_err(Into::into)
  470. }
  471. /// Starts dragging the window.
  472. pub fn start_dragging(&self) -> crate::Result<()> {
  473. self.window.dispatcher.start_dragging().map_err(Into::into)
  474. }
  475. pub(crate) fn verify_salt(&self, salt: String) -> bool {
  476. self.manager.verify_salt(salt)
  477. }
  478. }