From a21473f60c6cfad6335db3b0b45cdff23f8b3a89 Mon Sep 17 00:00:00 2001 From: Matias Linares Date: Thu, 19 Nov 2015 21:11:34 -0300 Subject: Implemented socket handler. First steps on the socket handling. Dotwm will use this for communication between different clients trying to modify the behaviour (just take a look into hlwm's herbstclient program). It's needed a parser for the configuration, make the protocol and get it working better. For now I'm checking if it's anything into the socket every time I've a XEvent. But it shouldn't be this way. --- .gitignore | 1 + Cargo.lock | 15 ++++++++ Cargo.toml | 1 + autostart | 4 +++ src/command.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 107 ++++++++++++++------------------------------------------- src/socket.rs | 63 +++++++++++++++++++++++++++++++++ 7 files changed, 197 insertions(+), 84 deletions(-) create mode 100755 autostart create mode 100644 src/socket.rs diff --git a/.gitignore b/.gitignore index eb5a316..44279aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target +dotwm.sock diff --git a/Cargo.lock b/Cargo.lock index b881a57..eabeb47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,9 +3,15 @@ name = "dotwm" version = "0.1.0" dependencies = [ "libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unix_socket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cfg-if" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.1.12" @@ -21,6 +27,15 @@ name = "pkg-config" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unix_socket" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "x11" version = "2.2.1" diff --git a/Cargo.toml b/Cargo.toml index a83691d..66e2b19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Matias Linares "] [dependencies] libc = "0.2.*" +unix_socket = "*" [dependencies.x11] version = "*" diff --git a/autostart b/autostart new file mode 100755 index 0000000..82cc3f6 --- /dev/null +++ b/autostart @@ -0,0 +1,4 @@ +#!/bin/mksh + +echo -n "hola" | netcat -U ./dotwm.sock +echo -n "done" | netcat -U ./dotwm.sock diff --git a/src/command.rs b/src/command.rs index b728776..3bebc52 100644 --- a/src/command.rs +++ b/src/command.rs @@ -2,13 +2,22 @@ //! Command execution module. //! +use std::collections::HashMap; use std::ffi::OsStr; -use std::process::{Command,Child}; use std::io::Result; +use std::ops::Deref; +use std::process::{Command,Child}; +use std::process; +use std::ptr; use libc::c_int; use libc::pid_t; -use std::ptr; + +use x11::xlib; +use x11::xlib::{XEvent, GrabModeAsync}; + +use dotwm::DotWM; +use safe_x11::grab_key; const WNOHANG: c_int = 0x00000001; @@ -31,3 +40,80 @@ pub fn collect_zombies() { 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)>; + +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); + } +} + +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 +} + +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 +} + +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 +} + +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); +} + +/// 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)); +} diff --git a/src/main.rs b/src/main.rs index f00523d..e652dca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,103 +2,28 @@ extern crate libc; extern crate x11; +extern crate unix_socket; pub mod safe_x11; pub mod command; pub mod dotwm; pub mod event; +pub mod socket; use dotwm::DotWM; -use command::{exec_cmd,collect_zombies}; +use command::*; use event::{Event,next_event}; +use socket::{configure_wm, listen_socket}; -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; - -/// Map for keys => functions -pub 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); -} - -/// 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"]); -/// ``` -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)); -} +use std::thread; +use std::sync::mpsc::channel; +use unix_socket::UnixListener; fn main() { println!("Creating dotwm"); @@ -127,8 +52,26 @@ fn main() { add_binding(&mut dotwm, &mut bindings, keysym::XK_q, xlib::Mod4Mask | xlib::ShiftMask, quit_dotwm, &[]); + let (transmission, receiver) = channel(); + + thread::spawn(move || { + println!("Creating socket"); + let listener = UnixListener::bind("./dotwm.sock").unwrap(); + + for stream in listener.incoming() { + match stream { + Ok(stream) => transmission.send(stream).unwrap() , + Err(e) => println!("{}", e), + } + } + }); + + configure_wm(&mut dotwm, &receiver); + // Main loop loop { + listen_socket(&mut dotwm, &receiver); + // Event handling. let event = next_event(dotwm.display); println!("Event {:?}", event); match event { diff --git a/src/socket.rs b/src/socket.rs new file mode 100644 index 0000000..b3bb9cc --- /dev/null +++ b/src/socket.rs @@ -0,0 +1,63 @@ +// See LICENSE file for copyright and license details. + +use std::io::{Read,Write}; +use std::sync::mpsc::{Receiver, TryRecvError}; + +use unix_socket::UnixStream; + +use dotwm::DotWM; +use command::*; + +#[allow(unused_variables)] +fn handle_socket(dotwm: &mut DotWM, stream: UnixStream) { + let mut s = stream.try_clone().unwrap(); + let mut buf = String::new(); + s.read_to_string(&mut buf).unwrap(); + println!("buf: {}", buf); + + let _ = write!(s, "ok"); +} + +#[allow(unused_variables)] +/// Handles the configuration and returns true when we're finished. +fn handle_configure(dotwm: &mut DotWM, s: UnixStream) -> bool { + let mut stream = match s.try_clone() { + Ok(s) => s, + Err(_) => { println!("Error"); return true }, + }; + + let mut input = String::new(); + stream.read_to_string(&mut input).unwrap(); + + if input != "done" { + let _ = write!(stream, "ok"); + false + } else { + let _ = write!(stream, "exit"); + true + } +} + +pub fn configure_wm(dotwm: &mut DotWM, rx: &Receiver) { + exec_cmd("./autostart", &[]).unwrap(); + loop { + match rx.recv() { + Ok(stream) => { + if handle_configure(dotwm, stream) { + break; + } + }, + Err(e) => panic!("Socket: {}", e), + } + } +} + +pub fn listen_socket(dotwm: &mut DotWM, rx: &Receiver) { + loop { + match rx.try_recv() { + Ok(stream) => handle_socket(dotwm, stream) , + Err(TryRecvError::Empty) => break, + Err(TryRecvError::Disconnected) => panic!("Socket disconnected"), + } + } +} -- cgit v1.2.3-70-g09d2