window_enumerator/models.rs
1use crate::types::WindowInfo;
2
3#[cfg(feature = "sorting")]
4use crate::types::{PositionSort, SortCriteria};
5
6#[cfg(feature = "sorting")]
7use crate::utils::matches_criteria;
8
9/// Extension methods for [`WindowInfo`] providing display and validation functionality.
10impl WindowInfo {
11 /// Prints detailed information about the window to stdout.
12 ///
13 /// # Examples
14 /// ```
15 /// # use window_enumerator::WindowInfo;
16 /// # use window_enumerator::WindowPosition;
17 /// # let window = WindowInfo {
18 /// # hwnd: 12345,
19 /// # pid: 1234,
20 /// # title: "Test".to_string(),
21 /// # class_name: "TestClass".to_string(),
22 /// # process_name: "test.exe".to_string(),
23 /// # process_file: std::path::PathBuf::from("test.exe"),
24 /// # index: 1,
25 /// # position: WindowPosition::default(),
26 /// # };
27 /// window.print();
28 /// ```
29 pub fn print(&self) {
30 println!("Index: {}", self.index);
31 println!("Window Handle: 0x{:x}", self.hwnd);
32 println!("Process ID: {}", self.pid);
33 println!("Title: {}", self.title);
34 println!("Class Name: {}", self.class_name);
35 println!("Process Name: {}", self.process_name);
36 println!("Process File: {}", self.process_file.display());
37 println!(
38 "Position: ({}, {}) Size: {}x{}",
39 self.position.x, self.position.y, self.position.width, self.position.height
40 );
41 println!("----------------------------------------");
42 }
43
44 /// Prints compact window information to stdout.
45 ///
46 /// # Examples
47 /// ```
48 /// # use window_enumerator::WindowInfo;
49 /// # use window_enumerator::WindowPosition;
50 /// # let window = WindowInfo {
51 /// # hwnd: 12345,
52 /// # pid: 1234,
53 /// # title: "Test".to_string(),
54 /// # class_name: "TestClass".to_string(),
55 /// # process_name: "test.exe".to_string(),
56 /// # process_file: std::path::PathBuf::from("test.exe"),
57 /// # index: 1,
58 /// # position: WindowPosition::default(),
59 /// # };
60 /// window.print_compact();
61 /// ```
62 pub fn print_compact(&self) {
63 println!(
64 "[{}] 0x{:x} (PID: {}) @ ({},{}) - {}",
65 self.index, self.hwnd, self.pid, self.position.x, self.position.y, self.title
66 );
67 }
68
69 /// Checks if the window handle is still valid.
70 ///
71 /// This verifies that the window still exists in the system.
72 ///
73 /// # Examples
74 /// ```
75 /// # use window_enumerator::WindowInfo;
76 /// # use window_enumerator::WindowPosition;
77 /// # let window = WindowInfo {
78 /// # hwnd: 12345,
79 /// # pid: 1234,
80 /// # title: "Test".to_string(),
81 /// # class_name: "TestClass".to_string(),
82 /// # process_name: "test.exe".to_string(),
83 /// # process_file: std::path::PathBuf::from("test.exe"),
84 /// # index: 1,
85 /// # position: WindowPosition::default(),
86 /// # };
87 /// let is_valid = window.is_valid();
88 /// ```
89 #[cfg(feature = "windows")]
90 pub fn is_valid(&self) -> bool {
91 use windows::Win32::Foundation::*;
92 use windows::Win32::UI::WindowsAndMessaging::*;
93
94 unsafe { IsWindow(HWND(self.hwnd)).as_bool() }
95 }
96}
97
98/// Provides window sorting functionality.
99#[cfg(feature = "sorting")]
100pub struct WindowSorter;
101
102#[cfg(feature = "sorting")]
103impl WindowSorter {
104 /// Sorts a vector of windows according to the specified criteria.
105 ///
106 /// # Arguments
107 ///
108 /// * `windows` - The windows to sort (modified in-place)
109 /// * `sort_criteria` - The criteria to use for sorting
110 pub fn sort_windows(windows: &mut [WindowInfo], sort_criteria: &SortCriteria) {
111 // ← 修改参数类型为切片
112 if sort_criteria.pid == 0 && sort_criteria.title == 0 && sort_criteria.position.is_none() {
113 return; // No sorting criteria
114 }
115
116 windows.sort_by(|a, b| {
117 let mut ordering = std::cmp::Ordering::Equal;
118
119 // PID sorting
120 if sort_criteria.pid != 0 {
121 ordering = a.pid.cmp(&b.pid);
122 if sort_criteria.pid < 0 {
123 ordering = ordering.reverse();
124 }
125 if ordering != std::cmp::Ordering::Equal {
126 return ordering;
127 }
128 }
129
130 // Title sorting
131 if sort_criteria.title != 0 {
132 ordering = a.title.to_lowercase().cmp(&b.title.to_lowercase());
133 if sort_criteria.title < 0 {
134 ordering = ordering.reverse();
135 }
136 if ordering != std::cmp::Ordering::Equal {
137 return ordering;
138 }
139 }
140
141 // Position sorting
142 if let Some(ref position_sort) = sort_criteria.position {
143 ordering = Self::compare_positions(a, b, position_sort);
144 if ordering != std::cmp::Ordering::Equal {
145 return ordering;
146 }
147 }
148
149 ordering
150 });
151 }
152
153 /// Compares two windows based on position sorting criteria.
154 fn compare_positions(
155 a: &WindowInfo,
156 b: &WindowInfo,
157 position_sort: &PositionSort,
158 ) -> std::cmp::Ordering {
159 match position_sort {
160 PositionSort::X(order) => {
161 let ordering = a.position.x.cmp(&b.position.x);
162 if *order < 0 {
163 ordering.reverse()
164 } else {
165 ordering
166 }
167 }
168 PositionSort::Y(order) => {
169 let ordering = a.position.y.cmp(&b.position.y);
170 if *order < 0 {
171 ordering.reverse()
172 } else {
173 ordering
174 }
175 }
176 PositionSort::XY(x_order, y_order) => {
177 // Sort by X first
178 let x_ordering = a.position.x.cmp(&b.position.x);
179 if x_ordering != std::cmp::Ordering::Equal {
180 return if *x_order < 0 {
181 x_ordering.reverse()
182 } else {
183 x_ordering
184 };
185 }
186
187 // If X is equal, sort by Y
188 let y_ordering = a.position.y.cmp(&b.position.y);
189 if *y_order < 0 {
190 y_ordering.reverse()
191 } else {
192 y_ordering
193 }
194 }
195 }
196 }
197
198 /// Filters and sorts windows according to the specified criteria.
199 ///
200 /// # Arguments
201 ///
202 /// * `windows` - The windows to filter and sort
203 /// * `criteria` - The filter criteria
204 /// * `sort_criteria` - The sort criteria
205 ///
206 /// # Returns
207 ///
208 /// A new vector containing the filtered and sorted windows.
209 pub fn filter_and_sort_windows(
210 windows: &[WindowInfo],
211 criteria: &crate::types::FilterCriteria,
212 sort_criteria: &SortCriteria,
213 ) -> Vec<WindowInfo> {
214 let mut filtered: Vec<WindowInfo> = windows
215 .iter()
216 .filter(|window| matches_criteria(window, criteria))
217 .cloned()
218 .collect();
219
220 Self::sort_windows(&mut filtered, sort_criteria);
221 filtered
222 }
223}