fixed some bugs related to floating window stacking

This commit is contained in:
NoOneBtw 2021-05-04 18:52:08 +02:00
parent 95d7740119
commit 134e727b25
6 changed files with 142 additions and 129 deletions

View file

@ -1,3 +1,2 @@
imports_granularity = "Crate" #wrap_comments = true
wrap_comments = true
max_width = 80 max_width = 80

View file

@ -1,7 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::collections::HashMap;
use std::num::NonZeroI32; use std::num::NonZeroI32;
use std::{collections::HashMap, ops::Rem, usize};
use log::{error, info}; use log::{error, info};
@ -113,31 +113,6 @@ mod client {
self.to_owned() self.to_owned()
} }
} }
/*
impl Borrow<Window> for Client {
fn borrow(&self) -> &Window {
&self.window
}
}
impl ClientKey for Rc<Client> {
fn key(&self) -> u64 {
self.window
}
}
impl<'a> Borrow<dyn ClientKey + 'a> for Client {
fn borrow(&self) -> &(dyn ClientKey + 'a) {
self
}
}
impl<'a> Borrow<dyn ClientKey + 'a> for Rc<Client> {
fn borrow(&self) -> &(dyn ClientKey + 'a) {
self
}
}
*/
} }
pub use client::*; pub use client::*;
@ -218,56 +193,15 @@ pub enum ClientEntry<T> {
Vacant, Vacant,
} }
impl<T> Into<Option<T>> for ClientEntry<T> {
fn into(self) -> Option<T> {
match self {
Self::Vacant => None,
Self::Tiled(client) | Self::Floating(client) => Some(client),
}
}
}
impl<T> ClientEntry<T> {
pub fn into_option(self) -> Option<T> {
self.into()
}
pub fn unwrap(self) -> T {
self.into_option().unwrap()
}
pub fn is_vacant(&self) -> bool {
match self {
ClientEntry::Vacant => true,
_ => false,
}
}
pub fn is_floating(&self) -> bool {
match self {
ClientEntry::Floating(_) => true,
_ => false,
}
}
pub fn is_tiled(&self) -> bool {
match self {
ClientEntry::Tiled(_) => true,
_ => false,
}
}
pub fn is_occupied(&self) -> bool {
!self.is_vacant()
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ClientState { pub struct ClientState {
pub(self) clients: Clients, pub(self) clients: Clients,
pub(self) floating_clients: Clients, pub(self) floating_clients: Clients,
focused: Option<ClientRef>, focused: Option<ClientRef>,
pub(self) virtual_screens: VecDeque<VirtualScreen>, pub(self) virtual_screens: VecDeque<VirtualScreen>,
gap: i32,
screen_size: (i32, i32),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -286,6 +220,8 @@ impl Default for ClientState {
floating_clients: Default::default(), floating_clients: Default::default(),
focused: None, focused: None,
virtual_screens: vss, virtual_screens: vss,
gap: 0,
screen_size: (1, 1),
} }
} }
} }
@ -295,13 +231,24 @@ impl ClientState {
Self::default() Self::default()
} }
pub fn with_virtualscreens(num: usize) -> Self { pub fn with_gap(self, gap: i32) -> Self {
Self { gap, ..self }
}
pub fn with_screen_size(self, screen_size: (i32, i32)) -> Self {
Self {
screen_size,
..self
}
}
pub fn with_virtualscreens(self, num: usize) -> Self {
let mut vss = VecDeque::<VirtualScreen>::new(); let mut vss = VecDeque::<VirtualScreen>::new();
vss.resize_with(num, Default::default); vss.resize_with(num, Default::default);
Self { Self {
virtual_screens: vss, virtual_screens: vss,
..Default::default() ..self
} }
} }
@ -333,6 +280,9 @@ impl ClientState {
self.focus_client(&key); self.focus_client(&key);
// adding a client changes the liling layout, rearrange
self.arrange_virtual_screen();
// TODO: eventually make this function return a `ClientEntry` instead of an `Option`. // TODO: eventually make this function return a `ClientEntry` instead of an `Option`.
self.get(&key).into_option() self.get(&key).into_option()
} }
@ -351,6 +301,9 @@ impl ClientState {
self.clients.remove(&key.key()); self.clients.remove(&key.key());
self.floating_clients.remove(&key.key()); self.floating_clients.remove(&key.key());
// removing a client changes the liling layout, rearrange
self.arrange_virtual_screen();
} }
pub fn contains<K>(&self, key: &K) -> bool pub fn contains<K>(&self, key: &K) -> bool
@ -460,12 +413,18 @@ impl ClientState {
} }
} }
pub fn rotate_right(&mut self) { pub fn rotate_right(&mut self, n: Option<usize>) {
self.virtual_screens.rotate_right(1); self.virtual_screens
.rotate_right(n.unwrap_or(1).rem(self.virtual_screens.len()));
self.arrange_virtual_screen();
} }
pub fn rotate_left(&mut self) { pub fn rotate_left(&mut self, n: Option<usize>) {
self.virtual_screens.rotate_left(1); self.virtual_screens
.rotate_left(n.unwrap_or(1).rem(self.virtual_screens.len()));
self.arrange_virtual_screen();
} }
/** /**
@ -508,6 +467,7 @@ impl ClientState {
true => { true => {
self.floating_clients.insert(key, floating_client); self.floating_clients.insert(key, floating_client);
} }
false => { false => {
self.clients.insert(key, floating_client); self.clients.insert(key, floating_client);
if let Some(vs) = self.virtual_screens.front_mut() { if let Some(vs) = self.virtual_screens.front_mut() {
@ -520,14 +480,22 @@ impl ClientState {
error!("wtf? Client was present in tiled and floating list.") error!("wtf? Client was present in tiled and floating list.")
} }
}; };
// we added or removed a client from the tiling so the layout changed, rearrange
self.arrange_virtual_screen();
} }
fn remove_from_virtual_screens<K>(&mut self, key: &K) fn remove_from_virtual_screens<K>(&mut self, key: &K)
where where
K: ClientKey, K: ClientKey,
{ {
if let Some(vs) = self.get_mut_virtualscreen_for_client(key) { if self.contains(key) {
vs.remove(key); if let Some(vs) = self.get_mut_virtualscreen_for_client(key) {
vs.remove(key);
// we removed a client so the layout changed, rearrange
self.arrange_virtual_screen();
}
} }
} }
@ -578,7 +546,9 @@ impl ClientState {
if focused == key.key() { if focused == key.key() {
(ClientEntry::Vacant, ClientEntry::Vacant) (ClientEntry::Vacant, ClientEntry::Vacant)
} else { } else {
// focus the new client and return reference to it and the previously focused client. // focus the new client and return reference to it
// and the previously focused client.
self.focused = Some(key.key()); self.focused = Some(key.key());
(self.get(key), self.get(&focused)) (self.get(key), self.get(&focused))
} }
@ -599,7 +569,8 @@ impl ClientState {
} }
/** /**
sets `self.focused` to `None` and returns a reference to the previously focused Client if any. sets `self.focused` to `None` and returns a reference to
the previously focused Client if any.
*/ */
pub fn unfocus(&mut self) -> ClientEntry<&Client> { pub fn unfocus(&mut self) -> ClientEntry<&Client> {
match self.focused { match self.focused {
@ -627,6 +598,8 @@ impl ClientState {
{ {
if let Some(vs) = self.get_mut_virtualscreen_for_client(key) { if let Some(vs) = self.get_mut_virtualscreen_for_client(key) {
vs.switch_stack_for_client(key); vs.switch_stack_for_client(key);
self.arrange_virtual_screen();
} }
} }
@ -635,13 +608,9 @@ impl ClientState {
screen width and screen height. screen width and screen height.
Optionally adds a gap between windows `gap.unwrap_or(0)` pixels wide. Optionally adds a gap between windows `gap.unwrap_or(0)` pixels wide.
*/ */
pub fn arrange_virtual_screen( pub fn arrange_virtual_screen(&mut self) {
&mut self, let gap = self.gap;
width: i32, let (width, height) = self.screen_size;
height: i32,
gap: Option<i32>,
) {
let gap = gap.unwrap_or(0);
// should be fine to unwrap since we will always have at least 1 virtual screen // should be fine to unwrap since we will always have at least 1 virtual screen
if let Some(vs) = self.virtual_screens.front_mut() { if let Some(vs) = self.virtual_screens.front_mut() {
@ -692,7 +661,7 @@ impl ClientState {
} }
} }
info!("{:#?}", self); //info!("{:#?}", self);
} }
// Should have xlib send those changes back to the x server after this function // Should have xlib send those changes back to the x server after this function
@ -777,3 +746,47 @@ impl VirtualScreen {
} }
} }
} }
impl<T> Into<Option<T>> for ClientEntry<T> {
fn into(self) -> Option<T> {
match self {
Self::Vacant => None,
Self::Tiled(client) | Self::Floating(client) => Some(client),
}
}
}
impl<T> ClientEntry<T> {
pub fn into_option(self) -> Option<T> {
self.into()
}
pub fn unwrap(self) -> T {
self.into_option().unwrap()
}
pub fn is_vacant(&self) -> bool {
match self {
ClientEntry::Vacant => true,
_ => false,
}
}
pub fn is_floating(&self) -> bool {
match self {
ClientEntry::Floating(_) => true,
_ => false,
}
}
pub fn is_tiled(&self) -> bool {
match self {
ClientEntry::Tiled(_) => true,
_ => false,
}
}
pub fn is_occupied(&self) -> bool {
!self.is_vacant()
}
}

View file

@ -45,7 +45,7 @@ fn main() {
log_prologue(); log_prologue();
state::WindowManager::new(WMConfig::default()).init().run(); state::WindowManager::new(WMConfig::default()).run();
} }
fn log_prologue() { fn log_prologue() {

View file

@ -13,7 +13,7 @@ use xlib::{
}; };
use crate::{ use crate::{
clients::{Client, ClientKey, ClientState}, clients::{Client, ClientEntry, ClientKey, ClientState},
xlib::KeyOrButton, xlib::KeyOrButton,
xlib::XLib, xlib::XLib,
}; };
@ -40,8 +40,8 @@ pub struct WindowManager {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Direction { pub enum Direction {
Left, Left(Option<usize>),
Right, Right(Option<usize>),
} }
enum MoveResizeInfo { enum MoveResizeInfo {
@ -70,10 +70,13 @@ struct KeyBinding {
impl WindowManager { impl WindowManager {
pub fn new(config: WMConfig) -> Self { pub fn new(config: WMConfig) -> Self {
let clients =
ClientState::with_virtualscreens(config.num_virtualscreens);
let xlib = XLib::new(); let xlib = XLib::new();
let clients = ClientState::new()
.with_virtualscreens(config.num_virtualscreens)
.with_gap(config.gap.unwrap_or(1))
.with_screen_size(xlib.dimensions());
Self { Self {
clients, clients,
move_resize_window: MoveResizeInfo::None, move_resize_window: MoveResizeInfo::None,
@ -82,9 +85,10 @@ impl WindowManager {
last_rotation: None, last_rotation: None,
config, config,
} }
.init()
} }
pub fn init(mut self) -> Self { fn init(mut self) -> Self {
self.xlib.add_global_keybind(KeyOrButton::button( self.xlib.add_global_keybind(KeyOrButton::button(
1, 1,
self.config.mod_key, self.config.mod_key,
@ -152,12 +156,12 @@ impl WindowManager {
self.add_keybind(KeyBinding::new( self.add_keybind(KeyBinding::new(
self.xlib.make_key("Left", self.config.mod_key), self.xlib.make_key("Left", self.config.mod_key),
|wm, _| wm.rotate_virtual_screen(Direction::Left), |wm, _| wm.rotate_virtual_screen(Direction::Left(None)),
)); ));
self.add_keybind(KeyBinding::new( self.add_keybind(KeyBinding::new(
self.xlib.make_key("Right", self.config.mod_key), self.xlib.make_key("Right", self.config.mod_key),
|wm, _| wm.rotate_virtual_screen(Direction::Right), |wm, _| wm.rotate_virtual_screen(Direction::Right(None)),
)); ));
self.add_keybind(KeyBinding::new( self.add_keybind(KeyBinding::new(
@ -177,12 +181,12 @@ impl WindowManager {
self.add_keybind(KeyBinding::new( self.add_keybind(KeyBinding::new(
self.xlib.make_key("J", self.config.mod_key | ShiftMask), self.xlib.make_key("J", self.config.mod_key | ShiftMask),
|wm, _| wm.rotate_virtual_screen(Direction::Left), |wm, _| wm.rotate_virtual_screen(Direction::Left(None)),
)); ));
self.add_keybind(KeyBinding::new( self.add_keybind(KeyBinding::new(
self.xlib.make_key("K", self.config.mod_key | ShiftMask), self.xlib.make_key("K", self.config.mod_key | ShiftMask),
|wm, _| wm.rotate_virtual_screen(Direction::Right), |wm, _| wm.rotate_virtual_screen(Direction::Right(None)),
)); ));
self.xlib.init(); self.xlib.init();
@ -262,8 +266,8 @@ impl WindowManager {
self.last_rotation = Some(dir); self.last_rotation = Some(dir);
match dir { match dir {
Direction::Left => self.clients.rotate_left(), Direction::Left(n) => self.clients.rotate_left(n),
Direction::Right => self.clients.rotate_right(), Direction::Right(n) => self.clients.rotate_right(n),
} }
self.arrange_clients(); self.arrange_clients();
@ -273,7 +277,7 @@ impl WindowManager {
self.clients.iter_visible().next().map(|(k, _)| k).cloned(); self.clients.iter_visible().next().map(|(k, _)| k).cloned();
if let Some(key) = to_focus { if let Some(key) = to_focus {
self.focus_client(&key); self.focus_client(&key, false);
} }
} }
@ -286,7 +290,7 @@ impl WindowManager {
.cloned(); .cloned();
if let Some(k) = k { if let Some(k) = k {
self.focus_client(&k); self.focus_client(&k, false);
} }
} }
@ -299,7 +303,7 @@ impl WindowManager {
.cloned(); .cloned();
if let Some(k) = k { if let Some(k) = k {
self.focus_client(&k); self.focus_client(&k, false);
} }
} }
@ -320,10 +324,6 @@ impl WindowManager {
} }
fn arrange_clients(&mut self) { fn arrange_clients(&mut self) {
let (width, height) = self.xlib.dimensions();
self.clients
.arrange_virtual_screen(width, height, self.config.gap);
self.clients self.clients
.iter_visible() .iter_visible()
.for_each(|(_, c)| self.xlib.move_resize_client(c)); .for_each(|(_, c)| self.xlib.move_resize_client(c));
@ -333,7 +333,7 @@ impl WindowManager {
self.raise_floating_clients(); self.raise_floating_clients();
} }
fn focus_client<K>(&mut self, key: &K) fn focus_client<K>(&mut self, key: &K, try_raise: bool)
where where
K: ClientKey, K: ClientKey,
{ {
@ -343,12 +343,19 @@ impl WindowManager {
self.xlib.unfocus_client(old); self.xlib.unfocus_client(old);
} }
if let Some(new) = new.into_option() { match new {
self.xlib.focus_client(new); ClientEntry::Floating(new) => {
self.xlib.raise_client(new); self.xlib.focus_client(new);
}
self.raise_floating_clients(); if try_raise {
self.xlib.raise_client(new);
}
}
ClientEntry::Tiled(new) => {
self.xlib.focus_client(new);
}
_ => {}
}
} }
fn new_client(&mut self, window: Window) { fn new_client(&mut self, window: Window) {
@ -368,7 +375,7 @@ impl WindowManager {
self.clients.insert(client).unwrap(); self.clients.insert(client).unwrap();
self.xlib.map_window(window); self.xlib.map_window(window);
self.focus_client(&window); self.focus_client(&window, true);
self.arrange_clients(); self.arrange_clients();
} }
@ -377,15 +384,12 @@ impl WindowManager {
let event: &XMapRequestEvent = event.as_ref(); let event: &XMapRequestEvent = event.as_ref();
if !self.clients.contains(&event.window) { if !self.clients.contains(&event.window) {
info!("MapRequest: new client: {:?}", event.window);
self.new_client(event.window); self.new_client(event.window);
} }
} }
fn unmap_notify(&mut self, event: &XEvent) { fn unmap_notify(&mut self, event: &XEvent) {
let event: &XUnmapEvent = event.as_ref(); let event: &XUnmapEvent = event.as_ref();
info!("unmap_notify: {:?}", event.window);
self.clients.remove(&event.window); self.clients.remove(&event.window);
@ -394,7 +398,6 @@ impl WindowManager {
fn destroy_notify(&mut self, event: &XEvent) { fn destroy_notify(&mut self, event: &XEvent) {
let event: &XDestroyWindowEvent = event.as_ref(); let event: &XDestroyWindowEvent = event.as_ref();
info!("destroy_notify: {:?}", event.window);
self.clients.remove(&event.window); self.clients.remove(&event.window);
@ -413,7 +416,7 @@ impl WindowManager {
fn enter_notify(&mut self, event: &XEvent) { fn enter_notify(&mut self, event: &XEvent) {
let event: &XCrossingEvent = event.as_ref(); let event: &XCrossingEvent = event.as_ref();
self.focus_client(&event.window); self.focus_client(&event.window, false);
} }
/// ensure event.subwindow refers to a valid client. /// ensure event.subwindow refers to a valid client.
@ -514,7 +517,7 @@ impl WindowManager {
} }
fn button_press(&mut self, event: &XButtonPressedEvent) { fn button_press(&mut self, event: &XButtonPressedEvent) {
self.focus_client(&event.subwindow); self.focus_client(&event.subwindow, true);
match event.button { match event.button {
1 | 3 => match self.move_resize_window { 1 | 3 => match self.move_resize_window {
@ -587,8 +590,8 @@ impl std::ops::Not for Direction {
fn not(self) -> Self::Output { fn not(self) -> Self::Output {
match self { match self {
Direction::Left => Direction::Right, Direction::Left(n) => Direction::Right(n),
Direction::Right => Direction::Left, Direction::Right(n) => Direction::Left(n),
} }
} }
} }

View file

@ -216,12 +216,10 @@ impl XLib {
} }
self.send_event(client, self.atoms.take_focus); self.send_event(client, self.atoms.take_focus);
self.raise_client(client);
} }
pub fn unfocus_client(&self, client: &Client) { pub fn unfocus_client(&self, client: &Client) {
info!("unfocusing client: {:?}", client); //info!("unfocusing client: {:?}", client);
unsafe { unsafe {
xlib::XSetInputFocus( xlib::XSetInputFocus(
self.dpy(), self.dpy(),

View file

@ -4,4 +4,4 @@
/usr/bin/xsetroot -solid darkslategrey /usr/bin/xsetroot -solid darkslategrey
/usr/bin/feh --bg-fill "/mnt/storage/rust/wm/starship.jpg" /usr/bin/feh --bg-fill "/mnt/storage/rust/wm/starship.jpg"
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
exec /mnt/storage/rust/wm/target/debug/wm >& /home/user/.local/portlights.log exec /mnt/storage/rust/wm/target/release/wm >& /home/user/.local/portlights.log