summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatias Linares <matiaslina@openmailbox.org>2015-11-28 22:16:43 -0300
committerMatias Linares <matiaslina@openmailbox.org>2015-11-28 22:16:43 -0300
commite1ec354306742a5804a20e2651cf49945cd17287 (patch)
tree7f607096fa43f96680d933b7a046f603227e566c
parent901d03b3a8ac0b7d8533fd9a8d43238d665d9cb8 (diff)
downloaddotwm-e1ec354306742a5804a20e2651cf49945cd17287.tar.gz
Better socket handling
The socket interface now allows almost everything that vould be done by the internals of the window manager. Also the Window manager now closes fine (on a success exit).
-rwxr-xr-xautostart24
-rw-r--r--src/command.rs29
-rw-r--r--src/dotwm.rs3
-rw-r--r--src/main.rs33
-rw-r--r--src/socket/mod.rs49
-rw-r--r--src/socket/parser.rs215
6 files changed, 255 insertions, 98 deletions
diff --git a/autostart b/autostart
index 1e98405..a0b4919 100755
--- a/autostart
+++ b/autostart
@@ -1,10 +1,22 @@
#!/bin/mksh
netcat -U dotwm.sock <<EOF
-add-binding Mod4Mask p exec dmenu_run
-add-binding Mod4Mask h move_win -10 0
-add-binding Mod4Mask j move_win 0 10
-add-binding Mod4Mask k move_win 0 -10
-add-binding Mod4Mask l move_win 10 0
-add-binding Mod4Mask Return exec xterm
+bind Mod4 p exec dmenu_run
+bind Mod4 h move-win -10 0
+bind Mod4 j move-win 0 10
+bind Mod4 k move-win 0 -10
+bind Mod4 l move-win 10 0
+bind Mod4 Return exec xterm
+
+bind Mod4-Control h resize-win -10 0
+bind Mod4-Control j resize-win 0 10
+bind Mod4-Control k resize-win 0 -10
+bind Mod4-Control l resize-win 10 0
+
+bind Mod4-Shift h move-win-to 0 0
+bind Mod4-Shift j move-win-to 100 100
+bind Mod4-Shift k move-win-to 200 200
+bind Mod4-Shift l move-win-to 0 1000
+
+bind Mod4 Tab focus-next
EOF
diff --git a/src/command.rs b/src/command.rs
index 3bebc52..0ccee17 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -7,7 +7,6 @@ use std::ffi::OsStr;
use std::io::Result;
use std::ops::Deref;
use std::process::{Command,Child};
-use std::process;
use std::ptr;
use libc::c_int;
@@ -47,6 +46,7 @@ pub type ExecFn = fn(&mut DotWM, XEvent, &[String]) -> bool;
/// Map for keys => functions
pub type BindingHash = HashMap<(u32, u32), (ExecFn, Vec<String>)>;
+/// 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();
@@ -54,6 +54,7 @@ pub fn exec_func(wm: &mut DotWM, bindings: &mut BindingHash, key: u32, modifiers
}
}
+/// 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![];
@@ -65,6 +66,7 @@ pub fn exec(_: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool {
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::<i32>().unwrap();
let y = args[1].parse::<i32>().unwrap();
@@ -74,6 +76,24 @@ pub fn move_win(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool {
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::<i32>().unwrap();
+ let y = args[1].parse::<i32>().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::<i32>().unwrap();
let h = args[1].parse::<i32>().unwrap();
@@ -85,13 +105,16 @@ pub fn resize_win(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool {
true
}
+/// Focus the next window on the list
pub fn focus_next(wm: &mut DotWM, _: xlib::XEvent, _: &[String]) -> bool {
wm.focus_next();
true
}
-pub fn quit_dotwm(_: &mut DotWM, _: xlib::XEvent, _: &[String]) -> bool {
- process::exit(0);
+/// 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.
diff --git a/src/dotwm.rs b/src/dotwm.rs
index e531f0a..cd909b5 100644
--- a/src/dotwm.rs
+++ b/src/dotwm.rs
@@ -35,6 +35,8 @@ pub struct DotWM {
pub display: *mut Display,
/// References to all the windows.
pub window_list: Vec<XWindow>,
+ /// Check if the window manager needs to end.
+ pub finish: bool,
// Map with the keys as (key, mod)
cw_idx: usize,
}
@@ -56,6 +58,7 @@ impl DotWM {
DotWM {
display: d,
cw_idx: 0,
+ finish: false,
window_list: vec![],
}
}
diff --git a/src/main.rs b/src/main.rs
index 21133ef..c9cc11e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -23,35 +23,26 @@ use x11::xlib;
use x11::xlib::XEvent;
use x11::keysym;
+use std::fs;
use std::io::{Read,Write};
use unix_socket::UnixListener;
+const SOCKET_PATH: &'static str = "./dotwm.sock";
+
fn main() {
println!("Creating dotwm");
let mut dotwm = DotWM::new();
let mut bindings: BindingHash = HashMap::new();
let x11_fd = safe_x11::x11_fd(dotwm.display);
- // 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_Return, xlib::Mod4Mask, exec, &["xterm"]);
- add_binding(&mut dotwm,&mut bindings, keysym::XK_Tab, xlib::Mod4Mask, focus_next, &[]);
add_binding(&mut dotwm, &mut bindings, keysym::XK_q, xlib::Mod4Mask | xlib::ShiftMask, quit_dotwm, &[]);
- let listener = UnixListener::bind("./dotwm.sock").unwrap();
+ let listener = UnixListener::bind(SOCKET_PATH).unwrap();
exec_cmd("./autostart", &[]).unwrap();
// Main loop
- loop {
+ while !dotwm.finish {
let event = unsafe { select_event(dotwm.display, x11_fd, &listener) };
match event {
Event::Key(mut e, true) => {
@@ -84,12 +75,22 @@ fn main() {
s.read_to_string(&mut buf).unwrap();
for line in buf.lines() {
- let result = parser::parse(&mut dotwm, &mut bindings, &line);
- let _ = write!(s, "{}", result);
+ let res = parser::parse(&line);
+ match res {
+ Ok(pcmd) => {
+ pcmd.handle(&mut dotwm, &mut bindings);
+ let _ = write!(s, "+ok");
+ },
+ Err(e) => {
+ let _ = write!(s, "-{}", e);
+ },
+ }
}
},
_ => println!("Unknown event"),
}
collect_zombies();
}
+
+ let _ = fs::remove_file(SOCKET_PATH);
}
diff --git a/src/socket/mod.rs b/src/socket/mod.rs
index e260284..667969b 100644
--- a/src/socket/mod.rs
+++ b/src/socket/mod.rs
@@ -2,7 +2,6 @@
pub mod parser;
-use std::io::{Read,Write};
use std::sync::mpsc::{Receiver, TryRecvError};
use unix_socket::UnixStream;
@@ -10,6 +9,34 @@ use unix_socket::UnixStream;
use dotwm::DotWM;
use command::*;
+#[derive(Debug,PartialEq)]
+pub enum FnType {
+ Bind,
+ Exec,
+}
+
+pub struct ParsedCmd<'a> {
+ pub f: FnType,
+ pub modifiers: Vec<u32>,
+ pub key: u32,
+ pub args: Vec<&'a str>,
+ pub func: ExecFn,
+}
+
+impl<'a> ParsedCmd<'a> {
+ pub fn handle(self, wm: &mut DotWM, bindings: &mut BindingHash) {
+ match self.f {
+ FnType::Bind => {
+ let modifier = self.modifiers.iter()
+ .fold(0, |acc, x| acc | x );
+ add_binding(wm, bindings,
+ self.key, modifier, self.func, &self.args);
+ },
+ _ => (),
+ }
+ }
+}
+
pub fn next_socket_event(rx: &Receiver<UnixStream>) -> Option<UnixStream> {
match rx.try_recv() {
Ok(stream) => Some(stream),
@@ -17,23 +44,3 @@ pub fn next_socket_event(rx: &Receiver<UnixStream>) -> Option<UnixStream> {
Err(TryRecvError::Disconnected) => panic!("Socket disconnected"),
}
}
-
-/// Listen a socket parsing and executing all the commands.
-pub fn listen_socket(dotwm: &mut DotWM, bindings: &mut BindingHash, rx: &Receiver<UnixStream>) {
- loop {
- match rx.try_recv() {
- Ok(stream) => {
- let mut s = stream.try_clone().unwrap();
- let mut buf = String::new();
- s.read_to_string(&mut buf).unwrap();
-
- for line in buf.lines() {
- let result = parser::parse(dotwm, bindings, &line);
- let _ = write!(s, "{}", result);
- }
- },
- Err(TryRecvError::Empty) => break,
- Err(TryRecvError::Disconnected) => panic!("Socket disconnected"),
- }
- }
-}
diff --git a/src/socket/parser.rs b/src/socket/parser.rs
index e8dd9ec..0de0248 100644
--- a/src/socket/parser.rs
+++ b/src/socket/parser.rs
@@ -9,94 +9,205 @@ use x11::xlib;
use x11::keysym;
use command::*;
-use dotwm::DotWM;
+use ::socket::ParsedCmd;
+use ::socket::FnType;
-use nom::{IResult,alpha,multispace};
-use nom::IResult::*;
-use std::str;
-
-named!(token<&str>,
- map_res!(
- alpha, str::from_utf8));
+macro_rules! simple_try {
+ ($expr:expr) => (match $expr {
+ Ok(val) => val,
+ Err(err) => {
+ return Err(err)
+ }
+ })
+}
-fn slice2str(input: Vec<&[u8]>) -> Vec<&str> {
- let res: Vec<&str> = input.iter()
- .map(|x| str::from_utf8(x).unwrap())
- .collect();
- res
+fn modifier_from<'a>(s: &'a str) -> Result<u32, &'static str> {
+ match s {
+ "Mod1" => Ok(xlib::Mod4Mask),
+ "Mod2" => Ok(xlib::Mod4Mask),
+ "Mod3" => Ok(xlib::Mod4Mask),
+ "Mod4" => Ok(xlib::Mod4Mask),
+ "Control" => Ok(xlib::ControlMask),
+ "Shift" => Ok(xlib::ShiftMask),
+ _ => Err("unknown modifier"),
+ }
}
-named!(args<Vec<&str> >,
- map!(
- separated_list!(
- multispace, alpha),
- slice2str));
+fn modifiers<'a>(s: &'a str) -> Result<Vec<u32>, &'static str> {
+ let mut result = vec![];
-fn modifier<'a>(s: &'a str) -> Result<u32, ()> {
- match s {
- "Mod1Mask" => Ok(xlib::Mod4Mask),
- "Mod2Mask" => Ok(xlib::Mod4Mask),
- "Mod3Mask" => Ok(xlib::Mod4Mask),
- "Mod4Mask" => Ok(xlib::Mod4Mask),
- "ControlMask" => Ok(xlib::ControlMask),
- "ShiftMask" => Ok(xlib::ShiftMask),
- _ => Err(()),
+ for smod in s.split("-") {
+ let modifier = simple_try!(modifier_from(smod));
+ result.push(modifier);
}
+
+ Ok(result)
}
-fn str_to_key<'a>(s: &'a str) -> Result<u32, ()> {
+fn key<'a>(s: &'a str) -> Result<u32, &'static str> {
match s {
+ "a" => Ok(keysym::XK_a),
+ "b" => Ok(keysym::XK_b),
+ "c" => Ok(keysym::XK_c),
+ "d" => Ok(keysym::XK_d),
+ "e" => Ok(keysym::XK_e),
+ "f" => Ok(keysym::XK_f),
+ "g" => Ok(keysym::XK_g),
"h" => Ok(keysym::XK_h),
+ "i" => Ok(keysym::XK_i),
"j" => Ok(keysym::XK_j),
"k" => Ok(keysym::XK_k),
"l" => Ok(keysym::XK_l),
- "Tab" => Ok(keysym::XK_Tab),
+ "m" => Ok(keysym::XK_m),
+ "n" => Ok(keysym::XK_n),
+ "o" => Ok(keysym::XK_o),
"p" => Ok(keysym::XK_p),
- "Return" => Ok(keysym::XK_Return),
"q" => Ok(keysym::XK_q),
- _ => Err(()),
+ "r" => Ok(keysym::XK_r),
+ "s" => Ok(keysym::XK_s),
+ "t" => Ok(keysym::XK_t),
+ "u" => Ok(keysym::XK_u),
+ "v" => Ok(keysym::XK_v),
+ "w" => Ok(keysym::XK_w),
+ "x" => Ok(keysym::XK_x),
+ "y" => Ok(keysym::XK_y),
+ "z" => Ok(keysym::XK_z),
+ "A" => Ok(keysym::XK_A),
+ "B" => Ok(keysym::XK_B),
+ "C" => Ok(keysym::XK_C),
+ "D" => Ok(keysym::XK_D),
+ "E" => Ok(keysym::XK_E),
+ "F" => Ok(keysym::XK_F),
+ "G" => Ok(keysym::XK_G),
+ "H" => Ok(keysym::XK_H),
+ "I" => Ok(keysym::XK_I),
+ "J" => Ok(keysym::XK_J),
+ "K" => Ok(keysym::XK_K),
+ "L" => Ok(keysym::XK_L),
+ "M" => Ok(keysym::XK_M),
+ "N" => Ok(keysym::XK_N),
+ "O" => Ok(keysym::XK_O),
+ "P" => Ok(keysym::XK_P),
+ "Q" => Ok(keysym::XK_Q),
+ "R" => Ok(keysym::XK_R),
+ "S" => Ok(keysym::XK_S),
+ "T" => Ok(keysym::XK_T),
+ "U" => Ok(keysym::XK_U),
+ "V" => Ok(keysym::XK_V),
+ "W" => Ok(keysym::XK_W),
+ "X" => Ok(keysym::XK_X),
+ "Y" => Ok(keysym::XK_Y),
+ "Z" => Ok(keysym::XK_Z),
+ "Tab" => Ok(keysym::XK_Tab),
+ "Return" => Ok(keysym::XK_Return),
+ _ => Err("unknown key"),
}
}
-fn str_to_func<'a>(s: &'a str) -> Result<ExecFn,()> {
+fn func<'a>(s: &'a str) -> Result<ExecFn, &'static str> {
match s {
"exec" => Ok(exec),
- "move_win" => Ok(move_win),
- "resize_win" => Ok(resize_win),
- _ => Err(()),
+ "move-win" => Ok(move_win),
+ "move-win-to" => Ok(move_win_to),
+ "resize-win" => Ok(resize_win),
+ "focus-next" => Ok(focus_next),
+ "quit" => Ok(quit_dotwm),
+ _ => Err("unknown function"),
}
}
-pub fn parse<'a>(dotwm: &mut DotWM, bindings: &mut BindingHash, input: &'a str) -> &'a str {
- let args: Vec<&str> = input.split_whitespace().collect();
+pub fn parse<'a>(input: &'a str) -> Result<ParsedCmd<'a>, &'static str> {
+ let args: Vec<&'a str> = input.split_whitespace().collect();
match args.first() {
Some(cmd) => {
match cmd {
- &"add-binding" => {
- let modifier = modifier(args[1]).unwrap();
- let key = str_to_key(args[2]).unwrap();
- let func = str_to_func(args[3]).unwrap();
- let arguments = &args[4..];
+ &"bind" => {
+ if args.len() > 2 {
+ let modifiers = simple_try!(modifiers(args[1]));
+ let key = simple_try!(key(args[2]));
+ let func = simple_try!(func(args[3]));
+ let arguments: &[&'a str]= &args[4..];
- add_binding(dotwm, bindings, key, modifier, func, arguments);
+ Ok(ParsedCmd {
+ f: FnType::Bind,
+ modifiers: modifiers,
+ key: key,
+ args: arguments.to_vec(),
+ func: func,
+ })
+ } else {
+ Err("missing arguments")
+ }
+ },
+ &"exec" => {
+ Ok(ParsedCmd {
+ f: FnType::Exec,
+ modifiers: vec![],
+ key: 0,
+ args: vec![],
+ func: exec
+ })
+ },
+ _ => {
+ Err("unknown command")
},
- &"exec" => { println!("exec"); },
- _ => { println!("anotherthing ._."); },
}
},
- None => println!("error"),
+ None => Err("no input"),
+ }
+}
+
+#[test]
+fn parse_unknown() {
+ let res = parse("unknown");
+ if let Err(e) = res {
+ assert_eq!(e, "unknown command");
+ } else {
+ assert!(false);
}
- "ok"
}
#[test]
-fn parse_test() {
- assert_eq!(token(&b"exec"[..]), IResult::Done(&b""[..], "exec"));
+fn parse_bind_modifier() {
+ let res = parse("bind modifier1 k exec ");
+ if let Err(e) = res {
+ assert_eq!(e, "unknown modifier");
+ } else {
+ assert!(false);
+ }
+
+ let res2 = parse("bind Mod4 k exec ");
+ if let Ok(modifier) = res2 {
+ assert_eq!(modifier.modifiers[0], xlib::Mod4Mask);
+ } else {
+ assert!(false);
+ }
}
#[test]
-fn parse_args() {
- assert_eq!(args(&b"hola chau"[..]),
- IResult::Done(&b""[..], vec!["hola", "chau"]));
+fn parse_bind_key() {
+ let res = parse("bind Mod4 ' exec ");
+ if let Err(e) = res {
+ assert_eq!(e, "unknown key");
+ } else {
+ assert!(false);
+ }
+
+ let res2 = parse("bind Mod4 k exec ");
+ if let Ok(modifier) = res2 {
+ assert_eq!(modifier.key, keysym::XK_k);
+ } else {
+ assert!(false);
+ }
+}
+
+#[test]
+fn parse_exec() {
+ let res = parse("exec Mod4 ' exec ");
+ if let Ok(pcmd) = res {
+ assert_eq!(pcmd.f, FnType::Exec);
+ } else {
+ assert!(false);
+ }
}