use x11::xlib; use x11::xlib::{ Display, XErrorEvent, }; use safe_x11::{ open_display, close_display, }; use safe_x11::window::XWindow; use std::ptr; use std::process::exit; use std::mem::uninitialized; use libc::c_int; #[allow(unused_variables)] unsafe extern "C" fn error_handler(d: *mut Display, evptr: *mut XErrorEvent) -> c_int { println!("ERRORR"); let ev = ptr::read(evptr); if ev.error_code == xlib::BadAccess { println!("Another widnow manager is running :C"); exit(1); } 0 } pub struct DotWM { /// Reference to the X display. pub display: *mut Display, /// References to all the windows. pub window_list: Vec, // Map with the keys as (key, mod) cw_idx: usize, } /// DotWM state. impl DotWM { /// Create a state of the Dot Window Manager pub fn new() -> DotWM { let d = open_display("").unwrap(); unsafe { xlib::XSetErrorHandler(Some(error_handler)) }; // Some testings. unsafe { let root = xlib::XDefaultRootWindow(d); let mut attrs: xlib::XSetWindowAttributes = uninitialized(); attrs.event_mask = xlib::SubstructureNotifyMask; xlib::XChangeWindowAttributes(d, root, xlib::CWEventMask, &mut attrs); } DotWM { display: d, cw_idx: 0, window_list: vec![], } } pub fn add_window(&mut self, w: xlib::Window) { 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.cw_idx = self.window_list.len() - 1; self.focus_current_window(); } } 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 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 { 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()); } } impl Drop for DotWM { fn drop(&mut self) { println!("Closing display"); close_display(self.display); } }