// See LICENSE file for copyright and license details. // needed for clippy. #![allow(unknown_lints)] #![cfg_attr(feature="clippy", feature(plugin))] #![cfg_attr(feature="clippy", plugin(clippy))] extern crate libc; extern crate x11; #[macro_use] extern crate lazy_static; extern crate dirs; pub mod safe_x11; pub mod command; pub mod dotwm; pub mod event; pub mod socket; pub mod desktop; use std::collections::HashMap; use std::mem::MaybeUninit; use std::fs; use std::path::{PathBuf}; use std::io::{Read,Write}; use std::os::unix::net::UnixListener; use x11::xlib; use x11::keysym; use dotwm::DotWM; use command::*; use event::{Event,select_event}; use socket::parser; fn dotwm_dir() -> PathBuf { let mut path = dirs::config_dir().unwrap(); path.push("dotwm"); if !path.exists() && !path.is_dir() { println!("Creating config directory in {:?}", path); fs::create_dir(&path).unwrap(); } path } fn socket_path() -> PathBuf { let mut path = dotwm_dir(); path.push("dotwm.sock"); path } fn run_autostart() { let mut autostart = dotwm_dir(); autostart.push("autostart"); println!("Trying to exec {:?}", autostart); let found = exec_cmd(autostart, &[]).is_ok(); if !found { exec_cmd("./autostart", &[]).unwrap(); } } 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); add_binding(&mut dotwm, &mut bindings, keysym::XK_q, xlib::Mod4Mask | xlib::ShiftMask, quit_dotwm, &[]); let sp = socket_path(); let listener = UnixListener::bind(&sp).unwrap(); run_autostart(); // Main loop while !dotwm.finish { let event = unsafe { select_event(dotwm.display, x11_fd, &listener) }; 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!("Creating window {}", map_event.window); dotwm.add_window(map_event.window); } } Event::Unmap(e) => { dotwm.remove_window(e.window); }, Event::Enter(e) => { if let Some(idx) = dotwm.window_idx(e.window) { dotwm.change_focus_of(idx); } }, Event::Expose(_) => { }, Event::Drag(e) => { // We can "compress" the drag notify here. unsafe{ let mut new_ev = MaybeUninit::uninit().assume_init(); while xlib::XCheckTypedEvent(dotwm.display, xlib::MotionNotify, &mut new_ev) != 0 {}; }; exec_func(&mut dotwm, &mut bindings, 1, e.state, xlib::XEvent::from(e)); }, Event::Socket(stream) => { let mut s = stream.try_clone().expect("Cannot clone stream"); let mut buf = String::new(); s.read_to_string(&mut buf).expect("Cannot read from string"); for line in buf.lines() { let res = parser::parse(line); match res { Ok(pcmd) => { pcmd.handle(&mut dotwm, &mut bindings); let _ = write!(s, "+ok\n"); }, Err(e) => { let _ = write!(s, "-{}\n", e); }, } } }, _ => (), } collect_zombies(); } let _ = fs::remove_file(sp); }