window.rs 42 KB

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