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