use x11::xlib; use x11::xlib::{ Display, }; use safe_x11::window::XWindow; use safe_x11::{ screen_size, }; pub struct Desktop { #[allow(dead_code)] display: *mut Display, #[allow(dead_code)] tag: String, window_list: Vec, cw_idx: usize, } impl Desktop { pub fn new(display: *mut Display, tag: &'static str) -> Desktop { Desktop { display: display, tag: String::from(tag), window_list: vec![], cw_idx: 0, } } /// Tells if the current index is valid for indexing the window list. /// /// This is a precondition that must be valid wherever one index that /// list. fn valid_idx(&self) -> bool { self.cw_idx != usize::max_value() } pub fn current_window(&self) -> Option<&XWindow> { if self.cw_idx < self.window_list.len() { self.window_list.get(self.cw_idx) } else { None } } pub fn current_window_mut(&mut self) -> Option<&mut XWindow> { if self.cw_idx < self.window_list.len() { self.window_list.get_mut(self.cw_idx) } else { None } } /// Add a window to the current desktop pub fn add_window(&mut self, w: xlib::Window) { if self.find_window(w).is_some() { return; } self.unfocus_current_window(); if let Some(w) = XWindow::new(self.display, w) { w.select_input(xlib::EnterWindowMask | xlib::ExposureMask); self.window_list.push(w); // Last windows get focus. self.focus_current_window(); } } /// Remove a window. pub fn remove_window(&mut self, w: xlib::Window) { let pos = self.window_list.iter().position(|xw| xw.inner == w); if let Some(idx) = pos { let new_idx = if idx == 0 { if self.window_list.len() == 1 { usize::max_value() } else { 0 } } else { idx - 1 }; self.window_list.remove(idx); self.cw_idx = new_idx; self.focus_current_window(); } } /// Changes the focus from the current window to the window on the idx /// postition on the window_list. pub fn change_focus_of(&mut self, idx: usize) { let w = &self.window_list[idx]; self.unfocus_current_window(); self.cw_idx = idx; w.set_border_width(1); w.set_border_color("red"); w.raise(); } /// Find a given window and returns it's position on the window_list. pub fn find_window(&self, w: xlib::Window) -> Option { self.window_list.iter().position(|xw| xw.inner == w) } /// Focus the next window. /// /// There're 3 posibilities. There's no window, there's one window or there /// are more windows. pub fn focus_next(&mut self) { if self.valid_idx() { // Unfocus the current window. let prev_win = &self.window_list[self.cw_idx]; prev_win.unfocus(); // And give focus to the next one. let next_win_idx = if self.cw_idx < self.window_list.len() - 1 { self.cw_idx + 1 } else { 0 }; let curr_win = &self.window_list[next_win_idx]; curr_win.focus(); self.cw_idx = next_win_idx; } } fn focus_current_window(&self) { self.current_window().map(|x| x.focus()); } fn unfocus_current_window(&self) { self.current_window().map(|x| x.unfocus()); } /// Get a list of the geometries for every window in the screen (including /// the screen borders. The form is (x, y). /// /// # Example /// /// Having a screen of 800x600, and a window on 10(x), 10(y) with dimensions /// 400(width) and 300(height): /// /// ``` /// for (x, y) in dotwm.geometries() { /// println!("x: {} - y: {}", x, y); /// } /// ``` /// /// The output will be: /// /// ``` /// (0,0) /// (800, 600) /// (10, 10) /// (410, 310) /// ``` pub fn geometries(&self) -> Vec<(i32,i32)> { let (screen_width, screen_height) = screen_size(self.display); let mut result: Vec<(i32,i32)> = vec![ (0, 0), (screen_width as i32, screen_height as i32), ]; for w in &self.window_list { let attrs = w.attributes(); result.push((attrs.x, attrs.y)); result.push((attrs.x + attrs.width, attrs.y + attrs.height)); } result } pub fn x_geometries(&self) -> Vec { self.geometries().iter().map(|x| x.0).collect() } pub fn y_geometries(&self) -> Vec { self.geometries().iter().map(|x| x.1).collect() } pub fn show_windows(&self) { for win in &self.window_list { win.map(); } } pub fn hide_windows(&self) { for win in &self.window_list { win.unmap(); } } }