added floating windows and reenabled ability to resize/move windows

This commit is contained in:
noonebtw 2021-01-19 08:01:13 +01:00
parent 518c254c93
commit 482d97be53
3 changed files with 108 additions and 32 deletions

View file

@ -10,3 +10,4 @@ edition = "2018"
nix = "0.19.1" nix = "0.19.1"
x11 = {version = "2.18.2", features = ["xlib"] } x11 = {version = "2.18.2", features = ["xlib"] }
log = "0.4.13" log = "0.4.13"
simple_logger = "1.11.0"

View file

@ -1,4 +1,5 @@
use std::io::Result; use std::io::Result;
use log::info;
mod wm; mod wm;
@ -26,7 +27,8 @@ unsafe extern "C" fn xlib_error_handler(
fn main() -> Result<()> { fn main() -> Result<()> {
println!("Hello, world!"); simple_logger::SimpleLogger::new().init().unwrap();
info!("Hello, World!");
wm::WMState::init().run(); wm::WMState::init().run();

133
src/wm.rs
View file

@ -95,6 +95,7 @@ impl Default for WMAtoms {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Client { pub struct Client {
window: Window, window: Window,
floating: bool,
size: (i32, i32), size: (i32, i32),
position: (i32, i32), position: (i32, i32),
} }
@ -103,6 +104,7 @@ impl Default for Client {
fn default() -> Self { fn default() -> Self {
Self { Self {
window: 0, window: 0,
floating: false,
size: (0, 0), size: (0, 0),
position: (0, 0), position: (0, 0),
} }
@ -346,13 +348,19 @@ impl WMState {
Mod1Mask, Mod1Mask,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
) )
//.add_event_handler(Self::handle_move_window) .grab_button(
2,
Mod1Mask,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
)
.grab_button( .grab_button(
3, 3,
Mod1Mask, Mod1Mask,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
) )
//.add_event_handler(Self::handle_resize_window) .add_event_handler(Self::handle_toggle_floating)
.add_event_handler(Self::handle_move_window)
.add_event_handler(Self::handle_resize_window)
.add_key_handler("T", Mod1Mask, |state, _| { .add_key_handler("T", Mod1Mask, |state, _| {
println!("spawning terminal"); println!("spawning terminal");
let _ = state.spawn("xterm", &[]); let _ = state.spawn("xterm", &[]);
@ -366,7 +374,10 @@ impl WMState {
.next() .next()
.and_then(|(_, c)| Some(c.clone()))) .and_then(|(_, c)| Some(c.clone())))
.and_then(|c| { .and_then(|c| {
c.borrow_mut().floating = false;
let weak_c = Rc::downgrade(&c); let weak_c = Rc::downgrade(&c);
if mstate if mstate
.master_stack .master_stack
.iter() .iter()
@ -738,6 +749,7 @@ impl WMState {
} }
fn arrange_clients(&self) { fn arrange_clients(&self) {
info!("[arrange_clients] refreshing stack");
self.refresh_stack(); self.refresh_stack();
let (screen_w, screen_h) = unsafe { let (screen_w, screen_h) = unsafe {
@ -752,12 +764,30 @@ impl WMState {
if !state.clients.is_empty() { if !state.clients.is_empty() {
// if master stack is empty, populate with first entry in clients list // if master stack is empty, populate with first entry in clients list
if state.master_stack.is_empty() { if state.master_stack.is_empty() {
let first_client = Rc::downgrade(state.clients.iter().next().unwrap().1); info!(
state.master_stack.push(first_client); "[arrange_clients] master stack was empty, pushing first client if exists:"
);
let _ = state
.clients
.iter()
.filter(|(_, c)| !c.borrow().floating)
.next()
.map(|(_, c)| Rc::downgrade(c))
.and_then(|w| {
info!("[arrange_clients] {:#?}", w);
Some(state.master_stack.push(w))
});
} }
let window_w = { let window_w = {
let has_aux_stack = state.clients.len() != state.master_stack.len(); // if clients and master_stack are the same length there is no windows in the aux
// stack, in the future might have to change this to filter for
// transient/floating windows
let has_aux_stack = state
.clients
.iter()
.filter(|&(_, c)| !c.borrow().floating)
.count() != state.master_stack.len();
if has_aux_stack { if has_aux_stack {
screen_w / 2 screen_w / 2
@ -801,23 +831,28 @@ impl WMState {
} }
} }
// filter only windows that arent inthe master stack, essentially aux stack let (aux_windows, aux_window_count) = {
for (i, (_, client)) in state let filter = state.clients.iter().filter(|&(_, c)| {
.clients
.iter()
.filter(|&(_, c)| {
state state
.master_stack .master_stack
.iter() .iter()
.filter(|w| w.upgrade().unwrap() == *c) .filter(|w| w.upgrade().unwrap() == *c)
.count() == 0 .count() == 0 && !c.borrow().floating
}) });
.enumerate()
{ (filter.clone(), filter.count())
};
info!(
"[arrange_clients] {} client(s) in aux stack",
aux_window_count
);
// filter only windows that arent inthe master stack, essentially aux stack
for (i, (_, client)) in aux_windows.enumerate() {
let mut wc = { let mut wc = {
let mut client = client.borrow_mut(); let mut client = client.borrow_mut();
let window_h = let window_h = screen_h / aux_window_count as i32;
screen_h / (state.clients.len() - state.master_stack.len()) as i32;
client.size = (window_w, window_h); client.size = (window_w, window_h);
client.position = (window_w, window_h * i as i32); client.position = (window_w, window_h * i as i32);
@ -854,15 +889,9 @@ impl WMState {
fn refresh_stack(&self) { fn refresh_stack(&self) {
Some(self.mut_state.borrow_mut()).and_then(|mut state| { Some(self.mut_state.borrow_mut()).and_then(|mut state| {
state.master_stack = state state
.master_stack .master_stack
.iter() .retain(|c| c.upgrade().filter(|c| !c.borrow().floating).is_some());
.filter_map(|weak_client| {
weak_client
.upgrade()
.and_then(|_| Some(weak_client.clone()))
})
.collect();
Some(()) Some(())
}); });
@ -900,10 +929,37 @@ impl WMState {
} }
} }
fn handle_toggle_floating(&self, event: &XEvent) {
if event.get_type() == xlib::ButtonPress {
let event = unsafe { event.button };
let clean_mask = self.xlib_state.clean_mask();
if event.button == 2
&& event.state & clean_mask == Mod1Mask & clean_mask
&& event.subwindow != 0
{
self.mut_state
.borrow_mut()
.clients
.entry(event.subwindow)
.and_modify(|c| {
let mut c = c.borrow_mut();
info!(
"[handle_toggle_floating] {:#?} floating -> {:?}",
c, !c.floating
);
c.floating = !c.floating;
});
self.arrange_clients();
}
}
}
fn handle_move_window(&self, event: &XEvent) { fn handle_move_window(&self, event: &XEvent) {
let clean_mask = self.xlib_state.clean_mask(); let clean_mask = self.xlib_state.clean_mask();
let move_window = &mut self.mut_state.borrow_mut().move_window; let move_window = self.mut_state.borrow_mut().move_window;
if unsafe { if unsafe {
move_window.is_none() move_window.is_none()
@ -920,19 +976,27 @@ impl WMState {
(attr.x, attr.y) (attr.x, attr.y)
}; };
*move_window = Some(unsafe { self.mut_state.borrow_mut().move_window = Some(unsafe {
( (
event.button.subwindow, event.button.subwindow,
(event.button.x, event.button.y), (event.button.x, event.button.y),
win_pos, win_pos,
) )
}); });
self.mut_state
.borrow_mut()
.clients
.entry(unsafe { event.button.subwindow })
.and_modify(|c| c.borrow_mut().floating = true);
self.arrange_clients();
} else if unsafe { } else if unsafe {
move_window.is_some() move_window.is_some()
&& event.get_type() == xlib::ButtonRelease && event.get_type() == xlib::ButtonRelease
&& event.button.button == 1 && event.button.button == 1
} { } {
*move_window = None; self.mut_state.borrow_mut().move_window = None;
} else if move_window.is_some() && event.get_type() == xlib::MotionNotify { } else if move_window.is_some() && event.get_type() == xlib::MotionNotify {
let move_window = move_window.unwrap(); let move_window = move_window.unwrap();
@ -977,7 +1041,7 @@ impl WMState {
fn handle_resize_window(&self, event: &XEvent) { fn handle_resize_window(&self, event: &XEvent) {
let clean_mask = self.xlib_state.clean_mask(); let clean_mask = self.xlib_state.clean_mask();
let resize_window = &mut self.mut_state.borrow_mut().resize_window; let resize_window = self.mut_state.borrow().resize_window;
if unsafe { if unsafe {
resize_window.is_none() resize_window.is_none()
@ -992,7 +1056,8 @@ impl WMState {
xlib::XGetWindowAttributes(self.dpy(), event.button.subwindow, &mut attr); xlib::XGetWindowAttributes(self.dpy(), event.button.subwindow, &mut attr);
*resize_window = Some((event.button.subwindow, (attr.x, attr.y))); self.mut_state.borrow_mut().resize_window =
Some((event.button.subwindow, (attr.x, attr.y)));
xlib::XWarpPointer( xlib::XWarpPointer(
self.dpy(), self.dpy(),
@ -1006,12 +1071,20 @@ impl WMState {
attr.height + attr.border_width - 1, attr.height + attr.border_width - 1,
); );
}; };
self.mut_state
.borrow_mut()
.clients
.entry(unsafe { event.button.subwindow })
.and_modify(|c| c.borrow_mut().floating = true);
self.arrange_clients();
} else if unsafe { } else if unsafe {
resize_window.is_some() resize_window.is_some()
&& event.get_type() == xlib::ButtonRelease && event.get_type() == xlib::ButtonRelease
&& event.button.button == 3 && event.button.button == 3
} { } {
*resize_window = None; self.mut_state.borrow_mut().resize_window = None;
} else if resize_window.is_some() && event.get_type() == xlib::MotionNotify { } else if resize_window.is_some() && event.get_type() == xlib::MotionNotify {
let resize_window = resize_window.unwrap(); let resize_window = resize_window.unwrap();