1#![deny(unsafe_op_in_unsafe_fn)]
2#![deny(clippy::all)]
3
4#[cfg(target_os = "macos")]
5#[macro_use]
6extern crate objc2;
7
8#[cfg(target_os = "macos")]
9#[macro_use]
10extern crate core;
11
12mod common;
13
14#[cfg(target_os = "windows")]
15mod win32;
16
17#[cfg(target_os = "linux")]
18mod linux;
19
20#[cfg(target_os = "macos")]
21mod macos;
22
23#[cfg(target_os = "windows")]
24use win32::init_platform_api;
25
26#[cfg(target_os = "linux")]
27use linux::init_platform_api;
28
29#[cfg(target_os = "macos")]
30use macos::init_platform_api;
31
32#[cfg(all(feature = "macos_permission", target_os = "macos"))]
33pub use macos::permission;
37
38pub use common::{
39 api::{empty_entity, os_name, Api},
40 result::Result,
41 x_win_struct::{
42 icon_info::IconInfo, process_info::ProcessInfo, usage_info::UsageInfo, window_info::WindowInfo,
43 window_position::WindowPosition,
44 },
45};
46
47pub fn get_window_icon(window_info: &WindowInfo) -> Result<IconInfo> {
52 let api = init_platform_api();
53 let icon_info = api.get_app_icon(window_info)?;
54 Ok(icon_info)
55}
56
57pub fn get_browser_url(window_info: &WindowInfo) -> Result<String> {
62 let api = init_platform_api();
63 let browser_url = api.get_browser_url(window_info)?;
64 Ok(browser_url)
65}
66
67pub fn get_active_window() -> Result<WindowInfo> {
72 let api = init_platform_api();
73 let active_window = api.get_active_window()?;
74 Ok(active_window)
75}
76
77pub fn get_open_windows() -> Result<Vec<WindowInfo>> {
82 let api = init_platform_api();
83 let open_windows = api.get_open_windows()?;
84 Ok(open_windows)
85}
86
87pub fn install_extension() -> Result<bool> {
93 #[cfg(not(target_os = "linux"))]
94 {
95 Ok(false)
96 }
97 #[cfg(target_os = "linux")]
98 {
99 linux::gnome_install_extension()
100 }
101}
102
103pub fn uninstall_extension() -> Result<bool> {
109 #[cfg(not(target_os = "linux"))]
110 {
111 Ok(false)
112 }
113 #[cfg(target_os = "linux")]
114 {
115 linux::gnome_uninstall_extension()
116 }
117}
118
119pub fn enable_extension() -> Result<bool> {
124 #[cfg(not(target_os = "linux"))]
125 {
126 Ok(false)
127 }
128 #[cfg(target_os = "linux")]
129 {
130 linux::gnome_enable_extension()
131 }
132}
133
134pub fn disable_extension() -> Result<bool> {
139 #[cfg(not(target_os = "linux"))]
140 {
141 Ok(false)
142 }
143 #[cfg(target_os = "linux")]
144 {
145 linux::gnome_disable_extension()
146 }
147}
148
149pub fn is_enabled_extension() -> Result<bool> {
154 #[cfg(not(target_os = "linux"))]
155 {
156 Ok(false)
157 }
158 #[cfg(target_os = "linux")]
159 {
160 linux::gnome_is_enabled_extension()
161 }
162}
163
164pub fn is_installed_extension() -> Result<bool> {
169 #[cfg(not(target_os = "linux"))]
170 {
171 Ok(false)
172 }
173 #[cfg(target_os = "linux")]
174 {
175 linux::gnome_is_installed_extension()
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 #[cfg(not(target_os = "linux"))]
183 use std::process::Command;
184 #[cfg(not(target_os = "linux"))]
185 use std::{thread, time};
186
187 #[cfg(not(target_os = "linux"))]
188 struct TestContext;
189
190 #[cfg(not(target_os = "linux"))]
191 impl TestContext {
192 fn setup() -> Self {
193 let output = if cfg!(target_os = "windows") {
194 Command::new("cmd")
195 .args([
196 "/C",
197 "start",
198 "microsoft-edge:https://github.com",
199 "--no-first-run",
200 "--restore-last-session",
201 ])
202 .output()
203 .expect("failed to execute process")
204 } else {
205 Command::new("open")
206 .args(["-a", "Safari", "https://github.com"])
207 .output()
208 .expect("failed to execute process")
209 };
210 println!(
211 "[START] Command Status: {:?}; Command stdout: {:?}; Command stderr: {:?}",
212 output.status,
213 std::str::from_utf8(&output.stdout).unwrap_or("Error when convert output"),
214 std::str::from_utf8(&output.stderr).unwrap_or("Error when convert stderr")
215 );
216 thread::sleep(time::Duration::from_secs(3));
217 TestContext
218 }
219 }
220
221 #[cfg(not(target_os = "linux"))]
222 impl Drop for TestContext {
223 fn drop(&mut self) {
224 let output = if cfg!(target_os = "windows") {
225 Command::new("cmd")
226 .args(["/C", "taskkill", "/f", "/im", "msedge.exe"])
227 .output()
228 .expect("failed to execute process")
229 } else {
230 Command::new("killall")
231 .args(["Safari"])
232 .output()
233 .expect("failed to execute process")
234 };
235 println!(
236 "[DONE] Command Status: {:?}; Command stdout: {:?}; Command stderr: {:?}",
237 output.status,
238 std::str::from_utf8(&output.stdout).unwrap_or("Error when convert output"),
239 std::str::from_utf8(&output.stderr).unwrap_or("Error when convert stderr")
240 );
241 thread::sleep(time::Duration::from_secs(3));
242 }
243 }
244
245 fn test_osname() -> String {
246 #[cfg(target_os = "linux")]
247 {
248 r#"linux"#.to_owned()
249 }
250 #[cfg(target_os = "macos")]
251 {
252 r#"darwin"#.to_owned()
253 }
254 #[cfg(target_os = "windows")]
255 {
256 r#"win32"#.to_owned()
257 }
258 }
259
260 fn test_struct(window_info: WindowInfo) -> Result<()> {
261 assert_ne!(window_info.id, 0);
262 assert_ne!(window_info.title, String::from(""));
263 #[cfg(target_os = "linux")]
264 assert_eq!(window_info.os, r#"linux"#);
265 #[cfg(target_os = "macos")]
266 assert_eq!(window_info.os, r#"darwin"#);
267 #[cfg(target_os = "windows")]
268 assert_eq!(window_info.os, r#"win32"#);
269 Ok(())
270 }
271
272 #[test]
273 fn test_get_active_window() -> Result<()> {
274 let window_info = get_active_window().unwrap();
275 test_struct(window_info)
276 }
277
278 #[test]
279 fn test_get_open_windows() -> Result<()> {
280 let open_windows = get_open_windows().unwrap();
281 assert_ne!(open_windows.len(), 0);
282 let window_info = open_windows.first().unwrap().to_owned();
283 test_struct(window_info)
284 }
285
286 #[test]
287 fn test_os_name() -> Result<()> {
288 let os_name = os_name();
289 assert_eq!(os_name, test_osname());
290 Ok(())
291 }
292
293 #[test]
294 fn test_empty_entity() -> Result<()> {
295 let window_info = empty_entity();
296 assert_eq!(window_info.id, 0);
297 assert_eq!(window_info.title, String::from(""));
298 assert_eq!(window_info.os, test_osname());
299 Ok(())
300 }
301
302 #[test]
303 fn test_get_window_icon() -> Result<()> {
304 let window_info: &WindowInfo = &get_active_window().unwrap();
305 let icon_info = get_window_icon(window_info).unwrap();
306 assert_ne!(icon_info.data, "");
307 assert_ne!(icon_info.height, 0);
308 assert_ne!(icon_info.width, 0);
309 let open_windows = &get_open_windows().unwrap();
310 assert_ne!(open_windows.len(), 0);
311 let window_info = open_windows.first().unwrap().to_owned();
312 let icon_info = get_window_icon(&window_info).unwrap();
313 assert_ne!(icon_info.data, "");
314 assert_ne!(icon_info.height, 0);
315 assert_ne!(icon_info.width, 0);
316 Ok(())
317 }
318
319 #[cfg(not(target_os = "linux"))]
320 #[test]
321 #[ignore = "Not working on ci/cd"]
322 fn test_get_brower_url() -> Result<()> {
323 #[allow(unused)]
324 let _context = TestContext::setup();
325 let open_windows = &get_open_windows().unwrap();
326 assert_ne!(open_windows.len(), 0);
327 let window_info = open_windows.first().unwrap().to_owned();
328 let url = get_browser_url(&window_info).unwrap();
329 println!("URL: {:?}; process: {:?}", url, window_info.info.name);
330 assert!(url.starts_with("http"));
331 let window_info = &get_active_window().unwrap().to_owned();
332 let url = get_browser_url(window_info).unwrap();
333 println!("URL: {:?}; process: {:?}", url, window_info.info.name);
334 assert!(url.starts_with("http"));
335 Ok(())
336 }
337
338 #[cfg(target_os = "linux")]
339 #[test]
340 fn test_get_brower_url() -> Result<()> {
341 let open_windows = &get_open_windows().unwrap();
342 assert_ne!(open_windows.len(), 0);
343 let window_info = open_windows.first().unwrap().to_owned();
344 let url = get_browser_url(&window_info).unwrap();
345 assert!(url.eq("URL recovery not supported on Linux distribution!"));
346 let window_info = &get_active_window().unwrap().to_owned();
347 let url = get_browser_url(&window_info).unwrap();
348 assert!(url.eq("URL recovery not supported on Linux distribution!"));
349 Ok(())
350 }
351
352 #[cfg(all(feature = "macos_permission", target_os = "macos"))]
353 #[test]
354 #[ignore = "Not working on ci/cd"]
355 fn test_check_screen_record_permission() -> Result<()> {
356 use macos::permission::check_screen_record_permission;
357 let value = check_screen_record_permission();
358 assert_eq!(value, true);
359 Ok(())
360 }
361
362 #[cfg(all(feature = "macos_permission", target_os = "macos"))]
363 #[test]
364 #[ignore = "Not working on ci/cd"]
365 fn test_request_screen_record_permission() -> Result<()> {
366 use macos::permission::request_screen_record_permission;
367 let value = request_screen_record_permission();
368 assert_eq!(value, true);
369 Ok(())
370 }
371
372 #[cfg(target_os = "linux")]
373 #[test]
374 #[ignore = "Not working on ci/cd"]
375 fn test_install_extension() -> Result<()> {
376 let value = install_extension()?;
377 assert_eq!(value, true);
378 Ok(())
379 }
380
381 #[cfg(target_os = "linux")]
382 #[test]
383 #[ignore = "Not working on ci/cd"]
384 fn test_uninstall_extension() -> Result<()> {
385 let value = uninstall_extension()?;
386 assert_eq!(value, true);
387 Ok(())
388 }
389
390 #[cfg(target_os = "linux")]
391 #[test]
392 #[ignore = "Not working on ci/cd"]
393 fn test_enable_extension() -> Result<()> {
394 let value = enable_extension()?;
395 assert_eq!(value, true);
396 Ok(())
397 }
398
399 #[cfg(target_os = "linux")]
400 #[test]
401 #[ignore = "Not working on ci/cd"]
402 fn test_disable_extension() -> Result<()> {
403 let value = disable_extension()?;
404 assert_eq!(value, true);
405 Ok(())
406 }
407
408 #[cfg(target_os = "linux")]
409 #[test]
410 #[ignore = "Not working on ci/cd"]
411 fn test_is_enabled_extension() -> Result<()> {
412 let value = is_enabled_extension()?;
413 assert_eq!(value, true);
414 Ok(())
415 }
416
417 #[cfg(target_os = "linux")]
418 #[test]
419 #[ignore = "Not working on ci/cd"]
420 fn test_is_installed_extension() -> Result<()> {
421 let value = is_installed_extension()?;
422 assert_eq!(value, true);
423 Ok(())
424 }
425}