lib.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. // Copyright 2019-2024 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. //! This crate contains common code that is reused in many places and offers useful utilities like parsing configuration files, detecting platform triples, injecting the CSP, and managing assets.
  7. #![doc(
  8. html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
  9. html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
  10. )]
  11. #![warn(missing_docs, rust_2018_idioms)]
  12. #![allow(clippy::deprecated_semver)]
  13. use std::{
  14. ffi::OsString,
  15. fmt::Display,
  16. path::{Path, PathBuf},
  17. };
  18. use semver::Version;
  19. use serde::{Deserialize, Deserializer, Serialize, Serializer};
  20. use log::warn;
  21. pub mod acl;
  22. pub mod assets;
  23. pub mod config;
  24. pub mod html;
  25. pub mod io;
  26. pub mod mime_type;
  27. pub mod platform;
  28. /// Prepare application resources and sidecars.
  29. #[cfg(feature = "resources")]
  30. pub mod resources;
  31. #[cfg(feature = "build")]
  32. pub mod tokens;
  33. #[cfg(feature = "build")]
  34. pub mod build;
  35. /// Application pattern.
  36. pub mod pattern;
  37. /// `tauri::App` package information.
  38. #[derive(Debug, Clone)]
  39. pub struct PackageInfo {
  40. /// App name
  41. pub name: String,
  42. /// App version
  43. pub version: Version,
  44. /// The crate authors.
  45. pub authors: &'static str,
  46. /// The crate description.
  47. pub description: &'static str,
  48. /// The crate name.
  49. pub crate_name: &'static str,
  50. }
  51. impl PackageInfo {
  52. /// Returns the application package name.
  53. /// On macOS and Windows it's the `name` field, and on Linux it's the `name` in `kebab-case`.
  54. pub fn package_name(&self) -> String {
  55. #[cfg(target_os = "linux")]
  56. {
  57. use heck::ToKebabCase;
  58. self.name.clone().to_kebab_case()
  59. }
  60. #[cfg(not(target_os = "linux"))]
  61. self.name.clone()
  62. }
  63. }
  64. #[allow(deprecated)]
  65. mod window_effects {
  66. use super::*;
  67. #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
  68. #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
  69. #[serde(rename_all = "camelCase")]
  70. /// Platform-specific window effects
  71. pub enum WindowEffect {
  72. /// A default material appropriate for the view's effectiveAppearance. **macOS 10.14-**
  73. #[deprecated(
  74. since = "macOS 10.14",
  75. note = "You should instead choose an appropriate semantic material."
  76. )]
  77. AppearanceBased,
  78. /// **macOS 10.14-**
  79. #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
  80. Light,
  81. /// **macOS 10.14-**
  82. #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
  83. Dark,
  84. /// **macOS 10.14-**
  85. #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
  86. MediumLight,
  87. /// **macOS 10.14-**
  88. #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
  89. UltraDark,
  90. /// **macOS 10.10+**
  91. Titlebar,
  92. /// **macOS 10.10+**
  93. Selection,
  94. /// **macOS 10.11+**
  95. Menu,
  96. /// **macOS 10.11+**
  97. Popover,
  98. /// **macOS 10.11+**
  99. Sidebar,
  100. /// **macOS 10.14+**
  101. HeaderView,
  102. /// **macOS 10.14+**
  103. Sheet,
  104. /// **macOS 10.14+**
  105. WindowBackground,
  106. /// **macOS 10.14+**
  107. HudWindow,
  108. /// **macOS 10.14+**
  109. FullScreenUI,
  110. /// **macOS 10.14+**
  111. Tooltip,
  112. /// **macOS 10.14+**
  113. ContentBackground,
  114. /// **macOS 10.14+**
  115. UnderWindowBackground,
  116. /// **macOS 10.14+**
  117. UnderPageBackground,
  118. /// Mica effect that matches the system dark perefence **Windows 11 Only**
  119. Mica,
  120. /// Mica effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only**
  121. MicaDark,
  122. /// Mica effect with light mode **Windows 11 Only**
  123. MicaLight,
  124. /// Tabbed effect that matches the system dark perefence **Windows 11 Only**
  125. Tabbed,
  126. /// Tabbed effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only**
  127. TabbedDark,
  128. /// Tabbed effect with light mode **Windows 11 Only**
  129. TabbedLight,
  130. /// **Windows 7/10/11(22H1) Only**
  131. ///
  132. /// ## Notes
  133. ///
  134. /// This effect has bad performance when resizing/dragging the window on Windows 11 build 22621.
  135. Blur,
  136. /// **Windows 10/11 Only**
  137. ///
  138. /// ## Notes
  139. ///
  140. /// This effect has bad performance when resizing/dragging the window on Windows 10 v1903+ and Windows 11 build 22000.
  141. Acrylic,
  142. }
  143. /// Window effect state **macOS only**
  144. ///
  145. /// <https://developer.apple.com/documentation/appkit/nsvisualeffectview/state>
  146. #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
  147. #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
  148. #[serde(rename_all = "camelCase")]
  149. pub enum WindowEffectState {
  150. /// Make window effect state follow the window's active state
  151. FollowsWindowActiveState,
  152. /// Make window effect state always active
  153. Active,
  154. /// Make window effect state always inactive
  155. Inactive,
  156. }
  157. }
  158. pub use window_effects::{WindowEffect, WindowEffectState};
  159. /// How the window title bar should be displayed on macOS.
  160. #[derive(Debug, Clone, PartialEq, Eq, Copy)]
  161. #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
  162. pub enum TitleBarStyle {
  163. /// A normal title bar.
  164. Visible,
  165. /// Makes the title bar transparent, so the window background color is shown instead.
  166. ///
  167. /// Useful if you don't need to have actual HTML under the title bar. This lets you avoid the caveats of using `TitleBarStyle::Overlay`. Will be more useful when Tauri lets you set a custom window background color.
  168. Transparent,
  169. /// Shows the title bar as a transparent overlay over the window's content.
  170. ///
  171. /// Keep in mind:
  172. /// - The height of the title bar is different on different OS versions, which can lead to window the controls and title not being where you don't expect.
  173. /// - You need to define a custom drag region to make your window draggable, however due to a limitation you can't drag the window when it's not in focus <https://github.com/tauri-apps/tauri/issues/4316>.
  174. /// - The color of the window title depends on the system theme.
  175. Overlay,
  176. }
  177. impl Default for TitleBarStyle {
  178. fn default() -> Self {
  179. Self::Visible
  180. }
  181. }
  182. impl Serialize for TitleBarStyle {
  183. fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
  184. where
  185. S: Serializer,
  186. {
  187. serializer.serialize_str(self.to_string().as_ref())
  188. }
  189. }
  190. impl<'de> Deserialize<'de> for TitleBarStyle {
  191. fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
  192. where
  193. D: Deserializer<'de>,
  194. {
  195. let s = String::deserialize(deserializer)?;
  196. Ok(match s.to_lowercase().as_str() {
  197. "transparent" => Self::Transparent,
  198. "overlay" => Self::Overlay,
  199. _ => Self::Visible,
  200. })
  201. }
  202. }
  203. impl Display for TitleBarStyle {
  204. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  205. write!(
  206. f,
  207. "{}",
  208. match self {
  209. Self::Visible => "Visible",
  210. Self::Transparent => "Transparent",
  211. Self::Overlay => "Overlay",
  212. }
  213. )
  214. }
  215. }
  216. /// System theme.
  217. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  218. #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
  219. #[non_exhaustive]
  220. pub enum Theme {
  221. /// Light theme.
  222. Light,
  223. /// Dark theme.
  224. Dark,
  225. }
  226. impl Serialize for Theme {
  227. fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
  228. where
  229. S: Serializer,
  230. {
  231. serializer.serialize_str(self.to_string().as_ref())
  232. }
  233. }
  234. impl<'de> Deserialize<'de> for Theme {
  235. fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
  236. where
  237. D: Deserializer<'de>,
  238. {
  239. let s = String::deserialize(deserializer)?;
  240. Ok(match s.to_lowercase().as_str() {
  241. "dark" => Self::Dark,
  242. _ => Self::Light,
  243. })
  244. }
  245. }
  246. impl Display for Theme {
  247. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  248. write!(
  249. f,
  250. "{}",
  251. match self {
  252. Self::Light => "light",
  253. Self::Dark => "dark",
  254. }
  255. )
  256. }
  257. }
  258. /// Information about environment variables.
  259. #[derive(Debug, Clone)]
  260. #[non_exhaustive]
  261. pub struct Env {
  262. /// The APPIMAGE environment variable.
  263. #[cfg(target_os = "linux")]
  264. pub appimage: Option<std::ffi::OsString>,
  265. /// The APPDIR environment variable.
  266. #[cfg(target_os = "linux")]
  267. pub appdir: Option<std::ffi::OsString>,
  268. /// The command line arguments of the current process.
  269. pub args_os: Vec<OsString>,
  270. }
  271. #[allow(clippy::derivable_impls)]
  272. impl Default for Env {
  273. fn default() -> Self {
  274. let args_os = std::env::args_os().skip(1).collect();
  275. #[cfg(target_os = "linux")]
  276. {
  277. let env = Self {
  278. #[cfg(target_os = "linux")]
  279. appimage: std::env::var_os("APPIMAGE"),
  280. #[cfg(target_os = "linux")]
  281. appdir: std::env::var_os("APPDIR"),
  282. args_os,
  283. };
  284. if env.appimage.is_some() || env.appdir.is_some() {
  285. // validate that we're actually running on an AppImage
  286. // an AppImage is mounted to `/$TEMPDIR/.mount_${appPrefix}${hash}`
  287. // see https://github.com/AppImage/AppImageKit/blob/1681fd84dbe09c7d9b22e13cdb16ea601aa0ec47/src/runtime.c#L501
  288. // note that it is safe to use `std::env::current_exe` here since we just loaded an AppImage.
  289. let is_temp = std::env::current_exe()
  290. .map(|p| {
  291. p.display()
  292. .to_string()
  293. .starts_with(&format!("{}/.mount_", std::env::temp_dir().display()))
  294. })
  295. .unwrap_or(true);
  296. if !is_temp {
  297. warn!("`APPDIR` or `APPIMAGE` environment variable found but this application was not detected as an AppImage; this might be a security issue.");
  298. }
  299. }
  300. env
  301. }
  302. #[cfg(not(target_os = "linux"))]
  303. {
  304. Self { args_os }
  305. }
  306. }
  307. }
  308. /// The result type of `tauri-utils`.
  309. pub type Result<T> = std::result::Result<T, Error>;
  310. /// The error type of `tauri-utils`.
  311. #[derive(Debug, thiserror::Error)]
  312. #[non_exhaustive]
  313. pub enum Error {
  314. /// Target triple architecture error
  315. #[error("Unable to determine target-architecture")]
  316. Architecture,
  317. /// Target triple OS error
  318. #[error("Unable to determine target-os")]
  319. Os,
  320. /// Target triple environment error
  321. #[error("Unable to determine target-environment")]
  322. Environment,
  323. /// Tried to get resource on an unsupported platform
  324. #[error("Unsupported platform for reading resources")]
  325. UnsupportedPlatform,
  326. /// Get parent process error
  327. #[error("Could not get parent process")]
  328. ParentProcess,
  329. /// Get parent process PID error
  330. #[error("Could not get parent PID")]
  331. ParentPid,
  332. /// Get child process error
  333. #[error("Could not get child process")]
  334. ChildProcess,
  335. /// IO error
  336. #[error("{0}")]
  337. Io(#[from] std::io::Error),
  338. /// Invalid pattern.
  339. #[error("invalid pattern `{0}`. Expected either `brownfield` or `isolation`.")]
  340. InvalidPattern(String),
  341. /// Invalid glob pattern.
  342. #[cfg(feature = "resources")]
  343. #[error("{0}")]
  344. GlobPattern(#[from] glob::PatternError),
  345. /// Failed to use glob pattern.
  346. #[cfg(feature = "resources")]
  347. #[error("`{0}`")]
  348. Glob(#[from] glob::GlobError),
  349. /// Glob pattern did not find any results.
  350. #[cfg(feature = "resources")]
  351. #[error("path matching {0} not found.")]
  352. GlobPathNotFound(String),
  353. /// Error walking directory.
  354. #[cfg(feature = "resources")]
  355. #[error("{0}")]
  356. WalkdirError(#[from] walkdir::Error),
  357. /// Not allowed to walk dir.
  358. #[cfg(feature = "resources")]
  359. #[error("could not walk directory `{0}`, try changing `allow_walk` to true on the `ResourcePaths` constructor.")]
  360. NotAllowedToWalkDir(std::path::PathBuf),
  361. }
  362. /// Suppresses the unused-variable warnings of the given inputs.
  363. ///
  364. /// This does not move any values. Instead, it just suppresses the warning by taking a
  365. /// reference to the value.
  366. #[macro_export]
  367. macro_rules! consume_unused_variable {
  368. ($($arg:expr),*) => {
  369. $(
  370. let _ = &$arg;
  371. )*
  372. ()
  373. };
  374. }
  375. /// Prints to the standard error, with a newline.
  376. ///
  377. /// Equivalent to the [`eprintln!`] macro, except that it's only effective for debug builds.
  378. #[macro_export]
  379. macro_rules! debug_eprintln {
  380. () => ($crate::debug_eprintln!(""));
  381. ($($arg:tt)*) => {
  382. #[cfg(debug_assertions)]
  383. eprintln!($($arg)*);
  384. #[cfg(not(debug_assertions))]
  385. $crate::consume_unused_variable!($($arg)*);
  386. };
  387. }
  388. /// Reconstructs a path from its components using the platform separator then converts it to String and removes UNC prefixes on Windows if it exists.
  389. pub fn display_path<P: AsRef<Path>>(p: P) -> String {
  390. dunce::simplified(&p.as_ref().components().collect::<PathBuf>())
  391. .display()
  392. .to_string()
  393. }