extern crate libc; extern crate x11; pub mod safe_x11; pub mod command; pub mod dotwm; pub mod event; use dotwm::DotWM; use command::exec_cmd; use event::{Event,next_event}; use safe_x11::grab_key; use std::ops::Deref; use std::process; use std::collections::HashMap; use x11::xlib; use x11::xlib::GrabModeAsync; use x11::xlib::XEvent; use x11::keysym; /// Defines a callback to call no certains events. pub type ExecFn = fn(&mut DotWM, XEvent, &[String]) -> bool; type BindingHash = HashMap<(u32, u32), (ExecFn, Vec)>; fn exec_func(wm: &mut DotWM, bindings: &mut BindingHash, key: u32, modifiers: u32, ev: xlib::XEvent) { if let Some(&(func, ref args)) = bindings.get(&(key, modifiers)) { let v = args.clone(); func(wm, ev, &v); } } fn exec(_: &mut 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 } fn move_win(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool { let x = args[0].parse::().unwrap(); let y = args[1].parse::().unwrap(); if let Some(ref win) = wm.current_window() { win.move_offset(x, y); }; true } fn resize_win(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool { let w = args[0].parse::().unwrap(); let h = args[1].parse::().unwrap(); if let Some(ref win) = wm.current_window() { win.resize(w, h); }; true } fn focus_next(wm: &mut DotWM, _: xlib::XEvent, _: &[String]) -> bool { wm.focus_next(); true } fn quit_dotwm(_: &mut DotWM, _: xlib::XEvent, _: &[String]) -> bool { process::exit(0); } fn add_binding(wm: &mut DotWM, bindings: &mut BindingHash, key: u32, modifiers: u32, func: ExecFn, args: &[&str]) { grab_key(wm.display, key, modifiers, true, GrabModeAsync, GrabModeAsync); let mut v = vec![]; for arg in args { v.push(arg.to_string()); } bindings.insert((key, modifiers), (func, v)); } fn main() { println!("Creating dotwm"); let mut dotwm = DotWM::new(); let mut bindings: BindingHash = HashMap::new(); add_binding(&mut dotwm,&mut bindings, keysym::XK_Return, xlib::Mod4Mask, exec, &["xterm"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_p, xlib::Mod4Mask, exec, &["dmenu_run"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_Tab, xlib::Mod4Mask, focus_next, &[]); add_binding(&mut dotwm,&mut bindings, keysym::XK_h, xlib::Mod4Mask, move_win, &["-10", "0"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_j, xlib::Mod4Mask, move_win, &["0", "10"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_k, xlib::Mod4Mask, move_win, &["0", "-10"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_l, xlib::Mod4Mask, move_win, &["10", "0"]); // Resize add_binding(&mut dotwm,&mut bindings, keysym::XK_h, xlib::Mod4Mask | xlib::ControlMask, resize_win, &["-10", "0"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_j, xlib::Mod4Mask | xlib::ControlMask, resize_win, &["0", "10"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_k, xlib::Mod4Mask | xlib::ControlMask, resize_win, &["0", "-10"]); add_binding(&mut dotwm,&mut bindings, keysym::XK_l, xlib::Mod4Mask | xlib::ControlMask, resize_win, &["10", "0"]); add_binding(&mut dotwm, &mut bindings, keysym::XK_q, xlib::Mod4Mask | xlib::ShiftMask, quit_dotwm, &[]); // Main loop loop { let event = next_event(dotwm.display); println!("Event {:?}", event); match event { Event::Key(mut e, true) => { let keysym = unsafe { xlib::XLookupKeysym(&mut e, 0) as u32 }; let mask = e.state; exec_func(&mut dotwm, &mut bindings, keysym, mask, xlib::XEvent::from(e)); }, Event::Map(e) => { // If the window has override_redirect setted to true, this should not // be handled by the wm. let map_event = xlib::XMapEvent::from(e); if map_event.override_redirect == 0 { println!("Adding window"); dotwm.add_window(map_event.window); } else { println!("Map event 0 :("); } } Event::Unmap(e) => { dotwm.remove_window(e.window); }, Event::Enter(e) => { if let Some(idx) = dotwm.find_window(e.window) { dotwm.change_focus_of(idx); } }, _ => (), } } }