1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub struct SystemWindow {
5 pub handle: u64,
6 pub title: String,
7 pub process_name: String,
8 pub pid: u32,
9 pub x: i32,
10 pub y: i32,
11 pub width: u32,
12 pub height: u32,
13 pub is_visible: bool,
14 pub is_minimized: bool,
15 pub is_maximized: bool,
16}
17
18pub trait SystemWindowManager {
19 fn get_all_windows() -> Result<Vec<SystemWindow>, String>;
20 fn get_window_by_handle(handle: u64) -> Result<Option<SystemWindow>, String>;
21 fn move_window(handle: u64, x: i32, y: i32) -> Result<(), String>;
22 fn resize_window(handle: u64, width: u32, height: u32) -> Result<(), String>;
23 fn set_window_position_and_size(handle: u64, x: i32, y: i32, width: u32, height: u32) -> Result<(), String>;
24 fn minimize_window(handle: u64) -> Result<(), String>;
25 fn maximize_window(handle: u64) -> Result<(), String>;
26 fn restore_window(handle: u64) -> Result<(), String>;
27 fn close_window(handle: u64) -> Result<(), String>;
28 fn focus_window(handle: u64) -> Result<(), String>;
29 fn hide_window(handle: u64) -> Result<(), String>;
30 fn show_window(handle: u64) -> Result<(), String>;
31}
32
33#[cfg(windows)]
34mod windows_impl {
35 use super::*;
36 use std::ffi::OsString;
37 use std::os::windows::ffi::OsStringExt;
38 use std::ptr;
39 use winapi::shared::windef::{HWND, RECT};
40 use winapi::um::winuser::*;
41 use winapi::um::processthreadsapi::GetProcessId;
42 use winapi::um::psapi::GetModuleBaseNameW;
43 use winapi::um::handleapi::CloseHandle;
44 use winapi::um::processthreadsapi::OpenProcess;
45 use winapi::shared::minwindef::{DWORD, MAX_PATH};
46
47 pub struct WindowsManager;
48
49 impl SystemWindowManager for WindowsManager {
50 fn get_all_windows() -> Result<Vec<SystemWindow>, String> {
51 let mut windows = Vec::new();
52
53 unsafe {
54 EnumWindows(Some(enum_windows_proc), &mut windows as *mut Vec<SystemWindow> as isize);
55 }
56
57 Ok(windows)
58 }
59
60 fn get_window_by_handle(handle: u64) -> Result<Option<SystemWindow>, String> {
61 let hwnd = handle as HWND;
62
63 unsafe {
64 if IsWindow(hwnd) == 0 {
65 return Ok(None);
66 }
67
68 let window = get_window_info(hwnd)?;
69 Ok(Some(window))
70 }
71 }
72
73 fn move_window(handle: u64, x: i32, y: i32) -> Result<(), String> {
74 let hwnd = handle as HWND;
75
76 unsafe {
77 let mut rect: RECT = std::mem::zeroed();
78 if GetWindowRect(hwnd, &mut rect) == 0 {
79 return Err("Failed to get window rect".to_string());
80 }
81
82 let width = rect.right - rect.left;
83 let height = rect.bottom - rect.top;
84
85 if SetWindowPos(hwnd, ptr::null_mut(), x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE) == 0 {
86 return Err("Failed to move window".to_string());
87 }
88 }
89
90 Ok(())
91 }
92
93 fn resize_window(handle: u64, width: u32, height: u32) -> Result<(), String> {
94 let hwnd = handle as HWND;
95
96 unsafe {
97 let mut rect: RECT = std::mem::zeroed();
98 if GetWindowRect(hwnd, &mut rect) == 0 {
99 return Err("Failed to get window rect".to_string());
100 }
101
102 if SetWindowPos(hwnd, ptr::null_mut(), rect.left, rect.top, width as i32, height as i32, SWP_NOZORDER | SWP_NOACTIVATE) == 0 {
103 return Err("Failed to resize window".to_string());
104 }
105 }
106
107 Ok(())
108 }
109
110 fn set_window_position_and_size(handle: u64, x: i32, y: i32, width: u32, height: u32) -> Result<(), String> {
111 let hwnd = handle as HWND;
112
113 unsafe {
114 if SetWindowPos(hwnd, ptr::null_mut(), x, y, width as i32, height as i32, SWP_NOZORDER | SWP_NOACTIVATE) == 0 {
115 return Err("Failed to set window position and size".to_string());
116 }
117 }
118
119 Ok(())
120 }
121
122 fn minimize_window(handle: u64) -> Result<(), String> {
123 let hwnd = handle as HWND;
124
125 unsafe {
126 if ShowWindow(hwnd, SW_MINIMIZE) == 0 {
127 return Err("Failed to minimize window".to_string());
128 }
129 }
130
131 Ok(())
132 }
133
134 fn maximize_window(handle: u64) -> Result<(), String> {
135 let hwnd = handle as HWND;
136
137 unsafe {
138 if ShowWindow(hwnd, SW_MAXIMIZE) == 0 {
139 return Err("Failed to maximize window".to_string());
140 }
141 }
142
143 Ok(())
144 }
145
146 fn restore_window(handle: u64) -> Result<(), String> {
147 let hwnd = handle as HWND;
148
149 unsafe {
150 if ShowWindow(hwnd, SW_RESTORE) == 0 {
151 return Err("Failed to restore window".to_string());
152 }
153 }
154
155 Ok(())
156 }
157
158 fn close_window(handle: u64) -> Result<(), String> {
159 let hwnd = handle as HWND;
160
161 unsafe {
162 if PostMessageW(hwnd, WM_CLOSE, 0, 0) == 0 {
163 return Err("Failed to close window".to_string());
164 }
165 }
166
167 Ok(())
168 }
169
170 fn focus_window(handle: u64) -> Result<(), String> {
171 let hwnd = handle as HWND;
172
173 unsafe {
174 if SetForegroundWindow(hwnd) == 0 {
175 return Err("Failed to focus window".to_string());
176 }
177 }
178
179 Ok(())
180 }
181
182 fn hide_window(handle: u64) -> Result<(), String> {
183 let hwnd = handle as HWND;
184
185 unsafe {
186 if ShowWindow(hwnd, SW_HIDE) == 0 {
187 return Err("Failed to hide window".to_string());
188 }
189 }
190
191 Ok(())
192 }
193
194 fn show_window(handle: u64) -> Result<(), String> {
195 let hwnd = handle as HWND;
196
197 unsafe {
198 if ShowWindow(hwnd, SW_SHOW) == 0 {
199 return Err("Failed to show window".to_string());
200 }
201 }
202
203 Ok(())
204 }
205 }
206
207 unsafe extern "system" fn enum_windows_proc(hwnd: HWND, lparam: isize) -> i32 {
208 let windows = &mut *(lparam as *mut Vec<SystemWindow>);
209
210 if IsWindowVisible(hwnd) != 0 {
211 if let Ok(window) = get_window_info(hwnd) {
212 if !window.title.is_empty() {
213 windows.push(window);
214 }
215 }
216 }
217
218 1 }
220
221 unsafe fn get_window_info(hwnd: HWND) -> Result<SystemWindow, String> {
222 let mut title_buf = [0u16; 256];
223 let title_len = GetWindowTextW(hwnd, title_buf.as_mut_ptr(), title_buf.len() as i32);
224 let title = if title_len > 0 {
225 OsString::from_wide(&title_buf[..title_len as usize])
226 .to_string_lossy()
227 .to_string()
228 } else {
229 String::new()
230 };
231
232 let mut rect: RECT = std::mem::zeroed();
233 GetWindowRect(hwnd, &mut rect);
234
235 let pid = GetProcessId(hwnd as *mut _);
236 let process_name = get_process_name(pid).unwrap_or_else(|| "Unknown".to_string());
237
238 let placement = {
239 let mut wp: WINDOWPLACEMENT = std::mem::zeroed();
240 wp.length = std::mem::size_of::<WINDOWPLACEMENT>() as u32;
241 GetWindowPlacement(hwnd, &mut wp);
242 wp
243 };
244
245 Ok(SystemWindow {
246 handle: hwnd as u64,
247 title,
248 process_name,
249 pid,
250 x: rect.left,
251 y: rect.top,
252 width: (rect.right - rect.left) as u32,
253 height: (rect.bottom - rect.top) as u32,
254 is_visible: IsWindowVisible(hwnd) != 0,
255 is_minimized: placement.showCmd == SW_SHOWMINIMIZED as u32,
256 is_maximized: placement.showCmd == SW_SHOWMAXIMIZED as u32,
257 })
258 }
259
260 unsafe fn get_process_name(pid: DWORD) -> Option<String> {
261 let process_handle = OpenProcess(0x0400 | 0x0010, 0, pid); if process_handle.is_null() {
263 return None;
264 }
265
266 let mut name_buf = [0u16; MAX_PATH];
267 let name_len = GetModuleBaseNameW(process_handle, ptr::null_mut(), name_buf.as_mut_ptr(), MAX_PATH as u32);
268
269 CloseHandle(process_handle);
270
271 if name_len > 0 {
272 let name = OsString::from_wide(&name_buf[..name_len as usize])
273 .to_string_lossy()
274 .to_string();
275 Some(name)
276 } else {
277 None
278 }
279 }
280}
281
282#[cfg(target_os = "macos")]
283mod macos_impl {
284 use super::*;
285 use cocoa::appkit::*;
286 use cocoa::base::{id, nil, YES, NO, BOOL};
287 use cocoa::foundation::{NSArray, NSString, NSAutoreleasePool, NSDictionary, NSNumber};
288 use objc::runtime::Object;
289 use objc::{msg_send, sel, sel_impl};
290 use core_graphics::geometry::{CGPoint, CGSize, CGRect};
291 use core_graphics::window::{CGWindowListOption, CGWindowID, kCGWindowListOptionOnScreenOnly, kCGWindowListExcludeDesktopElements};
292 use core_graphics::display::CGDisplay;
293 use std::collections::HashMap;
294 use std::ffi::{CStr, CString};
295 use std::ptr;
296
297 pub struct MacOSManager;
298
299 impl SystemWindowManager for MacOSManager {
300 fn get_all_windows() -> Result<Vec<SystemWindow>, String> {
301 unsafe {
302 let window_list_info = core_graphics::window::CGWindowListCopyWindowInfo(
303 kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
304 0
305 );
306
307 if window_list_info.is_null() {
308 return Err("Failed to get window list".to_string());
309 }
310
311 let mut windows = Vec::new();
312 let count: i64 = msg_send![window_list_info, count];
313
314 for i in 0..count {
315 let window_info: id = msg_send![window_list_info, objectAtIndex: i];
316 if let Ok(window) = parse_window_info(window_info) {
317 windows.push(window);
318 }
319 }
320
321 Ok(windows)
322 }
323 }
324
325 fn get_window_by_handle(handle: u64) -> Result<Option<SystemWindow>, String> {
326 let windows = Self::get_all_windows()?;
327 Ok(windows.into_iter().find(|w| w.handle == handle))
328 }
329
330 fn move_window(handle: u64, x: i32, y: i32) -> Result<(), String> {
331 unsafe {
332 let window_id = handle as CGWindowID;
333 let app = NSApp();
334 let windows: id = msg_send![app, windows];
335 let count: usize = msg_send![windows, count];
336
337 for i in 0..count {
338 let window: id = msg_send![windows, objectAtIndex: i];
339 let window_number: i32 = msg_send![window, windowNumber];
340
341 if window_number as u64 == handle {
342 let point = NSPoint::new(x as f64, y as f64);
343 let _: () = msg_send![window, setFrameOrigin: point];
344 return Ok(());
345 }
346 }
347 }
348 Ok(())
349 }
350
351 fn resize_window(handle: u64, width: u32, height: u32) -> Result<(), String> {
352 unsafe {
353 let app = NSApp();
354 let windows: id = msg_send![app, windows];
355 let count: usize = msg_send![windows, count];
356
357 for i in 0..count {
358 let window: id = msg_send![windows, objectAtIndex: i];
359 let window_number: i32 = msg_send![window, windowNumber];
360
361 if window_number as u64 == handle {
362 let current_frame: NSRect = msg_send![window, frame];
363 let new_frame = NSRect::new(
364 current_frame.origin,
365 NSSize::new(width as f64, height as f64)
366 );
367 let _: () = msg_send![window, setFrame: new_frame display: YES];
368 return Ok(());
369 }
370 }
371 }
372 Ok(())
373 }
374
375 fn set_window_position_and_size(handle: u64, x: i32, y: i32, width: u32, height: u32) -> Result<(), String> {
376 unsafe {
377 let app = NSApp();
378 let windows: id = msg_send![app, windows];
379 let count: usize = msg_send![windows, count];
380
381 for i in 0..count {
382 let window: id = msg_send![windows, objectAtIndex: i];
383 let window_number: i32 = msg_send![window, windowNumber];
384
385 if window_number as u64 == handle {
386 let new_frame = NSRect::new(
387 NSPoint::new(x as f64, y as f64),
388 NSSize::new(width as f64, height as f64)
389 );
390 let _: () = msg_send![window, setFrame: new_frame display: YES];
391 return Ok(());
392 }
393 }
394 }
395 Ok(())
396 }
397
398 fn minimize_window(handle: u64) -> Result<(), String> {
399 unsafe {
400 if let Some(window) = find_window_by_handle(handle) {
401 let _: () = msg_send![window, miniaturize: nil];
402 }
403 }
404 Ok(())
405 }
406
407 fn maximize_window(handle: u64) -> Result<(), String> {
408 unsafe {
409 if let Some(window) = find_window_by_handle(handle) {
410 let _: () = msg_send![window, zoom: nil];
411 }
412 }
413 Ok(())
414 }
415
416 fn restore_window(handle: u64) -> Result<(), String> {
417 unsafe {
418 if let Some(window) = find_window_by_handle(handle) {
419 let is_miniaturized: BOOL = msg_send![window, isMiniaturized];
420 if is_miniaturized == YES {
421 let _: () = msg_send![window, deminiaturize: nil];
422 }
423 }
424 }
425 Ok(())
426 }
427
428 fn close_window(handle: u64) -> Result<(), String> {
429 unsafe {
430 if let Some(window) = find_window_by_handle(handle) {
431 let _: () = msg_send![window, close];
432 }
433 }
434 Ok(())
435 }
436
437 fn focus_window(handle: u64) -> Result<(), String> {
438 unsafe {
439 if let Some(window) = find_window_by_handle(handle) {
440 let _: () = msg_send![window, makeKeyAndOrderFront: nil];
441 let app = NSApp();
442 let _: () = msg_send![app, activateIgnoringOtherApps: YES];
443 }
444 }
445 Ok(())
446 }
447
448 fn hide_window(handle: u64) -> Result<(), String> {
449 unsafe {
450 if let Some(window) = find_window_by_handle(handle) {
451 let _: () = msg_send![window, orderOut: nil];
452 }
453 }
454 Ok(())
455 }
456
457 fn show_window(handle: u64) -> Result<(), String> {
458 unsafe {
459 if let Some(window) = find_window_by_handle(handle) {
460 let _: () = msg_send![window, orderFront: nil];
461 }
462 }
463 Ok(())
464 }
465 }
466
467 unsafe fn find_window_by_handle(handle: u64) -> Option<id> {
468 let app = NSApp();
469 let windows: id = msg_send![app, windows];
470 let count: usize = msg_send![windows, count];
471
472 for i in 0..count {
473 let window: id = msg_send![windows, objectAtIndex: i];
474 let window_number: i32 = msg_send![window, windowNumber];
475
476 if window_number as u64 == handle {
477 return Some(window);
478 }
479 }
480 None
481 }
482
483 unsafe fn parse_window_info(window_info: id) -> Result<SystemWindow, String> {
484 let window_id_key = NSString::alloc(nil).init_str("kCGWindowNumber");
485 let window_id_obj: id = msg_send![window_info, objectForKey: window_id_key];
486 let window_id: u64 = if !window_id_obj.is_null() {
487 let id_value: i64 = msg_send![window_id_obj, longLongValue];
488 id_value as u64
489 } else {
490 return Err("No window ID".to_string());
491 };
492
493 let name_key = NSString::alloc(nil).init_str("kCGWindowName");
494 let name_obj: id = msg_send![window_info, objectForKey: name_key];
495 let title = if !name_obj.is_null() {
496 let c_str: *const i8 = msg_send![name_obj, UTF8String];
497 if !c_str.is_null() {
498 CStr::from_ptr(c_str).to_string_lossy().to_string()
499 } else {
500 String::new()
501 }
502 } else {
503 String::new()
504 };
505
506 let owner_name_key = NSString::alloc(nil).init_str("kCGWindowOwnerName");
507 let owner_name_obj: id = msg_send![window_info, objectForKey: owner_name_key];
508 let process_name = if !owner_name_obj.is_null() {
509 let c_str: *const i8 = msg_send![owner_name_obj, UTF8String];
510 if !c_str.is_null() {
511 CStr::from_ptr(c_str).to_string_lossy().to_string()
512 } else {
513 "Unknown".to_string()
514 }
515 } else {
516 "Unknown".to_string()
517 };
518
519 let bounds_key = NSString::alloc(nil).init_str("kCGWindowBounds");
520 let bounds_obj: id = msg_send![window_info, objectForKey: bounds_key];
521 let (x, y, width, height) = if !bounds_obj.is_null() {
522 let x_key = NSString::alloc(nil).init_str("X");
524 let y_key = NSString::alloc(nil).init_str("Y");
525 let width_key = NSString::alloc(nil).init_str("Width");
526 let height_key = NSString::alloc(nil).init_str("Height");
527
528 let x_obj: id = msg_send![bounds_obj, objectForKey: x_key];
529 let y_obj: id = msg_send![bounds_obj, objectForKey: y_key];
530 let width_obj: id = msg_send![bounds_obj, objectForKey: width_key];
531 let height_obj: id = msg_send![bounds_obj, objectForKey: height_key];
532
533 let x: f64 = if !x_obj.is_null() { msg_send![x_obj, doubleValue] } else { 0.0 };
534 let y: f64 = if !y_obj.is_null() { msg_send![y_obj, doubleValue] } else { 0.0 };
535 let width: f64 = if !width_obj.is_null() { msg_send![width_obj, doubleValue] } else { 0.0 };
536 let height: f64 = if !height_obj.is_null() { msg_send![height_obj, doubleValue] } else { 0.0 };
537
538 (x as i32, y as i32, width as u32, height as u32)
539 } else {
540 (0, 0, 0, 0)
541 };
542
543 let pid_key = NSString::alloc(nil).init_str("kCGWindowOwnerPID");
544 let pid_obj: id = msg_send![window_info, objectForKey: pid_key];
545 let pid: u32 = if !pid_obj.is_null() {
546 let pid_value: i32 = msg_send![pid_obj, intValue];
547 pid_value as u32
548 } else {
549 0
550 };
551
552 Ok(SystemWindow {
553 handle: window_id,
554 title,
555 process_name,
556 pid,
557 x,
558 y,
559 width,
560 height,
561 is_visible: true, is_minimized: false, is_maximized: false, })
565 }
566}
567
568#[cfg(target_os = "linux")]
569mod linux_impl {
570 use super::*;
571 use x11::xlib::*;
572 use std::ptr;
573 use std::ffi::{CString, CStr};
574 use std::mem;
575
576 pub struct LinuxManager;
577
578 impl SystemWindowManager for LinuxManager {
579 fn get_all_windows() -> Result<Vec<SystemWindow>, String> {
580 unsafe {
581 let display = XOpenDisplay(ptr::null());
582 if display.is_null() {
583 return Err("Cannot open X11 display".to_string());
584 }
585
586 let root = XDefaultRootWindow(display);
587 let mut windows = Vec::new();
588
589 let mut root_return = 0;
591 let mut parent_return = 0;
592 let mut children_return = ptr::null_mut();
593 let mut nchildren_return = 0;
594
595 if XQueryTree(display, root, &mut root_return, &mut parent_return,
596 &mut children_return, &mut nchildren_return) != 0 {
597
598 let children = std::slice::from_raw_parts(children_return, nchildren_return as usize);
599
600 for &window in children {
601 if let Ok(sys_window) = get_window_info(display, window) {
602 if !sys_window.title.is_empty() && sys_window.is_visible {
603 windows.push(sys_window);
604 }
605 }
606 }
607
608 XFree(children_return as *mut _);
609 }
610
611 XCloseDisplay(display);
612 Ok(windows)
613 }
614 }
615
616 fn get_window_by_handle(handle: u64) -> Result<Option<SystemWindow>, String> {
617 unsafe {
618 let display = XOpenDisplay(ptr::null());
619 if display.is_null() {
620 return Ok(None);
621 }
622
623 let window = handle as Window;
624 let result = get_window_info(display, window);
625 XCloseDisplay(display);
626
627 match result {
628 Ok(window_info) => Ok(Some(window_info)),
629 Err(_) => Ok(None),
630 }
631 }
632 }
633
634 fn move_window(handle: u64, x: i32, y: i32) -> Result<(), String> {
635 unsafe {
636 let display = XOpenDisplay(ptr::null());
637 if display.is_null() {
638 return Err("Cannot open X11 display".to_string());
639 }
640
641 let window = handle as Window;
642 XMoveWindow(display, window, x, y);
643 XFlush(display);
644 XCloseDisplay(display);
645 }
646 Ok(())
647 }
648
649 fn resize_window(handle: u64, width: u32, height: u32) -> Result<(), String> {
650 unsafe {
651 let display = XOpenDisplay(ptr::null());
652 if display.is_null() {
653 return Err("Cannot open X11 display".to_string());
654 }
655
656 let window = handle as Window;
657 XResizeWindow(display, window, width, height);
658 XFlush(display);
659 XCloseDisplay(display);
660 }
661 Ok(())
662 }
663
664 fn set_window_position_and_size(handle: u64, x: i32, y: i32, width: u32, height: u32) -> Result<(), String> {
665 unsafe {
666 let display = XOpenDisplay(ptr::null());
667 if display.is_null() {
668 return Err("Cannot open X11 display".to_string());
669 }
670
671 let window = handle as Window;
672 XMoveResizeWindow(display, window, x, y, width, height);
673 XFlush(display);
674 XCloseDisplay(display);
675 }
676 Ok(())
677 }
678
679 fn minimize_window(handle: u64) -> Result<(), String> {
680 unsafe {
681 let display = XOpenDisplay(ptr::null());
682 if display.is_null() {
683 return Err("Cannot open X11 display".to_string());
684 }
685
686 let window = handle as Window;
687 XIconifyWindow(display, window, XDefaultScreen(display));
688 XFlush(display);
689 XCloseDisplay(display);
690 }
691 Ok(())
692 }
693
694 fn maximize_window(handle: u64) -> Result<(), String> {
695 unsafe {
696 let display = XOpenDisplay(ptr::null());
697 if display.is_null() {
698 return Err("Cannot open X11 display".to_string());
699 }
700
701 let window = handle as Window;
702 let screen = XDefaultScreen(display);
703 let screen_width = XDisplayWidth(display, screen) as u32;
704 let screen_height = XDisplayHeight(display, screen) as u32;
705
706 XMoveResizeWindow(display, window, 0, 0, screen_width, screen_height);
707 XFlush(display);
708 XCloseDisplay(display);
709 }
710 Ok(())
711 }
712
713 fn restore_window(handle: u64) -> Result<(), String> {
714 unsafe {
715 let display = XOpenDisplay(ptr::null());
716 if display.is_null() {
717 return Err("Cannot open X11 display".to_string());
718 }
719
720 let window = handle as Window;
721 XMapWindow(display, window);
722 XFlush(display);
723 XCloseDisplay(display);
724 }
725 Ok(())
726 }
727
728 fn close_window(handle: u64) -> Result<(), String> {
729 unsafe {
730 let display = XOpenDisplay(ptr::null());
731 if display.is_null() {
732 return Err("Cannot open X11 display".to_string());
733 }
734
735 let window = handle as Window;
736
737 let wm_delete_window = XInternAtom(display, b"WM_DELETE_WINDOW\0".as_ptr() as *const i8, 0);
739 let wm_protocols = XInternAtom(display, b"WM_PROTOCOLS\0".as_ptr() as *const i8, 0);
740
741 let mut event: XEvent = mem::zeroed();
742 event.client_message.type_ = ClientMessage;
743 event.client_message.window = window;
744 event.client_message.message_type = wm_protocols;
745 event.client_message.format = 32;
746 event.client_message.data.set_long(0, wm_delete_window as i64);
747
748 XSendEvent(display, window, 0, NoEventMask, &mut event);
749 XFlush(display);
750 XCloseDisplay(display);
751 }
752 Ok(())
753 }
754
755 fn focus_window(handle: u64) -> Result<(), String> {
756 unsafe {
757 let display = XOpenDisplay(ptr::null());
758 if display.is_null() {
759 return Err("Cannot open X11 display".to_string());
760 }
761
762 let window = handle as Window;
763 XRaiseWindow(display, window);
764 XSetInputFocus(display, window, RevertToParent, CurrentTime);
765 XFlush(display);
766 XCloseDisplay(display);
767 }
768 Ok(())
769 }
770
771 fn hide_window(handle: u64) -> Result<(), String> {
772 unsafe {
773 let display = XOpenDisplay(ptr::null());
774 if display.is_null() {
775 return Err("Cannot open X11 display".to_string());
776 }
777
778 let window = handle as Window;
779 XUnmapWindow(display, window);
780 XFlush(display);
781 XCloseDisplay(display);
782 }
783 Ok(())
784 }
785
786 fn show_window(handle: u64) -> Result<(), String> {
787 unsafe {
788 let display = XOpenDisplay(ptr::null());
789 if display.is_null() {
790 return Err("Cannot open X11 display".to_string());
791 }
792
793 let window = handle as Window;
794 XMapWindow(display, window);
795 XFlush(display);
796 XCloseDisplay(display);
797 }
798 Ok(())
799 }
800 }
801
802 unsafe fn get_window_info(display: *mut Display, window: Window) -> Result<SystemWindow, String> {
803 let mut attrs: XWindowAttributes = mem::zeroed();
804 if XGetWindowAttributes(display, window, &mut attrs) == 0 {
805 return Err("Failed to get window attributes".to_string());
806 }
807
808 let mut window_name = ptr::null_mut();
810 let title = if XFetchName(display, window, &mut window_name) != 0 && !window_name.is_null() {
811 let c_str = CStr::from_ptr(window_name);
812 let title = c_str.to_string_lossy().to_string();
813 XFree(window_name as *mut _);
814 title
815 } else {
816 String::new()
817 };
818
819 let mut class_hint: XClassHint = mem::zeroed();
821 let process_name = if XGetClassHint(display, window, &mut class_hint) != 0 {
822 let name = if !class_hint.res_class.is_null() {
823 CStr::from_ptr(class_hint.res_class).to_string_lossy().to_string()
824 } else if !class_hint.res_name.is_null() {
825 CStr::from_ptr(class_hint.res_name).to_string_lossy().to_string()
826 } else {
827 "Unknown".to_string()
828 };
829
830 if !class_hint.res_name.is_null() {
831 XFree(class_hint.res_name as *mut _);
832 }
833 if !class_hint.res_class.is_null() {
834 XFree(class_hint.res_class as *mut _);
835 }
836
837 name
838 } else {
839 "Unknown".to_string()
840 };
841
842 let mut x_return = 0;
844 let mut y_return = 0;
845 let mut child_return = 0;
846 XTranslateCoordinates(display, window, attrs.root, 0, 0, &mut x_return, &mut y_return, &mut child_return);
847
848 Ok(SystemWindow {
849 handle: window as u64,
850 title,
851 process_name,
852 pid: 0, x: x_return,
854 y: y_return,
855 width: attrs.width as u32,
856 height: attrs.height as u32,
857 is_visible: attrs.map_state == IsViewable,
858 is_minimized: attrs.map_state == IsUnmapped,
859 is_maximized: false, })
861 }
862}
863
864#[cfg(windows)]
866pub type PlatformWindowManager = windows_impl::WindowsManager;
867
868#[cfg(target_os = "macos")]
869pub type PlatformWindowManager = macos_impl::MacOSManager;
870
871#[cfg(target_os = "linux")]
872pub type PlatformWindowManager = linux_impl::LinuxManager;