From 83b7d0cb4f30c95ce6f27d2c0944727d75eb6e5e Mon Sep 17 00:00:00 2001 From: Matias Linares Date: Sun, 22 Nov 2015 20:02:10 -0300 Subject: Death to the threads. All the socket stuff is done syncing it with select calls so we can get either a X11 event or a Socket event. Also cleanup the C mess, it's done all in rust now :). --- Makefile | 15 -------------- src/event.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 45 +++++++++++++++++------------------------ src/safe_x11/Makefile | 7 ------- src/safe_x11/event.rs | 33 ------------------------------ src/safe_x11/mod.rs | 24 +++++++++++++++++++++- src/safe_x11/safex11.c | 32 ----------------------------- src/safe_x11/safex11.h | 7 ------- src/socket/mod.rs | 8 ++++++++ 9 files changed, 102 insertions(+), 124 deletions(-) delete mode 100644 Makefile delete mode 100644 src/safe_x11/Makefile delete mode 100644 src/safe_x11/event.rs delete mode 100644 src/safe_x11/safex11.c delete mode 100644 src/safe_x11/safex11.h diff --git a/Makefile b/Makefile deleted file mode 100644 index 7050f6d..0000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -all: - make -C src/safe_x11/ - mkdir -p target/debug - cp src/safe_x11/libsafex11.so target/debug - cargo build - -release: - make -C src/safe_x11/ release - mkdir -p target/release - cp src/safe_x11/libsafex11.so target/release - cargo build --release - -clean: - make -C src/safe_x11/ clean - cargo clean diff --git a/src/event.rs b/src/event.rs index 5a5b1b9..f683c63 100644 --- a/src/event.rs +++ b/src/event.rs @@ -11,13 +11,29 @@ use x11::xlib::{ XUnmapEvent, XMapEvent, XConfigureEvent, + + XPending, }; use x11::xlib; use x11::xlib::Display; + +use unix_socket::UnixStream; +use unix_socket::UnixListener; + use libc::c_int; +use libc::{ + FD_SET, + FD_ZERO, + FD_ISSET, + select, + fd_set, +}; use std::fmt; +use std::ptr; +use std::mem::uninitialized; +use std::cmp::max; -use safe_x11::event::next_xevent; +use safe_x11::next_xevent; pub enum Event { Key(XKeyEvent, bool), @@ -31,6 +47,7 @@ pub enum Event { Unmap(XUnmapEvent), Map(XMapEvent), Configure(XConfigureEvent), + Socket(UnixStream), NoEvent } @@ -48,6 +65,7 @@ impl fmt::Debug for Event { &Event::Unmap(ev) => format!("Unmap({})", XEvent::from(ev).get_type()), &Event::Map(ev) => format!("Map({})", XEvent::from(ev).get_type()), &Event::Configure(ev) => format!("Configure({})", XEvent::from(ev).get_type()), + &Event::Socket(_) => format!("Socket()"), &Event::NoEvent => format!("NoEvent"), }; @@ -55,8 +73,39 @@ impl fmt::Debug for Event { } } -pub fn next_event(display: *mut Display, fd: c_int) -> Event { - let ev = next_xevent(display, fd); +pub unsafe fn select_event(display: *mut Display, x11fd: c_int, socket_fd: c_int, + listener: &UnixListener) -> Event { + // Return right now if there're some XEvent on the queue + if XPending(display) > 0 { + return next_event(display); + } + + let mut read_fdset: fd_set = uninitialized(); + + FD_ZERO(&mut read_fdset); + FD_SET(x11fd, &mut read_fdset); + FD_SET(socket_fd, &mut read_fdset); + + select(max(x11fd, socket_fd) + 1, + &mut read_fdset, ptr::null_mut(), ptr::null_mut(), + ptr::null_mut()); + + if FD_ISSET(x11fd, &mut read_fdset) { + next_event(display) + } else if FD_ISSET(socket_fd, &mut read_fdset) { + let mut listener_iter = listener.incoming(); + if let Some(Ok(stream)) = listener_iter.nth(0) { + return Event::Socket(stream) + } else { + Event::NoEvent + } + } else { + Event::NoEvent + } +} + +pub fn next_event(display: *mut Display) -> Event { + let ev = next_xevent(display); match ev.get_type() { 2 => Event::Key(xlib::XKeyEvent::from(ev), true), diff --git a/src/main.rs b/src/main.rs index d871288..cd64f87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,9 +12,8 @@ pub mod socket; use dotwm::DotWM; use command::*; -use event::{Event,next_event}; -use socket::listen_socket; -use safe_x11::event as x11_event; +use event::{Event,select_event}; +use socket::parser; use std::collections::HashMap; @@ -22,15 +21,15 @@ use x11::xlib; use x11::xlib::XEvent; use x11::keysym; -use std::thread; -use std::sync::mpsc::channel; +use std::os::unix::io::AsRawFd; +use std::io::{Read,Write}; use unix_socket::UnixListener; fn main() { println!("Creating dotwm"); let mut dotwm = DotWM::new(); let mut bindings: BindingHash = HashMap::new(); - let x11_fd = x11_event::x11_fd(dotwm.display); + let x11_fd = safe_x11::x11_fd(dotwm.display); // Resize add_binding(&mut dotwm,&mut bindings, keysym::XK_h, xlib::Mod4Mask | xlib::ControlMask, @@ -42,33 +41,18 @@ fn main() { 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 (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), - } - } - }); + let listener = UnixListener::bind("./dotwm.sock").unwrap(); + let socket_fd = listener.as_raw_fd(); exec_cmd("./autostart", &[]).unwrap(); // Main loop loop { - println!("Listening socket"); - listen_socket(&mut dotwm, &mut bindings, &receiver); - // Event handling. - println!("Waiting event"); - let event = next_event(dotwm.display, x11_fd); - println!("Event {:?}", event); + let event = unsafe { select_event(dotwm.display, x11_fd, socket_fd, &listener) }; match event { Event::Key(mut e, true) => { let keysym = unsafe { xlib::XLookupKeysym(&mut e, 0) as u32 }; @@ -81,7 +65,6 @@ fn main() { // 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 :("); @@ -95,6 +78,16 @@ fn main() { dotwm.change_focus_of(idx); } }, + Event::Socket(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(&mut dotwm, &mut bindings, &line); + let _ = write!(s, "{}", result); + } + }, _ => println!("Unknown event"), } collect_zombies(); diff --git a/src/safe_x11/Makefile b/src/safe_x11/Makefile deleted file mode 100644 index 4ea8a63..0000000 --- a/src/safe_x11/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: - $(CC) -c -fPIC safex11.c -o safex11.o -lX11 - $(CC) -shared -o libsafex11.so safex11.o -lX11 - -clean: - rm safex11.o - rm *.so* diff --git a/src/safe_x11/event.rs b/src/safe_x11/event.rs deleted file mode 100644 index 8a4bc32..0000000 --- a/src/safe_x11/event.rs +++ /dev/null @@ -1,33 +0,0 @@ -use x11::xlib::{ - XConnectionNumber, - Display, - XEvent, -}; - -use std::mem::uninitialized; - -use libc::c_int; - -#[link(name = "safex11")] -extern { - /// Get an XEvent if there're one on the queue or wait a little before continue. - fn select_next_event(display: *mut Display, x11_fd: c_int, ev: *mut XEvent) -> c_int; -} - -/// Get the file descriptor for the XServer -pub fn x11_fd(display: *mut Display) -> c_int { - unsafe { XConnectionNumber(display) } -} - -/// Get the next event from the xserver. This call will not block forever -/// (like XNextEvent), instead it will wait for a certain time (1 second -/// for now, but it can change) so we're not blocking the socket interface -/// on the main thread. -pub fn next_xevent(display: *mut Display, fd: c_int) -> XEvent { - unsafe { - let mut last_event: XEvent = uninitialized(); - select_next_event(display, fd, &mut last_event) as i32; - last_event - } -} - diff --git a/src/safe_x11/mod.rs b/src/safe_x11/mod.rs index 06c7b3c..0283966 100644 --- a/src/safe_x11/mod.rs +++ b/src/safe_x11/mod.rs @@ -6,11 +6,15 @@ use x11::xlib; use x11::xlib::{ Display, + XConnectionNumber, Screen, Cursor, XDefaultRootWindow, XQueryTree, + XEvent, + XNextEvent, + // Windows Window, }; @@ -23,9 +27,9 @@ use std::error; use std::mem::uninitialized; use std::slice; use std::fmt; +use libc::c_int; pub mod window; -pub mod event; #[derive(Debug)] pub struct XSafeError<'a> { @@ -89,6 +93,24 @@ pub fn close_display(display: *mut Display) { unsafe { xlib::XCloseDisplay(display); } } +/// Get the file descriptor for the XServer +pub fn x11_fd(display: *mut Display) -> c_int { + unsafe { XConnectionNumber(display) } +} + +/// Get the next event from the xserver. This call will not block forever +/// (like XNextEvent), instead it will wait for a certain time (1 second +/// for now, but it can change) so we're not blocking the socket interface +/// on the main thread. +pub fn next_xevent(display: *mut Display) -> XEvent { + unsafe { + let mut last_event: XEvent = uninitialized(); + XNextEvent(display, &mut last_event); + last_event + } +} + + /// Grab pointer buttons. /// /// # Example diff --git a/src/safe_x11/safex11.c b/src/safe_x11/safex11.c deleted file mode 100644 index e4f87d8..0000000 --- a/src/safe_x11/safex11.c +++ /dev/null @@ -1,32 +0,0 @@ -#include "safex11.h" -#include -#include -#include - -int select_next_event(Display *display, int x11_fd, XEvent *retval) -{ - fd_set in_fds; - struct timeval tv; - XEvent ev; - /* check if there're some events on the queue first of all. */ - if(XPending(display) > 0) - goto EVENT_QUEUED; - - FD_ZERO(&in_fds); - FD_SET(x11_fd, &in_fds); - - /* one second */ - tv.tv_usec = 0; - tv.tv_sec = 1; - - /* Wait for X Event or a Timer */ - if(select(x11_fd+1, &in_fds, 0, 0, &tv)) - goto EVENT_QUEUED; - - return 0; - -EVENT_QUEUED: - XNextEvent(display, &ev); - *retval = ev; - return 1; -} diff --git a/src/safe_x11/safex11.h b/src/safe_x11/safex11.h deleted file mode 100644 index bbf4e80..0000000 --- a/src/safe_x11/safex11.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _WM_EVENT_H_ -#define _WM_EVENT_H_ -#include - -int select_next_event(Display *display, int x11_fd, XEvent *retval); - -#endif diff --git a/src/socket/mod.rs b/src/socket/mod.rs index 804f7ac..e260284 100644 --- a/src/socket/mod.rs +++ b/src/socket/mod.rs @@ -10,6 +10,14 @@ use unix_socket::UnixStream; use dotwm::DotWM; use command::*; +pub fn next_socket_event(rx: &Receiver) -> Option { + match rx.try_recv() { + Ok(stream) => Some(stream), + Err(TryRecvError::Empty) => None, + 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) { loop { -- cgit v1.2.3-70-g09d2