From 69f8194da778a692b6b0c14f43d9611c2072e8ba Mon Sep 17 00:00:00 2001 From: Matias Linares Date: Mon, 7 Dec 2015 16:19:36 -0300 Subject: Implement desktops. It's somewhat buggy. But works :). There're 2 desktops only for now, maybe later I will implement something more dynamic --- src/command.rs | 13 ++-- src/desktop.rs | 178 +++++++++++++++++++++++++++++++++++++++++++++++++ src/dotwm.rs | 174 ++++++++++++++++++++--------------------------- src/event.rs | 4 +- src/main.rs | 3 +- src/safe_x11/mod.rs | 7 +- src/safe_x11/window.rs | 20 +++++- src/socket/parser.rs | 4 +- 8 files changed, 286 insertions(+), 117 deletions(-) create mode 100644 src/desktop.rs (limited to 'src') diff --git a/src/command.rs b/src/command.rs index f351e14..8f7218e 100644 --- a/src/command.rs +++ b/src/command.rs @@ -95,8 +95,7 @@ pub fn move_win_to(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool { if let Some(ref win) = wm.current_window() { match win.move_to(x, y) { Ok(()) => true, - Err(e) => { - println!("{}", e); + Err(_) => { false } } @@ -194,7 +193,7 @@ pub fn resize_win_sticky(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bo let val = xgeo.iter().skip_while(|&a| *a <= win_right).next(); if let Some(xpoint) = val { - let new_width = (*xpoint - attrs.x); + let new_width = *xpoint - attrs.x; let _ = win.resize_to(new_width, attrs.height); } }, @@ -205,7 +204,6 @@ pub fn resize_win_sticky(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bo let val = ygeo.iter().skip_while(|&a| *a >= attrs.y + attrs.height).next(); if let Some(v) = val { let diff = attrs.height - (*v - attrs.y); - println!("Resizing to {}x{}", attrs.width, diff); if *v - attrs.y > 0 { let _ = win.resize_to(attrs.width, attrs.height - diff); } @@ -219,7 +217,6 @@ pub fn resize_win_sticky(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bo let val = ygeo.iter().skip_while(|&a| *a <= win_bot).next(); if let Some(v) = val { let new_height = *v - attrs.y; - println!("Resizing to {}x{}", attrs.width, new_height); let _ = win.resize_to(attrs.width, new_height); } }, @@ -274,3 +271,9 @@ pub fn add_binding(wm: &mut DotWM, bindings: &mut BindingHash, } bindings.insert((key, modifiers), (func, v)); } + +pub fn change_desktop(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool { + let num = args[0].parse::().unwrap(); + wm.change_desktop(num); + true +} diff --git a/src/desktop.rs b/src/desktop.rs new file mode 100644 index 0000000..7d2a8a5 --- /dev/null +++ b/src/desktop.rs @@ -0,0 +1,178 @@ +use x11::xlib; +use x11::xlib::{ + Display, +}; + +use safe_x11::window::XWindow; +use safe_x11::{ + screen_size, +}; + +pub struct Desktop { + #[allow(dead_code)] + display: *mut Display, + #[allow(dead_code)] + tag: String, + window_list: Vec, + cw_idx: usize, +} + +impl Desktop { + pub fn new(display: *mut Display, tag: &'static str) -> Desktop { + Desktop { + display: display, + tag: String::from(tag), + window_list: vec![], + cw_idx: 0, + } + } + + pub fn current_window(&self) -> Option<&XWindow> { + if self.cw_idx < self.window_list.len() { + self.window_list.get(self.cw_idx) + } else { + None + } + } + + pub fn current_window_mut(&mut self) -> Option<&mut XWindow> { + if self.cw_idx < self.window_list.len() { + self.window_list.get_mut(self.cw_idx) + } else { + None + } + } + + /// Add a window to the current desktop + pub fn add_window(&mut self, w: xlib::Window) { + if self.find_window(w).is_some() { + return; + } + self.unfocus_current_window(); + if let Some(w) = XWindow::new(self.display, w) { + w.select_input(xlib::EnterWindowMask); + self.window_list.push(w); + // Last windows get focus. + self.focus_current_window(); + } + } + + /// Remove a window. + pub fn remove_window(&mut self, w: xlib::Window) { + let pos = self.window_list.iter().position(|xw| xw.inner == w); + + match pos { + Some(idx) => { + let new_idx = if idx == 0 { usize::max_value() } else { idx - 1 }; + self.window_list.remove(idx); + self.cw_idx = new_idx; + self.focus_current_window(); + }, + None => (), + } + } + + pub fn change_focus_of(&mut self, idx: usize) { + let w = &self.window_list[idx]; + self.unfocus_current_window(); + self.cw_idx = idx; + w.set_border_width(1); + w.set_border_color("red"); + w.raise(); + } + + /// Find a given window and returns it's position on the window_list. + pub fn find_window(&self, w: xlib::Window) -> Option { + self.window_list.iter().position(|xw| xw.inner == 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) { + if self.window_list.len() > 0 { + // Unfocus the current window. + let prev_win = &self.window_list[self.cw_idx]; + prev_win.unfocus(); + + // And give focus to the next one. + let next_win_idx = if self.cw_idx < self.window_list.len() - 1 { + self.cw_idx + 1 + } else { + 0 + }; + + let curr_win = &self.window_list[next_win_idx]; + curr_win.focus(); + self.cw_idx = next_win_idx; + } + } + + fn focus_current_window(&self) { + self.current_window().map(|x| x.focus()); + } + + fn unfocus_current_window(&self) { + self.current_window().map(|x| x.unfocus()); + } + + /// Get a list of the geometries for every window in the screen (including + /// the screen borders. The form is (x, y). + /// + /// # Example + /// + /// Having a screen of 800x600, and a window on 10(x), 10(y) with dimensions + /// 400(width) and 300(height): + /// + /// ``` + /// for (x, y) in dotwm.geometries() { + /// println!("x: {} - y: {}", x, y); + /// } + /// ``` + /// + /// The output will be: + /// + /// ``` + /// (0,0) + /// (800, 600) + /// (10, 10) + /// (410, 310) + /// ``` + pub fn geometries(&self) -> Vec<(i32,i32)> { + let (screen_width, screen_height) = screen_size(self.display); + let mut result: Vec<(i32,i32)> = vec![ + (0, 0), + (screen_width as i32, screen_height as i32), + ]; + + for w in self.window_list.iter() { + let attrs = w.attributes(); + result.push((attrs.x, attrs.y)); + result.push((attrs.x + attrs.width, attrs.y + attrs.height)); + } + + result + } + + pub fn x_geometries(&self) -> Vec { + self.geometries().iter().map(|x| x.0).collect() + } + + pub fn y_geometries(&self) -> Vec { + self.geometries().iter().map(|x| x.1).collect() + } + + + pub fn show_windows(&self) { + for win in &self.window_list { + win.map(); + } + } + + pub fn hide_windows(&self) { + for win in &self.window_list { + win.unmap(); + } + } +} diff --git a/src/dotwm.rs b/src/dotwm.rs index b3ed782..2781ae8 100644 --- a/src/dotwm.rs +++ b/src/dotwm.rs @@ -12,26 +12,36 @@ use safe_x11::{ open_display, close_display, atom, - screen_size, }; -use safe_x11::window::XWindow; +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!("ERRORR"); + 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 } @@ -53,8 +63,6 @@ pub enum NetAtom { pub struct DotWM { /// Reference to the X display. pub display: *mut Display, - /// References to all the windows. - pub window_list: Vec, /// Check if the window manager needs to end. pub finish: bool, /// Vec holding atoms for ICCCM support @@ -62,8 +70,9 @@ pub struct DotWM { /// Vec holding atoms for EWHM support pub netatoms: HashMap, /// Number of the active desctop - current_desktop: usize, - cw_idx: usize, + pub desktop_idx: usize, + /// Desktops + pub desktops: Vec, } /// DotWM state. @@ -106,68 +115,64 @@ impl DotWM { DotWM { display: d, - cw_idx: 0, finish: false, wmatoms: wmatoms, netatoms: netatoms, - current_desktop: 0, - window_list: vec![], + 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.unfocus_current_window(); - if let Some(w) = XWindow::new(self.display, w) { - w.select_input(xlib::EnterWindowMask); - self.window_list.push(w); - // Last windows get focus. - self.cw_idx = self.window_list.len() - 1; - self.focus_current_window(); - } + self.current_desktop_mut().add_window(w); } pub fn current_window(&self) -> Option<&XWindow> { - if self.cw_idx < self.window_list.len() { - self.window_list.get(self.cw_idx) + 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> { - if self.cw_idx < self.window_list.len() { - self.window_list.get_mut(self.cw_idx) + 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 pos = self.window_list.iter().position(|xw| xw.inner == w); - - match pos { - Some(idx) => { - let new_idx = if idx == 0 { usize::max_value() } else { idx - 1 }; - self.window_list.remove(idx); - self.cw_idx = new_idx; - self.focus_current_window(); - }, - None => (), - } + //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) { - let w = &self.window_list[idx]; - self.unfocus_current_window(); - self.cw_idx = idx; - w.set_border_width(1); - w.set_border_color("red"); - w.raise(); + 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.window_list.iter().position(|xw| xw.inner == w) + self.current_desktop().find_window(w) } /// Focus the next window. @@ -175,82 +180,47 @@ impl DotWM { /// There're 3 posibilities. There's no window, there's one window or there /// are more windows. pub fn focus_next(&mut self) { - if self.window_list.len() > 0 { - // Unfocus the current window. - let prev_win = &self.window_list[self.cw_idx]; - prev_win.unfocus(); - - // And give focus to the next one. - let next_win_idx = if self.cw_idx < self.window_list.len() - 1 { - self.cw_idx + 1 - } else { - 0 - }; - - let curr_win = &self.window_list[next_win_idx]; - curr_win.focus(); - self.cw_idx = next_win_idx; - } + self.current_desktop_mut().focus_next(); } - fn focus_current_window(&self) { - self.current_window().map(|x| x.focus()); + pub fn x_geometries(&self) -> Vec { + self.current_desktop().geometries().iter().map(|x| x.0).collect() } - fn unfocus_current_window(&self) { - self.current_window().map(|x| x.unfocus()); + pub fn y_geometries(&self) -> Vec { + self.current_desktop().geometries().iter().map(|x| x.1).collect() } - /// Get a list of the geometries for every window in the screen (including - /// the screen borders. The form is (x, y). - /// - /// # Example - /// - /// Having a screen of 800x600, and a window on 10(x), 10(y) with dimensions - /// 400(width) and 300(height): - /// - /// ``` - /// for (x, y) in dotwm.geometries() { - /// println!("x: {} - y: {}", x, y); - /// } - /// ``` - /// - /// The output will be: - /// - /// ``` - /// (0,0) - /// (800, 600) - /// (10, 10) - /// (410, 310) - /// ``` - pub fn geometries(&self) -> Vec<(i32,i32)> { - let (screen_width, screen_height) = screen_size(self.display); - let mut result: Vec<(i32,i32)> = vec![ - (0, 0), - (screen_width as i32, screen_height as i32), - ]; - - for w in self.window_list.iter() { - let attrs = w.attributes(); - result.push((attrs.x, attrs.y)); - result.push((attrs.x + attrs.width, attrs.y + attrs.height)); + pub fn change_desktop(&mut self,desktop: usize) { + if desktop > self.desktops.len() { + return; } - result - } - - pub fn x_geometries(&self) -> Vec { - self.geometries().iter().map(|x| x.0).collect() - } + if desktop == self.desktop_idx { + return; + } - pub fn y_geometries(&self) -> Vec { - self.geometries().iter().map(|x| x.1).collect() + 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) { - println!("Closing display"); close_display(self.display); } } diff --git a/src/event.rs b/src/event.rs index 6f5c427..3832a36 100644 --- a/src/event.rs +++ b/src/event.rs @@ -121,8 +121,8 @@ pub fn next_event(display: *mut Display) -> Event { 18 => Event::Unmap(XUnmapEvent::from(ev)), 19 => Event::Map(XMapEvent::from(ev)), 22 => Event::Configure(XConfigureEvent::from(ev)), - e => { - println!("Unknown event {}", e); + _ => { + // println!("Unknown event {}", e); Event::NoEvent }, } diff --git a/src/main.rs b/src/main.rs index 21425c8..2a00ff5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ pub mod command; pub mod dotwm; pub mod event; pub mod socket; +pub mod desktop; use dotwm::DotWM; use command::*; @@ -57,8 +58,6 @@ fn main() { let map_event = xlib::XMapEvent::from(e); if map_event.override_redirect == 0 { dotwm.add_window(map_event.window); - } else { - println!("Map event 0 :("); } } Event::Unmap(e) => { diff --git a/src/safe_x11/mod.rs b/src/safe_x11/mod.rs index 2e368aa..9e5859a 100644 --- a/src/safe_x11/mod.rs +++ b/src/safe_x11/mod.rs @@ -78,10 +78,8 @@ impl<'a> fmt::Display for XSafeError<'a> { /// pub fn open_display(display: &str) -> Result<*mut Display, XSafeError> { let d = if display == "" { - println!("Opening default display"); unsafe { xlib::XOpenDisplay(0x0 as *const i8) } } else { - println!("Opening {}", display); let cstr = try!(CString::new(display)); unsafe { xlib::XOpenDisplay(cstr.as_ptr()) } }; @@ -121,6 +119,10 @@ pub fn screen_size(display: *mut Display) -> (u32, u32) { (dw, dh) } +pub fn root_window(display: *mut Display) -> Window { + unsafe { xlib::XDefaultRootWindow(display) } +} + /// Grab pointer buttons. /// /// # Example @@ -159,7 +161,6 @@ pub fn grab_button(display: *mut Display, button: u32, modifiers: u32, /// pub fn grab_key(display: *mut Display, key: u32, modifiers: u32, owner_events: bool, pointer_mode: i32, keyboard_mode: i32) { - println!("Modifiers {:x}", modifiers); unsafe { let default_win = xlib::XDefaultRootWindow(display); let keycode: i32 = xlib::XKeysymToKeycode(display, key as u64) as i32; diff --git a/src/safe_x11/window.rs b/src/safe_x11/window.rs index 34cce64..8a3bab4 100644 --- a/src/safe_x11/window.rs +++ b/src/safe_x11/window.rs @@ -20,6 +20,9 @@ use x11::xlib::{ ClientMessage,ClientMessageData, NoEventMask, XChangeProperty, + XChangeWindowAttributes, XSetWindowAttributes, + + XMapWindow, XUnmapWindow, }; use std::ptr; @@ -218,7 +221,6 @@ impl XWindow { let fs_atom_slice: &[Atom; 1] = &[fs_atom]; let fs_atom_ptr: *const u8 = unsafe { transmute(fs_atom_slice) }; - println!("Changing property!"); unsafe { XChangeProperty(self.display, self.inner, wm_state_atom, XA_ATOM, 32, PropModeReplace, fs_atom_ptr, @@ -227,11 +229,25 @@ impl XWindow { } if fullscreen { - println!("resizing!"); self.move_resize(0, 0, dw, dh); self.set_border_width(0); } else { self.set_border_width(1); } } + + pub fn map(&self) { + unsafe { XMapWindow(self.display, self.inner); } + } + + pub fn unmap(&self) { + unsafe { XUnmapWindow(self.display, self.inner); } + } +} + +pub fn change_window_attributes(display: *mut xlib::Display, win: Window, mask: u64, + window_attribs: *mut XSetWindowAttributes) { + unsafe { + XChangeWindowAttributes(display, win, mask, window_attribs); + } } diff --git a/src/socket/parser.rs b/src/socket/parser.rs index bd73ff6..30487d8 100644 --- a/src/socket/parser.rs +++ b/src/socket/parser.rs @@ -22,7 +22,6 @@ macro_rules! simple_try { } fn modifier_from<'a>(s: &'a str) -> Result { - println!("Getted modifier {}", s); match s { "Mod1" => Ok(xlib::Mod1Mask), "Mod2" => Ok(xlib::Mod2Mask), @@ -99,6 +98,8 @@ fn key<'a>(s: &'a str) -> Result { "X" => Ok(keysym::XK_X), "Y" => Ok(keysym::XK_Y), "Z" => Ok(keysym::XK_Z), + "1" => Ok(keysym::XK_1), + "2" => Ok(keysym::XK_2), "Tab" => Ok(keysym::XK_Tab), "Return" => Ok(keysym::XK_Return), _ => Err("unknown key"), @@ -116,6 +117,7 @@ fn func<'a>(s: &'a str) -> Result { "focus-next" => Ok(focus_next), "close-win" => Ok(close_win), "fullscreen" => Ok(fullscreen), + "change-desktop" => Ok(change_desktop), "quit" => Ok(quit_dotwm), _ => Err("unknown function"), } -- cgit v1.2.3-70-g09d2