lib.rs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! [![](https://github.com/tauri-apps/tauri/raw/dev/.github/splash.png)](https://tauri.app)
  5. //!
  6. //! Tauri is a framework for building tiny, blazing fast binaries for all major desktop platforms.
  7. //! Developers can integrate any front-end framework that compiles to HTML, JS and CSS for building their user interface.
  8. //! The backend of the application is a rust-sourced binary with an API that the front-end can interact with.
  9. //!
  10. //! # Cargo features
  11. //!
  12. //! 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:
  13. //!
  14. //! - **wry** *(enabled by default)*: Enables the [wry](https://github.com/tauri-apps/wry) runtime. Only disable it if you want a custom runtime.
  15. //! - **test**: Enables the [`test`] module exposing unit test helpers.
  16. //! - **dox**: Internal feature to generate Rust documentation without linking on Linux.
  17. //! - **objc-exception**: Wrap each msg_send! in a @try/@catch and panics if an exception is caught, preventing Objective-C from unwinding into Rust.
  18. //! - **linux-protocol-headers**: Enables headers support for custom protocol requests on Linux. Requires webkit2gtk v2.36 or above.
  19. //! - **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.
  20. //! - **custom-protocol**: Feature managed by the Tauri CLI. When enabled, Tauri assumes a production environment instead of a development one.
  21. //! - **devtools**: Enables the developer tools (Web inspector) and [`Window::open_devtools`]. Enabled by default on debug builds.
  22. //! On macOS it uses private APIs, so you can't enable it if your app will be published to the App Store.
  23. //! - **native-tls**: Provides TLS support to connect over HTTPS.
  24. //! - **native-tls-vendored**: Compile and statically link to a vendored copy of OpenSSL.
  25. //! - **rustls-tls**: Provides TLS support to connect over HTTPS using rustls.
  26. //! - **process-relaunch-dangerous-allow-symlink-macos**: Allows the [`process::current_binary`] function to allow symlinks on macOS (this is dangerous, see the Security section in the documentation website).
  27. //! - **system-tray**: Enables application system tray API. Enabled by default if the `systemTray` config is defined on the `tauri.conf.json` file.
  28. //! - **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.
  29. //! - **window-data-url**: Enables usage of data URLs on the webview.
  30. //! - **compression** *(enabled by default): Enables asset compression. You should only disable this if you want faster compile times in release builds - it produces larger binaries.
  31. //! - **config-json5**: Adds support to JSON5 format for `tauri.conf.json`.
  32. //! - **config-toml**: Adds support to TOML format for the configuration `Tauri.toml`.
  33. //! - **icon-ico**: Adds support to set `.ico` window icons. Enables [`Icon::File`] and [`Icon::Raw`] variants.
  34. //! - **icon-png**: Adds support to set `.png` window icons. Enables [`Icon::File`] and [`Icon::Raw`] variants.
  35. //!
  36. //! ## Cargo allowlist features
  37. //!
  38. //! 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.
  39. //! These features are automatically enabled by the Tauri CLI based on the `allowlist` configuration under `tauri.conf.json`.
  40. //!
  41. //! ### Protocol allowlist
  42. //!
  43. //! - **protocol-asset**: Enables the `asset` custom protocol.
  44. #![doc(
  45. html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
  46. html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
  47. )]
  48. #![warn(missing_docs, rust_2018_idioms)]
  49. #![cfg_attr(doc_cfg, feature(doc_cfg))]
  50. /// Setups the binding that initializes an iOS plugin.
  51. #[cfg(target_os = "ios")]
  52. #[macro_export]
  53. macro_rules! ios_plugin_binding {
  54. ($fn_name: ident) => {
  55. tauri::swift_rs::swift!(fn $fn_name() -> *const ::std::ffi::c_void);
  56. }
  57. }
  58. #[cfg(target_os = "ios")]
  59. #[doc(hidden)]
  60. pub use cocoa;
  61. #[cfg(target_os = "macos")]
  62. #[doc(hidden)]
  63. pub use embed_plist;
  64. /// The Tauri error enum.
  65. pub use error::Error;
  66. use runtime_authority::RuntimeAuthority;
  67. #[cfg(target_os = "ios")]
  68. #[doc(hidden)]
  69. pub use swift_rs;
  70. #[cfg(mobile)]
  71. pub use tauri_macros::mobile_entry_point;
  72. pub use tauri_macros::{command, generate_handler};
  73. pub mod api;
  74. pub(crate) mod app;
  75. #[cfg(feature = "protocol-asset")]
  76. pub(crate) mod asset_protocol;
  77. pub mod async_runtime;
  78. pub mod command;
  79. mod error;
  80. mod event;
  81. mod hooks;
  82. mod manager;
  83. mod pattern;
  84. pub mod plugin;
  85. pub mod runtime_authority;
  86. mod vibrancy;
  87. pub mod window;
  88. use tauri_runtime as runtime;
  89. #[cfg(target_os = "ios")]
  90. mod ios;
  91. #[cfg(target_os = "android")]
  92. mod jni_helpers;
  93. /// Path APIs.
  94. pub mod path;
  95. pub mod process;
  96. /// The allowlist scopes.
  97. pub mod scope;
  98. mod state;
  99. pub use tauri_utils as utils;
  100. /// A Tauri [`Runtime`] wrapper around wry.
  101. #[cfg(feature = "wry")]
  102. #[cfg_attr(doc_cfg, doc(cfg(feature = "wry")))]
  103. pub type Wry = tauri_runtime_wry::Wry<EventLoopMessage>;
  104. #[cfg(all(feature = "wry", target_os = "android"))]
  105. #[cfg_attr(doc_cfg, doc(cfg(all(feature = "wry", target_os = "android"))))]
  106. #[doc(hidden)]
  107. #[macro_export]
  108. macro_rules! android_binding {
  109. ($domain:ident, $package:ident, $main: ident, $wry: path) => {
  110. ::tauri::wry::android_binding!($domain, $package, $main, $wry);
  111. ::tauri::wry::application::android_fn!(
  112. app_tauri,
  113. plugin,
  114. PluginManager,
  115. handlePluginResponse,
  116. [i32, JString, JString],
  117. );
  118. #[allow(non_snake_case)]
  119. pub unsafe fn handlePluginResponse(
  120. env: JNIEnv,
  121. _: JClass,
  122. id: i32,
  123. success: JString,
  124. error: JString,
  125. ) {
  126. ::tauri::handle_android_plugin_response(env, id, success, error);
  127. }
  128. };
  129. }
  130. #[cfg(all(feature = "wry", target_os = "android"))]
  131. #[doc(hidden)]
  132. pub use plugin::mobile::handle_android_plugin_response;
  133. #[cfg(all(feature = "wry", target_os = "android"))]
  134. #[doc(hidden)]
  135. pub use tauri_runtime_wry::wry;
  136. /// `Result<T, ::tauri::Error>`
  137. pub type Result<T> = std::result::Result<T, Error>;
  138. /// A task to run on the main thread.
  139. pub type SyncTask = Box<dyn FnOnce() + Send>;
  140. use serde::Serialize;
  141. use std::{collections::HashMap, fmt, sync::Arc};
  142. // Export types likely to be used by the application.
  143. pub use runtime::http;
  144. #[cfg(feature = "wry")]
  145. #[cfg_attr(doc_cfg, doc(cfg(feature = "wry")))]
  146. pub use tauri_runtime_wry::webview_version;
  147. #[cfg(target_os = "macos")]
  148. #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
  149. pub use runtime::{menu::NativeImage, ActivationPolicy};
  150. #[cfg(target_os = "macos")]
  151. pub use self::utils::TitleBarStyle;
  152. #[cfg(all(desktop, feature = "system-tray"))]
  153. #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
  154. pub use {
  155. self::app::tray::{SystemTray, SystemTrayEvent, SystemTrayHandle, SystemTrayMenuItemHandle},
  156. self::runtime::menu::{SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmenu},
  157. };
  158. pub use {
  159. self::app::WindowMenuEvent,
  160. self::event::{Event, EventHandler},
  161. self::runtime::menu::{AboutMetadata, CustomMenuItem, Menu, MenuEntry, MenuItem, Submenu},
  162. self::window::menu::MenuEvent,
  163. };
  164. pub use {
  165. self::app::{
  166. App, AppHandle, AssetResolver, Builder, CloseRequestApi, GlobalWindowEvent, RunEvent,
  167. WindowEvent,
  168. },
  169. self::hooks::{
  170. Invoke, InvokeError, InvokeHandler, InvokeMessage, InvokePayload, InvokeResolver,
  171. InvokeResponder, InvokeResponse, OnPageLoad, PageLoadPayload, SetupHook,
  172. },
  173. self::manager::Asset,
  174. self::runtime::{
  175. webview::WebviewAttributes,
  176. window::{
  177. dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size},
  178. CursorIcon, FileDropEvent,
  179. },
  180. DeviceEventFilter, RunIteration, UserAttentionType,
  181. },
  182. self::state::{State, StateManager},
  183. self::utils::{
  184. assets::Assets,
  185. config::{Config, WindowUrl},
  186. Env, PackageInfo, Theme,
  187. },
  188. self::window::{Monitor, Window, WindowBuilder},
  189. scope::*,
  190. };
  191. /// The Tauri version.
  192. pub const VERSION: &str = env!("CARGO_PKG_VERSION");
  193. #[cfg(target_os = "ios")]
  194. #[doc(hidden)]
  195. pub fn log_stdout() {
  196. use std::{
  197. ffi::CString,
  198. fs::File,
  199. io::{BufRead, BufReader},
  200. os::unix::prelude::*,
  201. thread,
  202. };
  203. let mut logpipe: [RawFd; 2] = Default::default();
  204. unsafe {
  205. libc::pipe(logpipe.as_mut_ptr());
  206. libc::dup2(logpipe[1], libc::STDOUT_FILENO);
  207. libc::dup2(logpipe[1], libc::STDERR_FILENO);
  208. }
  209. thread::spawn(move || unsafe {
  210. let file = File::from_raw_fd(logpipe[0]);
  211. let mut reader = BufReader::new(file);
  212. let mut buffer = String::new();
  213. loop {
  214. buffer.clear();
  215. if let Ok(len) = reader.read_line(&mut buffer) {
  216. if len == 0 {
  217. break;
  218. } else if let Ok(msg) = CString::new(buffer.clone())
  219. .map_err(|_| ())
  220. .and_then(|c| c.into_string().map_err(|_| ()))
  221. {
  222. log::info!("{}", msg);
  223. }
  224. }
  225. }
  226. });
  227. }
  228. /// The user event type.
  229. #[derive(Debug, Clone)]
  230. pub enum EventLoopMessage {}
  231. /// The webview runtime interface. A wrapper around [`runtime::Runtime`] with the proper user event type associated.
  232. pub trait Runtime: runtime::Runtime<EventLoopMessage> {}
  233. impl<W: runtime::Runtime<EventLoopMessage>> Runtime for W {}
  234. /// Reads the config file at compile time and generates a [`Context`] based on its content.
  235. ///
  236. /// The default config file path is a `tauri.conf.json` file inside the Cargo manifest directory of
  237. /// the crate being built.
  238. ///
  239. /// # Custom Config Path
  240. ///
  241. /// You may pass a string literal to this macro to specify a custom path for the Tauri config file.
  242. /// If the path is relative, it will be search for relative to the Cargo manifest of the compiling
  243. /// crate.
  244. ///
  245. /// # Note
  246. ///
  247. /// This macro should not be called if you are using [`tauri-build`] to generate the context from
  248. /// inside your build script as it will just cause excess computations that will be discarded. Use
  249. /// either the [`tauri-build`] method or this macro - not both.
  250. ///
  251. /// [`tauri-build`]: https://docs.rs/tauri-build
  252. pub use tauri_macros::generate_context;
  253. /// Include a [`Context`] that was generated by [`tauri-build`] inside your build script.
  254. ///
  255. /// You should either use [`tauri-build`] and this macro to include the compile time generated code,
  256. /// or [`generate_context!`]. Do not use both at the same time, as they generate the same code and
  257. /// will cause excess computations that will be discarded.
  258. ///
  259. /// [`tauri-build`]: https://docs.rs/tauri-build
  260. #[macro_export]
  261. macro_rules! tauri_build_context {
  262. () => {
  263. include!(concat!(env!("OUT_DIR"), "/tauri-build-context.rs"))
  264. };
  265. }
  266. pub use pattern::Pattern;
  267. /// A icon definition.
  268. #[derive(Debug, Clone)]
  269. #[non_exhaustive]
  270. pub enum Icon {
  271. /// Icon from file path.
  272. #[cfg(any(feature = "icon-ico", feature = "icon-png"))]
  273. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "icon-ico", feature = "icon-png"))))]
  274. File(std::path::PathBuf),
  275. /// Icon from raw RGBA bytes. Width and height is parsed at runtime.
  276. #[cfg(any(feature = "icon-ico", feature = "icon-png"))]
  277. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "icon-ico", feature = "icon-png"))))]
  278. Raw(Vec<u8>),
  279. /// Icon from raw RGBA bytes.
  280. Rgba {
  281. /// RGBA bytes of the icon image.
  282. rgba: Vec<u8>,
  283. /// Icon width.
  284. width: u32,
  285. /// Icon height.
  286. height: u32,
  287. },
  288. }
  289. impl TryFrom<Icon> for runtime::Icon {
  290. type Error = Error;
  291. fn try_from(icon: Icon) -> Result<Self> {
  292. #[allow(irrefutable_let_patterns)]
  293. if let Icon::Rgba {
  294. rgba,
  295. width,
  296. height,
  297. } = icon
  298. {
  299. Ok(Self {
  300. rgba,
  301. width,
  302. height,
  303. })
  304. } else {
  305. #[cfg(not(any(feature = "icon-ico", feature = "icon-png")))]
  306. panic!("unexpected Icon variant");
  307. #[cfg(any(feature = "icon-ico", feature = "icon-png"))]
  308. {
  309. let bytes = match icon {
  310. Icon::File(p) => std::fs::read(p)?,
  311. Icon::Raw(r) => r,
  312. Icon::Rgba { .. } => unreachable!(),
  313. };
  314. let extension = infer::get(&bytes)
  315. .expect("could not determine icon extension")
  316. .extension();
  317. match extension {
  318. #[cfg(feature = "icon-ico")]
  319. "ico" => {
  320. let icon_dir = ico::IconDir::read(std::io::Cursor::new(bytes))?;
  321. let entry = &icon_dir.entries()[0];
  322. Ok(Self {
  323. rgba: entry.decode()?.rgba_data().to_vec(),
  324. width: entry.width(),
  325. height: entry.height(),
  326. })
  327. }
  328. #[cfg(feature = "icon-png")]
  329. "png" => {
  330. let decoder = png::Decoder::new(std::io::Cursor::new(bytes));
  331. let mut reader = decoder.read_info()?;
  332. let mut buffer = Vec::new();
  333. while let Ok(Some(row)) = reader.next_row() {
  334. buffer.extend(row.data());
  335. }
  336. Ok(Self {
  337. rgba: buffer,
  338. width: reader.info().width,
  339. height: reader.info().height,
  340. })
  341. }
  342. _ => panic!(
  343. "image `{extension}` extension not supported; please file a Tauri feature request. `png` or `ico` icons are supported with the `icon-png` and `icon-ico` feature flags"
  344. ),
  345. }
  346. }
  347. }
  348. }
  349. }
  350. /// User supplied data required inside of a Tauri application.
  351. ///
  352. /// # Stability
  353. /// This is the output of the [`generate_context`] macro, and is not considered part of the stable API.
  354. /// Unless you know what you are doing and are prepared for this type to have breaking changes, do not create it yourself.
  355. pub struct Context<A: Assets> {
  356. pub(crate) config: Config,
  357. pub(crate) assets: Arc<A>,
  358. pub(crate) default_window_icon: Option<Icon>,
  359. pub(crate) app_icon: Option<Vec<u8>>,
  360. #[cfg(desktop)]
  361. pub(crate) system_tray_icon: Option<Icon>,
  362. pub(crate) package_info: PackageInfo,
  363. pub(crate) _info_plist: (),
  364. pub(crate) pattern: Pattern,
  365. pub(crate) runtime_authority: RuntimeAuthority,
  366. }
  367. impl<A: Assets> fmt::Debug for Context<A> {
  368. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  369. let mut d = f.debug_struct("Context");
  370. d.field("config", &self.config)
  371. .field("default_window_icon", &self.default_window_icon)
  372. .field("app_icon", &self.app_icon)
  373. .field("package_info", &self.package_info)
  374. .field("pattern", &self.pattern);
  375. #[cfg(desktop)]
  376. d.field("system_tray_icon", &self.system_tray_icon);
  377. d.finish()
  378. }
  379. }
  380. impl<A: Assets> Context<A> {
  381. /// The config the application was prepared with.
  382. #[inline(always)]
  383. pub fn config(&self) -> &Config {
  384. &self.config
  385. }
  386. /// A mutable reference to the config the application was prepared with.
  387. #[inline(always)]
  388. pub fn config_mut(&mut self) -> &mut Config {
  389. &mut self.config
  390. }
  391. /// The assets to be served directly by Tauri.
  392. #[inline(always)]
  393. pub fn assets(&self) -> Arc<A> {
  394. self.assets.clone()
  395. }
  396. /// A mutable reference to the assets to be served directly by Tauri.
  397. #[inline(always)]
  398. pub fn assets_mut(&mut self) -> &mut Arc<A> {
  399. &mut self.assets
  400. }
  401. /// The default window icon Tauri should use when creating windows.
  402. #[inline(always)]
  403. pub fn default_window_icon(&self) -> Option<&Icon> {
  404. self.default_window_icon.as_ref()
  405. }
  406. /// A mutable reference to the default window icon Tauri should use when creating windows.
  407. #[inline(always)]
  408. pub fn default_window_icon_mut(&mut self) -> &mut Option<Icon> {
  409. &mut self.default_window_icon
  410. }
  411. /// The icon to use on the system tray UI.
  412. #[cfg(desktop)]
  413. #[inline(always)]
  414. pub fn system_tray_icon(&self) -> Option<&Icon> {
  415. self.system_tray_icon.as_ref()
  416. }
  417. /// A mutable reference to the icon to use on the system tray UI.
  418. #[cfg(desktop)]
  419. #[inline(always)]
  420. pub fn system_tray_icon_mut(&mut self) -> &mut Option<Icon> {
  421. &mut self.system_tray_icon
  422. }
  423. /// Package information.
  424. #[inline(always)]
  425. pub fn package_info(&self) -> &PackageInfo {
  426. &self.package_info
  427. }
  428. /// A mutable reference to the package information.
  429. #[inline(always)]
  430. pub fn package_info_mut(&mut self) -> &mut PackageInfo {
  431. &mut self.package_info
  432. }
  433. /// The application pattern.
  434. #[inline(always)]
  435. pub fn pattern(&self) -> &Pattern {
  436. &self.pattern
  437. }
  438. /// Create a new [`Context`] from the minimal required items.
  439. #[inline(always)]
  440. #[allow(clippy::too_many_arguments)]
  441. pub fn new(
  442. config: Config,
  443. assets: Arc<A>,
  444. default_window_icon: Option<Icon>,
  445. app_icon: Option<Vec<u8>>,
  446. package_info: PackageInfo,
  447. info_plist: (),
  448. pattern: Pattern,
  449. runtime_authority: RuntimeAuthority,
  450. ) -> Self {
  451. Self {
  452. config,
  453. assets,
  454. default_window_icon,
  455. app_icon,
  456. #[cfg(desktop)]
  457. system_tray_icon: None,
  458. package_info,
  459. _info_plist: info_plist,
  460. pattern,
  461. runtime_authority,
  462. }
  463. }
  464. /// Sets the app tray icon.
  465. #[cfg(desktop)]
  466. #[inline(always)]
  467. pub fn set_system_tray_icon(&mut self, icon: Icon) {
  468. self.system_tray_icon.replace(icon);
  469. }
  470. /// Sets the app shell scope.
  471. #[cfg(shell_scope)]
  472. #[inline(always)]
  473. pub fn set_shell_scope(&mut self, scope: scope::ShellScopeConfig) {
  474. self.shell_scope = scope;
  475. }
  476. }
  477. // TODO: expand these docs
  478. /// Manages a running application.
  479. pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
  480. /// The application handle associated with this manager.
  481. fn app_handle(&self) -> AppHandle<R> {
  482. self.managed_app_handle()
  483. }
  484. /// The [`Config`] the manager was created with.
  485. fn config(&self) -> Arc<Config> {
  486. self.manager().config()
  487. }
  488. /// The [`PackageInfo`] the manager was created with.
  489. fn package_info(&self) -> &PackageInfo {
  490. self.manager().package_info()
  491. }
  492. /// Emits a event to all windows.
  493. ///
  494. /// Only the webviews receives this event.
  495. /// To trigger Rust listeners, use [`Self::trigger_global`], [`Window::trigger`] or [`Window::emit_and_trigger`].
  496. ///
  497. /// # Examples
  498. /// ```
  499. /// use tauri::Manager;
  500. ///
  501. /// #[tauri::command]
  502. /// fn synchronize(app: tauri::AppHandle) {
  503. /// // emits the synchronized event to all windows
  504. /// app.emit_all("synchronized", ());
  505. /// }
  506. /// ```
  507. fn emit_all<S: Serialize + Clone>(&self, event: &str, payload: S) -> Result<()> {
  508. self.manager().emit_filter(event, None, payload, |_| true)
  509. }
  510. /// Emits an event to the window with the specified label.
  511. ///
  512. /// # Examples
  513. /// ```
  514. /// use tauri::Manager;
  515. ///
  516. /// #[tauri::command]
  517. /// fn download(app: tauri::AppHandle) {
  518. /// for i in 1..100 {
  519. /// std::thread::sleep(std::time::Duration::from_millis(150));
  520. /// // emit a download progress event to the updater window
  521. /// app.emit_to("updater", "download-progress", i);
  522. /// }
  523. /// }
  524. /// ```
  525. fn emit_to<S: Serialize + Clone>(&self, label: &str, event: &str, payload: S) -> Result<()> {
  526. self
  527. .manager()
  528. .emit_filter(event, None, payload, |w| label == w.label())
  529. }
  530. /// Listen to a event triggered on any window ([`Window::trigger`] or [`Window::emit_and_trigger`]) or with [`Self::trigger_global`].
  531. ///
  532. /// # Examples
  533. /// ```
  534. /// use tauri::Manager;
  535. ///
  536. /// #[tauri::command]
  537. /// fn synchronize(window: tauri::Window) {
  538. /// // emits the synchronized event to all windows
  539. /// window.emit_and_trigger("synchronized", ());
  540. /// }
  541. ///
  542. /// tauri::Builder::default()
  543. /// .setup(|app| {
  544. /// app.listen_global("synchronized", |event| {
  545. /// println!("app is in sync");
  546. /// });
  547. /// Ok(())
  548. /// })
  549. /// .invoke_handler(tauri::generate_handler![synchronize]);
  550. /// ```
  551. fn listen_global<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
  552. where
  553. F: Fn(Event) + Send + 'static,
  554. {
  555. self.manager().listen(event.into(), None, handler)
  556. }
  557. /// Listen to a global event only once.
  558. ///
  559. /// See [`Self::listen_global`] for more information.
  560. fn once_global<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
  561. where
  562. F: FnOnce(Event) + Send + 'static,
  563. {
  564. self.manager().once(event.into(), None, handler)
  565. }
  566. /// Trigger a global event to Rust listeners.
  567. /// To send the events to the webview, see [`Self::emit_all`] and [`Self::emit_to`].
  568. /// To trigger listeners registed on an specific window, see [`Window::trigger`].
  569. /// To trigger all listeners, see [`Window::emit_and_trigger`].
  570. ///
  571. /// A global event does not have a source or target window attached.
  572. ///
  573. /// # Examples
  574. /// ```
  575. /// use tauri::Manager;
  576. ///
  577. /// #[tauri::command]
  578. /// fn download(app: tauri::AppHandle) {
  579. /// for i in 1..100 {
  580. /// std::thread::sleep(std::time::Duration::from_millis(150));
  581. /// // emit a download progress event to all listeners registed in Rust
  582. /// app.trigger_global("download-progress", Some(i.to_string()));
  583. /// }
  584. /// }
  585. /// ```
  586. fn trigger_global(&self, event: &str, data: Option<String>) {
  587. self.manager().trigger(event, None, data)
  588. }
  589. /// Remove an event listener.
  590. ///
  591. /// # Examples
  592. /// ```
  593. /// use tauri::Manager;
  594. ///
  595. /// tauri::Builder::default()
  596. /// .setup(|app| {
  597. /// let handle = app.handle();
  598. /// let handler = app.listen_global("ready", move |event| {
  599. /// println!("app is ready");
  600. ///
  601. /// // we no longer need to listen to the event
  602. /// // we also could have used `app.once_global` instead
  603. /// handle.unlisten(event.id());
  604. /// });
  605. ///
  606. /// // stop listening to the event when you do not need it anymore
  607. /// app.unlisten(handler);
  608. ///
  609. ///
  610. /// Ok(())
  611. /// });
  612. /// ```
  613. fn unlisten(&self, handler_id: EventHandler) {
  614. self.manager().unlisten(handler_id)
  615. }
  616. /// Fetch a single window from the manager.
  617. fn get_window(&self, label: &str) -> Option<Window<R>> {
  618. self.manager().get_window(label)
  619. }
  620. /// Fetch the focused window. Returns `None` if there is not any focused window.
  621. fn get_focused_window(&self) -> Option<Window<R>> {
  622. self.manager().get_focused_window()
  623. }
  624. /// Fetch all managed windows.
  625. fn windows(&self) -> HashMap<String, Window<R>> {
  626. self.manager().windows()
  627. }
  628. /// Add `state` to the state managed by the application.
  629. ///
  630. /// If the state for the `T` type has previously been set, the state is unchanged and false is returned. Otherwise true is returned.
  631. ///
  632. /// Managed state can be retrieved by any command handler via the
  633. /// [`State`](crate::State) guard. In particular, if a value of type `T`
  634. /// is managed by Tauri, adding `State<T>` to the list of arguments in a
  635. /// command handler instructs Tauri to retrieve the managed value.
  636. /// Additionally, [`state`](Self#method.state) can be used to retrieve the value manually.
  637. ///
  638. /// # Mutability
  639. ///
  640. /// Since the managed state is global and must be [`Send`] + [`Sync`], mutations can only happen through interior mutability:
  641. ///
  642. /// ```rust,no_run
  643. /// use std::{collections::HashMap, sync::Mutex};
  644. /// use tauri::State;
  645. /// // here we use Mutex to achieve interior mutability
  646. /// struct Storage {
  647. /// store: Mutex<HashMap<u64, String>>,
  648. /// }
  649. /// struct Connection;
  650. /// struct DbConnection {
  651. /// db: Mutex<Option<Connection>>,
  652. /// }
  653. ///
  654. /// #[tauri::command]
  655. /// fn connect(connection: State<DbConnection>) {
  656. /// // initialize the connection, mutating the state with interior mutability
  657. /// *connection.db.lock().unwrap() = Some(Connection {});
  658. /// }
  659. ///
  660. /// #[tauri::command]
  661. /// fn storage_insert(key: u64, value: String, storage: State<Storage>) {
  662. /// // mutate the storage behind the Mutex
  663. /// storage.store.lock().unwrap().insert(key, value);
  664. /// }
  665. ///
  666. /// tauri::Builder::default()
  667. /// .manage(Storage { store: Default::default() })
  668. /// .manage(DbConnection { db: Default::default() })
  669. /// .invoke_handler(tauri::generate_handler![connect, storage_insert])
  670. /// // on an actual app, remove the string argument
  671. /// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
  672. /// .expect("error while running tauri application");
  673. /// ```
  674. ///
  675. /// # Examples
  676. ///
  677. /// ```rust,no_run
  678. /// use tauri::{Manager, State};
  679. ///
  680. /// struct MyInt(isize);
  681. /// struct MyString(String);
  682. ///
  683. /// #[tauri::command]
  684. /// fn int_command(state: State<MyInt>) -> String {
  685. /// format!("The stateful int is: {}", state.0)
  686. /// }
  687. ///
  688. /// #[tauri::command]
  689. /// fn string_command<'r>(state: State<'r, MyString>) {
  690. /// println!("state: {}", state.inner().0);
  691. /// }
  692. ///
  693. /// tauri::Builder::default()
  694. /// .setup(|app| {
  695. /// app.manage(MyInt(0));
  696. /// app.manage(MyString("tauri".into()));
  697. /// // `MyInt` is already managed, so `manage()` returns false
  698. /// assert!(!app.manage(MyInt(1)));
  699. /// // read the `MyInt` managed state with the turbofish syntax
  700. /// let int = app.state::<MyInt>();
  701. /// assert_eq!(int.0, 0);
  702. /// // read the `MyString` managed state with the `State` guard
  703. /// let val: State<MyString> = app.state();
  704. /// assert_eq!(val.0, "tauri");
  705. /// Ok(())
  706. /// })
  707. /// .invoke_handler(tauri::generate_handler![int_command, string_command])
  708. /// // on an actual app, remove the string argument
  709. /// .run(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
  710. /// .expect("error while running tauri application");
  711. /// ```
  712. fn manage<T>(&self, state: T) -> bool
  713. where
  714. T: Send + Sync + 'static,
  715. {
  716. self.manager().state().set(state)
  717. }
  718. /// Retrieves the managed state for the type `T`.
  719. ///
  720. /// # Panics
  721. ///
  722. /// Panics if the state for the type `T` has not been previously [managed](Self::manage).
  723. /// Use [try_state](Self::try_state) for a non-panicking version.
  724. fn state<T>(&self) -> State<'_, T>
  725. where
  726. T: Send + Sync + 'static,
  727. {
  728. self
  729. .manager()
  730. .inner
  731. .state
  732. .try_get()
  733. .expect("state() called before manage() for given type")
  734. }
  735. /// Attempts to retrieve the managed state for the type `T`.
  736. ///
  737. /// Returns `Some` if the state has previously been [managed](Self::manage). Otherwise returns `None`.
  738. fn try_state<T>(&self) -> Option<State<'_, T>>
  739. where
  740. T: Send + Sync + 'static,
  741. {
  742. self.manager().inner.state.try_get()
  743. }
  744. /// Gets the managed [`Env`].
  745. fn env(&self) -> Env {
  746. self.state::<Env>().inner().clone()
  747. }
  748. /// Gets the scope for the IPC.
  749. fn ipc_scope(&self) -> IpcScope {
  750. self.state::<Scopes>().inner().ipc.clone()
  751. }
  752. /// Gets the scope for the asset protocol.
  753. #[cfg(feature = "protocol-asset")]
  754. fn asset_protocol_scope(&self) -> FsScope {
  755. self.state::<Scopes>().inner().asset_protocol.clone()
  756. }
  757. /// The path resolver.
  758. fn path(&self) -> &crate::path::PathResolver<R> {
  759. self.state::<crate::path::PathResolver<R>>().inner()
  760. }
  761. }
  762. /// Prevent implementation details from leaking out of the [`Manager`] trait.
  763. pub(crate) mod sealed {
  764. use super::Runtime;
  765. use crate::{app::AppHandle, manager::WindowManager};
  766. /// A running [`Runtime`] or a dispatcher to it.
  767. pub enum RuntimeOrDispatch<'r, R: Runtime> {
  768. /// Reference to the running [`Runtime`].
  769. Runtime(&'r R),
  770. /// Handle to the running [`Runtime`].
  771. RuntimeHandle(R::Handle),
  772. /// A dispatcher to the running [`Runtime`].
  773. Dispatch(R::Dispatcher),
  774. }
  775. /// Managed handle to the application runtime.
  776. pub trait ManagerBase<R: Runtime> {
  777. /// The manager behind the [`Managed`] item.
  778. fn manager(&self) -> &WindowManager<R>;
  779. fn runtime(&self) -> RuntimeOrDispatch<'_, R>;
  780. fn managed_app_handle(&self) -> AppHandle<R>;
  781. }
  782. }
  783. #[cfg(any(test, feature = "test"))]
  784. #[cfg_attr(doc_cfg, doc(cfg(feature = "test")))]
  785. pub mod test;
  786. #[cfg(test)]
  787. mod tests {
  788. use cargo_toml::Manifest;
  789. use once_cell::sync::OnceCell;
  790. use std::{env::var, fs::read_to_string, path::PathBuf};
  791. static MANIFEST: OnceCell<Manifest> = OnceCell::new();
  792. const CHECKED_FEATURES: &str = include_str!(concat!(env!("OUT_DIR"), "/checked_features"));
  793. fn get_manifest() -> &'static Manifest {
  794. MANIFEST.get_or_init(|| {
  795. let manifest_dir = PathBuf::from(var("CARGO_MANIFEST_DIR").unwrap());
  796. Manifest::from_path(manifest_dir.join("Cargo.toml")).expect("failed to parse Cargo manifest")
  797. })
  798. }
  799. #[test]
  800. fn features_are_documented() {
  801. let manifest_dir = PathBuf::from(var("CARGO_MANIFEST_DIR").unwrap());
  802. let lib_code = read_to_string(manifest_dir.join("src/lib.rs")).expect("failed to read lib.rs");
  803. for f in get_manifest().features.keys() {
  804. if !(f.starts_with("__") || f == "default" || lib_code.contains(&format!("*{f}**"))) {
  805. panic!("Feature {f} is not documented");
  806. }
  807. }
  808. }
  809. #[test]
  810. fn aliased_features_exist() {
  811. let checked_features = CHECKED_FEATURES.split(',');
  812. let manifest = get_manifest();
  813. for checked_feature in checked_features {
  814. if !manifest.features.iter().any(|(f, _)| f == checked_feature) {
  815. panic!(
  816. "Feature {checked_feature} was checked in the alias build step but it does not exist in core/tauri/Cargo.toml"
  817. );
  818. }
  819. }
  820. }
  821. }
  822. #[cfg(test)]
  823. mod test_utils {
  824. use proptest::prelude::*;
  825. pub fn assert_send<T: Send>() {}
  826. pub fn assert_sync<T: Sync>() {}
  827. #[allow(dead_code)]
  828. pub fn assert_not_allowlist_error<T>(res: anyhow::Result<T>) {
  829. if let Err(e) = res {
  830. assert!(!e.to_string().contains("not on the allowlist"));
  831. }
  832. }
  833. proptest! {
  834. #![proptest_config(ProptestConfig::with_cases(10000))]
  835. #[test]
  836. // check to see if spawn executes a function.
  837. fn check_spawn_task(task in "[a-z]+") {
  838. // create dummy task function
  839. let dummy_task = async move {
  840. format!("{task}-run-dummy-task");
  841. };
  842. // call spawn
  843. crate::async_runtime::spawn(dummy_task);
  844. }
  845. }
  846. }