aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--src/command.rs38
-rw-r--r--src/desktop.rs28
-rw-r--r--src/dotwm.rs10
-rw-r--r--src/event.rs6
-rw-r--r--src/main.rs11
-rw-r--r--src/safe_x11/mod.rs8
-rw-r--r--src/safe_x11/window.rs15
-rw-r--r--src/socket/mod.rs22
-rw-r--r--src/socket/parser.rs46
10 files changed, 167 insertions, 19 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8548148..30cd182 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
[root]
name = "dotwm"
-version = "0.1.0"
+version = "0.2.0"
dependencies = [
"clippy 0.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/src/command.rs b/src/command.rs
index f5e3e83..eaadf77 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -17,7 +17,7 @@ use x11::xlib::{XEvent, GrabModeAsync};
use dotwm::DotWM;
use dotwm::NetAtom;
-use safe_x11::{grab_key,ungrab_key};
+use safe_x11::{grab_key,ungrab_key,grab_button,ungrab_button};
const WNOHANG: c_int = 0x00000001;
@@ -132,6 +132,25 @@ pub fn move_win_sticky(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool
true
}
+/// Drag the window. for now the dragging is relative to the center of the
+/// window because win.cursor_coords is always `None`. Later we should
+/// be able to `XGrabButton` on the child windows (not only on the root) and
+/// set `win.cursor_coords` respectively.
+pub fn move_win_drag(wm: &mut DotWM, e: xlib::XEvent, _: &[String]) -> bool {
+ let ev = xlib::XMotionEvent::from(e);
+ if let Some(ref win) = wm.current_window() {
+ let attr = win.attributes();
+ let (x0, y0) = win.cursor_coords.unwrap_or((attr.width/2, attr.height/2));
+ // Move around the center of the cursor.
+ let x = ev.x - x0;
+ let y = ev.y - y0;
+ win.move_to(x, y).is_ok()
+ } else {
+ println!("move_win_drag - nop");
+ false
+ }
+}
+
/// Resize the window certain amount in x and y.
pub fn resize_win(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool {
let w = args[0].parse::<i32>().unwrap();
@@ -222,6 +241,23 @@ pub fn add_binding(wm: &mut DotWM, bindings: &mut BindingHash,
bindings.insert((key, modifiers), (func, v));
}
+/// Add a button binding to the WM.
+pub fn add_button_binding(wm: &mut DotWM, bindings: &mut BindingHash,
+ button: u32, modifiers: u32, func: ExecFn, args: &[&str]) {
+ ungrab_button(wm.display, button, modifiers);
+ grab_button(wm.display, button, modifiers, true,
+ xlib::ButtonPressMask|xlib::ButtonReleaseMask|xlib::PointerMotionMask,
+ GrabModeAsync, GrabModeAsync, 0, 0);
+ let mut v = vec![];
+ for arg in args {
+ v.push(arg.to_string());
+ }
+ // for now we need the button1Mask here
+ bindings.insert((button, modifiers | xlib::Button1Mask), (func, v));
+}
+
+/// Change the desktop, args parameter only have one usize on it that is the
+/// index of the desktop (i.e.: 0 for the first, 1 for the second, etc).
pub fn change_desktop(wm: &mut DotWM, _: xlib::XEvent, args: &[String]) -> bool {
let num = args[0].parse::<usize>().unwrap();
wm.change_desktop(num);
diff --git a/src/desktop.rs b/src/desktop.rs
index 454c05b..20502e0 100644
--- a/src/desktop.rs
+++ b/src/desktop.rs
@@ -35,6 +35,7 @@ impl Desktop {
self.cw_idx != usize::max_value()
}
+ /// Get the current window focused on this desktop.
pub fn current_window(&self) -> Option<&XWindow> {
if self.cw_idx < self.window_list.len() {
self.window_list.get(self.cw_idx)
@@ -43,6 +44,7 @@ impl Desktop {
}
}
+ /// Same as `current_window` but getting a mut reference.
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)
@@ -53,11 +55,16 @@ impl Desktop {
/// Add a window to the current desktop
pub fn add_window(&mut self, w: xlib::Window) {
- if self.find_window(w).is_some() {
+ if self.window_idx(w).is_some() {
return;
}
self.unfocus_current_window();
if let Some(w) = XWindow::new(self.display, w) {
+ // Throw an event when:
+ // * We enter a window
+ // * The window is exposed
+ // * We move around the window
+ //w.select_input(xlib::EnterWindowMask | xlib::ExposureMask | xlib::PointerMotionMask);
w.select_input(xlib::EnterWindowMask | xlib::ExposureMask);
self.window_list.push(w);
// Last windows get focus.
@@ -100,10 +107,27 @@ impl Desktop {
}
/// Find a given window and returns it's position on the window_list.
- pub fn find_window(&self, w: xlib::Window) -> Option<usize> {
+ pub fn window_idx(&self, w: xlib::Window) -> Option<usize> {
self.window_list.iter().position(|xw| xw.inner == w)
}
+ /// Find a `XWindow` given a `xlib::Window`.
+ pub fn find_window(&self, w: xlib::Window) -> Option<&XWindow> {
+ if let Some(idx) = self.window_idx(w) {
+ self.window_list.get(idx)
+ } else {
+ None
+ }
+ }
+ /// Same as `find_window` but returning a mut reference.
+ pub fn find_window_mut(&mut self, w: xlib::Window) -> Option<&mut XWindow> {
+ if let Some(idx) = self.window_idx(w) {
+ self.window_list.get_mut(idx)
+ } else {
+ None
+ }
+ }
+
/// Focus the next window.
///
/// There're 3 posibilities. There's no window, there's one window or there
diff --git a/src/dotwm.rs b/src/dotwm.rs
index fd28765..248e969 100644
--- a/src/dotwm.rs
+++ b/src/dotwm.rs
@@ -171,10 +171,18 @@ impl DotWM {
}
/// Find a given window and returns it's position on the window_list.
- pub fn find_window(&self, w: xlib::Window) -> Option<usize> {
+ pub fn window_idx(&self, w: xlib::Window) -> Option<usize> {
+ self.current_desktop().window_idx(w)
+ }
+
+ pub fn find_window(&self, w: xlib::Window) -> Option<&XWindow> {
self.current_desktop().find_window(w)
}
+ pub fn find_window_mut(&mut self, w: xlib::Window) -> Option<&mut XWindow> {
+ self.current_desktop_mut().find_window_mut(w)
+ }
+
/// Focus the next window.
///
/// There're 3 posibilities. There's no window, there's one window or there
diff --git a/src/event.rs b/src/event.rs
index 768e37a..055a94b 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -62,7 +62,7 @@ impl fmt::Debug for Event {
Event::Drag(ev) => format!("Drag({})", XEvent::from(ev).get_type()),
Event::Generic(ev) => format!("Generic({})", XEvent::from(ev).get_type()),
Event::Enter(ev) => format!("Enter({})", XEvent::from(ev).get_type()),
- Event::Leave(ev) => format!("Enter({})", XEvent::from(ev).get_type()),
+ Event::Leave(ev) => format!("Leave({})", XEvent::from(ev).get_type()),
Event::Create(ev) => format!("Create({})", XEvent::from(ev).get_type()),
Event::Destroy(ev) => format!("Destroy({})", XEvent::from(ev).get_type()),
Event::Unmap(ev) => format!("Unmap({})", XEvent::from(ev).get_type()),
@@ -125,8 +125,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)),
- _ => {
- // println!("Unknown event {}", e);
+ e => {
+ println!("Unknown event {}", e);
Event::NoEvent
},
}
diff --git a/src/main.rs b/src/main.rs
index dcef752..f745e92 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -23,6 +23,7 @@ use event::{Event,select_event};
use socket::parser;
use std::collections::HashMap;
+use std::mem::uninitialized;
use x11::xlib;
use x11::keysym;
@@ -77,12 +78,20 @@ fn main() {
dotwm.remove_window(e.window);
},
Event::Enter(e) => {
- if let Some(idx) = dotwm.find_window(e.window) {
+ 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 = uninitialized();
+ 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().unwrap();
let mut buf = String::new();
diff --git a/src/safe_x11/mod.rs b/src/safe_x11/mod.rs
index 613424a..4a1e029 100644
--- a/src/safe_x11/mod.rs
+++ b/src/safe_x11/mod.rs
@@ -137,6 +137,14 @@ pub fn grab_button(display: *mut Display, button: u32, modifiers: u32,
}
}
+/// Unregister a combination of keys that will send a `XEvent`
+pub fn ungrab_button(display: *mut Display, button: u32, modifiers: u32) {
+ unsafe {
+ let default_win = xlib::XDefaultRootWindow(display);
+ xlib::XUngrabButton(display, button, modifiers, default_win);
+ }
+}
+
/// Register a combination of keys that will send a `XEvent`
///
pub fn grab_key(display: *mut Display, key: u32, modifiers: u32, owner_events: bool,
diff --git a/src/safe_x11/window.rs b/src/safe_x11/window.rs
index eac4dbd..6c483d9 100644
--- a/src/safe_x11/window.rs
+++ b/src/safe_x11/window.rs
@@ -41,6 +41,8 @@ pub struct XWindow {
// The Application window.
pub inner: Window,
fullscreen: bool,
+ // Coordinates relative to the window where the cursor clicked on it.
+ pub cursor_coords: Option<(i32, i32)>,
prev_attribs: XWindowAttributes,
}
@@ -64,11 +66,11 @@ impl XWindow {
pub fn new(d: *mut xlib::Display, w: Window) -> Option<XWindow> {
if w != 0 {
let attrs: XWindowAttributes = unsafe { uninitialized() };
- println!("Window created!");
Some(XWindow {
display: d,
inner: w,
fullscreen: false,
+ cursor_coords: None,
prev_attribs: attrs,
})
} else {
@@ -155,8 +157,9 @@ impl XWindow {
let s = XDefaultScreenOfDisplay(self.display);
ptr::read(s)
};
+ let attrs = self.attributes();
- if 0 > x && x <= screen.width || 0 > y && y <= screen.height {
+ if x < -attrs.width && x <= screen.width || -attrs.height > y && y <= screen.height {
Err("Cannot move the window outside the screen!")
} else {
unsafe {
@@ -381,6 +384,14 @@ impl XWindow {
}
}
+use std::fmt;
+
+impl fmt::Display for XWindow {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Window({})", self.inner)
+ }
+}
+
pub fn change_window_attributes(display: *mut xlib::Display, win: Window, mask: u64,
window_attribs: *mut XSetWindowAttributes) {
unsafe {
diff --git a/src/socket/mod.rs b/src/socket/mod.rs
index c29db2b..6ee1c09 100644
--- a/src/socket/mod.rs
+++ b/src/socket/mod.rs
@@ -11,7 +11,8 @@ use command::*;
#[derive(Debug,PartialEq)]
pub enum FnType {
- Bind,
+ BindKey,
+ BindButton,
Exec,
}
@@ -25,11 +26,20 @@ pub struct ParsedCmd<'a> {
impl<'a> ParsedCmd<'a> {
pub fn handle(self, wm: &mut DotWM, bindings: &mut BindingHash) {
- if self.f == FnType::Bind {
- let modifier: u32 = self.modifiers.iter()
- .fold(0, |acc, x| acc | x );
- add_binding(wm, bindings,
- self.key, modifier, self.func, &self.args);
+ match self.f {
+ FnType::BindKey => {
+ let modifier: u32 = self.modifiers.iter()
+ .fold(0, |acc, x| acc | x );
+ add_binding(wm, bindings,
+ self.key, modifier, self.func, &self.args);
+ },
+ FnType::BindButton => {
+ let modifier: u32 = self.modifiers.iter()
+ .fold(0, |acc, x| acc | x);
+ add_button_binding(wm, bindings, self.key,
+ modifier, self.func, &self.args);
+ },
+ _ => {},
}
}
}
diff --git a/src/socket/parser.rs b/src/socket/parser.rs
index e475962..0989aec 100644
--- a/src/socket/parser.rs
+++ b/src/socket/parser.rs
@@ -44,6 +44,15 @@ fn modifiers<'a>(s: &'a str) -> Result<Vec<u32>, &'static str> {
Ok(result)
}
+fn button<'a>(s: &'a str) -> Result<u32, &'static str> {
+ match s {
+ "button1" => Ok(xlib::Button1),
+ "button2" => Ok(xlib::Button2),
+ "button3" => Ok(xlib::Button3),
+ _ => Err("unknown button")
+ }
+}
+
fn key<'a>(s: &'a str) -> Result<u32, &'static str> {
match s {
"a" => Ok(keysym::XK_a),
@@ -102,7 +111,10 @@ fn key<'a>(s: &'a str) -> Result<u32, &'static str> {
"2" => Ok(keysym::XK_2),
"Tab" => Ok(keysym::XK_Tab),
"Return" => Ok(keysym::XK_Return),
- _ => Err("unknown key"),
+ e => {
+ println!("Unknown Key {}", e);
+ Err("Unknown key")
+ },
}
}
@@ -112,6 +124,7 @@ fn func<'a>(s: &'a str) -> Result<ExecFn, &'static str> {
"move-win" => Ok(move_win),
"move-win-to" => Ok(move_win_to),
"move-win-sticky" => Ok(move_win_sticky),
+ "move-win-drag" => Ok(move_win_drag),
"resize-win" => Ok(resize_win),
"resize-win-sticky" => Ok(resize_win_sticky),
"focus-next" => Ok(focus_next),
@@ -137,7 +150,25 @@ pub fn parse<'a>(input: &'a str) -> Result<ParsedCmd<'a>, &'static str> {
let arguments: &[&'a str]= &args[4..];
Ok(ParsedCmd {
- f: FnType::Bind,
+ f: FnType::BindKey,
+ modifiers: modifiers,
+ key: key,
+ args: arguments.to_vec(),
+ func: func,
+ })
+ } else {
+ Err("missing arguments")
+ }
+ },
+ "bind-button" => {
+ if args.len() > 2 {
+ let modifiers = simple_try!(modifiers(args[1]));
+ let key = simple_try!(button(args[2]));
+ let func = simple_try!(func(args[3]));
+ let arguments: &[&'a str] = &args[4..];
+
+ Ok(ParsedCmd {
+ f: FnType::BindButton,
modifiers: modifiers,
key: key,
args: arguments.to_vec(),
@@ -218,3 +249,14 @@ fn parse_exec() {
assert!(false);
}
}
+
+#[test]
+fn parse_button() {
+ let res = parse("bind-button Mod4 button1 move-win-drag");
+
+ if let Ok(pcmd) = res {
+ assert_eq!(pcmd.f, FnType::BindButton);
+ } else {
+ assert!(false);
+ }
+}