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)]
161#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
162#[non_exhaustive]
163pub enum TitleBarStyle {
164 Visible,
166 Transparent,
170 Overlay,
177}
178
179impl Default for TitleBarStyle {
180 fn default() -> Self {
181 Self::Visible
182 }
183}
184
185impl Serialize for TitleBarStyle {
186 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
187 where
188 S: Serializer,
189 {
190 serializer.serialize_str(self.to_string().as_ref())
191 }
192}
193
194impl<'de> Deserialize<'de> for TitleBarStyle {
195 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
196 where
197 D: Deserializer<'de>,
198 {
199 let s = String::deserialize(deserializer)?;
200 Ok(match s.to_lowercase().as_str() {
201 "transparent" => Self::Transparent,
202 "overlay" => Self::Overlay,
203 _ => Self::Visible,
204 })
205 }
206}
207
208impl Display for TitleBarStyle {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 write!(
211 f,
212 "{}",
213 match self {
214 Self::Visible => "Visible",
215 Self::Transparent => "Transparent",
216 Self::Overlay => "Overlay",
217 }
218 )
219 }
220}
221
222#[derive(Debug, Copy, Clone, PartialEq, Eq)]
224#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
225#[non_exhaustive]
226pub enum Theme {
227 Light,
229 Dark,
231}
232
233impl Serialize for Theme {
234 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
235 where
236 S: Serializer,
237 {
238 serializer.serialize_str(self.to_string().as_ref())
239 }
240}
241
242impl<'de> Deserialize<'de> for Theme {
243 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
244 where
245 D: Deserializer<'de>,
246 {
247 let s = String::deserialize(deserializer)?;
248 Ok(match s.to_lowercase().as_str() {
249 "dark" => Self::Dark,
250 _ => Self::Light,
251 })
252 }
253}
254
255impl Display for Theme {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 write!(
258 f,
259 "{}",
260 match self {
261 Self::Light => "light",
262 Self::Dark => "dark",
263 }
264 )
265 }
266}
267
268#[derive(Debug, Clone)]
270#[non_exhaustive]
271pub struct Env {
272 #[cfg(target_os = "linux")]
274 pub appimage: Option<std::ffi::OsString>,
275 #[cfg(target_os = "linux")]
277 pub appdir: Option<std::ffi::OsString>,
278 pub args_os: Vec<OsString>,
280}
281
282#[allow(clippy::derivable_impls)]
283impl Default for Env {
284 fn default() -> Self {
285 let args_os = std::env::args_os().collect();
286 #[cfg(target_os = "linux")]
287 {
288 let env = Self {
289 #[cfg(target_os = "linux")]
290 appimage: std::env::var_os("APPIMAGE"),
291 #[cfg(target_os = "linux")]
292 appdir: std::env::var_os("APPDIR"),
293 args_os,
294 };
295 if env.appimage.is_some() || env.appdir.is_some() {
296 let is_temp = std::env::current_exe()
301 .map(|p| {
302 p.display()
303 .to_string()
304 .starts_with(&format!("{}/.mount_", std::env::temp_dir().display()))
305 })
306 .unwrap_or(true);
307
308 if !is_temp {
309 log::warn!("`APPDIR` or `APPIMAGE` environment variable found but this application was not detected as an AppImage; this might be a security issue.");
310 }
311 }
312 env
313 }
314 #[cfg(not(target_os = "linux"))]
315 {
316 Self { args_os }
317 }
318 }
319}
320
321pub type Result<T> = std::result::Result<T, Error>;
323
324#[derive(Debug, thiserror::Error)]
326#[non_exhaustive]
327pub enum Error {
328 #[error("Unable to determine target-architecture")]
330 Architecture,
331 #[error("Unable to determine target-os")]
333 Os,
334 #[error("Unable to determine target-environment")]
336 Environment,
337 #[error("Unsupported platform for reading resources")]
339 UnsupportedPlatform,
340 #[error("Could not get parent process")]
342 ParentProcess,
343 #[error("Could not get parent PID")]
345 ParentPid,
346 #[error("Could not get child process")]
348 ChildProcess,
349 #[error("{0}")]
351 Io(#[from] std::io::Error),
352 #[error("invalid pattern `{0}`. Expected either `brownfield` or `isolation`.")]
354 InvalidPattern(String),
355 #[cfg(feature = "resources")]
357 #[error("{0}")]
358 GlobPattern(#[from] glob::PatternError),
359 #[cfg(feature = "resources")]
361 #[error("`{0}`")]
362 Glob(#[from] glob::GlobError),
363 #[cfg(feature = "resources")]
365 #[error("glob pattern {0} path not found or didn't match any files.")]
366 GlobPathNotFound(String),
367 #[cfg(feature = "resources")]
369 #[error("{0}")]
370 WalkdirError(#[from] walkdir::Error),
371 #[cfg(feature = "resources")]
373 #[error("could not walk directory `{0}`, try changing `allow_walk` to true on the `ResourcePaths` constructor.")]
374 NotAllowedToWalkDir(std::path::PathBuf),
375 #[cfg(feature = "resources")]
377 #[error("resource path `{0}` doesn't exist")]
378 ResourcePathNotFound(std::path::PathBuf),
379}
380
381pub fn display_path<P: AsRef<Path>>(p: P) -> String {
383 dunce::simplified(&p.as_ref().components().collect::<PathBuf>())
384 .display()
385 .to_string()
386}
387
388pub fn write_if_changed<P, C>(path: P, content: C) -> std::io::Result<()>
392where
393 P: AsRef<Path>,
394 C: AsRef<[u8]>,
395{
396 if let Ok(existing) = std::fs::read(&path) {
397 if existing == content.as_ref() {
398 return Ok(());
399 }
400 }
401
402 std::fs::write(path, content)
403}