diff options
Diffstat (limited to 'src/dotwm.rs')
-rw-r--r-- | src/dotwm.rs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/dotwm.rs b/src/dotwm.rs new file mode 100644 index 0000000..2d64584 --- /dev/null +++ b/src/dotwm.rs @@ -0,0 +1,140 @@ +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<String>)>, + cw_idx: usize, + pub window_list: Vec<XWindow>, +} + +/// 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); + } +} |