1#![doc(
8 html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png",
9 html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png"
10)]
11#![warn(missing_docs, rust_2018_idioms)]
12#![allow(clippy::deprecated_semver)]
13
14use std::{
15 ffi::OsString,
16 fmt::Display,
17 path::{Path, PathBuf},
18};
19
20use semver::Version;
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22
23pub mod acl;
24pub mod assets;
25pub mod config;
26pub mod html;
27pub mod io;
28pub mod mime_type;
29pub mod platform;
30pub mod plugin;
31#[cfg(feature = "resources")]
33pub mod resources;
34#[cfg(feature = "build")]
35pub mod tokens;
36
37#[cfg(feature = "build")]
38pub mod build;
39
40pub mod pattern;
42
43#[derive(Debug, Clone)]
45pub struct PackageInfo {
46 pub name: String,
48 pub version: Version,
50 pub authors: &'static str,
52 pub description: &'static str,
54 pub crate_name: &'static str,
56}
57
58#[allow(deprecated)]
59mod window_effects {
60 use super::*;
61
62 #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
63 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
64 #[serde(rename_all = "camelCase")]
65 pub enum WindowEffect {
67 #[deprecated(
69 since = "macOS 10.14",
70 note = "You should instead choose an appropriate semantic material."
71 )]
72 AppearanceBased,
73 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
75 Light,
76 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
78 Dark,
79 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
81 MediumLight,
82 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
84 UltraDark,
85 Titlebar,
87 Selection,
89 Menu,
91 Popover,
93 Sidebar,
95 HeaderView,
97 Sheet,
99 WindowBackground,
101 HudWindow,
103 FullScreenUI,
105 Tooltip,
107 ContentBackground,
109 UnderWindowBackground,
111 UnderPageBackground,
113 Mica,
115 MicaDark,
117 MicaLight,
119 Tabbed,
121 TabbedDark,
123 TabbedLight,
125 Blur,
131 Acrylic,
137 }
138
139 #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
143 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
144 #[serde(rename_all = "camelCase")]
145 pub enum WindowEffectState {
146 FollowsWindowActiveState,
148 Active,
150 Inactive,
152 }
153}
154
155pub use window_effects::{WindowEffect, WindowEffectState};
156
157#[derive(Debug, Clone, PartialEq, Eq, Copy)]
159#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
160#[non_exhaustive]
161pub enum TitleBarStyle {
162 Visible,
164 Transparent,
168 Overlay,
175}
176
177impl Default for TitleBarStyle {
178 fn default() -> Self {
179 Self::Visible
180 }
181}
182
183impl Serialize for TitleBarStyle {
184 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
185 where
186 S: Serializer,
187 {
188 serializer.serialize_str(self.to_string().as_ref())
189 }
190}
191
192impl<'de> Deserialize<'de> for TitleBarStyle {
193 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
194 where
195 D: Deserializer<'de>,
196 {
197 let s = String::deserialize(deserializer)?;
198 Ok(match s.to_lowercase().as_str() {
199 "transparent" => Self::Transparent,
200 "overlay" => Self::Overlay,
201 _ => Self::Visible,
202 })
203 }
204}
205
206impl Display for TitleBarStyle {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 write!(
209 f,
210 "{}",
211 match self {
212 Self::Visible => "Visible",
213 Self::Transparent => "Transparent",
214 Self::Overlay => "Overlay",
215 }
216 )
217 }
218}
219
220#[derive(Debug, Copy, Clone, PartialEq, Eq)]
222#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
223#[non_exhaustive]
224pub enum Theme {
225 Light,
227 Dark,
229}
230
231impl Serialize for Theme {
232 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
233 where
234 S: Serializer,
235 {
236 serializer.serialize_str(self.to_string().as_ref())
237 }
238}
239
240impl<'de> Deserialize<'de> for Theme {
241 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
242 where
243 D: Deserializer<'de>,
244 {
245 let s = String::deserialize(deserializer)?;
246 Ok(match s.to_lowercase().as_str() {
247 "dark" => Self::Dark,
248 _ => Self::Light,
249 })
250 }
251}
252
253impl Display for Theme {
254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255 write!(
256 f,
257 "{}",
258 match self {
259 Self::Light => "light",
260 Self::Dark => "dark",
261 }
262 )
263 }
264}
265
266#[derive(Debug, Clone)]
268#[non_exhaustive]
269pub struct Env {
270 #[cfg(target_os = "linux")]
272 pub appimage: Option<std::ffi::OsString>,
273 #[cfg(target_os = "linux")]
275 pub appdir: Option<std::ffi::OsString>,
276 pub args_os: Vec<OsString>,
278}
279
280#[allow(clippy::derivable_impls)]
281impl Default for Env {
282 fn default() -> Self {
283 let args_os = std::env::args_os().collect();
284 #[cfg(target_os = "linux")]
285 {
286 let env = Self {
287 #[cfg(target_os = "linux")]
288 appimage: std::env::var_os("APPIMAGE"),
289 #[cfg(target_os = "linux")]
290 appdir: std::env::var_os("APPDIR"),
291 args_os,
292 };
293 if env.appimage.is_some() || env.appdir.is_some() {
294 let is_temp = std::env::current_exe()
299 .map(|p| {
300 p.display()
301 .to_string()
302 .starts_with(&format!("{}/.mount_", std::env::temp_dir().display()))
303 })
304 .unwrap_or(true);
305
306 if !is_temp {
307 log::warn!("`APPDIR` or `APPIMAGE` environment variable found but this application was not detected as an AppImage; this might be a security issue.");
308 }
309 }
310 env
311 }
312 #[cfg(not(target_os = "linux"))]
313 {
314 Self { args_os }
315 }
316 }
317}
318
319pub type Result<T> = std::result::Result<T, Error>;
321
322#[derive(Debug, thiserror::Error)]
324#[non_exhaustive]
325pub enum Error {
326 #[error("Unable to determine target-architecture")]
328 Architecture,
329 #[error("Unable to determine target-os")]
331 Os,
332 #[error("Unable to determine target-environment")]
334 Environment,
335 #[error("Unsupported platform for reading resources")]
337 UnsupportedPlatform,
338 #[error("Could not get parent process")]
340 ParentProcess,
341 #[error("Could not get parent PID")]
343 ParentPid,
344 #[error("Could not get child process")]
346 ChildProcess,
347 #[error("{0}")]
349 Io(#[from] std::io::Error),
350 #[error("invalid pattern `{0}`. Expected either `brownfield` or `isolation`.")]
352 InvalidPattern(String),
353 #[cfg(feature = "resources")]
355 #[error("{0}")]
356 GlobPattern(#[from] glob::PatternError),
357 #[cfg(feature = "resources")]
359 #[error("`{0}`")]
360 Glob(#[from] glob::GlobError),
361 #[cfg(feature = "resources")]
363 #[error("glob pattern {0} path not found or didn't match any files.")]
364 GlobPathNotFound(String),
365 #[cfg(feature = "resources")]
367 #[error("{0}")]
368 WalkdirError(#[from] walkdir::Error),
369 #[cfg(feature = "resources")]
371 #[error("could not walk directory `{0}`, try changing `allow_walk` to true on the `ResourcePaths` constructor.")]
372 NotAllowedToWalkDir(std::path::PathBuf),
373 #[cfg(feature = "resources")]
375 #[error("resource path `{0}` doesn't exist")]
376 ResourcePathNotFound(std::path::PathBuf),
377}
378
379pub fn display_path<P: AsRef<Path>>(p: P) -> String {
381 dunce::simplified(&p.as_ref().components().collect::<PathBuf>())
382 .display()
383 .to_string()
384}
385
386pub fn write_if_changed<P, C>(path: P, content: C) -> std::io::Result<()>
390where
391 P: AsRef<Path>,
392 C: AsRef<[u8]>,
393{
394 if let Ok(existing) = std::fs::read(&path) {
395 if existing == content.as_ref() {
396 return Ok(());
397 }
398 }
399
400 std::fs::write(path, content)
401}