1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5use chrono::{DateTime, Utc};
6use crate::workspace::Workspace;
7use crate::layout::LayoutType;
8use crate::config::Config;
9use crate::system_window::{SystemWindow, SystemWindowManager, PlatformWindowManager};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ManagedWindow {
13 pub id: String,
14 pub title: String,
15 pub app_name: String,
16 pub workspace_id: String,
17 pub position: WindowPosition,
18 pub size: WindowSize,
19 pub state: WindowState,
20 pub created_at: DateTime<Utc>,
21 pub last_focused: DateTime<Utc>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct WindowPosition {
26 pub x: i32,
27 pub y: i32,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct WindowSize {
32 pub width: u32,
33 pub height: u32,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub enum WindowState {
38 Normal,
39 Minimized,
40 Maximized,
41 Fullscreen,
42}
43
44pub struct WindowManager {
45 pub windows: Arc<Mutex<HashMap<String, ManagedWindow>>>,
46 pub workspaces: Arc<Mutex<HashMap<String, Workspace>>>,
47 pub active_workspace: Arc<Mutex<String>>,
48 pub config: Arc<Mutex<Config>>,
49 pub system_windows: Arc<Mutex<HashMap<u64, SystemWindow>>>,
50}
51
52impl WindowManager {
53 pub fn new() -> Self {
54 let mut workspaces = HashMap::new();
55 let default_workspace_id = Uuid::new_v4().to_string();
56
57 workspaces.insert(
58 default_workspace_id.clone(),
59 Workspace::new("Default".to_string(), LayoutType::Tiling)
60 );
61
62 Self {
63 windows: Arc::new(Mutex::new(HashMap::new())),
64 workspaces: Arc::new(Mutex::new(workspaces)),
65 active_workspace: Arc::new(Mutex::new(default_workspace_id)),
66 config: Arc::new(Mutex::new(Config::default())),
67 system_windows: Arc::new(Mutex::new(HashMap::new())),
68 }
69 }
70
71 pub fn add_window(&self, title: String, app_name: String) -> Result<String, String> {
72 let window_id = Uuid::new_v4().to_string();
73 let active_workspace = self.active_workspace.lock().unwrap().clone();
74
75 let window = ManagedWindow {
76 id: window_id.clone(),
77 title,
78 app_name,
79 workspace_id: active_workspace.clone(),
80 position: WindowPosition { x: 0, y: 0 },
81 size: WindowSize { width: 800, height: 600 },
82 state: WindowState::Normal,
83 created_at: Utc::now(),
84 last_focused: Utc::now(),
85 };
86
87 self.windows.lock().unwrap().insert(window_id.clone(), window);
88
89 if let Some(workspace) = self.workspaces.lock().unwrap().get_mut(&active_workspace) {
91 workspace.add_window(window_id.clone());
92 }
93
94 self.arrange_workspace(&active_workspace)?;
95
96 Ok(window_id)
97 }
98
99 pub fn remove_window(&self, window_id: &str) -> Result<(), String> {
100 if let Some(window) = self.windows.lock().unwrap().remove(window_id) {
101 if let Some(workspace) = self.workspaces.lock().unwrap().get_mut(&window.workspace_id) {
102 workspace.remove_window(window_id);
103 self.arrange_workspace(&window.workspace_id)?;
104 }
105 Ok(())
106 } else {
107 Err("Window not found".to_string())
108 }
109 }
110
111 pub fn get_windows(&self) -> Vec<ManagedWindow> {
112 self.windows.lock().unwrap().values().cloned().collect()
113 }
114
115 pub fn get_workspace_windows(&self, workspace_id: &str) -> Vec<ManagedWindow> {
116 self.windows
117 .lock()
118 .unwrap()
119 .values()
120 .filter(|w| w.workspace_id == workspace_id)
121 .cloned()
122 .collect()
123 }
124
125 pub fn focus_window(&self, window_id: &str) -> Result<(), String> {
126 if let Some(window) = self.windows.lock().unwrap().get_mut(window_id) {
127 window.last_focused = Utc::now();
128
129 if let Some(workspace) = self.workspaces.lock().unwrap().get_mut(&window.workspace_id) {
131 workspace.focus_window(window_id);
132 }
133
134 Ok(())
135 } else {
136 Err("Window not found".to_string())
137 }
138 }
139
140 pub fn arrange_workspace(&self, workspace_id: &str) -> Result<(), String> {
141 let workspace = self.workspaces.lock().unwrap();
142 let workspace = workspace.get(workspace_id).ok_or("Workspace not found")?;
143
144 let window_ids = workspace.get_windows();
145 let layout = workspace.layout.clone();
146
147 drop(workspace);
148
149 let config = self.config.lock().unwrap();
150 let screen_width = config.screen_width;
151 let screen_height = config.screen_height;
152 let gap = config.window_gap;
153 drop(config);
154
155 match layout {
156 LayoutType::Tiling => self.arrange_tiling(&window_ids, screen_width, screen_height, gap),
157 LayoutType::Floating => Ok(()), LayoutType::Monocle => self.arrange_monocle(&window_ids, screen_width, screen_height),
159 }
160 }
161
162 fn arrange_tiling(&self, window_ids: &[String], screen_width: u32, screen_height: u32, gap: u32) -> Result<(), String> {
163 if window_ids.is_empty() {
164 return Ok(());
165 }
166
167 let mut windows = self.windows.lock().unwrap();
168 let count = window_ids.len();
169
170 if count == 1 {
171 if let Some(window) = windows.get_mut(&window_ids[0]) {
172 window.position = WindowPosition { x: gap as i32, y: gap as i32 };
173 window.size = WindowSize {
174 width: screen_width - (gap * 2),
175 height: screen_height - (gap * 2),
176 };
177 }
178 } else {
179 let cols = (count as f64).sqrt().ceil() as usize;
180 let rows = (count + cols - 1) / cols;
181
182 let window_width = (screen_width - gap * (cols as u32 + 1)) / cols as u32;
183 let window_height = (screen_height - gap * (rows as u32 + 1)) / rows as u32;
184
185 for (i, window_id) in window_ids.iter().enumerate() {
186 if let Some(window) = windows.get_mut(window_id) {
187 let col = i % cols;
188 let row = i / cols;
189
190 window.position = WindowPosition {
191 x: (gap + col as u32 * (window_width + gap)) as i32,
192 y: (gap + row as u32 * (window_height + gap)) as i32,
193 };
194 window.size = WindowSize {
195 width: window_width,
196 height: window_height,
197 };
198 }
199 }
200 }
201
202 Ok(())
203 }
204
205 fn arrange_monocle(&self, window_ids: &[String], screen_width: u32, screen_height: u32) -> Result<(), String> {
206 let mut windows = self.windows.lock().unwrap();
207
208 for window_id in window_ids {
209 if let Some(window) = windows.get_mut(window_id) {
210 window.position = WindowPosition { x: 0, y: 0 };
211 window.size = WindowSize {
212 width: screen_width,
213 height: screen_height,
214 };
215 }
216 }
217
218 Ok(())
219 }
220
221 pub fn create_workspace(&self, name: String, layout: LayoutType) -> String {
222 let workspace_id = Uuid::new_v4().to_string();
223 let workspace = Workspace::new(name, layout);
224
225 self.workspaces.lock().unwrap().insert(workspace_id.clone(), workspace);
226 workspace_id
227 }
228
229 pub fn switch_workspace(&self, workspace_id: &str) -> Result<(), String> {
230 if self.workspaces.lock().unwrap().contains_key(workspace_id) {
231 *self.active_workspace.lock().unwrap() = workspace_id.to_string();
232 Ok(())
233 } else {
234 Err("Workspace not found".to_string())
235 }
236 }
237
238 pub fn get_workspaces(&self) -> Vec<Workspace> {
239 self.workspaces.lock().unwrap().values().cloned().collect()
240 }
241
242 pub fn get_active_workspace(&self) -> String {
243 self.active_workspace.lock().unwrap().clone()
244 }
245
246 pub fn get_system_windows(&self) -> Result<Vec<SystemWindow>, String> {
248 let windows = PlatformWindowManager::get_all_windows()?;
249 *self.system_windows.lock().unwrap() = windows.iter()
250 .map(|w| (w.handle, w.clone()))
251 .collect();
252 Ok(windows)
253 }
254
255 pub fn move_system_window(&self, handle: u64, x: i32, y: i32) -> Result<(), String> {
256 PlatformWindowManager::move_window(handle, x, y)?;
257
258 if let Ok(Some(window)) = PlatformWindowManager::get_window_by_handle(handle) {
260 self.system_windows.lock().unwrap().insert(handle, window);
261 }
262
263 Ok(())
264 }
265
266 pub fn resize_system_window(&self, handle: u64, width: u32, height: u32) -> Result<(), String> {
267 PlatformWindowManager::resize_window(handle, width, height)?;
268
269 if let Ok(Some(window)) = PlatformWindowManager::get_window_by_handle(handle) {
270 self.system_windows.lock().unwrap().insert(handle, window);
271 }
272
273 Ok(())
274 }
275
276 pub fn set_system_window_bounds(&self, handle: u64, x: i32, y: i32, width: u32, height: u32) -> Result<(), String> {
277 PlatformWindowManager::set_window_position_and_size(handle, x, y, width, height)?;
278
279 if let Ok(Some(window)) = PlatformWindowManager::get_window_by_handle(handle) {
280 self.system_windows.lock().unwrap().insert(handle, window);
281 }
282
283 Ok(())
284 }
285
286 pub fn minimize_system_window(&self, handle: u64) -> Result<(), String> {
287 PlatformWindowManager::minimize_window(handle)
288 }
289
290 pub fn maximize_system_window(&self, handle: u64) -> Result<(), String> {
291 PlatformWindowManager::maximize_window(handle)
292 }
293
294 pub fn restore_system_window(&self, handle: u64) -> Result<(), String> {
295 PlatformWindowManager::restore_window(handle)
296 }
297
298 pub fn close_system_window(&self, handle: u64) -> Result<(), String> {
299 PlatformWindowManager::close_window(handle)?;
300 self.system_windows.lock().unwrap().remove(&handle);
301 Ok(())
302 }
303
304 pub fn focus_system_window(&self, handle: u64) -> Result<(), String> {
305 PlatformWindowManager::focus_window(handle)
306 }
307
308 pub fn hide_system_window(&self, handle: u64) -> Result<(), String> {
309 PlatformWindowManager::hide_window(handle)
310 }
311
312 pub fn show_system_window(&self, handle: u64) -> Result<(), String> {
313 PlatformWindowManager::show_window(handle)
314 }
315
316 pub fn arrange_system_windows(&self, window_handles: &[u64]) -> Result<(), String> {
317 let config = self.config.lock().unwrap();
318 let screen_width = config.screen_width;
319 let screen_height = config.screen_height;
320 let gap = config.window_gap;
321 drop(config);
322
323 if window_handles.is_empty() {
324 return Ok(());
325 }
326
327 let count = window_handles.len();
328
329 if count == 1 {
330 self.set_system_window_bounds(
331 window_handles[0],
332 gap as i32,
333 gap as i32,
334 screen_width - (gap * 2),
335 screen_height - (gap * 2)
336 )?;
337 } else {
338 let cols = (count as f64).sqrt().ceil() as usize;
339 let rows = (count + cols - 1) / cols;
340
341 let window_width = (screen_width - gap * (cols as u32 + 1)) / cols as u32;
342 let window_height = (screen_height - gap * (rows as u32 + 1)) / rows as u32;
343
344 for (i, &handle) in window_handles.iter().enumerate() {
345 let col = i % cols;
346 let row = i / cols;
347
348 let x = (gap + col as u32 * (window_width + gap)) as i32;
349 let y = (gap + row as u32 * (window_height + gap)) as i32;
350
351 self.set_system_window_bounds(handle, x, y, window_width, window_height)?;
352 }
353 }
354
355 Ok(())
356 }
357}