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}