use x11::xlib; use x11::xlib::{ Display, XErrorEvent, XEvent, GrabModeAsync, }; use safe_x11::{ open_display, close_display, grab_key, }; use safe_x11::window::XWindow; use std::ptr; use std::process::exit; use std::mem::uninitialized; use std::collections::HashMap; 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 } /// Defines a callback to call no certains events. pub type ExecFn = fn(&DotWM, XEvent, &[String]) -> bool; pub struct DotWM { pub display: *mut Display, // Map with the keys as (key, mod) bindings: HashMap<(u32, u32), (ExecFn, Vec)>, cw_idx: usize, pub window_list: Vec, } /// 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, bindings: HashMap::new(), cw_idx: 0, window_list: vec![], } } /// Add a binding to the WM. /// /// # Example /// /// ``` /// fn exec(_: &DotWM, _: xlib::XEvent, args: &[String]) -> bool { /// if let Some(program) = args.first() { /// let mut prog_args = vec![]; /// for arg in args[1..].iter() { /// prog_args.push(arg); /// } /// exec_cmd(program, prog_args.deref()).unwrap(); /// } /// true /// } /// /// // ... /// /// dotwm.add_binding(keysym::XK_Return, xlib::Mod4Mask, exec, /// &["xterm"]); /// ``` pub fn add_binding(&mut self, key: u32, modifiers: u32, func: ExecFn, args: &[&str]) { grab_key(self.display, key, modifiers, true, GrabModeAsync, GrabModeAsync); let mut v = vec![]; for arg in args { v.push(arg.to_string()); } self.bindings.insert((key, modifiers), (func, v)); } pub fn exec_func(&mut self, key: u32, modifiers: u32, ev: xlib::XEvent) { if let Some(&(func, ref args)) = self.bindings.get(&(key, modifiers)) { let v = args.clone(); func(&self, ev, &v); } } pub fn add_window(&mut self, w: xlib::Window) { if let Some(w) = XWindow::new(self.display, w) { self.window_list.push(w); // Last windows get focus. self.cw_idx = self.window_list.len() - 1; } } 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) => { self.window_list.remove(idx); self.cw_idx = usize::max_value(); }, None => (), } } } impl Drop for DotWM { fn drop(&mut self) { println!("Closing display"); close_display(self.display); } }