lib.rs 12 KB

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