window.rs 60 KB

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