window.rs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539
  1. // Copyright 2019-2022 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. #[cfg(target_os = "macos")]
  8. use crate::TitleBarStyle;
  9. use crate::{
  10. app::AppHandle,
  11. command::{CommandArg, CommandItem},
  12. event::{Event, EventHandler},
  13. hooks::{InvokePayload, InvokeResponder},
  14. manager::WindowManager,
  15. runtime::{
  16. http::{Request as HttpRequest, Response as HttpResponse},
  17. menu::Menu,
  18. monitor::Monitor as RuntimeMonitor,
  19. webview::{WebviewAttributes, WindowBuilder as _},
  20. window::{
  21. dpi::{PhysicalPosition, PhysicalSize, Position, Size},
  22. DetachedWindow, JsEventListenerKey, PendingWindow,
  23. },
  24. Dispatch, RuntimeHandle, UserAttentionType,
  25. },
  26. sealed::ManagerBase,
  27. sealed::RuntimeOrDispatch,
  28. utils::config::WindowUrl,
  29. CursorIcon, EventLoopMessage, Icon, Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager,
  30. PageLoadPayload, Runtime, Theme, WindowEvent,
  31. };
  32. use serde::Serialize;
  33. #[cfg(windows)]
  34. use windows::Win32::Foundation::HWND;
  35. use tauri_macros::default_runtime;
  36. use std::{
  37. fmt,
  38. hash::{Hash, Hasher},
  39. path::PathBuf,
  40. sync::Arc,
  41. };
  42. pub(crate) type WebResourceRequestHandler = dyn Fn(&HttpRequest, &mut HttpResponse) + Send + Sync;
  43. #[derive(Clone, Serialize)]
  44. struct WindowCreatedEvent {
  45. label: String,
  46. }
  47. /// Monitor descriptor.
  48. #[derive(Debug, Clone, Serialize)]
  49. #[serde(rename_all = "camelCase")]
  50. pub struct Monitor {
  51. pub(crate) name: Option<String>,
  52. pub(crate) size: PhysicalSize<u32>,
  53. pub(crate) position: PhysicalPosition<i32>,
  54. pub(crate) scale_factor: f64,
  55. }
  56. impl From<RuntimeMonitor> for Monitor {
  57. fn from(monitor: RuntimeMonitor) -> Self {
  58. Self {
  59. name: monitor.name,
  60. size: monitor.size,
  61. position: monitor.position,
  62. scale_factor: monitor.scale_factor,
  63. }
  64. }
  65. }
  66. impl Monitor {
  67. /// Returns a human-readable name of the monitor.
  68. /// Returns None if the monitor doesn't exist anymore.
  69. pub fn name(&self) -> Option<&String> {
  70. self.name.as_ref()
  71. }
  72. /// Returns the monitor's resolution.
  73. pub fn size(&self) -> &PhysicalSize<u32> {
  74. &self.size
  75. }
  76. /// Returns the top-left corner position of the monitor relative to the larger full screen area.
  77. pub fn position(&self) -> &PhysicalPosition<i32> {
  78. &self.position
  79. }
  80. /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
  81. pub fn scale_factor(&self) -> f64 {
  82. self.scale_factor
  83. }
  84. }
  85. /// A builder for a webview window managed by Tauri.
  86. #[default_runtime(crate::Wry, wry)]
  87. pub struct WindowBuilder<'a, R: Runtime> {
  88. manager: WindowManager<R>,
  89. runtime: RuntimeOrDispatch<'a, R>,
  90. app_handle: AppHandle<R>,
  91. label: String,
  92. pub(crate) window_builder: <R::Dispatcher as Dispatch<EventLoopMessage>>::WindowBuilder,
  93. pub(crate) webview_attributes: WebviewAttributes,
  94. web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,
  95. }
  96. impl<'a, R: Runtime> fmt::Debug for WindowBuilder<'a, R> {
  97. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  98. f.debug_struct("WindowBuilder")
  99. .field("manager", &self.manager)
  100. .field("app_handle", &self.app_handle)
  101. .field("label", &self.label)
  102. .field("window_builder", &self.window_builder)
  103. .field("webview_attributes", &self.webview_attributes)
  104. .finish()
  105. }
  106. }
  107. impl<'a, R: Runtime> WindowBuilder<'a, R> {
  108. /// Initializes a webview window builder with the given window label and URL to load on the webview.
  109. ///
  110. /// # Examples
  111. ///
  112. /// - Create a window in the setup hook:
  113. ///
  114. /// ```
  115. /// tauri::Builder::default()
  116. /// .setup(|app| {
  117. /// let window = tauri::WindowBuilder::new(app, "label", tauri::WindowUrl::App("index.html".into()))
  118. /// .build()?;
  119. /// Ok(())
  120. /// });
  121. /// ```
  122. ///
  123. /// - Create a window in a separate thread:
  124. ///
  125. /// ```
  126. /// tauri::Builder::default()
  127. /// .setup(|app| {
  128. /// let handle = app.handle();
  129. /// std::thread::spawn(move || {
  130. /// let window = tauri::WindowBuilder::new(&handle, "label", tauri::WindowUrl::App("index.html".into()))
  131. /// .build()
  132. /// .unwrap();
  133. /// });
  134. /// Ok(())
  135. /// });
  136. /// ```
  137. ///
  138. /// - Create a window in a command:
  139. ///
  140. /// ```
  141. /// #[tauri::command]
  142. /// async fn create_window(app: tauri::AppHandle) {
  143. /// let window = tauri::WindowBuilder::new(&app, "label", tauri::WindowUrl::External("https://tauri.app/".parse().unwrap()))
  144. /// .build()
  145. /// .unwrap();
  146. /// }
  147. /// ```
  148. ///
  149. /// # Known issues
  150. ///
  151. /// On Windows, this function deadlocks when used in a synchronous command, see [the Webview2 issue].
  152. /// You should use `async` commands when creating windows.
  153. ///
  154. /// [the Webview2 issue]: https://github.com/tauri-apps/wry/issues/583
  155. pub fn new<M: Manager<R>, L: Into<String>>(manager: &'a M, label: L, url: WindowUrl) -> Self {
  156. let runtime = manager.runtime();
  157. let app_handle = manager.app_handle();
  158. Self {
  159. manager: manager.manager().clone(),
  160. runtime,
  161. app_handle,
  162. label: label.into(),
  163. window_builder: <R::Dispatcher as Dispatch<EventLoopMessage>>::WindowBuilder::new(),
  164. webview_attributes: WebviewAttributes::new(url),
  165. web_resource_request_handler: None,
  166. }
  167. }
  168. /// Defines a closure to be executed when the webview makes an HTTP request for a web resource, allowing you to modify the response.
  169. ///
  170. /// Currently only implemented for the `tauri` URI protocol.
  171. ///
  172. /// **NOTE:** Currently this is **not** executed when using external URLs such as a development server,
  173. /// but it might be implemented in the future. **Always** check the request URL.
  174. ///
  175. /// # Examples
  176. ///
  177. /// ```rust,no_run
  178. /// use tauri::{
  179. /// utils::config::{Csp, CspDirectiveSources, WindowUrl},
  180. /// http::header::HeaderValue,
  181. /// window::WindowBuilder,
  182. /// };
  183. /// use std::collections::HashMap;
  184. /// tauri::Builder::default()
  185. /// .setup(|app| {
  186. /// WindowBuilder::new(app, "core", WindowUrl::App("index.html".into()))
  187. /// .on_web_resource_request(|request, response| {
  188. /// if request.uri().starts_with("tauri://") {
  189. /// // if we have a CSP header, Tauri is loading an HTML file
  190. /// // for this example, let's dynamically change the CSP
  191. /// if let Some(csp) = response.headers_mut().get_mut("Content-Security-Policy") {
  192. /// // use the tauri helper to parse the CSP policy to a map
  193. /// let mut csp_map: HashMap<String, CspDirectiveSources> = Csp::Policy(csp.to_str().unwrap().to_string()).into();
  194. /// csp_map.entry("script-src".to_string()).or_insert_with(Default::default).push("'unsafe-inline'");
  195. /// // use the tauri helper to get a CSP string from the map
  196. /// let csp_string = Csp::from(csp_map).to_string();
  197. /// *csp = HeaderValue::from_str(&csp_string).unwrap();
  198. /// }
  199. /// }
  200. /// })
  201. /// .build()?;
  202. /// Ok(())
  203. /// });
  204. /// ```
  205. pub fn on_web_resource_request<F: Fn(&HttpRequest, &mut HttpResponse) + Send + Sync + 'static>(
  206. mut self,
  207. f: F,
  208. ) -> Self {
  209. self.web_resource_request_handler.replace(Box::new(f));
  210. self
  211. }
  212. /// Creates a new webview window.
  213. pub fn build(mut self) -> crate::Result<Window<R>> {
  214. let web_resource_request_handler = self.web_resource_request_handler.take();
  215. let pending = PendingWindow::new(
  216. self.window_builder.clone(),
  217. self.webview_attributes.clone(),
  218. self.label.clone(),
  219. )?;
  220. let labels = self.manager.labels().into_iter().collect::<Vec<_>>();
  221. let pending = self.manager.prepare_window(
  222. self.app_handle.clone(),
  223. pending,
  224. &labels,
  225. web_resource_request_handler,
  226. )?;
  227. let window = match &mut self.runtime {
  228. RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending),
  229. RuntimeOrDispatch::RuntimeHandle(handle) => handle.create_window(pending),
  230. RuntimeOrDispatch::Dispatch(dispatcher) => dispatcher.create_window(pending),
  231. }
  232. .map(|window| self.manager.attach_window(self.app_handle.clone(), window))?;
  233. self.manager.emit_filter(
  234. "tauri://window-created",
  235. None,
  236. Some(WindowCreatedEvent {
  237. label: window.label().into(),
  238. }),
  239. |w| w != &window,
  240. )?;
  241. Ok(window)
  242. }
  243. }
  244. /// Desktop APIs.
  245. #[cfg(desktop)]
  246. impl<'a, R: Runtime> WindowBuilder<'a, R> {
  247. /// Sets the menu for the window.
  248. #[must_use]
  249. pub fn menu(mut self, menu: Menu) -> Self {
  250. self.window_builder = self.window_builder.menu(menu);
  251. self
  252. }
  253. /// Show window in the center of the screen.
  254. #[must_use]
  255. pub fn center(mut self) -> Self {
  256. self.window_builder = self.window_builder.center();
  257. self
  258. }
  259. /// The initial position of the window's.
  260. #[must_use]
  261. pub fn position(mut self, x: f64, y: f64) -> Self {
  262. self.window_builder = self.window_builder.position(x, y);
  263. self
  264. }
  265. /// Window size.
  266. #[must_use]
  267. pub fn inner_size(mut self, width: f64, height: f64) -> Self {
  268. self.window_builder = self.window_builder.inner_size(width, height);
  269. self
  270. }
  271. /// Window min inner size.
  272. #[must_use]
  273. pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
  274. self.window_builder = self.window_builder.min_inner_size(min_width, min_height);
  275. self
  276. }
  277. /// Window max inner size.
  278. #[must_use]
  279. pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
  280. self.window_builder = self.window_builder.max_inner_size(max_width, max_height);
  281. self
  282. }
  283. /// Whether the window is resizable or not.
  284. #[must_use]
  285. pub fn resizable(mut self, resizable: bool) -> Self {
  286. self.window_builder = self.window_builder.resizable(resizable);
  287. self
  288. }
  289. /// The title of the window in the title bar.
  290. #[must_use]
  291. pub fn title<S: Into<String>>(mut self, title: S) -> Self {
  292. self.window_builder = self.window_builder.title(title);
  293. self
  294. }
  295. /// Whether to start the window in fullscreen or not.
  296. #[must_use]
  297. pub fn fullscreen(mut self, fullscreen: bool) -> Self {
  298. self.window_builder = self.window_builder.fullscreen(fullscreen);
  299. self
  300. }
  301. /// Sets the window to be initially focused.
  302. #[must_use]
  303. #[deprecated(
  304. since = "1.2.0",
  305. note = "The window is automatically focused by default. This function Will be removed in 2.0.0. Use `focused` instead."
  306. )]
  307. pub fn focus(mut self) -> Self {
  308. self.window_builder = self.window_builder.focused(true);
  309. self
  310. }
  311. /// Whether the window will be initially focused or not.
  312. #[must_use]
  313. pub fn focused(mut self, focused: bool) -> Self {
  314. self.window_builder = self.window_builder.focused(focused);
  315. self
  316. }
  317. /// Whether the window should be maximized upon creation.
  318. #[must_use]
  319. pub fn maximized(mut self, maximized: bool) -> Self {
  320. self.window_builder = self.window_builder.maximized(maximized);
  321. self
  322. }
  323. /// Whether the window should be immediately visible upon creation.
  324. #[must_use]
  325. pub fn visible(mut self, visible: bool) -> Self {
  326. self.window_builder = self.window_builder.visible(visible);
  327. self
  328. }
  329. /// Forces a theme or uses the system settings if None was provided.
  330. ///
  331. /// ## Platform-specific
  332. ///
  333. /// - **macOS**: Only supported on macOS 10.14+.
  334. #[must_use]
  335. pub fn theme(mut self, theme: Option<Theme>) -> Self {
  336. self.window_builder = self.window_builder.theme(theme);
  337. self
  338. }
  339. /// Whether the window should be transparent. If this is true, writing colors
  340. /// with alpha values different than `1.0` will produce a transparent window.
  341. #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
  342. #[cfg_attr(
  343. doc_cfg,
  344. doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
  345. )]
  346. #[must_use]
  347. pub fn transparent(mut self, transparent: bool) -> Self {
  348. self.window_builder = self.window_builder.transparent(transparent);
  349. self
  350. }
  351. /// Whether the window should have borders and bars.
  352. #[must_use]
  353. pub fn decorations(mut self, decorations: bool) -> Self {
  354. self.window_builder = self.window_builder.decorations(decorations);
  355. self
  356. }
  357. /// Whether the window should always be on top of other windows.
  358. #[must_use]
  359. pub fn always_on_top(mut self, always_on_top: bool) -> Self {
  360. self.window_builder = self.window_builder.always_on_top(always_on_top);
  361. self
  362. }
  363. /// Sets the window icon.
  364. pub fn icon(mut self, icon: Icon) -> crate::Result<Self> {
  365. self.window_builder = self.window_builder.icon(icon.try_into()?)?;
  366. Ok(self)
  367. }
  368. /// Sets whether or not the window icon should be added to the taskbar.
  369. #[must_use]
  370. pub fn skip_taskbar(mut self, skip: bool) -> Self {
  371. self.window_builder = self.window_builder.skip_taskbar(skip);
  372. self
  373. }
  374. /// Sets a parent to the window to be created.
  375. ///
  376. /// A child window has the WS_CHILD style and is confined to the client area of its parent window.
  377. ///
  378. /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
  379. #[cfg(windows)]
  380. #[must_use]
  381. pub fn parent_window(mut self, parent: HWND) -> Self {
  382. self.window_builder = self.window_builder.parent_window(parent);
  383. self
  384. }
  385. /// Sets a parent to the window to be created.
  386. #[cfg(target_os = "macos")]
  387. #[must_use]
  388. pub fn parent_window(mut self, parent: *mut std::ffi::c_void) -> Self {
  389. self.window_builder = self.window_builder.parent_window(parent);
  390. self
  391. }
  392. /// Set an owner to the window to be created.
  393. ///
  394. /// From MSDN:
  395. /// - An owned window is always above its owner in the z-order.
  396. /// - The system automatically destroys an owned window when its owner is destroyed.
  397. /// - An owned window is hidden when its owner is minimized.
  398. ///
  399. /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
  400. #[cfg(windows)]
  401. #[must_use]
  402. pub fn owner_window(mut self, owner: HWND) -> Self {
  403. self.window_builder = self.window_builder.owner_window(owner);
  404. self
  405. }
  406. /// Sets the [`TitleBarStyle`].
  407. #[cfg(target_os = "macos")]
  408. #[must_use]
  409. pub fn title_bar_style(mut self, style: TitleBarStyle) -> Self {
  410. self.window_builder = self.window_builder.title_bar_style(style);
  411. self
  412. }
  413. /// Hide the window title.
  414. #[cfg(target_os = "macos")]
  415. #[must_use]
  416. pub fn hidden_title(mut self, hidden: bool) -> Self {
  417. self.window_builder = self.window_builder.hidden_title(hidden);
  418. self
  419. }
  420. /// Defines the window [tabbing identifier] for macOS.
  421. ///
  422. /// Windows with matching tabbing identifiers will be grouped together.
  423. /// If the tabbing identifier is not set, automatic tabbing will be disabled.
  424. ///
  425. /// [tabbing identifier]: <https://developer.apple.com/documentation/appkit/nswindow/1644704-tabbingidentifier>
  426. #[cfg(target_os = "macos")]
  427. #[must_use]
  428. pub fn tabbing_identifier(mut self, identifier: &str) -> Self {
  429. self.window_builder = self.window_builder.tabbing_identifier(identifier);
  430. self
  431. }
  432. /// Sets whether clicking an inactive window also clicks through to the webview.
  433. #[must_use]
  434. pub fn accept_first_mouse(mut self, accept: bool) -> Self {
  435. self.webview_attributes.accept_first_mouse = accept;
  436. self
  437. }
  438. }
  439. /// Webview attributes.
  440. impl<'a, R: Runtime> WindowBuilder<'a, R> {
  441. /// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
  442. /// but before the HTML document has been parsed and before any other script included by the HTML document is run.
  443. ///
  444. /// Since it runs on all top-level document and child frame page navigations,
  445. /// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
  446. ///
  447. /// # Examples
  448. ///
  449. /// ```rust
  450. /// use tauri::{WindowBuilder, Runtime};
  451. ///
  452. /// const INIT_SCRIPT: &str = r#"
  453. /// if (window.location.origin === 'https://tauri.app') {
  454. /// console.log("hello world from js init script");
  455. ///
  456. /// window.__MY_CUSTOM_PROPERTY__ = { foo: 'bar' };
  457. /// }
  458. /// "#;
  459. ///
  460. /// fn main() {
  461. /// tauri::Builder::default()
  462. /// .setup(|app| {
  463. /// let window = tauri::WindowBuilder::new(app, "label", tauri::WindowUrl::App("index.html".into()))
  464. /// .initialization_script(INIT_SCRIPT)
  465. /// .build()?;
  466. /// Ok(())
  467. /// });
  468. /// }
  469. /// ```
  470. #[must_use]
  471. pub fn initialization_script(mut self, script: &str) -> Self {
  472. self
  473. .webview_attributes
  474. .initialization_scripts
  475. .push(script.to_string());
  476. self
  477. }
  478. /// Set the user agent for the webview
  479. #[must_use]
  480. pub fn user_agent(mut self, user_agent: &str) -> Self {
  481. self.webview_attributes.user_agent = Some(user_agent.to_string());
  482. self
  483. }
  484. /// Data directory for the webview.
  485. #[must_use]
  486. pub fn data_directory(mut self, data_directory: PathBuf) -> Self {
  487. self
  488. .webview_attributes
  489. .data_directory
  490. .replace(data_directory);
  491. self
  492. }
  493. /// Disables the file drop handler. This is required to use drag and drop APIs on the front end on Windows.
  494. #[must_use]
  495. pub fn disable_file_drop_handler(mut self) -> Self {
  496. self.webview_attributes.file_drop_handler_enabled = false;
  497. self
  498. }
  499. /// Enables clipboard access for the page rendered on **Linux** and **Windows**.
  500. ///
  501. /// **macOS** doesn't provide such method and is always enabled by default,
  502. /// but you still need to add menu item accelerators to use shortcuts.
  503. #[must_use]
  504. pub fn enable_clipboard_access(mut self) -> Self {
  505. self.webview_attributes.clipboard = true;
  506. self
  507. }
  508. }
  509. // TODO: expand these docs since this is a pretty important type
  510. /// A webview window managed by Tauri.
  511. ///
  512. /// This type also implements [`Manager`] which allows you to manage other windows attached to
  513. /// the same application.
  514. #[default_runtime(crate::Wry, wry)]
  515. #[derive(Debug)]
  516. pub struct Window<R: Runtime> {
  517. /// The webview window created by the runtime.
  518. window: DetachedWindow<EventLoopMessage, R>,
  519. /// The manager to associate this webview window with.
  520. manager: WindowManager<R>,
  521. pub(crate) app_handle: AppHandle<R>,
  522. }
  523. unsafe impl<R: Runtime> raw_window_handle::HasRawWindowHandle for Window<R> {
  524. fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
  525. self.window.dispatcher.raw_window_handle().unwrap()
  526. }
  527. }
  528. impl<R: Runtime> Clone for Window<R> {
  529. fn clone(&self) -> Self {
  530. Self {
  531. window: self.window.clone(),
  532. manager: self.manager.clone(),
  533. app_handle: self.app_handle.clone(),
  534. }
  535. }
  536. }
  537. impl<R: Runtime> Hash for Window<R> {
  538. /// Only use the [`Window`]'s label to represent its hash.
  539. fn hash<H: Hasher>(&self, state: &mut H) {
  540. self.window.label.hash(state)
  541. }
  542. }
  543. impl<R: Runtime> Eq for Window<R> {}
  544. impl<R: Runtime> PartialEq for Window<R> {
  545. /// Only use the [`Window`]'s label to compare equality.
  546. fn eq(&self, other: &Self) -> bool {
  547. self.window.label.eq(&other.window.label)
  548. }
  549. }
  550. impl<R: Runtime> Manager<R> for Window<R> {
  551. fn emit_to<S: Serialize + Clone>(
  552. &self,
  553. label: &str,
  554. event: &str,
  555. payload: S,
  556. ) -> crate::Result<()> {
  557. self
  558. .manager()
  559. .emit_filter(event, Some(self.label()), payload, |w| label == w.label())
  560. }
  561. fn emit_all<S: Serialize + Clone>(&self, event: &str, payload: S) -> crate::Result<()> {
  562. self
  563. .manager()
  564. .emit_filter(event, Some(self.label()), payload, |_| true)
  565. }
  566. }
  567. impl<R: Runtime> ManagerBase<R> for Window<R> {
  568. fn manager(&self) -> &WindowManager<R> {
  569. &self.manager
  570. }
  571. fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
  572. RuntimeOrDispatch::Dispatch(self.dispatcher())
  573. }
  574. fn managed_app_handle(&self) -> AppHandle<R> {
  575. self.app_handle.clone()
  576. }
  577. }
  578. impl<'de, R: Runtime> CommandArg<'de, R> for Window<R> {
  579. /// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
  580. fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
  581. Ok(command.message.window())
  582. }
  583. }
  584. /// The platform webview handle. Accessed with [`Window#method.with_webview`];
  585. #[cfg(all(any(desktop, target_os = "android"), feature = "wry"))]
  586. #[cfg_attr(
  587. doc_cfg,
  588. doc(cfg(all(any(desktop, target_os = "android"), feature = "wry")))
  589. )]
  590. pub struct PlatformWebview(tauri_runtime_wry::Webview);
  591. #[cfg(all(any(desktop, target_os = "android"), feature = "wry"))]
  592. impl PlatformWebview {
  593. /// Returns [`webkit2gtk::WebView`] handle.
  594. #[cfg(any(
  595. target_os = "linux",
  596. target_os = "dragonfly",
  597. target_os = "freebsd",
  598. target_os = "netbsd",
  599. target_os = "openbsd"
  600. ))]
  601. #[cfg_attr(
  602. doc_cfg,
  603. doc(cfg(any(
  604. target_os = "linux",
  605. target_os = "dragonfly",
  606. target_os = "freebsd",
  607. target_os = "netbsd",
  608. target_os = "openbsd"
  609. )))
  610. )]
  611. pub fn inner(&self) -> std::rc::Rc<webkit2gtk::WebView> {
  612. self.0.clone()
  613. }
  614. /// Returns the WebView2 controller.
  615. #[cfg(windows)]
  616. #[cfg_attr(doc_cfg, doc(cfg(windows)))]
  617. pub fn controller(
  618. &self,
  619. ) -> webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller {
  620. self.0.controller.clone()
  621. }
  622. /// Returns the [WKWebView] handle.
  623. ///
  624. /// [WKWebView]: https://developer.apple.com/documentation/webkit/wkwebview
  625. #[cfg(target_os = "macos")]
  626. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  627. pub fn inner(&self) -> cocoa::base::id {
  628. self.0.webview
  629. }
  630. /// Returns WKWebView [controller] handle.
  631. ///
  632. /// [controller]: https://developer.apple.com/documentation/webkit/wkusercontentcontroller
  633. #[cfg(target_os = "macos")]
  634. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  635. pub fn controller(&self) -> cocoa::base::id {
  636. self.0.manager
  637. }
  638. /// Returns [NSWindow] associated with the WKWebView webview.
  639. ///
  640. /// [NSWindow]: https://developer.apple.com/documentation/appkit/nswindow
  641. #[cfg(target_os = "macos")]
  642. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  643. pub fn ns_window(&self) -> cocoa::base::id {
  644. self.0.ns_window
  645. }
  646. /// Returns handle for JNI execution.
  647. #[cfg(target_os = "android")]
  648. pub fn jni_handle(&self) -> tauri_runtime_wry::wry::webview::JniHandle {
  649. self.0
  650. }
  651. }
  652. /// APIs specific to the wry runtime.
  653. #[cfg(feature = "wry")]
  654. impl Window<crate::Wry> {
  655. /// Executes the closure accessing the platform's webview handle.
  656. ///
  657. /// The closure is executed in the main thread.
  658. ///
  659. /// # Examples
  660. ///
  661. /// ```rust,no_run
  662. /// #[cfg(target_os = "macos")]
  663. /// #[macro_use]
  664. /// extern crate objc;
  665. /// use tauri::Manager;
  666. ///
  667. /// fn main() {
  668. /// tauri::Builder::default()
  669. /// .setup(|app| {
  670. /// let main_window = app.get_window("main").unwrap();
  671. /// main_window.with_webview(|webview| {
  672. /// #[cfg(target_os = "linux")]
  673. /// {
  674. /// // see https://docs.rs/webkit2gtk/latest/webkit2gtk/struct.WebView.html
  675. /// // and https://docs.rs/webkit2gtk/latest/webkit2gtk/trait.WebViewExt.html
  676. /// use webkit2gtk::traits::WebViewExt;
  677. /// webview.inner().set_zoom_level(4.);
  678. /// }
  679. ///
  680. /// #[cfg(windows)]
  681. /// unsafe {
  682. /// // see https://docs.rs/webview2-com/0.17.0/webview2_com/Microsoft/Web/WebView2/Win32/struct.ICoreWebView2Controller.html
  683. /// webview.controller().SetZoomFactor(4.).unwrap();
  684. /// }
  685. ///
  686. /// #[cfg(target_os = "macos")]
  687. /// unsafe {
  688. /// let () = msg_send![webview.inner(), setPageZoom: 4.];
  689. /// let () = msg_send![webview.controller(), removeAllUserScripts];
  690. /// let bg_color: cocoa::base::id = msg_send![class!(NSColor), colorWithDeviceRed:0.5 green:0.2 blue:0.4 alpha:1.];
  691. /// let () = msg_send![webview.ns_window(), setBackgroundColor: bg_color];
  692. /// }
  693. ///
  694. /// #[cfg(target_os = "android")]
  695. /// {
  696. /// use jni::objects::JValue;
  697. /// webview.jni_handle().exec(|env, _, webview| {
  698. /// env.call_method(webview, "zoomBy", "(F)V", &[JValue::Float(4.)]).unwrap();
  699. /// })
  700. /// }
  701. /// });
  702. /// Ok(())
  703. /// });
  704. /// }
  705. /// ```
  706. #[cfg(any(desktop, target_os = "android"))]
  707. #[cfg_attr(
  708. doc_cfg,
  709. doc(cfg(all(feature = "wry", any(desktop, target_os = "android"))))
  710. )]
  711. pub fn with_webview<F: FnOnce(PlatformWebview) + Send + 'static>(
  712. &self,
  713. f: F,
  714. ) -> crate::Result<()> {
  715. self
  716. .window
  717. .dispatcher
  718. .with_webview(|w| f(PlatformWebview(w)))
  719. .map_err(Into::into)
  720. }
  721. }
  722. /// Base window functions.
  723. impl<R: Runtime> Window<R> {
  724. /// Create a new window that is attached to the manager.
  725. pub(crate) fn new(
  726. manager: WindowManager<R>,
  727. window: DetachedWindow<EventLoopMessage, R>,
  728. app_handle: AppHandle<R>,
  729. ) -> Self {
  730. Self {
  731. window,
  732. manager,
  733. app_handle,
  734. }
  735. }
  736. /// Initializes a webview window builder with the given window label and URL to load on the webview.
  737. ///
  738. /// Data URLs are only supported with the `window-data-url` feature flag.
  739. pub fn builder<'a, M: Manager<R>, L: Into<String>>(
  740. manager: &'a M,
  741. label: L,
  742. url: WindowUrl,
  743. ) -> WindowBuilder<'a, R> {
  744. WindowBuilder::<'a, R>::new(manager, label.into(), url)
  745. }
  746. pub(crate) fn invoke_responder(&self) -> Arc<InvokeResponder<R>> {
  747. self.manager.invoke_responder()
  748. }
  749. /// The current window's dispatcher.
  750. pub(crate) fn dispatcher(&self) -> R::Dispatcher {
  751. self.window.dispatcher.clone()
  752. }
  753. /// Runs the given closure on the main thread.
  754. pub fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
  755. self
  756. .window
  757. .dispatcher
  758. .run_on_main_thread(f)
  759. .map_err(Into::into)
  760. }
  761. /// The label of this window.
  762. pub fn label(&self) -> &str {
  763. &self.window.label
  764. }
  765. /// Registers a window event listener.
  766. pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
  767. self
  768. .window
  769. .dispatcher
  770. .on_window_event(move |event| f(&event.clone().into()));
  771. }
  772. /// Registers a menu event listener.
  773. pub fn on_menu_event<F: Fn(MenuEvent) + Send + 'static>(&self, f: F) -> uuid::Uuid {
  774. let menu_ids = self.window.menu_ids.clone();
  775. self.window.dispatcher.on_menu_event(move |event| {
  776. let id = menu_ids
  777. .lock()
  778. .unwrap()
  779. .get(&event.menu_item_id)
  780. .unwrap()
  781. .clone();
  782. f(MenuEvent { menu_item_id: id })
  783. })
  784. }
  785. }
  786. /// Window getters.
  787. impl<R: Runtime> Window<R> {
  788. /// Gets a handle to the window menu.
  789. pub fn menu_handle(&self) -> MenuHandle<R> {
  790. MenuHandle {
  791. ids: self.window.menu_ids.clone(),
  792. dispatcher: self.dispatcher(),
  793. }
  794. }
  795. /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
  796. pub fn scale_factor(&self) -> crate::Result<f64> {
  797. self.window.dispatcher.scale_factor().map_err(Into::into)
  798. }
  799. /// 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.
  800. pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
  801. self.window.dispatcher.inner_position().map_err(Into::into)
  802. }
  803. /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
  804. pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
  805. self.window.dispatcher.outer_position().map_err(Into::into)
  806. }
  807. /// Returns the physical size of the window's client area.
  808. ///
  809. /// The client area is the content of the window, excluding the title bar and borders.
  810. pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
  811. self.window.dispatcher.inner_size().map_err(Into::into)
  812. }
  813. /// Returns the physical size of the entire window.
  814. ///
  815. /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
  816. pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
  817. self.window.dispatcher.outer_size().map_err(Into::into)
  818. }
  819. /// Gets the window's current fullscreen state.
  820. pub fn is_fullscreen(&self) -> crate::Result<bool> {
  821. self.window.dispatcher.is_fullscreen().map_err(Into::into)
  822. }
  823. /// Gets the window's current maximized state.
  824. pub fn is_maximized(&self) -> crate::Result<bool> {
  825. self.window.dispatcher.is_maximized().map_err(Into::into)
  826. }
  827. /// Gets the window’s current decoration state.
  828. pub fn is_decorated(&self) -> crate::Result<bool> {
  829. self.window.dispatcher.is_decorated().map_err(Into::into)
  830. }
  831. /// Gets the window’s current resizable state.
  832. pub fn is_resizable(&self) -> crate::Result<bool> {
  833. self.window.dispatcher.is_resizable().map_err(Into::into)
  834. }
  835. /// Gets the window's current visibility state.
  836. pub fn is_visible(&self) -> crate::Result<bool> {
  837. self.window.dispatcher.is_visible().map_err(Into::into)
  838. }
  839. /// Returns the monitor on which the window currently resides.
  840. ///
  841. /// Returns None if current monitor can't be detected.
  842. pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
  843. self
  844. .window
  845. .dispatcher
  846. .current_monitor()
  847. .map(|m| m.map(Into::into))
  848. .map_err(Into::into)
  849. }
  850. /// Returns the primary monitor of the system.
  851. ///
  852. /// Returns None if it can't identify any monitor as a primary one.
  853. pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
  854. self
  855. .window
  856. .dispatcher
  857. .primary_monitor()
  858. .map(|m| m.map(Into::into))
  859. .map_err(Into::into)
  860. }
  861. /// Returns the list of all the monitors available on the system.
  862. pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
  863. self
  864. .window
  865. .dispatcher
  866. .available_monitors()
  867. .map(|m| m.into_iter().map(Into::into).collect())
  868. .map_err(Into::into)
  869. }
  870. /// Returns the native handle that is used by this window.
  871. #[cfg(target_os = "macos")]
  872. pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
  873. self
  874. .window
  875. .dispatcher
  876. .raw_window_handle()
  877. .map_err(Into::into)
  878. .and_then(|handle| {
  879. if let raw_window_handle::RawWindowHandle::AppKit(h) = handle {
  880. Ok(h.ns_window)
  881. } else {
  882. Err(crate::Error::InvalidWindowHandle)
  883. }
  884. })
  885. }
  886. /// Returns the native handle that is used by this window.
  887. #[cfg(windows)]
  888. pub fn hwnd(&self) -> crate::Result<HWND> {
  889. self
  890. .window
  891. .dispatcher
  892. .raw_window_handle()
  893. .map_err(Into::into)
  894. .and_then(|handle| {
  895. if let raw_window_handle::RawWindowHandle::Win32(h) = handle {
  896. Ok(HWND(h.hwnd as _))
  897. } else {
  898. Err(crate::Error::InvalidWindowHandle)
  899. }
  900. })
  901. }
  902. /// Returns the `ApplicationWindow` from gtk crate that is used by this window.
  903. ///
  904. /// Note that this can only be used on the main thread.
  905. #[cfg(any(
  906. target_os = "linux",
  907. target_os = "dragonfly",
  908. target_os = "freebsd",
  909. target_os = "netbsd",
  910. target_os = "openbsd"
  911. ))]
  912. pub fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow> {
  913. self.window.dispatcher.gtk_window().map_err(Into::into)
  914. }
  915. /// Returns the current window theme.
  916. ///
  917. /// ## Platform-specific
  918. ///
  919. /// - **macOS**: Only supported on macOS 10.14+.
  920. pub fn theme(&self) -> crate::Result<Theme> {
  921. self.window.dispatcher.theme().map_err(Into::into)
  922. }
  923. }
  924. /// Desktop window setters and actions.
  925. #[cfg(desktop)]
  926. impl<R: Runtime> Window<R> {
  927. /// Centers the window.
  928. pub fn center(&self) -> crate::Result<()> {
  929. self.window.dispatcher.center().map_err(Into::into)
  930. }
  931. /// Requests user attention to the window, this has no effect if the application
  932. /// is already focused. How requesting for user attention manifests is platform dependent,
  933. /// see `UserAttentionType` for details.
  934. ///
  935. /// Providing `None` will unset the request for user attention. Unsetting the request for
  936. /// user attention might not be done automatically by the WM when the window receives input.
  937. ///
  938. /// ## Platform-specific
  939. ///
  940. /// - **macOS:** `None` has no effect.
  941. /// - **Linux:** Urgency levels have the same effect.
  942. pub fn request_user_attention(
  943. &self,
  944. request_type: Option<UserAttentionType>,
  945. ) -> crate::Result<()> {
  946. self
  947. .window
  948. .dispatcher
  949. .request_user_attention(request_type)
  950. .map_err(Into::into)
  951. }
  952. /// Opens the dialog to prints the contents of the webview.
  953. /// Currently only supported on macOS on `wry`.
  954. /// `window.print()` works on all platforms.
  955. pub fn print(&self) -> crate::Result<()> {
  956. self.window.dispatcher.print().map_err(Into::into)
  957. }
  958. /// Determines if this window should be resizable.
  959. pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
  960. self
  961. .window
  962. .dispatcher
  963. .set_resizable(resizable)
  964. .map_err(Into::into)
  965. }
  966. /// Set this window's title.
  967. pub fn set_title(&self, title: &str) -> crate::Result<()> {
  968. self
  969. .window
  970. .dispatcher
  971. .set_title(title.to_string())
  972. .map_err(Into::into)
  973. }
  974. /// Maximizes this window.
  975. pub fn maximize(&self) -> crate::Result<()> {
  976. self.window.dispatcher.maximize().map_err(Into::into)
  977. }
  978. /// Un-maximizes this window.
  979. pub fn unmaximize(&self) -> crate::Result<()> {
  980. self.window.dispatcher.unmaximize().map_err(Into::into)
  981. }
  982. /// Minimizes this window.
  983. pub fn minimize(&self) -> crate::Result<()> {
  984. self.window.dispatcher.minimize().map_err(Into::into)
  985. }
  986. /// Un-minimizes this window.
  987. pub fn unminimize(&self) -> crate::Result<()> {
  988. self.window.dispatcher.unminimize().map_err(Into::into)
  989. }
  990. /// Show this window.
  991. pub fn show(&self) -> crate::Result<()> {
  992. self.window.dispatcher.show().map_err(Into::into)
  993. }
  994. /// Hide this window.
  995. pub fn hide(&self) -> crate::Result<()> {
  996. self.window.dispatcher.hide().map_err(Into::into)
  997. }
  998. /// Closes this window.
  999. /// # Panics
  1000. ///
  1001. /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure.
  1002. /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure.
  1003. ///
  1004. /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic.
  1005. pub fn close(&self) -> crate::Result<()> {
  1006. self.window.dispatcher.close().map_err(Into::into)
  1007. }
  1008. /// Determines if this window should be [decorated].
  1009. ///
  1010. /// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
  1011. pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
  1012. self
  1013. .window
  1014. .dispatcher
  1015. .set_decorations(decorations)
  1016. .map_err(Into::into)
  1017. }
  1018. /// Determines if this window should always be on top of other windows.
  1019. pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
  1020. self
  1021. .window
  1022. .dispatcher
  1023. .set_always_on_top(always_on_top)
  1024. .map_err(Into::into)
  1025. }
  1026. /// Resizes this window.
  1027. pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
  1028. self
  1029. .window
  1030. .dispatcher
  1031. .set_size(size.into())
  1032. .map_err(Into::into)
  1033. }
  1034. /// Sets this window's minimum size.
  1035. pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
  1036. self
  1037. .window
  1038. .dispatcher
  1039. .set_min_size(size.map(|s| s.into()))
  1040. .map_err(Into::into)
  1041. }
  1042. /// Sets this window's maximum size.
  1043. pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
  1044. self
  1045. .window
  1046. .dispatcher
  1047. .set_max_size(size.map(|s| s.into()))
  1048. .map_err(Into::into)
  1049. }
  1050. /// Sets this window's position.
  1051. pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
  1052. self
  1053. .window
  1054. .dispatcher
  1055. .set_position(position.into())
  1056. .map_err(Into::into)
  1057. }
  1058. /// Determines if this window should be fullscreen.
  1059. pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
  1060. self
  1061. .window
  1062. .dispatcher
  1063. .set_fullscreen(fullscreen)
  1064. .map_err(Into::into)
  1065. }
  1066. /// Bring the window to front and focus.
  1067. pub fn set_focus(&self) -> crate::Result<()> {
  1068. self.window.dispatcher.set_focus().map_err(Into::into)
  1069. }
  1070. /// Sets this window' icon.
  1071. pub fn set_icon(&self, icon: Icon) -> crate::Result<()> {
  1072. self
  1073. .window
  1074. .dispatcher
  1075. .set_icon(icon.try_into()?)
  1076. .map_err(Into::into)
  1077. }
  1078. /// Whether to show the window icon in the task bar or not.
  1079. pub fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
  1080. self
  1081. .window
  1082. .dispatcher
  1083. .set_skip_taskbar(skip)
  1084. .map_err(Into::into)
  1085. }
  1086. /// Grabs the cursor, preventing it from leaving the window.
  1087. ///
  1088. /// There's no guarantee that the cursor will be hidden. You should
  1089. /// hide it by yourself if you want so.
  1090. ///
  1091. /// ## Platform-specific
  1092. ///
  1093. /// - **Linux:** Unsupported.
  1094. /// - **macOS:** This locks the cursor in a fixed location, which looks visually awkward.
  1095. pub fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
  1096. self
  1097. .window
  1098. .dispatcher
  1099. .set_cursor_grab(grab)
  1100. .map_err(Into::into)
  1101. }
  1102. /// Modifies the cursor's visibility.
  1103. ///
  1104. /// If `false`, this will hide the cursor. If `true`, this will show the cursor.
  1105. ///
  1106. /// ## Platform-specific
  1107. ///
  1108. /// - **Windows:** The cursor is only hidden within the confines of the window.
  1109. /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
  1110. /// outside of the window.
  1111. pub fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
  1112. self
  1113. .window
  1114. .dispatcher
  1115. .set_cursor_visible(visible)
  1116. .map_err(Into::into)
  1117. }
  1118. /// Modifies the cursor icon of the window.
  1119. pub fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
  1120. self
  1121. .window
  1122. .dispatcher
  1123. .set_cursor_icon(icon)
  1124. .map_err(Into::into)
  1125. }
  1126. /// Changes the position of the cursor in window coordinates.
  1127. pub fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
  1128. self
  1129. .window
  1130. .dispatcher
  1131. .set_cursor_position(position)
  1132. .map_err(Into::into)
  1133. }
  1134. /// Ignores the window cursor events.
  1135. pub fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
  1136. self
  1137. .window
  1138. .dispatcher
  1139. .set_ignore_cursor_events(ignore)
  1140. .map_err(Into::into)
  1141. }
  1142. /// Starts dragging the window.
  1143. pub fn start_dragging(&self) -> crate::Result<()> {
  1144. self.window.dispatcher.start_dragging().map_err(Into::into)
  1145. }
  1146. }
  1147. /// Webview APIs.
  1148. impl<R: Runtime> Window<R> {
  1149. /// Handles this window receiving an [`InvokeMessage`].
  1150. pub fn on_message(self, payload: InvokePayload) -> crate::Result<()> {
  1151. let manager = self.manager.clone();
  1152. match payload.cmd.as_str() {
  1153. "__initialized" => {
  1154. let payload: PageLoadPayload = serde_json::from_value(payload.inner)?;
  1155. manager.run_on_page_load(self, payload);
  1156. }
  1157. _ => {
  1158. let message = InvokeMessage::new(
  1159. self.clone(),
  1160. manager.state(),
  1161. payload.cmd.to_string(),
  1162. payload.inner,
  1163. );
  1164. let resolver = InvokeResolver::new(self, payload.callback, payload.error);
  1165. let invoke = Invoke { message, resolver };
  1166. if let Some(module) = &payload.tauri_module {
  1167. crate::endpoints::handle(
  1168. module.to_string(),
  1169. invoke,
  1170. manager.config(),
  1171. manager.package_info(),
  1172. );
  1173. } else if payload.cmd.starts_with("plugin:") {
  1174. manager.extend_api(invoke);
  1175. } else {
  1176. manager.run_invoke_handler(invoke);
  1177. }
  1178. }
  1179. }
  1180. Ok(())
  1181. }
  1182. /// Evaluates JavaScript on this window.
  1183. pub fn eval(&self, js: &str) -> crate::Result<()> {
  1184. self.window.dispatcher.eval_script(js).map_err(Into::into)
  1185. }
  1186. pub(crate) fn register_js_listener(&self, window_label: Option<String>, event: String, id: u64) {
  1187. self
  1188. .window
  1189. .js_event_listeners
  1190. .lock()
  1191. .unwrap()
  1192. .entry(JsEventListenerKey {
  1193. window_label,
  1194. event,
  1195. })
  1196. .or_insert_with(Default::default)
  1197. .insert(id);
  1198. }
  1199. pub(crate) fn unregister_js_listener(&self, id: u64) {
  1200. let mut empty = None;
  1201. let mut js_listeners = self.window.js_event_listeners.lock().unwrap();
  1202. let iter = js_listeners.iter_mut();
  1203. for (key, ids) in iter {
  1204. if ids.contains(&id) {
  1205. ids.remove(&id);
  1206. if ids.is_empty() {
  1207. empty.replace(key.clone());
  1208. }
  1209. break;
  1210. }
  1211. }
  1212. if let Some(key) = empty {
  1213. js_listeners.remove(&key);
  1214. }
  1215. }
  1216. /// Whether this window registered a listener to an event from the given window and event name.
  1217. pub(crate) fn has_js_listener(&self, window_label: Option<String>, event: &str) -> bool {
  1218. self
  1219. .window
  1220. .js_event_listeners
  1221. .lock()
  1222. .unwrap()
  1223. .contains_key(&JsEventListenerKey {
  1224. window_label,
  1225. event: event.into(),
  1226. })
  1227. }
  1228. /// Opens the developer tools window (Web Inspector).
  1229. /// The devtools is only enabled on debug builds or with the `devtools` feature flag.
  1230. ///
  1231. /// ## Platform-specific
  1232. ///
  1233. /// - **macOS:** Only supported on macOS 10.15+.
  1234. /// This is a private API on macOS, so you cannot use this if your application will be published on the App Store.
  1235. ///
  1236. /// # Examples
  1237. ///
  1238. /// ```rust,no_run
  1239. /// use tauri::Manager;
  1240. /// tauri::Builder::default()
  1241. /// .setup(|app| {
  1242. /// #[cfg(debug_assertions)]
  1243. /// app.get_window("main").unwrap().open_devtools();
  1244. /// Ok(())
  1245. /// });
  1246. /// ```
  1247. #[cfg(any(debug_assertions, feature = "devtools"))]
  1248. #[cfg_attr(doc_cfg, doc(cfg(any(debug_assertions, feature = "devtools"))))]
  1249. pub fn open_devtools(&self) {
  1250. self.window.dispatcher.open_devtools();
  1251. }
  1252. /// Closes the developer tools window (Web Inspector).
  1253. /// The devtools is only enabled on debug builds or with the `devtools` feature flag.
  1254. ///
  1255. /// ## Platform-specific
  1256. ///
  1257. /// - **macOS:** Only supported on macOS 10.15+.
  1258. /// This is a private API on macOS, so you cannot use this if your application will be published on the App Store.
  1259. /// - **Windows:** Unsupported.
  1260. ///
  1261. /// # Examples
  1262. ///
  1263. /// ```rust,no_run
  1264. /// use tauri::Manager;
  1265. /// tauri::Builder::default()
  1266. /// .setup(|app| {
  1267. /// #[cfg(debug_assertions)]
  1268. /// {
  1269. /// let window = app.get_window("main").unwrap();
  1270. /// window.open_devtools();
  1271. /// std::thread::spawn(move || {
  1272. /// std::thread::sleep(std::time::Duration::from_secs(10));
  1273. /// window.close_devtools();
  1274. /// });
  1275. /// }
  1276. /// Ok(())
  1277. /// });
  1278. /// ```
  1279. #[cfg(any(debug_assertions, feature = "devtools"))]
  1280. #[cfg_attr(doc_cfg, doc(cfg(any(debug_assertions, feature = "devtools"))))]
  1281. pub fn close_devtools(&self) {
  1282. self.window.dispatcher.close_devtools();
  1283. }
  1284. /// Checks if the developer tools window (Web Inspector) is opened.
  1285. /// The devtools is only enabled on debug builds or with the `devtools` feature flag.
  1286. ///
  1287. /// ## Platform-specific
  1288. ///
  1289. /// - **macOS:** Only supported on macOS 10.15+.
  1290. /// This is a private API on macOS, so you cannot use this if your application will be published on the App Store.
  1291. /// - **Windows:** Unsupported.
  1292. ///
  1293. /// # Examples
  1294. ///
  1295. /// ```rust,no_run
  1296. /// use tauri::Manager;
  1297. /// tauri::Builder::default()
  1298. /// .setup(|app| {
  1299. /// #[cfg(debug_assertions)]
  1300. /// {
  1301. /// let window = app.get_window("main").unwrap();
  1302. /// if !window.is_devtools_open() {
  1303. /// window.open_devtools();
  1304. /// }
  1305. /// }
  1306. /// Ok(())
  1307. /// });
  1308. /// ```
  1309. #[cfg(any(debug_assertions, feature = "devtools"))]
  1310. #[cfg_attr(doc_cfg, doc(cfg(any(debug_assertions, feature = "devtools"))))]
  1311. pub fn is_devtools_open(&self) -> bool {
  1312. self
  1313. .window
  1314. .dispatcher
  1315. .is_devtools_open()
  1316. .unwrap_or_default()
  1317. }
  1318. }
  1319. /// Event system APIs.
  1320. impl<R: Runtime> Window<R> {
  1321. /// Emits an event to both the JavaScript and the Rust listeners.
  1322. pub fn emit_and_trigger<S: Serialize + Clone>(
  1323. &self,
  1324. event: &str,
  1325. payload: S,
  1326. ) -> crate::Result<()> {
  1327. self.trigger(event, Some(serde_json::to_string(&payload)?));
  1328. self.emit(event, payload)
  1329. }
  1330. pub(crate) fn emit_internal<S: Serialize>(
  1331. &self,
  1332. event: &str,
  1333. source_window_label: Option<&str>,
  1334. payload: S,
  1335. ) -> crate::Result<()> {
  1336. self.eval(&format!(
  1337. "window['{}']({{event: {}, windowLabel: {}, payload: {}}})",
  1338. self.manager.event_emit_function_name(),
  1339. serde_json::to_string(event)?,
  1340. serde_json::to_string(&source_window_label)?,
  1341. serde_json::to_value(payload)?,
  1342. ))?;
  1343. Ok(())
  1344. }
  1345. /// Emits an event to the JavaScript listeners on the current window.
  1346. ///
  1347. /// The event is only delivered to listeners that used the `WebviewWindow#listen` method on the @tauri-apps/api `window` module.
  1348. pub fn emit<S: Serialize + Clone>(&self, event: &str, payload: S) -> crate::Result<()> {
  1349. self
  1350. .manager
  1351. .emit_filter(event, Some(self.label()), payload, |w| {
  1352. w.has_js_listener(None, event) || w.has_js_listener(Some(self.label().into()), event)
  1353. })?;
  1354. Ok(())
  1355. }
  1356. /// Listen to an event on this window.
  1357. ///
  1358. /// This listener only receives events that are triggered using the
  1359. /// [`trigger`](Window#method.trigger) and [`emit_and_trigger`](Window#method.emit_and_trigger) methods or
  1360. /// the `appWindow.emit` function from the @tauri-apps/api `window` module.
  1361. pub fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
  1362. where
  1363. F: Fn(Event) + Send + 'static,
  1364. {
  1365. let label = self.window.label.clone();
  1366. self.manager.listen(event.into(), Some(label), handler)
  1367. }
  1368. /// Unlisten to an event on this window.
  1369. pub fn unlisten(&self, handler_id: EventHandler) {
  1370. self.manager.unlisten(handler_id)
  1371. }
  1372. /// Listen to an event on this window a single time.
  1373. pub fn once<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
  1374. where
  1375. F: FnOnce(Event) + Send + 'static,
  1376. {
  1377. let label = self.window.label.clone();
  1378. self.manager.once(event.into(), Some(label), handler)
  1379. }
  1380. /// Triggers an event to the Rust listeners on this window.
  1381. ///
  1382. /// The event is only delivered to listeners that used the [`listen`](Window#method.listen) method.
  1383. pub fn trigger(&self, event: &str, data: Option<String>) {
  1384. let label = self.window.label.clone();
  1385. self.manager.trigger(event, Some(label), data)
  1386. }
  1387. }
  1388. #[cfg(test)]
  1389. mod tests {
  1390. #[test]
  1391. fn window_is_send_sync() {
  1392. crate::test_utils::assert_send::<super::Window>();
  1393. crate::test_utils::assert_sync::<super::Window>();
  1394. }
  1395. }