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 config_v1;
27#[cfg(feature = "html-manipulation")]
28pub mod html;
29pub mod io;
30pub mod mime_type;
31pub mod platform;
32pub mod plugin;
33#[cfg(feature = "resources")]
35pub mod resources;
36#[cfg(feature = "build")]
37pub mod tokens;
38
39#[cfg(feature = "build")]
40pub mod build;
41
42pub mod pattern;
44
45#[derive(Debug, Clone)]
47pub struct PackageInfo {
48 pub name: String,
50 pub version: Version,
52 pub authors: &'static str,
54 pub description: &'static str,
56 pub crate_name: &'static str,
58}
59
60#[allow(deprecated)]
61mod window_effects {
62 use super::*;
63
64 #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
65 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
66 #[serde(rename_all = "camelCase")]
67 pub enum WindowEffect {
69 #[deprecated(
71 since = "macOS 10.14",
72 note = "You should instead choose an appropriate semantic material."
73 )]
74 AppearanceBased,
75 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
77 Light,
78 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
80 Dark,
81 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
83 MediumLight,
84 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
86 UltraDark,
87 Titlebar,
89 Selection,
91 Menu,
93 Popover,
95 Sidebar,
97 HeaderView,
99 Sheet,
101 WindowBackground,
103 HudWindow,
105 FullScreenUI,
107 Tooltip,
109 ContentBackground,
111 UnderWindowBackground,
113 UnderPageBackground,
115 Mica,
117 MicaDark,
119 MicaLight,
121 Tabbed,
123 TabbedDark,
125 TabbedLight,
127 Blur,
133 Acrylic,
139 }
140
141 #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
145 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
146 #[serde(rename_all = "camelCase")]
147 pub enum WindowEffectState {
148 FollowsWindowActiveState,
150 Active,
152 Inactive,
154 }
155}
156
157pub use window_effects::{WindowEffect, WindowEffectState};
158
159#[derive(Debug, Clone, PartialEq, Eq, Copy, Default)]
161#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
162#[non_exhaustive]
163pub enum TitleBarStyle {
164 #[default]
166 Visible,
167 Transparent,
171 Overlay,
178}
179
180impl Serialize for TitleBarStyle {
181 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
182 where
183 S: Serializer,
184 {
185 serializer.serialize_str(self.to_string().as_ref())
186 }
187}
188
189impl<'de> Deserialize<'de> for TitleBarStyle {
190 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
191 where
192 D: Deserializer<'de>,
193 {
194 let s = String::deserialize(deserializer)?;
195 Ok(match s.to_lowercase().as_str() {
196 "transparent" => Self::Transparent,
197 "overlay" => Self::Overlay,
198 _ => Self::Visible,
199 })
200 }
201}
202
203impl 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
217#[derive(Debug, Copy, Clone, PartialEq, Eq)]
219#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
220#[non_exhaustive]
221pub enum Theme {
222 Light,
224 Dark,
226}
227
228impl Serialize for Theme {
229 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
230 where
231 S: Serializer,
232 {
233 serializer.serialize_str(self.to_string().as_ref())
234 }
235}
236
237impl<'de> Deserialize<'de> for Theme {
238 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
239 where
240 D: Deserializer<'de>,
241 {
242 let s = String::deserialize(deserializer)?;
243 Ok(match s.to_lowercase().as_str() {
244 "dark" => Self::Dark,
245 _ => Self::Light,
246 })
247 }
248}
249
250impl Display for Theme {
251 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
252 write!(
253 f,
254 "{}",
255 match self {
256 Self::Light => "light",
257 Self::Dark => "dark",
258 }
259 )
260 }
261}
262
263#[derive(Debug, Clone)]
265#[non_exhaustive]
266pub struct Env {
267 #[cfg(target_os = "linux")]
269 pub appimage: Option<std::ffi::OsString>,
270 #[cfg(target_os = "linux")]
272 pub appdir: Option<std::ffi::OsString>,
273 pub args_os: Vec<OsString>,
275}
276
277#[allow(clippy::derivable_impls)]
278impl Default for Env {
279 fn default() -> Self {
280 let args_os = std::env::args_os().collect();
281 #[cfg(target_os = "linux")]
282 {
283 let env = Self {
284 #[cfg(target_os = "linux")]
285 appimage: std::env::var_os("APPIMAGE"),
286 #[cfg(target_os = "linux")]
287 appdir: std::env::var_os("APPDIR"),
288 args_os,
289 };
290 if env.appimage.is_some() || env.appdir.is_some() {
291 let is_temp = std::env::current_exe()
296 .map(|p| {
297 p.display()
298 .to_string()
299 .starts_with(&format!("{}/.mount_", std::env::temp_dir().display()))
300 })
301 .unwrap_or(true);
302
303 if !is_temp {
304 log::warn!("`APPDIR` or `APPIMAGE` environment variable found but this application was not detected as an AppImage; this might be a security issue.");
305 }
306 }
307 env
308 }
309 #[cfg(not(target_os = "linux"))]
310 {
311 Self { args_os }
312 }
313 }
314}
315
316pub type Result<T> = std::result::Result<T, Error>;
318
319#[derive(Debug, thiserror::Error)]
321#[non_exhaustive]
322pub enum Error {
323 #[error("Unable to determine target-architecture")]
325 Architecture,
326 #[error("Unable to determine target-os")]
328 Os,
329 #[error("Unable to determine target-environment")]
331 Environment,
332 #[error("Unsupported platform for reading resources")]
334 UnsupportedPlatform,
335 #[error("Could not get parent process")]
337 ParentProcess,
338 #[error("Could not get parent PID")]
340 ParentPid,
341 #[error("Could not get child process")]
343 ChildProcess,
344 #[error("{0}")]
346 Io(#[from] std::io::Error),
347 #[error("invalid pattern `{0}`. Expected either `brownfield` or `isolation`.")]
349 InvalidPattern(String),
350 #[cfg(feature = "resources")]
352 #[error("{0}")]
353 GlobPattern(#[from] glob::PatternError),
354 #[cfg(feature = "resources")]
356 #[error("`{0}`")]
357 Glob(#[from] glob::GlobError),
358 #[cfg(feature = "resources")]
360 #[error("glob pattern {0} path not found or didn't match any files.")]
361 GlobPathNotFound(String),
362 #[cfg(feature = "resources")]
364 #[error("{0}")]
365 WalkdirError(#[from] walkdir::Error),
366 #[cfg(feature = "resources")]
368 #[error("could not walk directory `{0}`, try changing `allow_walk` to true on the `ResourcePaths` constructor.")]
369 NotAllowedToWalkDir(std::path::PathBuf),
370 #[cfg(feature = "resources")]
372 #[error("resource path `{0}` doesn't exist")]
373 ResourcePathNotFound(std::path::PathBuf),
374}
375
376pub fn display_path<P: AsRef<Path>>(p: P) -> String {
378 dunce::simplified(&p.as_ref().components().collect::<PathBuf>())
379 .display()
380 .to_string()
381}
382
383pub fn write_if_changed<P, C>(path: P, content: C) -> std::io::Result<()>
387where
388 P: AsRef<Path>,
389 C: AsRef<[u8]>,
390{
391 if let Ok(existing) = std::fs::read(&path) {
392 if existing == content.as_ref() {
393 return Ok(());
394 }
395 }
396
397 std::fs::write(path, content)
398}