diff options
Diffstat (limited to 'src/desktop.rs')
-rw-r--r-- | src/desktop.rs | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/desktop.rs b/src/desktop.rs new file mode 100644 index 0000000..7d2a8a5 --- /dev/null +++ b/src/desktop.rs @@ -0,0 +1,178 @@ +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<XWindow>, + 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, + } + } + + 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); + 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); + + match pos { + Some(idx) => { + let new_idx = if idx == 0 { usize::max_value() } else { idx - 1 }; + self.window_list.remove(idx); + self.cw_idx = new_idx; + self.focus_current_window(); + }, + None => (), + } + } + + 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<usize> { + 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.window_list.len() > 0 { + // 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.iter() { + 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<i32> { + self.geometries().iter().map(|x| x.0).collect() + } + + pub fn y_geometries(&self) -> Vec<i32> { + 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(); + } + } +} |