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;
29#[cfg(feature = "html-manipulation-2")]
30pub mod html2;
31pub mod io;
32pub mod mime_type;
33pub mod platform;
34pub mod plugin;
35#[cfg(feature = "resources")]
37pub mod resources;
38#[cfg(any(feature = "build", feature = "build-2"))]
39pub mod tokens;
40
41#[cfg(any(feature = "build", feature = "build-2"))]
42pub mod build;
43
44pub mod pattern;
46
47#[derive(Debug, Clone)]
49pub struct PackageInfo {
50 pub name: String,
52 pub version: Version,
54 pub authors: &'static str,
56 pub description: &'static str,
58 pub crate_name: &'static str,
60}
61
62#[allow(deprecated)]
63mod window_effects {
64 use super::*;
65
66 #[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
67 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
68 #[serde(rename_all = "camelCase")]
69 pub enum WindowEffect {
71 #[deprecated(
73 since = "macOS 10.14",
74 note = "You should instead choose an appropriate semantic material."
75 )]
76 AppearanceBased,
77 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
79 Light,
80 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
82 Dark,
83 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
85 MediumLight,
86 #[deprecated(since = "macOS 10.14", note = "Use a semantic material instead.")]
88 UltraDark,
89 Titlebar,
91 Selection,
93 Menu,
95 Popover,
97 Sidebar,
99 HeaderView,
101 Sheet,
103 WindowBackground,
105 HudWindow,
107 FullScreenUI,
109 Tooltip,
111 ContentBackground,
113 UnderWindowBackground,
115 UnderPageBackground,
117 Mica,
119 MicaDark,
121 MicaLight,
123 Tabbed,
125 TabbedDark,
127 TabbedLight,
129 Blur,
135 Acrylic,
141 }
142
143 #[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 FollowsWindowActiveState,
152 Active,
154 Inactive,
156 }
157}
158
159pub use window_effects::{WindowEffect, WindowEffectState};
160
161#[derive(Debug, Clone, PartialEq, Eq, Copy, Default)]
163#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
164#[non_exhaustive]
165pub enum TitleBarStyle {
166 #[default]
168 Visible,
169 Transparent,
173 Overlay,
180}
181
182impl 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
191impl<'de> Deserialize<'de> for TitleBarStyle {
192 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
193 where
194 D: Deserializer<'de>,
195 {
196 let s = String::deserialize(deserializer)?;
197 Ok(match s.to_lowercase().as_str() {
198 "transparent" => Self::Transparent,
199 "overlay" => Self::Overlay,
200 _ => Self::Visible,
201 })
202 }
203}
204
205impl Display for TitleBarStyle {
206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207 write!(
208 f,
209 "{}",
210 match self {
211 Self::Visible => "Visible",
212 Self::Transparent => "Transparent",
213 Self::Overlay => "Overlay",
214 }
215 )
216 }
217}
218
219#[derive(Debug, Copy, Clone, PartialEq, Eq)]
221#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
222#[non_exhaustive]
223pub enum Theme {
224 Light,
226 Dark,
228}
229
230impl Serialize for Theme {
231 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
232 where
233 S: Serializer,
234 {
235 serializer.serialize_str(self.to_string().as_ref())
236 }
237}
238
239impl<'de> Deserialize<'de> for Theme {
240 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
241 where
242 D: Deserializer<'de>,
243 {
244 let s = String::deserialize(deserializer)?;
245 Ok(match s.to_lowercase().as_str() {
246 "dark" => Self::Dark,
247 _ => Self::Light,
248 })
249 }
250}
251
252impl Display for Theme {
253 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 write!(
255 f,
256 "{}",
257 match self {
258 Self::Light => "light",
259 Self::Dark => "dark",
260 }
261 )
262 }
263}
264
265#[derive(Debug, Clone)]
267#[non_exhaustive]
268pub struct Env {
269 #[cfg(target_os = "linux")]
271 pub appimage: Option<std::ffi::OsString>,
272 #[cfg(target_os = "linux")]
274 pub appdir: Option<std::ffi::OsString>,
275 pub args_os: Vec<OsString>,
277}
278
279#[allow(clippy::derivable_impls)]
280impl Default for Env {
281 fn default() -> Self {
282 let args_os = std::env::args_os().collect();
283 #[cfg(target_os = "linux")]
284 {
285 let env = Self {
286 #[cfg(target_os = "linux")]
287 appimage: std::env::var_os("APPIMAGE"),
288 #[cfg(target_os = "linux")]
289 appdir: std::env::var_os("APPDIR"),
290 args_os,
291 };
292 if env.appimage.is_some() || env.appdir.is_some() {
293 let is_temp = std::env::current_exe()
298 .map(|p| {
299 p.display()
300 .to_string()
301 .starts_with(&format!("{}/.mount_", std::env::temp_dir().display()))
302 })
303 .unwrap_or(true);
304
305 if !is_temp {
306 log::warn!("`APPDIR` or `APPIMAGE` environment variable found but this application was not detected as an AppImage; this might be a security issue.");
307 }
308 }
309 env
310 }
311 #[cfg(not(target_os = "linux"))]
312 {
313 Self { args_os }
314 }
315 }
316}
317
318pub type Result<T> = std::result::Result<T, Error>;
320
321#[derive(Debug, thiserror::Error)]
323#[non_exhaustive]
324pub enum Error {
325 #[error("Unable to determine target-architecture")]
327 Architecture,
328 #[error("Unable to determine target-os")]
330 Os,
331 #[error("Unable to determine target-environment")]
333 Environment,
334 #[error("Unsupported platform for reading resources")]
336 UnsupportedPlatform,
337 #[error("Could not get parent process")]
339 ParentProcess,
340 #[error("Could not get parent PID")]
342 ParentPid,
343 #[error("Could not get child process")]
345 ChildProcess,
346 #[error("{0}")]
348 Io(#[from] std::io::Error),
349 #[error("invalid pattern `{0}`. Expected either `brownfield` or `isolation`.")]
351 InvalidPattern(String),
352 #[cfg(feature = "resources")]
354 #[error("{0}")]
355 GlobPattern(#[from] glob::PatternError),
356 #[cfg(feature = "resources")]
358 #[error("`{0}`")]
359 Glob(#[from] glob::GlobError),
360 #[cfg(feature = "resources")]
362 #[error("glob pattern {0} path not found or didn't match any files.")]
363 GlobPathNotFound(String),
364 #[cfg(feature = "resources")]
366 #[error("{0}")]
367 WalkdirError(#[from] walkdir::Error),
368 #[cfg(feature = "resources")]
370 #[error("could not walk directory `{0}`, try changing `allow_walk` to true on the `ResourcePaths` constructor.")]
371 NotAllowedToWalkDir(std::path::PathBuf),
372 #[cfg(feature = "resources")]
374 #[error("resource path `{0}` doesn't exist")]
375 ResourcePathNotFound(std::path::PathBuf),
376}
377
378pub fn display_path<P: AsRef<Path>>(p: P) -> String {
380 dunce::simplified(&p.as_ref().components().collect::<PathBuf>())
381 .display()
382 .to_string()
383}
384
385pub fn write_if_changed<P, C>(path: P, content: C) -> std::io::Result<()>
389where
390 P: AsRef<Path>,
391 C: AsRef<[u8]>,
392{
393 if let Ok(existing) = std::fs::read(&path) {
394 if existing == content.as_ref() {
395 return Ok(());
396 }
397 }
398
399 std::fs::write(path, content)
400}