window.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! The Tauri window types and functions.
  5. pub(crate) mod menu;
  6. pub use menu::{MenuEvent, MenuHandle};
  7. use crate::{
  8. app::AppHandle,
  9. command::{CommandArg, CommandItem},
  10. event::{Event, EventHandler},
  11. manager::WindowManager,
  12. runtime::{
  13. monitor::Monitor as RuntimeMonitor,
  14. webview::{InvokePayload, WebviewAttributes, WindowBuilder},
  15. window::{
  16. dpi::{PhysicalPosition, PhysicalSize, Position, Size},
  17. DetachedWindow, PendingWindow, WindowEvent,
  18. },
  19. Dispatch, Icon, Runtime, UserAttentionType,
  20. },
  21. sealed::ManagerBase,
  22. sealed::RuntimeOrDispatch,
  23. utils::config::WindowUrl,
  24. Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager, PageLoadPayload,
  25. };
  26. use serde::Serialize;
  27. use tauri_macros::default_runtime;
  28. use std::hash::{Hash, Hasher};
  29. /// Monitor descriptor.
  30. #[derive(Debug, Clone, Serialize)]
  31. #[serde(rename_all = "camelCase")]
  32. pub struct Monitor {
  33. pub(crate) name: Option<String>,
  34. pub(crate) size: PhysicalSize<u32>,
  35. pub(crate) position: PhysicalPosition<i32>,
  36. pub(crate) scale_factor: f64,
  37. }
  38. impl From<RuntimeMonitor> for Monitor {
  39. fn from(monitor: RuntimeMonitor) -> Self {
  40. Self {
  41. name: monitor.name,
  42. size: monitor.size,
  43. position: monitor.position,
  44. scale_factor: monitor.scale_factor,
  45. }
  46. }
  47. }
  48. impl Monitor {
  49. /// Returns a human-readable name of the monitor.
  50. /// Returns None if the monitor doesn't exist anymore.
  51. pub fn name(&self) -> Option<&String> {
  52. self.name.as_ref()
  53. }
  54. /// Returns the monitor's resolution.
  55. pub fn size(&self) -> &PhysicalSize<u32> {
  56. &self.size
  57. }
  58. /// Returns the top-left corner position of the monitor relative to the larger full screen area.
  59. pub fn position(&self) -> &PhysicalPosition<i32> {
  60. &self.position
  61. }
  62. /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
  63. pub fn scale_factor(&self) -> f64 {
  64. self.scale_factor
  65. }
  66. }
  67. // TODO: expand these docs since this is a pretty important type
  68. /// A webview window managed by Tauri.
  69. ///
  70. /// This type also implements [`Manager`] which allows you to manage other windows attached to
  71. /// the same application.
  72. #[default_runtime(crate::Wry, wry)]
  73. #[derive(Debug)]
  74. pub struct Window<R: Runtime> {
  75. /// The webview window created by the runtime.
  76. window: DetachedWindow<R>,
  77. /// The manager to associate this webview window with.
  78. manager: WindowManager<R>,
  79. pub(crate) app_handle: AppHandle<R>,
  80. }
  81. impl<R: Runtime> Clone for Window<R> {
  82. fn clone(&self) -> Self {
  83. Self {
  84. window: self.window.clone(),
  85. manager: self.manager.clone(),
  86. app_handle: self.app_handle.clone(),
  87. }
  88. }
  89. }
  90. impl<R: Runtime> Hash for Window<R> {
  91. /// Only use the [`Window`]'s label to represent its hash.
  92. fn hash<H: Hasher>(&self, state: &mut H) {
  93. self.window.label.hash(state)
  94. }
  95. }
  96. impl<R: Runtime> Eq for Window<R> {}
  97. impl<R: Runtime> PartialEq for Window<R> {
  98. /// Only use the [`Window`]'s label to compare equality.
  99. fn eq(&self, other: &Self) -> bool {
  100. self.window.label.eq(&other.window.label)
  101. }
  102. }
  103. impl<R: Runtime> Manager<R> for Window<R> {}
  104. impl<R: Runtime> ManagerBase<R> for Window<R> {
  105. fn manager(&self) -> &WindowManager<R> {
  106. &self.manager
  107. }
  108. fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
  109. RuntimeOrDispatch::Dispatch(self.dispatcher())
  110. }
  111. fn app_handle(&self) -> AppHandle<R> {
  112. self.app_handle.clone()
  113. }
  114. }
  115. impl<'de, R: Runtime> CommandArg<'de, R> for Window<R> {
  116. /// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
  117. fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
  118. Ok(command.message.window())
  119. }
  120. }
  121. impl<R: Runtime> Window<R> {
  122. /// Create a new window that is attached to the manager.
  123. pub(crate) fn new(
  124. manager: WindowManager<R>,
  125. window: DetachedWindow<R>,
  126. app_handle: AppHandle<R>,
  127. ) -> Self {
  128. Self {
  129. window,
  130. manager,
  131. app_handle,
  132. }
  133. }
  134. /// Creates a new webview window.
  135. ///
  136. /// # Panics
  137. ///
  138. /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure.
  139. /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure.
  140. ///
  141. /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic.
  142. pub fn create_window<F>(
  143. &mut self,
  144. label: String,
  145. url: WindowUrl,
  146. setup: F,
  147. ) -> crate::Result<Window<R>>
  148. where
  149. F: FnOnce(
  150. <R::Dispatcher as Dispatch>::WindowBuilder,
  151. WebviewAttributes,
  152. ) -> (
  153. <R::Dispatcher as Dispatch>::WindowBuilder,
  154. WebviewAttributes,
  155. ),
  156. {
  157. let (window_builder, webview_attributes) = setup(
  158. <R::Dispatcher as Dispatch>::WindowBuilder::new(),
  159. WebviewAttributes::new(url),
  160. );
  161. self.create_new_window(PendingWindow::new(
  162. window_builder,
  163. webview_attributes,
  164. label,
  165. ))
  166. }
  167. /// The current window's dispatcher.
  168. pub(crate) fn dispatcher(&self) -> R::Dispatcher {
  169. self.window.dispatcher.clone()
  170. }
  171. #[allow(dead_code)]
  172. pub(crate) fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
  173. self
  174. .window
  175. .dispatcher
  176. .run_on_main_thread(f)
  177. .map_err(Into::into)
  178. }
  179. /// How to handle this window receiving an [`InvokeMessage`].
  180. pub(crate) fn on_message(self, command: String, payload: InvokePayload) -> crate::Result<()> {
  181. let manager = self.manager.clone();
  182. match command.as_str() {
  183. "__initialized" => {
  184. let payload: PageLoadPayload = serde_json::from_value(payload.inner)?;
  185. manager.run_on_page_load(self, payload);
  186. }
  187. _ => {
  188. let message = InvokeMessage::new(
  189. self.clone(),
  190. manager.state(),
  191. command.to_string(),
  192. payload.inner,
  193. );
  194. let resolver = InvokeResolver::new(self, payload.callback, payload.error);
  195. let invoke = Invoke { message, resolver };
  196. if manager.verify_invoke_key(payload.key) {
  197. if let Some(module) = &payload.tauri_module {
  198. let module = module.to_string();
  199. crate::endpoints::handle(module, invoke, manager.config(), manager.package_info());
  200. } else if command.starts_with("plugin:") {
  201. manager.extend_api(invoke);
  202. } else {
  203. manager.run_invoke_handler(invoke);
  204. }
  205. } else {
  206. panic!(
  207. r#"The invoke key "{}" is invalid. This means that an external, possible malicious script is trying to access the system interface."#,
  208. payload.key
  209. );
  210. }
  211. }
  212. }
  213. Ok(())
  214. }
  215. /// The label of this window.
  216. pub fn label(&self) -> &str {
  217. &self.window.label
  218. }
  219. /// Emits an event to the current window.
  220. pub fn emit<S: Serialize>(&self, event: &str, payload: S) -> crate::Result<()> {
  221. self.eval(&format!(
  222. "window['{}']({{event: {}, payload: {}}})",
  223. self.manager.event_emit_function_name(),
  224. serde_json::to_string(event)?,
  225. serde_json::to_value(payload)?,
  226. ))?;
  227. Ok(())
  228. }
  229. /// Emits an event on all windows except this one.
  230. pub fn emit_others<S: Serialize + Clone>(&self, event: &str, payload: S) -> crate::Result<()> {
  231. self.manager.emit_filter(event, payload, |w| w != self)
  232. }
  233. /// Listen to an event on this window.
  234. pub fn listen<F>(&self, event: impl Into<String>, 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<F>(&self, event: impl Into<String>, 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(&self, event: &str, data: Option<String>) {
  251. let label = self.window.label.clone();
  252. self.manager.trigger(event, Some(label), data)
  253. }
  254. /// Evaluates JavaScript on this window.
  255. pub fn eval(&self, js: &str) -> crate::Result<()> {
  256. self.window.dispatcher.eval_script(js).map_err(Into::into)
  257. }
  258. /// Registers a window event listener.
  259. pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
  260. self.window.dispatcher.on_window_event(f);
  261. }
  262. /// Registers a menu event listener.
  263. pub fn on_menu_event<F: Fn(MenuEvent) + Send + 'static>(&self, f: F) -> uuid::Uuid {
  264. let menu_ids = self.manager.menu_ids();
  265. self.window.dispatcher.on_menu_event(move |event| {
  266. f(MenuEvent {
  267. menu_item_id: menu_ids.get(&event.menu_item_id).unwrap().clone(),
  268. })
  269. })
  270. }
  271. // Getters
  272. /// Gets a handle to the window menu.
  273. pub fn menu_handle(&self) -> MenuHandle<R> {
  274. MenuHandle {
  275. ids: self.manager.menu_ids(),
  276. dispatcher: self.dispatcher(),
  277. }
  278. }
  279. /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
  280. pub fn scale_factor(&self) -> crate::Result<f64> {
  281. self.window.dispatcher.scale_factor().map_err(Into::into)
  282. }
  283. /// 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.
  284. pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
  285. self.window.dispatcher.inner_position().map_err(Into::into)
  286. }
  287. /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
  288. pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
  289. self.window.dispatcher.outer_position().map_err(Into::into)
  290. }
  291. /// Returns the physical size of the window's client area.
  292. ///
  293. /// The client area is the content of the window, excluding the title bar and borders.
  294. pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
  295. self.window.dispatcher.inner_size().map_err(Into::into)
  296. }
  297. /// Returns the physical size of the entire window.
  298. ///
  299. /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
  300. pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
  301. self.window.dispatcher.outer_size().map_err(Into::into)
  302. }
  303. /// Gets the window's current fullscreen state.
  304. pub fn is_fullscreen(&self) -> crate::Result<bool> {
  305. self.window.dispatcher.is_fullscreen().map_err(Into::into)
  306. }
  307. /// Gets the window's current maximized state.
  308. pub fn is_maximized(&self) -> crate::Result<bool> {
  309. self.window.dispatcher.is_maximized().map_err(Into::into)
  310. }
  311. /// Gets the window’s current decoration state.
  312. pub fn is_decorated(&self) -> crate::Result<bool> {
  313. self.window.dispatcher.is_decorated().map_err(Into::into)
  314. }
  315. /// Gets the window’s current resizable state.
  316. pub fn is_resizable(&self) -> crate::Result<bool> {
  317. self.window.dispatcher.is_resizable().map_err(Into::into)
  318. }
  319. /// Gets the window's current vibility state.
  320. pub fn is_visible(&self) -> crate::Result<bool> {
  321. self.window.dispatcher.is_visible().map_err(Into::into)
  322. }
  323. /// Returns the monitor on which the window currently resides.
  324. ///
  325. /// Returns None if current monitor can't be detected.
  326. ///
  327. /// ## Platform-specific
  328. ///
  329. /// - **Linux:** Unsupported
  330. pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
  331. self
  332. .window
  333. .dispatcher
  334. .current_monitor()
  335. .map(|m| m.map(Into::into))
  336. .map_err(Into::into)
  337. }
  338. /// Returns the primary monitor of the system.
  339. ///
  340. /// Returns None if it can't identify any monitor as a primary one.
  341. ///
  342. /// ## Platform-specific
  343. ///
  344. /// - **Linux:** Unsupported
  345. pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
  346. self
  347. .window
  348. .dispatcher
  349. .primary_monitor()
  350. .map(|m| m.map(Into::into))
  351. .map_err(Into::into)
  352. }
  353. /// Returns the list of all the monitors available on the system.
  354. ///
  355. /// ## Platform-specific
  356. ///
  357. /// - **Linux:** Unsupported
  358. pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
  359. self
  360. .window
  361. .dispatcher
  362. .available_monitors()
  363. .map(|m| m.into_iter().map(Into::into).collect())
  364. .map_err(Into::into)
  365. }
  366. /// Returns the native handle that is used by this window.
  367. #[cfg(target_os = "macos")]
  368. pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
  369. self.window.dispatcher.ns_window().map_err(Into::into)
  370. }
  371. /// Returns the native handle that is used by this window.
  372. #[cfg(windows)]
  373. pub fn hwnd(&self) -> crate::Result<*mut std::ffi::c_void> {
  374. self
  375. .window
  376. .dispatcher
  377. .hwnd()
  378. .map(|hwnd| hwnd.0 as *mut _)
  379. .map_err(Into::into)
  380. }
  381. /// Returns the `ApplicatonWindow` from gtk crate that is used by this window.
  382. ///
  383. /// Note that this can only be used on the main thread.
  384. #[cfg(any(
  385. target_os = "linux",
  386. target_os = "dragonfly",
  387. target_os = "freebsd",
  388. target_os = "netbsd",
  389. target_os = "openbsd"
  390. ))]
  391. pub fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow> {
  392. self.window.dispatcher.gtk_window().map_err(Into::into)
  393. }
  394. // Setters
  395. /// Centers the window.
  396. pub fn center(&self) -> crate::Result<()> {
  397. self.window.dispatcher.center().map_err(Into::into)
  398. }
  399. /// Requests user attention to the window, this has no effect if the application
  400. /// is already focused. How requesting for user attention manifests is platform dependent,
  401. /// see `UserAttentionType` for details.
  402. ///
  403. /// Providing `None` will unset the request for user attention. Unsetting the request for
  404. /// user attention might not be done automatically by the WM when the window receives input.
  405. ///
  406. /// ## Platform-specific
  407. ///
  408. /// - **macOS:** `None` has no effect.
  409. pub fn request_user_attention(
  410. &self,
  411. request_type: Option<UserAttentionType>,
  412. ) -> crate::Result<()> {
  413. self
  414. .window
  415. .dispatcher
  416. .request_user_attention(request_type)
  417. .map_err(Into::into)
  418. }
  419. /// Opens the dialog to prints the contents of the webview.
  420. /// Currently only supported on macOS on `wry`.
  421. /// `window.print()` works on all platforms.
  422. pub fn print(&self) -> crate::Result<()> {
  423. self.window.dispatcher.print().map_err(Into::into)
  424. }
  425. /// Determines if this window should be resizable.
  426. pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
  427. self
  428. .window
  429. .dispatcher
  430. .set_resizable(resizable)
  431. .map_err(Into::into)
  432. }
  433. /// Set this window's title.
  434. pub fn set_title(&self, title: &str) -> crate::Result<()> {
  435. self
  436. .window
  437. .dispatcher
  438. .set_title(title.to_string())
  439. .map_err(Into::into)
  440. }
  441. /// Maximizes this window.
  442. pub fn maximize(&self) -> crate::Result<()> {
  443. self.window.dispatcher.maximize().map_err(Into::into)
  444. }
  445. /// Un-maximizes this window.
  446. pub fn unmaximize(&self) -> crate::Result<()> {
  447. self.window.dispatcher.unmaximize().map_err(Into::into)
  448. }
  449. /// Minimizes this window.
  450. pub fn minimize(&self) -> crate::Result<()> {
  451. self.window.dispatcher.minimize().map_err(Into::into)
  452. }
  453. /// Un-minimizes this window.
  454. pub fn unminimize(&self) -> crate::Result<()> {
  455. self.window.dispatcher.unminimize().map_err(Into::into)
  456. }
  457. /// Show this window.
  458. pub fn show(&self) -> crate::Result<()> {
  459. self.window.dispatcher.show().map_err(Into::into)
  460. }
  461. /// Hide this window.
  462. pub fn hide(&self) -> crate::Result<()> {
  463. self.window.dispatcher.hide().map_err(Into::into)
  464. }
  465. /// Closes this window.
  466. /// # Panics
  467. ///
  468. /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure.
  469. /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure.
  470. ///
  471. /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic.
  472. pub fn close(&self) -> crate::Result<()> {
  473. self.window.dispatcher.close().map_err(Into::into)
  474. }
  475. /// Determines if this window should be [decorated].
  476. ///
  477. /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
  478. pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
  479. self
  480. .window
  481. .dispatcher
  482. .set_decorations(decorations)
  483. .map_err(Into::into)
  484. }
  485. /// Determines if this window should always be on top of other windows.
  486. pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
  487. self
  488. .window
  489. .dispatcher
  490. .set_always_on_top(always_on_top)
  491. .map_err(Into::into)
  492. }
  493. /// Resizes this window.
  494. pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
  495. self
  496. .window
  497. .dispatcher
  498. .set_size(size.into())
  499. .map_err(Into::into)
  500. }
  501. /// Sets this window's minimum size.
  502. pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
  503. self
  504. .window
  505. .dispatcher
  506. .set_min_size(size.map(|s| s.into()))
  507. .map_err(Into::into)
  508. }
  509. /// Sets this window's maximum size.
  510. pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
  511. self
  512. .window
  513. .dispatcher
  514. .set_max_size(size.map(|s| s.into()))
  515. .map_err(Into::into)
  516. }
  517. /// Sets this window's position.
  518. pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
  519. self
  520. .window
  521. .dispatcher
  522. .set_position(position.into())
  523. .map_err(Into::into)
  524. }
  525. /// Determines if this window should be fullscreen.
  526. pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
  527. self
  528. .window
  529. .dispatcher
  530. .set_fullscreen(fullscreen)
  531. .map_err(Into::into)
  532. }
  533. /// Bring the window to front and focus.
  534. pub fn set_focus(&self) -> crate::Result<()> {
  535. self.window.dispatcher.set_focus().map_err(Into::into)
  536. }
  537. /// Sets this window' icon.
  538. pub fn set_icon(&self, icon: Icon) -> crate::Result<()> {
  539. self.window.dispatcher.set_icon(icon).map_err(Into::into)
  540. }
  541. /// Whether to show the window icon in the task bar or not.
  542. pub fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
  543. self
  544. .window
  545. .dispatcher
  546. .set_skip_taskbar(skip)
  547. .map_err(Into::into)
  548. }
  549. /// Starts dragging the window.
  550. pub fn start_dragging(&self) -> crate::Result<()> {
  551. self.window.dispatcher.start_dragging().map_err(Into::into)
  552. }
  553. }