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

View file

@ -1,7 +1,7 @@
#![allow(dead_code)]
use std::collections::HashMap;
use std::num::NonZeroI32;
use std::{collections::HashMap, ops::Rem, usize};
use log::{error, info};
@ -113,31 +113,6 @@ mod client {
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::*;
@ -218,56 +193,15 @@ pub enum ClientEntry<T> {
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)]
pub struct ClientState {
pub(self) clients: Clients,
pub(self) floating_clients: Clients,
focused: Option<ClientRef>,
pub(self) virtual_screens: VecDeque<VirtualScreen>,
gap: i32,
screen_size: (i32, i32),
}
#[derive(Debug, Clone)]
@ -286,6 +220,8 @@ impl Default for ClientState {
floating_clients: Default::default(),
focused: None,
virtual_screens: vss,
gap: 0,
screen_size: (1, 1),
}
}
}
@ -295,13 +231,24 @@ impl ClientState {
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();
vss.resize_with(num, Default::default);
Self {
virtual_screens: vss,
..Default::default()
..self
}
}
@ -333,6 +280,9 @@ impl ClientState {
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`.
self.get(&key).into_option()
}
@ -351,6 +301,9 @@ impl ClientState {
self.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
@ -460,12 +413,18 @@ impl ClientState {
}
}
pub fn rotate_right(&mut self) {
self.virtual_screens.rotate_right(1);
pub fn rotate_right(&mut self, n: Option<usize>) {
self.virtual_screens
.rotate_right(n.unwrap_or(1).rem(self.virtual_screens.len()));
self.arrange_virtual_screen();
}
pub fn rotate_left(&mut self) {
self.virtual_screens.rotate_left(1);
pub fn rotate_left(&mut self, n: Option<usize>) {
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 => {
self.floating_clients.insert(key, floating_client);
}
false => {
self.clients.insert(key, floating_client);
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.")
}
};
// 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)
where
K: ClientKey,
{
if let Some(vs) = self.get_mut_virtualscreen_for_client(key) {
vs.remove(key);
if self.contains(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() {
(ClientEntry::Vacant, ClientEntry::Vacant)
} 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.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> {
match self.focused {
@ -627,6 +598,8 @@ impl ClientState {
{
if let Some(vs) = self.get_mut_virtualscreen_for_client(key) {
vs.switch_stack_for_client(key);
self.arrange_virtual_screen();
}
}
@ -635,13 +608,9 @@ impl ClientState {
screen width and screen height.
Optionally adds a gap between windows `gap.unwrap_or(0)` pixels wide.
*/
pub fn arrange_virtual_screen(
&mut self,
width: i32,
height: i32,
gap: Option<i32>,
) {
let gap = gap.unwrap_or(0);
pub fn arrange_virtual_screen(&mut self) {
let gap = self.gap;
let (width, height) = self.screen_size;
// should be fine to unwrap since we will always have at least 1 virtual screen
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
@ -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();
state::WindowManager::new(WMConfig::default()).init().run();
state::WindowManager::new(WMConfig::default()).run();
}
fn log_prologue() {

View file

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

View file

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

View file

@ -4,4 +4,4 @@
/usr/bin/xsetroot -solid darkslategrey
/usr/bin/feh --bg-fill "/mnt/storage/rust/wm/starship.jpg"
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