tauri_winutils/
system_window.rs

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 // Continue enumeration
219    }
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); // PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
262        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            // Parse CGRect from dictionary
523            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, // Assume visible since we're getting on-screen windows
562            is_minimized: false, // Would need additional checks
563            is_maximized: false, // Would need additional checks
564        })
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                // Get all windows
590                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                // Try to close gracefully first
738                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        // Get window title
809        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        // Get window class (process name)
820        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        // Get window position relative to root
843        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, // Would need additional system calls to get PID
853            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, // Would need additional checks
860        })
861    }
862}
863
864// Platform-specific type alias
865#[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;