// See LICENSE file for copyright and license details. use x11::xlib; use x11::xlib::{ Display, XErrorEvent, Atom, XChangeProperty, }; use safe_x11::{ open_display, close_display, atom, }; use safe_x11::window::{ XWindow, }; use desktop::Desktop; use std::ptr; use std::process::exit; use std::mem::uninitialized; use std::collections::HashMap; use libc::c_int; use libc::c_char; #[allow(unused_variables)] unsafe extern "C" fn error_handler(d: *mut Display, evptr: *mut XErrorEvent) -> c_int { println!("ERROR"); let ev = ptr::read(evptr); if ev.error_code == xlib::BadAccess { println!("Another widnow manager is running :C"); exit(1); } println!("Error code {:?}", ev.error_code); let mut buf: [i8; 1000] = [0i8; 1000]; let bufptr = buf.as_mut_ptr(); xlib::XGetErrorText(d, ev.error_code as c_int, bufptr as *mut c_char, 1000); let string = String::from_raw_parts(bufptr as *mut u8, 1000, 1000); println!("Error: {}", string); 0 } #[derive(Hash,Eq,PartialEq)] pub enum WmAtom { Protocols, DeleteWindow, } #[derive(Hash,Eq,PartialEq)] pub enum NetAtom { NetSupported, NetFullscreen, NetWmState, NetActive, } /// State of the window manager. pub struct DotWM { /// Reference to the X display. pub display: *mut Display, /// Check if the window manager needs to end. pub finish: bool, /// Vec holding atoms for ICCCM support pub wmatoms: HashMap, /// Vec holding atoms for EWHM support pub netatoms: HashMap, /// Number of the active desctop pub desktop_idx: usize, /// Desktops pub desktops: Vec, } /// DotWM state. impl DotWM { /// Create a state of the Dot Window Manager pub fn new() -> DotWM { let d = open_display("").unwrap(); unsafe { xlib::XSetErrorHandler(Some(error_handler)) }; // Add substructure notify mask let root = unsafe { xlib::XDefaultRootWindow(d) }; unsafe { let mut attrs: xlib::XSetWindowAttributes = uninitialized(); attrs.event_mask = xlib::SubstructureNotifyMask; xlib::XChangeWindowAttributes(d, root, xlib::CWEventMask, &mut attrs); } // Get the wmatoms let mut wmatoms = HashMap::new(); wmatoms.insert(WmAtom::Protocols, atom(d, "WM_PROTOCOLS")); wmatoms.insert(WmAtom::DeleteWindow, atom(d, "WM_DELETE_WINDOW")); // Get the netatoms let mut netatoms = HashMap::new(); netatoms.insert(NetAtom::NetSupported, atom(d, "_NET_SUPPORTED")); netatoms.insert(NetAtom::NetFullscreen, atom(d, "_NET_WM_STATE_FULLSCREEN")); netatoms.insert(NetAtom::NetWmState, atom(d, "_NET_ACTIVE_WINDOW")); netatoms.insert(NetAtom::NetActive, atom(d, "_NET_WM_STATE")); // Propagate EWHM support unsafe { let atomvec: Vec<&Atom> = netatoms.values().collect(); let len: i32 = netatoms.len() as i32; let atomptr = atomvec.as_ptr(); XChangeProperty(d, root, netatoms[&NetAtom::NetSupported], xlib::XA_ATOM, 32, xlib::PropModeReplace, atomptr as *const u8, len); } DotWM { display: d, finish: false, wmatoms: wmatoms, netatoms: netatoms, desktop_idx: 0, desktops: vec![ Desktop::new(d, "main"), Desktop::new(d, "other") ], } } /// this should always return a desktop. pub fn current_desktop_mut(&mut self) -> &mut Desktop { self.desktops.get_mut(self.desktop_idx).unwrap() } pub fn current_desktop(&self) -> &Desktop { self.desktops.get(self.desktop_idx).unwrap() } /// Add a window to the current desktop pub fn add_window(&mut self, w: xlib::Window) { self.current_desktop_mut().add_window(w); } pub fn current_window(&self) -> Option<&XWindow> { let d = self.desktops.get(self.desktop_idx); if let Some(desktop) = d { desktop.current_window() } else { None } } pub fn current_window_mut(&mut self) -> Option<&mut XWindow> { let d = self.desktops.get_mut(self.desktop_idx); if let Some(desktop) = d { desktop.current_window_mut() } else { None } } pub fn remove_window(&mut self, w: xlib::Window) { //let iter = self.desktops.iter_mut(); //for desktop in iter { // desktop.remove_window(w); //} self.current_desktop_mut().remove_window(w); } pub fn change_focus_of(&mut self, idx: usize) { self.current_desktop_mut().change_focus_of(idx); } /// Find a given window and returns it's position on the window_list. pub fn find_window(&self, w: xlib::Window) -> Option { self.current_desktop().find_window(w) } /// Focus the next window. /// /// There're 3 posibilities. There's no window, there's one window or there /// are more windows. pub fn focus_next(&mut self) { self.current_desktop_mut().focus_next(); } pub fn x_geometries(&self) -> Vec { self.current_desktop().geometries().iter().map(|x| x.0).collect() } pub fn y_geometries(&self) -> Vec { self.current_desktop().geometries().iter().map(|x| x.1).collect() } pub fn change_desktop(&mut self,desktop: usize) { if desktop > self.desktops.len() { return; } if desktop == self.desktop_idx { return; } let new_desktop = &self.desktops[desktop]; let old_desktop = &self.desktops[self.desktop_idx]; new_desktop.show_windows(); // let mut do_not_propagate: xlib::XSetWindowAttributes = unsafe { uninitialized() }; // let root = root_window(self.display); // do_not_propagate.do_not_propagate_mask = xlib::SubstructureNotifyMask; // change_window_attributes(self.display, root, xlib::CWEventMask, // &mut do_not_propagate); old_desktop.hide_windows(); // let mut root_mask: xlib::XSetWindowAttributes = unsafe { uninitialized() }; // root_mask.event_mask = xlib::SubstructureRedirectMask|xlib::ButtonPressMask|xlib::SubstructureNotifyMask|xlib::PropertyChangeMask; // change_window_attributes(self.display, root, xlib::CWEventMask, // &mut root_mask); self.desktop_idx = desktop; } } impl Drop for DotWM { fn drop(&mut self) { close_display(self.display); } }