1use std::env;
4use std::fs;
5use std::process::Command;
6
7static SELECTION_TEMPORARY_FILE: &str = "/tmp/selection-tmp.png";
8
9pub enum ScreenshotKind {
10 Area,
11 Window,
12 Full,
13}
14
15enum SessionKind {
16 Wayland,
17 X11,
18 Macos,
19}
20
21enum DesktopKind {
22 GNOME,
23 KDE,
24 Sway,
25 Generic,
26 Macos,
27}
28
29fn session_type() -> SessionKind {
30 return match env::var("XDG_SESSION_TYPE") {
31 Ok(ok) => match ok.to_lowercase().as_ref() {
32 "wayland" => SessionKind::Wayland,
33 _ => SessionKind::X11,
34 },
35 Err(_) => {
36 if !cfg!(target_os = "macos") {
37 SessionKind::Macos
38 } else {
39 SessionKind::X11
40 }
41 }
42 };
43}
44
45fn screenshot_tool_selection(session: SessionKind) -> DesktopKind {
46 return match session {
47 SessionKind::Wayland => match Command::new("grim").arg("--version").spawn() {
48 Ok(_) => DesktopKind::Sway,
49 Err(_) => match Command::new("spectacle").arg("--version").spawn() {
50 Ok(_) => DesktopKind::KDE,
51 Err(_) => match Command::new("gnome-screenshot").arg("--version").spawn() {
52 Ok(_) => DesktopKind::GNOME,
53 Err(_) => panic!("Uncompatible Wayland desktop"),
54 },
55 },
56 },
57 SessionKind::X11 => match Command::new("spectacle").arg("--version").spawn() {
58 Ok(_) => DesktopKind::KDE,
59 Err(_) => match Command::new("gnome-screenshot").arg("--version").spawn() {
60 Ok(_) => DesktopKind::GNOME,
61 Err(_) => match Command::new("scrot").arg("--version").spawn() {
62 Ok(_) => DesktopKind::Generic,
63 Err(_) => panic!("Uncompatible X11 desktop (install scrot)"),
64 },
65 },
66 },
67 SessionKind::Macos => DesktopKind::Macos,
68 };
69}
70
71pub fn screenshot_area(file: String, freeze: bool) {
72 match screenshot_tool_selection(session_type()) {
73 DesktopKind::GNOME => gnome(ScreenshotKind::Area, file, freeze),
74 DesktopKind::KDE => kde(ScreenshotKind::Area, file),
75 DesktopKind::Sway => sway(ScreenshotKind::Area, file),
76 DesktopKind::Generic => scrot(ScreenshotKind::Area, file, freeze),
77 DesktopKind::Macos => mac(ScreenshotKind::Area, file),
78 }
79}
80pub fn screenshot_window(file: String) {
81 match screenshot_tool_selection(session_type()) {
82 DesktopKind::GNOME => gnome(ScreenshotKind::Window, file, false),
83 DesktopKind::KDE => kde(ScreenshotKind::Window, file),
84 DesktopKind::Sway => sway(ScreenshotKind::Window, file),
85 DesktopKind::Generic => scrot(ScreenshotKind::Window, file, false),
86 DesktopKind::Macos => mac(ScreenshotKind::Window, file),
87 }
88}
89pub fn screenshot_full(file: String) {
90 match screenshot_tool_selection(session_type()) {
91 DesktopKind::GNOME => gnome(ScreenshotKind::Full, file, false),
92 DesktopKind::KDE => kde(ScreenshotKind::Full, file),
93 DesktopKind::Sway => sway(ScreenshotKind::Full, file),
94 DesktopKind::Generic => scrot(ScreenshotKind::Full, file, false),
95 DesktopKind::Macos => mac(ScreenshotKind::Full, file),
96 }
97}
98fn gnome(option: ScreenshotKind, file: String, freeze: bool) {
99 match option {
100 ScreenshotKind::Area => {
101 let mut feh = match Command::new("feh").arg("--version").spawn() {
102 Ok(_) => {
103 Command::new("gnome-screenshot")
104 .args(&["-f", SELECTION_TEMPORARY_FILE])
105 .output()
106 .expect("gnome-screenshot did not launch");
107 Command::new("feh")
108 .args(&[SELECTION_TEMPORARY_FILE, "-F"])
109 .spawn()
110 .expect("'feh' did not launch to pause screen for selection")
111 }
112 Err(_) => Command::new("sh")
113 .arg("-c")
114 .arg("echo Feh does not exist")
115 .spawn()
116 .unwrap(),
117 };
118 Command::new("gnome-screenshot")
119 .args(&["-a", "-f", &file])
120 .output()
121 .expect("gnome-screenshot did not launch");
122 if freeze {
123 match fs::remove_file(SELECTION_TEMPORARY_FILE) {
124 Ok(ok) => ok,
125 Err(_) => eprintln!("Unable to remove temporary selection file"),
126 };
127 match feh.kill() {
128 Ok(ok) => ok,
129 Err(_) => eprintln!("Unable to kill feh, must have already been closed"),
130 };
131 }
132 }
133 ScreenshotKind::Window => {
134 Command::new("gnome-screenshot")
135 .args(&["-w", "-e", "shadow", "-f", &file])
136 .output()
137 .expect("gnome-screenshot did not launch");
138 }
139 ScreenshotKind::Full => {
140 Command::new("gnome-screenshot")
141 .args(&["-f", &file])
142 .output()
143 .expect("gnome-screenshot did not launch");
144 }
145 };
146}
147fn kde(option: ScreenshotKind, file: String) {
148 match option {
149 ScreenshotKind::Area => {
150 Command::new("spectacle")
151 .args(&["-rbno", &file])
152 .output()
153 .expect("spectacle did not launch");
154 }
155 ScreenshotKind::Window => {
156 Command::new("spectacle")
157 .args(&["-abno", &file])
158 .output()
159 .expect("spectacle did not launch");
160 }
161 ScreenshotKind::Full => {
162 Command::new("spectacle")
163 .args(&["-fbno", &file])
164 .output()
165 .expect("spectacle did not launch");
166 }
167 };
168}
169fn sway(option: ScreenshotKind, file: String) {
170 match option {
171 ScreenshotKind::Area => {
172 let slurp = Command::new("slurp")
173 .output()
174 .expect("slurp did not launch");
175 Command::new("grim")
176 .args(&["-g", &String::from_utf8(slurp.stdout).unwrap(), &file])
177 .output()
178 .expect("grim did not launch");
179 }
180 ScreenshotKind::Window => {
181 let slurp = Command::new("slurp")
182 .output()
183 .expect("slurp did not launch");
184 Command::new("grim")
185 .args(&["-g", &String::from_utf8(slurp.stdout).unwrap(), &file])
186 .output()
187 .expect("grim did not launch");
188 }
189 ScreenshotKind::Full => {
190 Command::new("grim")
191 .arg(&file)
192 .output()
193 .expect("grim did not launch");
194 }
195 };
196}
197fn mac(option: ScreenshotKind, file: String) {
198 match option {
199 ScreenshotKind::Area => {
200 Command::new("screencapture")
201 .args(&["-s", &file])
202 .output()
203 .expect("screencapture did not launch");
204 }
205 ScreenshotKind::Window => {
206 Command::new("screencapture")
207 .args(&["-w", &file])
208 .output()
209 .expect("screencapture did not launch");
210 }
211 ScreenshotKind::Full => {
212 Command::new("screencapture")
213 .args(&["-S", &file])
214 .output()
215 .expect("screencapture did not launch");
216 }
217 };
218}
219fn scrot(option: ScreenshotKind, file: String, freeze: bool) {
220 match option {
221 ScreenshotKind::Area => {
222 let mut feh = match Command::new("feh").arg("--version").spawn() {
223 Ok(_) => {
224 Command::new("scrot")
225 .arg(SELECTION_TEMPORARY_FILE)
226 .output()
227 .expect("scrot did not launch");
228 Command::new("feh")
229 .args(&[SELECTION_TEMPORARY_FILE, "-F"])
230 .spawn()
231 .expect("'feh' did not launch to pause screen for selection")
232 }
233 Err(_) => Command::new("sh")
234 .arg("-c")
235 .arg("echo Feh does not exist")
236 .spawn()
237 .unwrap(),
238 };
239 Command::new("scrot")
240 .args(&["--select", &file])
241 .output()
242 .expect("scrot did not launch");
243 if freeze {
244 match fs::remove_file(SELECTION_TEMPORARY_FILE) {
245 Ok(ok) => ok,
246 Err(_) => eprintln!("Unable to remove temporary selection file"),
247 };
248 match feh.kill() {
249 Ok(ok) => ok,
250 Err(_) => eprintln!("Unable to kill feh, must have already been closed"),
251 };
252 }
253 }
254 ScreenshotKind::Window => {
255 Command::new("scrot")
256 .args(&["--border", "--focused", &file])
257 .output()
258 .expect("gnome-screenshot did not launch");
259 }
260 ScreenshotKind::Full => {
261 Command::new("scrot")
262 .args(&[&file])
263 .output()
264 .expect("gnome-screenshot did not launch");
265 }
266 };
267}