auto_launch/lib.rs
1//! Auto launch any application or executable at startup. Supports Windows, Mac (via AppleScript or Launch Agent), and Linux.
2//!
3//! ## Usage
4//!
5//! The parameters of `AutoLaunch::new` are different on each platform.
6//! See the function definition or the demo below for details.
7//!
8//! Or you can construct the AutoLaunch by using `AutoLaunchBuilder`.
9//!
10//! ```rust
11//! # #[cfg(target_os = "linux")]
12//! # mod linux {
13//! use auto_launch::AutoLaunch;
14//!
15//! fn main() {
16//! let app_name = "the-app";
17//! let app_path = "/path/to/the-app";
18//! let args = &["--minimized"];
19//! let auto = AutoLaunch::new(app_name, app_path, args);
20//!
21//! // enable the auto launch
22//! auto.enable().is_ok();
23//! auto.is_enabled().unwrap();
24//!
25//! // disable the auto launch
26//! auto.disable().is_ok();
27//! auto.is_enabled().unwrap();
28//! }
29//! # }
30//! ```
31//!
32//! ### macOS
33//!
34//! macOS supports two ways to achieve auto launch (via AppleScript or Launch Agent).
35//! When the `use_launch_agent` is true, it will achieve by Launch Agent, otherwise by AppleScript.
36//!
37//! **Note**:
38//! - The `app_path` should be a absolute path and exists. Otherwise, it will cause an error when `enable`.
39//! - In case using AppleScript, the `app_name` should be same as the basename of `app_path`, or it will be corrected automatically.
40//!
41//! ```rust
42//! # #[cfg(target_os = "macos")]
43//! # mod macos {
44//! use auto_launch::AutoLaunch;
45//!
46//! fn main() {
47//! let app_name = "the-app";
48//! let app_path = "/path/to/the-app.app";
49//! let args = &["--minimized"];
50//! let auto = AutoLaunch::new(app_name, app_path, false, args);
51//!
52//! // enable the auto launch
53//! auto.enable().is_ok();
54//! auto.is_enabled().unwrap();
55//!
56//! // disable the auto launch
57//! auto.disable().is_ok();
58//! auto.is_enabled().unwrap();
59//! }
60//! # }
61//! ```
62//!
63//! ### Windows
64//!
65//! On Windows, it will add a registry entry under `\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run`.
66//!
67//! ```rust
68//! # #[cfg(target_os = "windows")]
69//! # mod win {
70//! use auto_launch::AutoLaunch;
71//!
72//! fn main() {
73//! let app_name = "the-app";
74//! let app_path = "C:\\path\\to\\the-app.exe";
75//! let args = &["--minimized"];
76//! let auto = AutoLaunch::new(app_name, app_path, args);
77//!
78//! // enable the auto launch
79//! auto.enable().is_ok();
80//! auto.is_enabled().unwrap();
81//!
82//! // disable the auto launch
83//! auto.disable().is_ok();
84//! auto.is_enabled().unwrap();
85//! }
86//! # }
87//! ```
88//!
89//! ### Builder
90//!
91//! AutoLaunch Builder helps to eliminate the constructor difference
92//! on various platforms.
93//!
94//! ```rust
95//! use auto_launch::*;
96//!
97//! fn main() {
98//! let auto = AutoLaunchBuilder::new()
99//! .set_app_name("the-app")
100//! .set_app_path("/path/to/the-app")
101//! .set_use_launch_agent(true)
102//! .set_args(&["--minimized"])
103//! .build()
104//! .unwrap();
105//!
106//! auto.enable().is_ok();
107//! auto.is_enabled().unwrap();
108//!
109//! auto.disable().is_ok();
110//! auto.is_enabled().unwrap();
111//! }
112//! ```
113//!
114
115#[derive(thiserror::Error, Debug)]
116pub enum Error {
117 #[error("app_name shouldn't be None")]
118 AppNameNotSpecified,
119 #[error("app_path shouldn't be None")]
120 AppPathNotSpecified,
121 #[error("app path doesn't exist: {0}")]
122 AppPathDoesntExist(std::path::PathBuf),
123 #[error("app path is not absolute: {0}")]
124 AppPathIsNotAbsolute(std::path::PathBuf),
125 #[error("Failed to execute apple script with status: {0}")]
126 AppleScriptFailed(i32),
127 #[error("Unsupported target os")]
128 UnsupportedOS,
129 #[error(transparent)]
130 Io(#[from] std::io::Error),
131}
132
133pub type Result<T> = std::result::Result<T, Error>;
134
135#[cfg(target_os = "linux")]
136mod linux;
137#[cfg(target_os = "macos")]
138mod macos;
139#[cfg(target_os = "windows")]
140mod windows;
141
142/// The parameters of `AutoLaunch::new` are different on each platform.
143///
144/// ### Linux
145///
146/// ```rust
147/// # #[cfg(target_os = "linux")]
148/// # {
149/// # use auto_launch::AutoLaunch;
150/// # let app_name = "the-app";
151/// # let app_path = "/path/to/the-app";
152/// # let args = &["--minimized"];
153/// AutoLaunch::new(app_name, app_path, args);
154/// # }
155/// ```
156///
157/// ### Macos
158///
159/// ```rust
160/// # #[cfg(target_os = "macos")]
161/// # {
162/// # use auto_launch::AutoLaunch;
163/// # let app_name = "the-app";
164/// # let app_path = "/path/to/the-app";
165/// # let use_launch_agent = false;
166/// # let args = &["--minimized"];
167/// AutoLaunch::new(app_name, app_path, use_launch_agent, args);
168/// # }
169/// ```
170///
171/// ### Windows
172///
173/// ```rust
174/// # #[cfg(target_os = "windows")]
175/// # {
176/// # use auto_launch::AutoLaunch;
177/// # let app_name = "the-app";
178/// # let app_path = "/path/to/the-app";
179/// # let args = &["--minimized"];
180/// AutoLaunch::new(app_name, app_path, args);
181/// # }
182/// ```
183#[derive(Debug, Clone, PartialEq, Eq)]
184pub struct AutoLaunch {
185 /// The application name
186 pub(crate) app_name: String,
187
188 /// The application executable path (absolute path will be better)
189 pub(crate) app_path: String,
190
191 #[cfg(target_os = "macos")]
192 /// Whether use Launch Agent for implement or use AppleScript
193 pub(crate) use_launch_agent: bool,
194
195 /// Args passed to the binary on startup
196 pub(crate) args: Vec<String>,
197}
198
199impl AutoLaunch {
200 /// check whether it is support the platform
201 ///
202 /// ## Usage
203 ///
204 /// ```rust
205 /// use auto_launch::AutoLaunch;
206 ///
207 /// dbg!(AutoLaunch::is_support());
208 /// ```
209 pub fn is_support() -> bool {
210 cfg!(any(
211 target_os = "linux",
212 target_os = "macos",
213 target_os = "windows",
214 ))
215 }
216
217 /// get the application name
218 pub fn get_app_name(&self) -> &str {
219 &self.app_name
220 }
221
222 /// get the application path
223 pub fn get_app_path(&self) -> &str {
224 &self.app_path
225 }
226
227 /// get the args
228 pub fn get_args(&self) -> &[String] {
229 &self.args
230 }
231}
232
233#[derive(Debug, Default, Clone)]
234/// AutoLaunch Builder helps to eliminate the constructor difference
235/// on various platforms.
236///
237/// ## Notes
238///
239/// The builder will not check whether the app_path matches the platform-specify file path.
240///
241/// ## Usage
242///
243/// ```rust
244/// use auto_launch::*;
245///
246/// fn main() {
247/// let auto = AutoLaunchBuilder::new()
248/// .set_app_name("the-app")
249/// .set_app_path("/path/to/the-app")
250/// .set_use_launch_agent(true)
251/// .set_args(&["--minimized"])
252/// .build()
253/// .unwrap();
254///
255/// auto.enable().is_ok();
256/// auto.is_enabled().unwrap();
257///
258/// auto.disable().is_ok();
259/// auto.is_enabled().unwrap();
260/// }
261/// ```
262pub struct AutoLaunchBuilder {
263 pub app_name: Option<String>,
264
265 pub app_path: Option<String>,
266
267 pub use_launch_agent: bool,
268
269 pub args: Option<Vec<String>>,
270}
271
272impl AutoLaunchBuilder {
273 pub fn new() -> AutoLaunchBuilder {
274 AutoLaunchBuilder::default()
275 }
276
277 /// Set the `app_name`
278 pub fn set_app_name(&mut self, name: &str) -> &mut Self {
279 self.app_name = Some(name.into());
280 self
281 }
282
283 /// Set the `app_path`
284 pub fn set_app_path(&mut self, path: &str) -> &mut Self {
285 self.app_path = Some(path.into());
286 self
287 }
288
289 /// Set the `use_launch_agent`
290 /// This setting only works on macOS
291 pub fn set_use_launch_agent(&mut self, use_launch_agent: bool) -> &mut Self {
292 self.use_launch_agent = use_launch_agent;
293 self
294 }
295
296 /// Set the args
297 pub fn set_args(&mut self, args: &[impl AsRef<str>]) -> &mut Self {
298 self.args = Some(args.iter().map(|s| s.as_ref().to_string()).collect());
299 self
300 }
301
302 /// Construct a AutoLaunch instance
303 ///
304 /// ## Errors
305 ///
306 /// - `app_name` is none
307 /// - `app_path` is none
308 ///
309 /// ## Panics
310 ///
311 /// - Unsupported target OS
312 pub fn build(&self) -> Result<AutoLaunch> {
313 let app_name = self.app_name.as_ref().ok_or(Error::AppNameNotSpecified)?;
314 let app_path = self.app_path.as_ref().ok_or(Error::AppPathNotSpecified)?;
315 let args = self.args.clone().unwrap_or_default();
316
317 #[cfg(target_os = "linux")]
318 return Ok(AutoLaunch::new(&app_name, &app_path, &args));
319 #[cfg(target_os = "macos")]
320 return Ok(AutoLaunch::new(
321 &app_name,
322 &app_path,
323 self.use_launch_agent,
324 &args,
325 ));
326 #[cfg(target_os = "windows")]
327 return Ok(AutoLaunch::new(&app_name, &app_path, &args));
328
329 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
330 return Err(Error::UnsupportedOS);
331 }
332}