Skip to main content

jay_config/
exec.rs

1//! Tools for spawning programs.
2
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::os::fd::OwnedFd;
6
7/// Sets an environment variable.
8///
9/// This does not affect the compositor itself but only programs spawned by the compositor.
10pub fn set_env(key: &str, val: &str) {
11    get!().set_env(key, val);
12}
13
14/// Unsets an environment variable.
15///
16/// This does not affect the compositor itself but only programs spawned by the compositor.
17pub fn unset_env(key: &str) {
18    get!().unset_env(key);
19}
20
21/// A command to be spawned.
22pub struct Command {
23    pub(crate) prog: String,
24    pub(crate) args: Vec<String>,
25    pub(crate) env: HashMap<String, String>,
26    pub(crate) fds: RefCell<HashMap<i32, OwnedFd>>,
27    pub(crate) tag: Option<String>,
28}
29
30impl Command {
31    /// Creates a new command to be spawned.
32    ///
33    /// `prog` should be the path to the program being spawned. If `prog` does not contain
34    /// a `/`, then it will be searched in `PATH` similar to how a shell would do it.
35    ///
36    /// The first argument passed to `prog`, `argv[0]`, is `prog` itself.
37    pub fn new(prog: &str) -> Self {
38        Self {
39            prog: prog.to_string(),
40            args: vec![],
41            env: Default::default(),
42            fds: Default::default(),
43            tag: Default::default(),
44        }
45    }
46
47    /// Adds an argument to be passed to the command.
48    pub fn arg(&mut self, arg: &str) -> &mut Self {
49        self.args.push(arg.to_string());
50        self
51    }
52
53    /// Sets an environment variable for this command only.
54    pub fn env(&mut self, key: &str, val: &str) -> &mut Self {
55        self.env.insert(key.to_string(), val.to_string());
56        self
57    }
58
59    /// Sets a file descriptor of the process.
60    ///
61    /// By default, the process starts with exactly stdin, stdout, and stderr open and all
62    /// pointing to `/dev/null`.
63    pub fn fd<F: Into<OwnedFd>>(&mut self, idx: i32, fd: F) -> &mut Self {
64        self.fds.borrow_mut().insert(idx, fd.into());
65        self
66    }
67
68    /// Sets the stdin of the process.
69    ///
70    /// This is equivalent to `fd(0, fd)`.
71    pub fn stdin<F: Into<OwnedFd>>(&mut self, fd: F) -> &mut Self {
72        self.fd(0, fd)
73    }
74
75    /// Sets the stdout of the process.
76    ///
77    /// This is equivalent to `fd(1, fd)`.
78    pub fn stdout<F: Into<OwnedFd>>(&mut self, fd: F) -> &mut Self {
79        self.fd(1, fd)
80    }
81
82    /// Sets the stderr of the process.
83    ///
84    /// This is equivalent to `fd(2, fd)`.
85    pub fn stderr<F: Into<OwnedFd>>(&mut self, fd: F) -> &mut Self {
86        self.fd(2, fd)
87    }
88
89    /// Runs the application with access to privileged wayland protocols.
90    ///
91    /// The default is `false`.
92    pub fn privileged(&mut self) -> &mut Self {
93        match get!(self).get_socket_path() {
94            Some(path) => {
95                self.env("WAYLAND_DISPLAY", &format!("{path}.jay"));
96            }
97            _ => {
98                log::error!("Compositor did not send the socket path");
99            }
100        }
101        self
102    }
103
104    /// Adds a tag to Wayland connections created by the spawned command.
105    pub fn tag(&mut self, tag: &str) -> &mut Self {
106        self.tag = Some(tag.to_owned());
107        self
108    }
109
110    /// Executes the command.
111    ///
112    /// This consumes all attached file descriptors.
113    pub fn spawn(&self) {
114        get!().spawn(self);
115    }
116}