// See LICENSE file for copyright and license details. //! Command execution module. //! use std::collections::HashMap; use std::ffi::OsStr; use std::io::Result; use std::ops::Deref; use std::process::{Command,Child}; use std::ptr; use libc::c_int; use libc::pid_t; use x11::xlib; use x11::xlib::{XEvent, GrabModeAsync}; use dotwm::DotWM; use safe_x11::grab_key; const WNOHANG: c_int = 0x00000001; extern { /// wait for a child process to stop or terminate. pub fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t; } /// Executes the given command. pub fn exec_cmd>(program: S, args: &[S]) -> Result { Command::new(program).args(args).spawn() } /// Collect all the zombies. There's no need to add another dependency for this /// since it's trivial to implement. /// /// See https://github.com/Kintaro/zombie for reference. pub fn collect_zombies() { unsafe { while waitpid(-1, ptr::null_mut(), WNOHANG) > 0 {} }; } /// Defines a callback to call no certains events. pub type ExecFn = fn(&mut DotWM, XEvent, &[String]) -> bool; /// Map for keys => functions pub type BindingHash = HashMap<(u32, u32), (ExecFn, Vec)>; /// Exec a binding function. pub 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); } } /// Exec a external function pub 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 } /// Move the window to a relative position pub 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 } /// Move the window to an absolute position. pub fn move_win_to(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() { match win.move_to(x, y) { Ok(()) => true, Err(e) => { println!("{}", e); false } } } else { true } } /// Resize the window certain amount in x and y. pub 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 } /// Focus the next window on the list pub fn focus_next(wm: &mut DotWM, _: xlib::XEvent, _: &[String]) -> bool { wm.focus_next(); true } /// Tells the window manager that is time to exit. pub fn quit_dotwm(wm: &mut DotWM, _: xlib::XEvent, _: &[String]) -> bool { wm.finish = true; true } /// Add a binding to the WM. /// /// # Example /// /// ``` /// fn quit_dotwm(_: &mut DotWM, _: xlib::XEvent, _: &[String]) -> bool { /// process::exit(0); /// } /// /// // ... /// /// add_binding(keysym::XK_Return, xlib::Mod4Mask, exec, /// &["xterm"]); /// ``` pub 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)); }