lib.rs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! Tauri is a framework for building tiny, blazing fast binaries for all major desktop platforms.
  5. //! Developers can integrate any front-end framework that compiles to HTML, JS and CSS for building their user interface.
  6. //! The backend of the application is a rust-sourced binary with an API that the front-end can interact with.
  7. //!
  8. //! # Cargo features
  9. //!
  10. //! The following are a list of [Cargo features](https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section) that can be enabled or disabled:
  11. //!
  12. //! - **wry** *(enabled by default)*: Enables the [wry](https://github.com/tauri-apps/wry) runtime. Only disable it if you want a custom runtime.
  13. //! - **isolation**: Enables the isolation pattern. Enabled by default if the `tauri > pattern > use` config option is set to `isolation` on the `tauri.conf.json` file.
  14. //! - **custom-protocol**: Feature managed by the Tauri CLI. When enabled, Tauri assumes a production environment instead of a development one.
  15. //! - **updater**: Enables the application auto updater. Enabled by default if the `updater` config is defined on the `tauri.conf.json` file.
  16. //! - **devtools**: Enables the developer tools (Web inspector) and [`Window::open_devtools`]. Enabled by default on debug builds.
  17. //! On macOS it uses private APIs, so you can't enable it if your app will be published to the App Store.
  18. //! - **http-api**: Enables the [`api::http`] module.
  19. //! - **reqwest-client**: Uses `reqwest` as HTTP client on the `http` APIs. Improves performance, but increases the bundle size.
  20. //! - **command**: Enables the [`api::process::Command`] APIs.
  21. //! - **dialog**: Enables the [`api::dialog`] module.
  22. //! - **notification**: Enables the [`api::notification`] module.
  23. //! - **cli**: Enables usage of `clap` for CLI argument parsing. Enabled by default if the `cli` config is defined on the `tauri.conf.json` file.
  24. //! - **system-tray**: Enables application system tray API. Enabled by default if the `systemTray` config is defined on the `tauri.conf.json` file.
  25. //! - **macos-private-api**: Enables features only available in **macOS**'s private APIs, currently the `transparent` window functionality and the `fullScreenEnabled` preference setting to `true`. Enabled by default if the `tauri > macosPrivateApi` config flag is set to `true` on the `tauri.conf.json` file.
  26. //! - **window-data-url**: Enables usage of data URLs on the webview.
  27. //!
  28. //! ## Cargo allowlist features
  29. //!
  30. //! The following are a list of [Cargo features](https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section) that enables commands for Tauri's API package.
  31. //! These features are automatically enabled by the Tauri CLI based on the `allowlist` configuration under `tauri.conf.json`.
  32. //!
  33. //! - **api-all**: Enables all API endpoints.
  34. //!
  35. //! ### Clipboard allowlist
  36. //!
  37. //! - **clipboard-all**: Enables all [Clipboard APIs](https://tauri.studio/en/docs/api/js/modules/clipboard/).
  38. //! - **clipboard-read-text**: Enables the [`readText` API](https://tauri.studio/en/docs/api/js/modules/clipboard/#readtext).
  39. //! - **clipboard-write-text**: Enables the [`writeText` API](https://tauri.studio/en/docs/api/js/modules/clipboard/#writetext).
  40. //!
  41. //! ### Dialog allowlist
  42. //!
  43. //! - **dialog-all**: Enables all [Dialog APIs](https://tauri.studio/en/docs/api/js/modules/dialog).
  44. //! - **dialog-ask**: Enables the [`ask` API](https://tauri.studio/en/docs/api/js/modules/dialog#ask).
  45. //! - **dialog-confirm**: Enables the [`confirm` API](https://tauri.studio/en/docs/api/js/modules/dialog#confirm).
  46. //! - **dialog-message**: Enables the [`message` API](https://tauri.studio/en/docs/api/js/modules/dialog#message).
  47. //! - **dialog-open**: Enables the [`open` API](https://tauri.studio/en/docs/api/js/modules/dialog#open).
  48. //! - **dialog-save**: Enables the [`save` API](https://tauri.studio/en/docs/api/js/modules/dialog#save).
  49. //!
  50. //! ### Filesystem allowlist
  51. //!
  52. //! - **fs-all**: Enables all [Filesystem APIs](https://tauri.studio/en/docs/api/js/modules/fs).
  53. //! - **fs-copy-file**: Enables the [`copyFile` API](https://tauri.studio/en/docs/api/js/modules/fs#copyfile).
  54. //! - **fs-create-dir**: Enables the [`createDir` API](https://tauri.studio/en/docs/api/js/modules/fs#createdir).
  55. //! - **fs-read-dir**: Enables the [`readDir` API](https://tauri.studio/en/docs/api/js/modules/fs#readdir).
  56. //! - **fs-read-file**: Enables the [`readTextFile` API](https://tauri.studio/en/docs/api/js/modules/fs#readtextfile) and the [`readBinaryFile` API](https://tauri.studio/en/docs/api/js/modules/fs#readbinaryfile).
  57. //! - **fs-remove-dir**: Enables the [`removeDir` API](https://tauri.studio/en/docs/api/js/modules/fs#removedir).
  58. //! - **fs-remove-file**: Enables the [`removeFile` API](https://tauri.studio/en/docs/api/js/modules/fs#removefile).
  59. //! - **fs-rename-file**: Enables the [`renameFile` API](https://tauri.studio/en/docs/api/js/modules/fs#renamefile).
  60. //! - **fs-write-file**: Enables the [`writeFile` API](https://tauri.studio/en/docs/api/js/modules/fs#writefile) and the [`writeBinaryFile` API](https://tauri.studio/en/docs/api/js/modules/fs#writebinaryfile).
  61. //!
  62. //! ### Global shortcut allowlist
  63. //!
  64. //! - **global-shortcut-all**: Enables all [GlobalShortcut APIs](https://tauri.studio/en/docs/api/js/modules/globalShortcut).
  65. //!
  66. //! ### HTTP allowlist
  67. //!
  68. //! - **http-all**: Enables all [HTTP APIs](https://tauri.studio/en/docs/api/js/modules/http).
  69. //! - **http-request**: Enables the [`request` APIs](https://tauri.studio/en/docs/api/js/classes/http.client/).
  70. //!
  71. //! ### Notification allowlist
  72. //!
  73. //! - **notification-all**: Enables all [Notification APIs](https://tauri.studio/en/docs/api/js/modules/notification).
  74. //!
  75. //! ### OS allowlist
  76. //!
  77. //! - **os-all**: Enables all [OS APIs](https://tauri.studio/en/docs/api/js/modules/os).
  78. //!
  79. //! ### Path allowlist
  80. //!
  81. //! - **path-all**: Enables all [Path APIs](https://tauri.studio/en/docs/api/js/modules/path).
  82. //!
  83. //! ### Process allowlist
  84. //!
  85. //! - **process-all**: Enables all [Process APIs](https://tauri.studio/en/docs/api/js/modules/process).
  86. //! - **process-exit**: Enables the [`exit` API](https://tauri.studio/en/docs/api/js/modules/process#exit).
  87. //! - **process-relaunch**: Enables the [`relaunch` API](https://tauri.studio/en/docs/api/js/modules/process#relaunch).
  88. //!
  89. //! ### Protocol allowlist
  90. //!
  91. //! - **protocol-all**: Enables all Protocol APIs.
  92. //! - **protocol-asset**: Enables the `asset` custom protocol.
  93. //!
  94. //! ### Shell allowlist
  95. //!
  96. //! - **shell-all**: Enables all [Clipboard APIs](https://tauri.studio/en/docs/api/js/modules/shell).
  97. //! - **shell-execute**: Enables [executing arbitrary programs](https://tauri.studio/en/docs/api/js/classes/shell.Command#constructor).
  98. //! - **shell-sidecar**: Enables [executing a `sidecar` program](https://tauri.studio/en/docs/api/js/classes/shell.Command#sidecar).
  99. //! - **shell-open**: Enables the [`open` API](https://tauri.studio/en/docs/api/js/modules/shell#open).
  100. //!
  101. //! ### Window allowlist
  102. //!
  103. //! - **window-all**: Enables all [Window APIs](https://tauri.studio/en/docs/api/js/modules/window).
  104. //! - **window-create**: Enables the API used to [create new windows](https://tauri.studio/en/docs/api/js/classes/window.webviewwindow/).
  105. //! - **window-center**: Enables the [`center` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#center).
  106. //! - **window-request-user-attention**: Enables the [`requestUserAttention` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#requestuserattention).
  107. //! - **window-set-resizable**: Enables the [`setResizable` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setresizable).
  108. //! - **window-set-title**: Enables the [`setTitle` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#settitle).
  109. //! - **window-maximize**: Enables the [`maximize` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#maximize).
  110. //! - **window-unmaximize**: Enables the [`unmaximize` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#unmaximize).
  111. //! - **window-minimize**: Enables the [`minimize` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#minimize).
  112. //! - **window-unminimize**: Enables the [`unminimize` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#unminimize).
  113. //! - **window-show**: Enables the [`show` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#show).
  114. //! - **window-hide**: Enables the [`hide` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#hide).
  115. //! - **window-close**: Enables the [`close` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#close).
  116. //! - **window-set-decorations**: Enables the [`setDecorations` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setdecorations).
  117. //! - **window-set-always-on-top**: Enables the [`setAlwaysOnTop` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setalwaysontop).
  118. //! - **window-set-size**: Enables the [`setSize` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setsize).
  119. //! - **window-set-min-size**: Enables the [`setMinSize` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setminsize).
  120. //! - **window-set-max-size**: Enables the [`setMaxSize` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setmaxsize).
  121. //! - **window-set-position**: Enables the [`setPosition` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setposition).
  122. //! - **window-set-fullscreen**: Enables the [`setFullscreen` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setfullscreen).
  123. //! - **window-set-focus**: Enables the [`setFocus` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setfocus).
  124. //! - **window-set-icon**: Enables the [`setIcon` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#seticon).
  125. //! - **window-set-skip-taskbar**: Enables the [`setSkipTaskbar` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#setskiptaskbar).
  126. //! - **window-start-dragging**: Enables the [`startDragging` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#startdragging).
  127. //! - **window-print**: Enables the [`print` API](https://tauri.studio/en/docs/api/js/classes/window.WebviewWindow#print).
  128. #![warn(missing_docs, rust_2018_idioms)]
  129. #![cfg_attr(doc_cfg, feature(doc_cfg))]
  130. #[cfg(target_os = "macos")]
  131. #[doc(hidden)]
  132. pub use embed_plist;
  133. /// The Tauri error enum.
  134. pub use error::Error;
  135. #[cfg(shell_scope)]
  136. #[doc(hidden)]
  137. pub use regex;
  138. pub use tauri_macros::{command, generate_handler};
  139. pub mod api;
  140. pub(crate) mod app;
  141. pub mod async_runtime;
  142. pub mod command;
  143. /// The Tauri API endpoints.
  144. mod endpoints;
  145. mod error;
  146. mod event;
  147. mod hooks;
  148. mod manager;
  149. mod pattern;
  150. pub mod plugin;
  151. pub mod window;
  152. pub use tauri_runtime as runtime;
  153. /// The allowlist scopes.
  154. pub mod scope;
  155. pub mod settings;
  156. mod state;
  157. #[cfg(updater)]
  158. #[cfg_attr(doc_cfg, doc(cfg(feature = "updater")))]
  159. pub mod updater;
  160. pub use tauri_utils as utils;
  161. /// A Tauri [`Runtime`] wrapper around wry.
  162. #[cfg(feature = "wry")]
  163. #[cfg_attr(doc_cfg, doc(cfg(feature = "wry")))]
  164. pub type Wry = tauri_runtime_wry::Wry<EventLoopMessage>;
  165. /// `Result<T, ::tauri::Error>`
  166. pub type Result<T> = std::result::Result<T, Error>;
  167. /// A task to run on the main thread.
  168. pub type SyncTask = Box<dyn FnOnce() + Send>;
  169. use serde::Serialize;
  170. use std::{collections::HashMap, fmt, sync::Arc};
  171. // Export types likely to be used by the application.
  172. pub use runtime::http;
  173. #[cfg(target_os = "macos")]
  174. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  175. pub use runtime::{menu::NativeImage, ActivationPolicy};
  176. #[cfg(feature = "system-tray")]
  177. #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
  178. pub use {
  179. self::app::tray::{SystemTrayEvent, SystemTrayHandle},
  180. self::runtime::{
  181. menu::{SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmenu},
  182. SystemTray,
  183. },
  184. };
  185. pub use {
  186. self::app::WindowMenuEvent,
  187. self::event::{Event, EventHandler},
  188. self::runtime::menu::{CustomMenuItem, Menu, MenuEntry, MenuItem, Submenu},
  189. self::window::menu::MenuEvent,
  190. };
  191. pub use {
  192. self::app::{
  193. App, AppHandle, AssetResolver, Builder, CloseRequestApi, GlobalWindowEvent, PathResolver,
  194. RunEvent,
  195. },
  196. self::hooks::{
  197. Invoke, InvokeError, InvokeHandler, InvokeMessage, InvokePayload, InvokeResolver,
  198. InvokeResponder, InvokeResponse, OnPageLoad, PageLoadPayload, SetupHook,
  199. },
  200. self::manager::Asset,
  201. self::runtime::{
  202. webview::{WebviewAttributes, WindowBuilder},
  203. window::{
  204. dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size},
  205. FileDropEvent, WindowEvent,
  206. },
  207. ClipboardManager, GlobalShortcutManager, RunIteration, TrayIcon, UserAttentionType,
  208. },
  209. self::state::{State, StateManager},
  210. self::utils::{
  211. assets::Assets,
  212. config::{Config, WindowUrl},
  213. Env, PackageInfo,
  214. },
  215. self::window::{Monitor, Window},
  216. scope::*,
  217. };
  218. /// Updater events.
  219. #[cfg(updater)]
  220. #[cfg_attr(doc_cfg, doc(cfg(feature = "updater")))]
  221. #[derive(Debug, Clone)]
  222. pub enum UpdaterEvent {
  223. /// An update is available.
  224. UpdateAvailable {
  225. /// The update body.
  226. body: String,
  227. /// The update release date.
  228. date: String,
  229. /// The update version.
  230. version: String,
  231. },
  232. /// The update is pending.
  233. Pending,
  234. /// The update has been applied and the app is now up to date.
  235. Updated,
  236. /// The app is already up to date.
  237. AlreadyUpToDate,
  238. /// An error occurred while updating.
  239. Error(String),
  240. }
  241. #[cfg(updater)]
  242. impl UpdaterEvent {
  243. pub(crate) fn status_message(self) -> &'static str {
  244. match self {
  245. Self::Pending => updater::EVENT_STATUS_PENDING,
  246. Self::Updated => updater::EVENT_STATUS_SUCCESS,
  247. Self::AlreadyUpToDate => updater::EVENT_STATUS_UPTODATE,
  248. Self::Error(_) => updater::EVENT_STATUS_ERROR,
  249. _ => unreachable!(),
  250. }
  251. }
  252. }
  253. /// The user event type.
  254. #[derive(Debug, Clone)]
  255. pub enum EventLoopMessage {
  256. /// Updater event.
  257. #[cfg(updater)]
  258. #[cfg_attr(doc_cfg, doc(cfg(feature = "updater")))]
  259. Updater(UpdaterEvent),
  260. }
  261. /// The webview runtime interface. A wrapper around [`runtime::Runtime`] with the proper user event type associated.
  262. pub trait Runtime: runtime::Runtime<EventLoopMessage> {}
  263. impl<W: runtime::Runtime<EventLoopMessage>> Runtime for W {}
  264. /// Reads the config file at compile time and generates a [`Context`] based on its content.
  265. ///
  266. /// The default config file path is a `tauri.conf.json` file inside the Cargo manifest directory of
  267. /// the crate being built.
  268. ///
  269. /// # Custom Config Path
  270. ///
  271. /// You may pass a string literal to this macro to specify a custom path for the Tauri config file.
  272. /// If the path is relative, it will be search for relative to the Cargo manifest of the compiling
  273. /// crate.
  274. ///
  275. /// # Note
  276. ///
  277. /// This macro should not be called if you are using [`tauri-build`] to generate the context from
  278. /// inside your build script as it will just cause excess computations that will be discarded. Use
  279. /// either the [`tauri-build`] method or this macro - not both.
  280. ///
  281. /// [`tauri-build`]: https://docs.rs/tauri-build
  282. pub use tauri_macros::generate_context;
  283. /// Include a [`Context`] that was generated by [`tauri-build`] inside your build script.
  284. ///
  285. /// You should either use [`tauri-build`] and this macro to include the compile time generated code,
  286. /// or [`generate_context!`]. Do not use both at the same time, as they generate the same code and
  287. /// will cause excess computations that will be discarded.
  288. ///
  289. /// [`tauri-build`]: https://docs.rs/tauri-build
  290. #[macro_export]
  291. macro_rules! tauri_build_context {
  292. () => {
  293. include!(concat!(env!("OUT_DIR"), "/tauri-build-context.rs"))
  294. };
  295. }
  296. pub use pattern::Pattern;
  297. /// A icon definition.
  298. #[derive(Debug, Clone)]
  299. #[non_exhaustive]
  300. pub enum Icon {
  301. /// Icon from file path.
  302. #[cfg(any(feature = "icon-ico", feature = "icon-png"))]
  303. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "icon-ico", feature = "icon-png"))))]
  304. File(std::path::PathBuf),
  305. /// Icon from raw RGBA bytes. Width and height is parsed at runtime.
  306. #[cfg(any(feature = "icon-ico", feature = "icon-png"))]
  307. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "icon-ico", feature = "icon-png"))))]
  308. Raw(Vec<u8>),
  309. /// Icon from raw RGBA bytes.
  310. Rgba {
  311. /// RGBA byes of the icon image.
  312. rgba: Vec<u8>,
  313. /// Icon width.
  314. width: u32,
  315. /// Icon height.
  316. height: u32,
  317. },
  318. }
  319. impl TryFrom<Icon> for runtime::WindowIcon {
  320. type Error = Error;
  321. fn try_from(icon: Icon) -> Result<Self> {
  322. #[allow(irrefutable_let_patterns)]
  323. if let Icon::Rgba {
  324. rgba,
  325. width,
  326. height,
  327. } = icon
  328. {
  329. Ok(Self {
  330. rgba,
  331. width,
  332. height,
  333. })
  334. } else {
  335. #[cfg(not(any(feature = "icon-ico", feature = "icon-png")))]
  336. panic!("unexpected Icon variant");
  337. #[cfg(any(feature = "icon-ico", feature = "icon-png"))]
  338. {
  339. let bytes = match icon {
  340. Icon::File(p) => std::fs::read(p)?,
  341. Icon::Raw(r) => r,
  342. Icon::Rgba { .. } => unreachable!(),
  343. };
  344. let extension = infer::get(&bytes)
  345. .expect("could not determine icon extension")
  346. .extension();
  347. match extension {
  348. #[cfg(feature = "icon-ico")]
  349. "ico" => {
  350. let icon_dir = ico::IconDir::read(std::io::Cursor::new(bytes))?;
  351. let entry = &icon_dir.entries()[0];
  352. Ok(Self {
  353. rgba: entry.decode()?.rgba_data().to_vec(),
  354. width: entry.width(),
  355. height: entry.height(),
  356. })
  357. }
  358. #[cfg(feature = "icon-png")]
  359. "png" => {
  360. let decoder = png::Decoder::new(std::io::Cursor::new(bytes));
  361. let (info, mut reader) = decoder.read_info()?;
  362. let mut buffer = Vec::new();
  363. while let Ok(Some(row)) = reader.next_row() {
  364. buffer.extend(row);
  365. }
  366. Ok(Self {
  367. rgba: buffer,
  368. width: info.width,
  369. height: info.height,
  370. })
  371. }
  372. _ => panic!(
  373. "image `{}` extension not supported; please file a Tauri feature request. `png` or `ico` icons are supported with the `icon-png` and `icon-ico` feature flags",
  374. extension
  375. ),
  376. }
  377. }
  378. }
  379. }
  380. }
  381. /// User supplied data required inside of a Tauri application.
  382. ///
  383. /// # Stability
  384. /// This is the output of the [`generate_context`] macro, and is not considered part of the stable API.
  385. /// Unless you know what you are doing and are prepared for this type to have breaking changes, do not create it yourself.
  386. pub struct Context<A: Assets> {
  387. pub(crate) config: Config,
  388. pub(crate) assets: Arc<A>,
  389. pub(crate) default_window_icon: Option<Icon>,
  390. pub(crate) system_tray_icon: Option<TrayIcon>,
  391. pub(crate) package_info: PackageInfo,
  392. pub(crate) _info_plist: (),
  393. pub(crate) pattern: Pattern,
  394. #[cfg(shell_scope)]
  395. pub(crate) shell_scope: scope::ShellScopeConfig,
  396. }
  397. impl<A: Assets> fmt::Debug for Context<A> {
  398. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  399. let mut d = f.debug_struct("Context");
  400. d.field("config", &self.config)
  401. .field("default_window_icon", &self.default_window_icon)
  402. .field("system_tray_icon", &self.system_tray_icon)
  403. .field("package_info", &self.package_info)
  404. .field("pattern", &self.pattern);
  405. #[cfg(shell_scope)]
  406. d.field("shell_scope", &self.shell_scope);
  407. d.finish()
  408. }
  409. }
  410. impl<A: Assets> Context<A> {
  411. /// The config the application was prepared with.
  412. #[inline(always)]
  413. pub fn config(&self) -> &Config {
  414. &self.config
  415. }
  416. /// A mutable reference to the config the application was prepared with.
  417. #[inline(always)]
  418. pub fn config_mut(&mut self) -> &mut Config {
  419. &mut self.config
  420. }
  421. /// The assets to be served directly by Tauri.
  422. #[inline(always)]
  423. pub fn assets(&self) -> Arc<A> {
  424. self.assets.clone()
  425. }
  426. /// A mutable reference to the assets to be served directly by Tauri.
  427. #[inline(always)]
  428. pub fn assets_mut(&mut self) -> &mut Arc<A> {
  429. &mut self.assets
  430. }
  431. /// The default window icon Tauri should use when creating windows.
  432. #[inline(always)]
  433. pub fn default_window_icon(&self) -> Option<&Icon> {
  434. self.default_window_icon.as_ref()
  435. }
  436. /// A mutable reference to the default window icon Tauri should use when creating windows.
  437. #[inline(always)]
  438. pub fn default_window_icon_mut(&mut self) -> &mut Option<Icon> {
  439. &mut self.default_window_icon
  440. }
  441. /// The icon to use on the system tray UI.
  442. #[inline(always)]
  443. pub fn system_tray_icon(&self) -> Option<&TrayIcon> {
  444. self.system_tray_icon.as_ref()
  445. }
  446. /// A mutable reference to the icon to use on the system tray UI.
  447. #[inline(always)]
  448. pub fn system_tray_icon_mut(&mut self) -> &mut Option<TrayIcon> {
  449. &mut self.system_tray_icon
  450. }
  451. /// Package information.
  452. #[inline(always)]
  453. pub fn package_info(&self) -> &PackageInfo {
  454. &self.package_info
  455. }
  456. /// A mutable reference to the package information.
  457. #[inline(always)]
  458. pub fn package_info_mut(&mut self) -> &mut PackageInfo {
  459. &mut self.package_info
  460. }
  461. /// The application pattern.
  462. #[inline(always)]
  463. pub fn pattern(&self) -> &Pattern {
  464. &self.pattern
  465. }
  466. /// The scoped shell commands, where the `HashMap` key is the name each configuration.
  467. #[cfg(shell_scope)]
  468. #[inline(always)]
  469. pub fn allowed_commands(&self) -> &scope::ShellScopeConfig {
  470. &self.shell_scope
  471. }
  472. /// Create a new [`Context`] from the minimal required items.
  473. #[inline(always)]
  474. #[allow(clippy::too_many_arguments)]
  475. pub fn new(
  476. config: Config,
  477. assets: Arc<A>,
  478. default_window_icon: Option<Icon>,
  479. system_tray_icon: Option<TrayIcon>,
  480. package_info: PackageInfo,
  481. info_plist: (),
  482. pattern: Pattern,
  483. #[cfg(shell_scope)] shell_scope: scope::ShellScopeConfig,
  484. ) -> Self {
  485. Self {
  486. config,
  487. assets,
  488. default_window_icon,
  489. system_tray_icon,
  490. package_info,
  491. _info_plist: info_plist,
  492. pattern,
  493. #[cfg(shell_scope)]
  494. shell_scope,
  495. }
  496. }
  497. }
  498. // TODO: expand these docs
  499. /// Manages a running application.
  500. pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
  501. /// The application handle associated with this manager.
  502. fn app_handle(&self) -> AppHandle<R> {
  503. self.managed_app_handle()
  504. }
  505. /// The [`Config`] the manager was created with.
  506. fn config(&self) -> Arc<Config> {
  507. self.manager().config()
  508. }
  509. /// Emits a event to all windows.
  510. fn emit_all<S: Serialize + Clone>(&self, event: &str, payload: S) -> Result<()> {
  511. self.manager().emit_filter(event, None, payload, |_| true)
  512. }
  513. /// Emits an event to a window with the specified label.
  514. fn emit_to<S: Serialize + Clone>(&self, label: &str, event: &str, payload: S) -> Result<()> {
  515. self
  516. .manager()
  517. .emit_filter(event, None, payload, |w| label == w.label())
  518. }
  519. /// Listen to a global event.
  520. fn listen_global<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
  521. where
  522. F: Fn(Event) + Send + 'static,
  523. {
  524. self.manager().listen(event.into(), None, handler)
  525. }
  526. /// Listen to a global event only once.
  527. fn once_global<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
  528. where
  529. F: FnOnce(Event) + Send + 'static,
  530. {
  531. self.manager().once(event.into(), None, handler)
  532. }
  533. /// Trigger a global event.
  534. fn trigger_global(&self, event: &str, data: Option<String>) {
  535. self.manager().trigger(event, None, data)
  536. }
  537. /// Remove an event listener.
  538. fn unlisten(&self, handler_id: EventHandler) {
  539. self.manager().unlisten(handler_id)
  540. }
  541. /// Fetch a single window from the manager.
  542. fn get_window(&self, label: &str) -> Option<Window<R>> {
  543. self.manager().get_window(label)
  544. }
  545. /// Fetch all managed windows.
  546. fn windows(&self) -> HashMap<String, Window<R>> {
  547. self.manager().windows()
  548. }
  549. /// Add `state` to the state managed by the application.
  550. ///
  551. /// This method can be called any number of times as long as each call
  552. /// refers to a different `T`.
  553. /// If a state for `T` is already managed, the function returns false and the value is ignored.
  554. ///
  555. /// Managed state can be retrieved by any command handler via the
  556. /// [`State`](crate::State) guard. In particular, if a value of type `T`
  557. /// is managed by Tauri, adding `State<T>` to the list of arguments in a
  558. /// command handler instructs Tauri to retrieve the managed value.
  559. ///
  560. /// # Panics
  561. ///
  562. /// Panics if state of type `T` is already being managed.
  563. ///
  564. /// # Mutability
  565. ///
  566. /// Since the managed state is global and must be [`Send`] + [`Sync`], mutations can only happen through interior mutability:
  567. ///
  568. /// ```rust,no_run
  569. /// use std::{collections::HashMap, sync::Mutex};
  570. /// use tauri::State;
  571. /// // here we use Mutex to achieve interior mutability
  572. /// struct Storage {
  573. /// store: Mutex<HashMap<u64, String>>,
  574. /// }
  575. /// struct Connection;
  576. /// struct DbConnection {
  577. /// db: Mutex<Option<Connection>>,
  578. /// }
  579. ///
  580. /// #[tauri::command]
  581. /// fn connect(connection: State<DbConnection>) {
  582. /// // initialize the connection, mutating the state with interior mutability
  583. /// *connection.db.lock().unwrap() = Some(Connection {});
  584. /// }
  585. ///
  586. /// #[tauri::command]
  587. /// fn storage_insert(key: u64, value: String, storage: State<Storage>) {
  588. /// // mutate the storage behind the Mutex
  589. /// storage.store.lock().unwrap().insert(key, value);
  590. /// }
  591. ///
  592. /// tauri::Builder::default()
  593. /// .manage(Storage { store: Default::default() })
  594. /// .manage(DbConnection { db: Default::default() })
  595. /// .invoke_handler(tauri::generate_handler![connect, storage_insert])
  596. /// // on an actual app, remove the string argument
  597. /// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
  598. /// .expect("error while running tauri application");
  599. /// ```
  600. ///
  601. /// # Examples
  602. ///
  603. /// ```rust,no_run
  604. /// use tauri::{Manager, State};
  605. ///
  606. /// struct MyInt(isize);
  607. /// struct MyString(String);
  608. ///
  609. /// #[tauri::command]
  610. /// fn int_command(state: State<MyInt>) -> String {
  611. /// format!("The stateful int is: {}", state.0)
  612. /// }
  613. ///
  614. /// #[tauri::command]
  615. /// fn string_command<'r>(state: State<'r, MyString>) {
  616. /// println!("state: {}", state.inner().0);
  617. /// }
  618. ///
  619. /// tauri::Builder::default()
  620. /// .setup(|app| {
  621. /// app.manage(MyInt(0));
  622. /// app.manage(MyString("tauri".into()));
  623. /// // `MyInt` is already managed, so `manage()` returns false
  624. /// assert!(!app.manage(MyInt(1)));
  625. /// // read the `MyInt` managed state with the turbofish syntax
  626. /// let int = app.state::<MyInt>();
  627. /// assert_eq!(int.0, 0);
  628. /// // read the `MyString` managed state with the `State` guard
  629. /// let val: State<MyString> = app.state();
  630. /// assert_eq!(val.0, "tauri");
  631. /// Ok(())
  632. /// })
  633. /// .invoke_handler(tauri::generate_handler![int_command, string_command])
  634. /// // on an actual app, remove the string argument
  635. /// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
  636. /// .expect("error while running tauri application");
  637. /// ```
  638. fn manage<T>(&self, state: T) -> bool
  639. where
  640. T: Send + Sync + 'static,
  641. {
  642. self.manager().state().set(state)
  643. }
  644. /// Retrieves the managed state for the type `T`.
  645. ///
  646. /// # Panics
  647. ///
  648. /// Panics if the state for the type `T` has not been previously [managed](Self::manage).
  649. /// Use [try_state](Self::try_state) for a non-panicking version.
  650. fn state<T>(&self) -> State<'_, T>
  651. where
  652. T: Send + Sync + 'static,
  653. {
  654. self
  655. .manager()
  656. .inner
  657. .state
  658. .try_get()
  659. .expect("state() called before manage() for given type")
  660. }
  661. /// Attempts to retrieve the managed state for the type `T`.
  662. ///
  663. /// Returns `Some` if the state has previously been [managed](Self::manage). Otherwise returns `None`.
  664. fn try_state<T>(&self) -> Option<State<'_, T>>
  665. where
  666. T: Send + Sync + 'static,
  667. {
  668. self.manager().inner.state.try_get()
  669. }
  670. /// Gets the managed [`Env`].
  671. fn env(&self) -> Env {
  672. self.state::<Env>().inner().clone()
  673. }
  674. /// Gets the scope for the filesystem APIs.
  675. fn fs_scope(&self) -> FsScope {
  676. self.state::<Scopes>().inner().fs.clone()
  677. }
  678. /// Gets the scope for the asset protocol.
  679. #[cfg(protocol_asset)]
  680. fn asset_protocol_scope(&self) -> FsScope {
  681. self.state::<Scopes>().inner().asset_protocol.clone()
  682. }
  683. /// Gets the scope for the shell execute APIs.
  684. #[cfg(shell_scope)]
  685. fn shell_scope(&self) -> ShellScope {
  686. self.state::<Scopes>().inner().shell.clone()
  687. }
  688. }
  689. /// Prevent implementation details from leaking out of the [`Manager`] trait.
  690. pub(crate) mod sealed {
  691. use super::Runtime;
  692. use crate::{app::AppHandle, manager::WindowManager};
  693. /// A running [`Runtime`] or a dispatcher to it.
  694. pub enum RuntimeOrDispatch<'r, R: Runtime> {
  695. /// Reference to the running [`Runtime`].
  696. Runtime(&'r R),
  697. /// Handle to the running [`Runtime`].
  698. RuntimeHandle(R::Handle),
  699. /// A dispatcher to the running [`Runtime`].
  700. Dispatch(R::Dispatcher),
  701. }
  702. /// Managed handle to the application runtime.
  703. pub trait ManagerBase<R: Runtime> {
  704. /// The manager behind the [`Managed`] item.
  705. fn manager(&self) -> &WindowManager<R>;
  706. fn runtime(&self) -> RuntimeOrDispatch<'_, R>;
  707. fn managed_app_handle(&self) -> AppHandle<R>;
  708. }
  709. }
  710. /// Utilities for unit testing on Tauri applications.
  711. #[cfg(test)]
  712. pub mod test;
  713. #[cfg(test)]
  714. mod test_utils {
  715. use proptest::prelude::*;
  716. pub fn assert_send<T: Send>() {}
  717. pub fn assert_sync<T: Sync>() {}
  718. #[allow(dead_code)]
  719. pub fn assert_not_allowlist_error<T>(res: anyhow::Result<T>) {
  720. if let Err(e) = res {
  721. assert!(!e.to_string().contains("not on the allowlist"));
  722. }
  723. }
  724. proptest! {
  725. #![proptest_config(ProptestConfig::with_cases(10000))]
  726. #[test]
  727. // check to see if spawn executes a function.
  728. fn check_spawn_task(task in "[a-z]+") {
  729. // create dummy task function
  730. let dummy_task = async move {
  731. format!("{}-run-dummy-task", task);
  732. };
  733. // call spawn
  734. crate::async_runtime::spawn(dummy_task);
  735. }
  736. }
  737. }