changed from a simple master_stack to virtual screens with master and
aux stack
This commit is contained in:
parent
482d97be53
commit
b011629e45
315
src/wm.rs
315
src/wm.rs
|
@ -128,6 +128,52 @@ impl PartialEq for Client {
|
||||||
|
|
||||||
impl Eq for Client {}
|
impl Eq for Client {}
|
||||||
|
|
||||||
|
use std::hash::{BuildHasherDefault, Hasher};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
struct IdentityHasher(usize);
|
||||||
|
|
||||||
|
impl Hasher for IdentityHasher {
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
self.0 as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, _bytes: &[u8]) {
|
||||||
|
unimplemented!("IdentityHasher only supports usize keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_u64(&mut self, i: u64) {
|
||||||
|
self.0 = i as usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_usize(&mut self, i: usize) {
|
||||||
|
self.0 = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BuildIdentityHasher = BuildHasherDefault<IdentityHasher>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct VirtualScreen {
|
||||||
|
master_stack: HashMap<Window, Weak<RefCell<Client>>, BuildIdentityHasher>,
|
||||||
|
aux_stack: HashMap<Window, Weak<RefCell<Client>>, BuildIdentityHasher>,
|
||||||
|
focused_client: Weak<RefCell<Client>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualScreen {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
master_stack: HashMap::default(),
|
||||||
|
aux_stack: HashMap::default(),
|
||||||
|
focused_client: Weak::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains_window(&self, window: &Window) -> bool {
|
||||||
|
self.master_stack.contains_key(window) || self.aux_stack.contains_key(window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct XLibState {
|
pub struct XLibState {
|
||||||
display: Display,
|
display: Display,
|
||||||
root: Window,
|
root: Window,
|
||||||
|
@ -306,7 +352,8 @@ pub struct WMStateMut {
|
||||||
resize_window: Option<(u64, (i32, i32))>,
|
resize_window: Option<(u64, (i32, i32))>,
|
||||||
clients: HashMap<Window, Rc<RefCell<Client>>>,
|
clients: HashMap<Window, Rc<RefCell<Client>>>,
|
||||||
focused_client: Weak<RefCell<Client>>,
|
focused_client: Weak<RefCell<Client>>,
|
||||||
master_stack: Vec<Weak<RefCell<Client>>>,
|
current_vscreen: usize,
|
||||||
|
virtual_screens: Vec<VirtualScreen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WMStateMut {
|
impl Default for WMStateMut {
|
||||||
|
@ -316,7 +363,119 @@ impl Default for WMStateMut {
|
||||||
resize_window: None,
|
resize_window: None,
|
||||||
clients: HashMap::new(),
|
clients: HashMap::new(),
|
||||||
focused_client: Weak::new(),
|
focused_client: Weak::new(),
|
||||||
master_stack: vec![],
|
current_vscreen: 0,
|
||||||
|
virtual_screens: vec![VirtualScreen::new()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WMStateMut {
|
||||||
|
fn stack_unstacked_clients(&mut self) {
|
||||||
|
info!("[stack_unstacked_clients] ");
|
||||||
|
let current_vscreen = self.current_vscreen;
|
||||||
|
|
||||||
|
self.clients
|
||||||
|
.iter()
|
||||||
|
.filter(|(w, c)| {
|
||||||
|
!c.borrow().floating && self.virtual_screens.iter().any(|vs| !vs.contains_window(w))
|
||||||
|
})
|
||||||
|
.map(|(w, c)| (w.clone(), Rc::downgrade(c)))
|
||||||
|
.collect::<Vec<(u64, Weak<RefCell<Client>>)>>()
|
||||||
|
.iter()
|
||||||
|
.for_each(|(w, c)| {
|
||||||
|
info!(
|
||||||
|
"[stack_unstacked_clients] inserting Window({:?}) into aux_stack",
|
||||||
|
w
|
||||||
|
);
|
||||||
|
|
||||||
|
self.virtual_screens[current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.insert(w.clone(), c.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_client_stacked(&self, window: &Window) -> bool {
|
||||||
|
self.virtual_screens
|
||||||
|
.iter()
|
||||||
|
.any(|vs| vs.contains_window(window))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_for_window(&self, window: &Window) -> Option<Rc<RefCell<Client>>> {
|
||||||
|
self.clients
|
||||||
|
.iter()
|
||||||
|
.filter(|&(w, _)| *w == *window)
|
||||||
|
.next()
|
||||||
|
.map(|(_, c)| c.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn switch_stack_for_client(&mut self, window: &Window) {
|
||||||
|
if let Some(client) = self.client_for_window(window) {
|
||||||
|
info!("[switch_stack_for_client] client: {:#?}", client.borrow());
|
||||||
|
client.borrow_mut().floating = false;
|
||||||
|
|
||||||
|
if self.virtual_screens[self.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.contains_key(window)
|
||||||
|
{
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.remove(window);
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.insert(*window, Rc::downgrade(&client));
|
||||||
|
info!("[switch_stack_for_client] moved to aux stack");
|
||||||
|
} else {
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.remove(window);
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.insert(*window, Rc::downgrade(&client));
|
||||||
|
info!("[switch_stack_for_client] moved to master stack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refresh_screen(&mut self) {
|
||||||
|
let current_vscreen = self.current_vscreen;
|
||||||
|
|
||||||
|
self.virtual_screens
|
||||||
|
.get_mut(current_vscreen)
|
||||||
|
.and_then(|vs| {
|
||||||
|
vs.master_stack.retain(|_, c| {
|
||||||
|
c.upgrade().is_some() && !c.upgrade().unwrap().borrow().floating
|
||||||
|
});
|
||||||
|
vs.aux_stack.retain(|_, c| {
|
||||||
|
c.upgrade().is_some() && !c.upgrade().unwrap().borrow().floating
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
});
|
||||||
|
|
||||||
|
self.stack_unstacked_clients();
|
||||||
|
|
||||||
|
if self.virtual_screens[current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
info!("[refresh_screen] master stack was empty, pushing first client if exists:");
|
||||||
|
|
||||||
|
self.virtual_screens[current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, c)| !c.upgrade().unwrap().borrow().floating)
|
||||||
|
.next()
|
||||||
|
.map(|(w, c)| (w.clone(), c.clone()))
|
||||||
|
.and_then(|(w, c)| {
|
||||||
|
info!("[arrange_clients] Window({:#?})", w);
|
||||||
|
|
||||||
|
self.virtual_screens[current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.insert(w, c);
|
||||||
|
self.virtual_screens[current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.remove(&w)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,39 +524,7 @@ impl WMState {
|
||||||
println!("spawning terminal");
|
println!("spawning terminal");
|
||||||
let _ = state.spawn("xterm", &[]);
|
let _ = state.spawn("xterm", &[]);
|
||||||
})
|
})
|
||||||
.add_key_handler("M", Mod1Mask, |state, event| {
|
.add_key_handler("M", Mod1Mask, Self::handle_switch_stack)
|
||||||
Some(state.mut_state.borrow_mut()).and_then(|mut mstate| {
|
|
||||||
(mstate
|
|
||||||
.clients
|
|
||||||
.iter()
|
|
||||||
.filter(|&(_, c)| c.borrow().window == unsafe { event.button.subwindow })
|
|
||||||
.next()
|
|
||||||
.and_then(|(_, c)| Some(c.clone())))
|
|
||||||
.and_then(|c| {
|
|
||||||
c.borrow_mut().floating = false;
|
|
||||||
|
|
||||||
let weak_c = Rc::downgrade(&c);
|
|
||||||
|
|
||||||
if mstate
|
|
||||||
.master_stack
|
|
||||||
.iter()
|
|
||||||
.filter(|w| w.ptr_eq(&weak_c))
|
|
||||||
.count() == 0
|
|
||||||
{
|
|
||||||
mstate.master_stack.push(Rc::downgrade(&c));
|
|
||||||
} else {
|
|
||||||
mstate.master_stack.retain(|w| !w.ptr_eq(&weak_c));
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(())
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
state.arrange_clients();
|
|
||||||
})
|
|
||||||
.add_key_handler("L", Mod1Mask, |state, _| {
|
|
||||||
println!("{:#?}", state.mut_state.borrow());
|
|
||||||
})
|
|
||||||
.add_key_handler("Q", Mod1Mask, |state, event| unsafe {
|
.add_key_handler("Q", Mod1Mask, |state, event| unsafe {
|
||||||
if event.key.subwindow != 0 {
|
if event.key.subwindow != 0 {
|
||||||
if state.xlib_state.atoms.delete.is_none()
|
if state.xlib_state.atoms.delete.is_none()
|
||||||
|
@ -710,18 +837,19 @@ impl WMState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_client(&self, client: Rc<RefCell<Client>>) {
|
fn focus_client(&self, client: Rc<RefCell<Client>>) {
|
||||||
let _ = self.mut_state.try_borrow_mut().and_then(|m| {
|
Some(self.mut_state.borrow_mut()).and_then(|mut state| {
|
||||||
let mut focused_client = RefMut::map(m, |m| &mut m.focused_client);
|
let current_vscreen = state.current_vscreen;
|
||||||
match focused_client.upgrade() {
|
|
||||||
Some(c) => {
|
|
||||||
self.unfocus_client(c.clone());
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
*focused_client = Rc::downgrade(&client);
|
state
|
||||||
|
.focused_client
|
||||||
|
.upgrade()
|
||||||
|
.and_then(|c| Some(self.unfocus_client(c)));
|
||||||
|
|
||||||
Ok(())
|
state.focused_client = Rc::downgrade(&client);
|
||||||
|
|
||||||
|
state.virtual_screens[current_vscreen].focused_client = state.focused_client.clone();
|
||||||
|
|
||||||
|
Some(())
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -749,9 +877,6 @@ impl WMState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arrange_clients(&self) {
|
fn arrange_clients(&self) {
|
||||||
info!("[arrange_clients] refreshing stack");
|
|
||||||
self.refresh_stack();
|
|
||||||
|
|
||||||
let (screen_w, screen_h) = unsafe {
|
let (screen_w, screen_h) = unsafe {
|
||||||
(
|
(
|
||||||
xlib::XDisplayWidth(self.dpy(), self.xlib_state.screen()),
|
xlib::XDisplayWidth(self.dpy(), self.xlib_state.screen()),
|
||||||
|
@ -760,48 +885,35 @@ impl WMState {
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(self.mut_state.borrow_mut()).and_then(|mut state| {
|
Some(self.mut_state.borrow_mut()).and_then(|mut state| {
|
||||||
// no need to arrange any clients if there is no clients
|
|
||||||
if !state.clients.is_empty() {
|
if !state.clients.is_empty() {
|
||||||
// if master stack is empty, populate with first entry in clients list
|
info!("[arrange_clients] refreshing screen");
|
||||||
if state.master_stack.is_empty() {
|
state.refresh_screen();
|
||||||
info!(
|
info!("[arrange_clients] refreshing screen");
|
||||||
"[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 = {
|
||||||
// if clients and master_stack are the same length there is no windows in the aux
|
if state.virtual_screens[state.current_vscreen]
|
||||||
// stack, in the future might have to change this to filter for
|
.aux_stack
|
||||||
// transient/floating windows
|
.is_empty()
|
||||||
let has_aux_stack = state
|
{
|
||||||
.clients
|
|
||||||
.iter()
|
|
||||||
.filter(|&(_, c)| !c.borrow().floating)
|
|
||||||
.count() != state.master_stack.len();
|
|
||||||
|
|
||||||
if has_aux_stack {
|
|
||||||
screen_w / 2
|
|
||||||
} else {
|
|
||||||
screen_w
|
screen_w
|
||||||
|
} else {
|
||||||
|
screen_w / 2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, weak_client) in state.master_stack.iter().enumerate() {
|
for (i, (_, weak_client)) in state.virtual_screens[state.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
let client = weak_client.upgrade().unwrap();
|
let client = weak_client.upgrade().unwrap();
|
||||||
|
|
||||||
let mut wc = {
|
let mut wc = {
|
||||||
let mut client = client.borrow_mut();
|
let mut client = client.borrow_mut();
|
||||||
let window_h = screen_h / state.master_stack.len() as i32;
|
let window_h = screen_h
|
||||||
|
/ state.virtual_screens[state.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.len() as i32;
|
||||||
|
|
||||||
client.size = (window_w, window_h);
|
client.size = (window_w, window_h);
|
||||||
client.position = (0, window_h * i as i32);
|
client.position = (0, window_h * i as i32);
|
||||||
|
@ -831,28 +943,17 @@ impl WMState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (aux_windows, aux_window_count) = {
|
for (i, (_, weak_client)) in state.virtual_screens[state.current_vscreen]
|
||||||
let filter = state.clients.iter().filter(|&(_, c)| {
|
.aux_stack
|
||||||
state
|
.iter()
|
||||||
.master_stack
|
.enumerate()
|
||||||
.iter()
|
{
|
||||||
.filter(|w| w.upgrade().unwrap() == *c)
|
let client = weak_client.upgrade().unwrap();
|
||||||
.count() == 0 && !c.borrow().floating
|
|
||||||
});
|
|
||||||
|
|
||||||
(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 = screen_h / aux_window_count as i32;
|
let window_h = screen_h
|
||||||
|
/ state.virtual_screens[state.current_vscreen].aux_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);
|
||||||
|
@ -887,16 +988,6 @@ impl WMState {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refresh_stack(&self) {
|
|
||||||
Some(self.mut_state.borrow_mut()).and_then(|mut state| {
|
|
||||||
state
|
|
||||||
.master_stack
|
|
||||||
.retain(|c| c.upgrade().filter(|c| !c.borrow().floating).is_some());
|
|
||||||
|
|
||||||
Some(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_client(&self, client: Rc<RefCell<Client>>) {
|
fn configure_client(&self, client: Rc<RefCell<Client>>) {
|
||||||
let mut event = {
|
let mut event = {
|
||||||
let client = client.borrow();
|
let client = client.borrow();
|
||||||
|
@ -929,6 +1020,14 @@ impl WMState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_switch_stack(&self, event: &XEvent) {
|
||||||
|
self.mut_state
|
||||||
|
.borrow_mut()
|
||||||
|
.switch_stack_for_client(unsafe { &event.button.subwindow });
|
||||||
|
|
||||||
|
self.arrange_clients();
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_toggle_floating(&self, event: &XEvent) {
|
fn handle_toggle_floating(&self, event: &XEvent) {
|
||||||
if event.get_type() == xlib::ButtonPress {
|
if event.get_type() == xlib::ButtonPress {
|
||||||
let event = unsafe { event.button };
|
let event = unsafe { event.button };
|
||||||
|
|
Loading…
Reference in a new issue