Merge pull request 'feature_ewmh' (#4) from feature_ewmh into main

Reviewed-on: https://desktop-host/git/janis/wm/pulls/4
This commit is contained in:
janis 2022-05-08 13:27:50 +02:00
commit 1aab741b49
8 changed files with 1039 additions and 261 deletions

View file

@ -23,3 +23,5 @@ derivative = "2.2.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "0.5" toml = "0.5"
num-traits = "0.2.14" num-traits = "0.2.14"
strum = {version = "0.24.0", features = ["derive"]}
bytemuck = "1.0.0"

View file

@ -4,3 +4,18 @@ pub mod window_event;
pub mod xlib; pub mod xlib;
pub use traits::*; pub use traits::*;
pub mod structs {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum WindowType {
Splash,
Dialog,
Normal,
Utility,
Menu,
Toolbar,
Dock,
Desktop,
}
}

View file

@ -1,4 +1,7 @@
use super::window_event::{self, KeyOrMouseBind}; use super::{
structs::WindowType,
window_event::{self, KeyOrMouseBind},
};
use crate::util::{Point, Size}; use crate::util::{Point, Size};
pub trait WindowServerBackend { pub trait WindowServerBackend {
@ -31,6 +34,8 @@ pub trait WindowServerBackend {
fn screen_size(&self) -> Size<i32>; fn screen_size(&self) -> Size<i32>;
fn get_window_size(&self, window: Self::Window) -> Option<Size<i32>>; fn get_window_size(&self, window: Self::Window) -> Option<Size<i32>>;
fn get_window_name(&self, window: Self::Window) -> Option<String>;
fn get_window_type(&self, window: Self::Window) -> WindowType;
fn grab_cursor(&self); fn grab_cursor(&self);
fn ungrab_cursor(&self); fn ungrab_cursor(&self);

View file

@ -1,10 +1,13 @@
#![allow(dead_code)] #![allow(dead_code)]
use super::keycodes::{KeyOrButton, MouseButton, VirtualKeyCode}; use super::{
keycodes::{KeyOrButton, MouseButton, VirtualKeyCode},
structs::WindowType,
};
use crate::util::{Point, Size}; use crate::util::{Point, Size};
use bitflags::bitflags; use bitflags::bitflags;
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum WindowEvent<Window> { pub enum WindowEvent<Window> {
KeyEvent(KeyEvent<Window>), KeyEvent(KeyEvent<Window>),
ButtonEvent(ButtonEvent<Window>), ButtonEvent(ButtonEvent<Window>),
@ -17,6 +20,8 @@ pub enum WindowEvent<Window> {
EnterEvent(EnterEvent<Window>), EnterEvent(EnterEvent<Window>),
ConfigureEvent(ConfigureEvent<Window>), ConfigureEvent(ConfigureEvent<Window>),
FullscreenEvent(FullscreenEvent<Window>), //1 { window: Window, event: 1 }, FullscreenEvent(FullscreenEvent<Window>), //1 { window: Window, event: 1 },
WindowNameEvent(WindowNameEvent<Window>),
WindowTypeChangedEvent(WindowTypeChangedEvent<Window>),
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -106,7 +111,7 @@ impl Into<u8> for ModifierKey {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct KeyEvent<Window> { pub struct KeyEvent<Window> {
pub window: Window, pub window: Window,
pub state: KeyState, pub state: KeyState,
@ -130,7 +135,7 @@ impl<Window> KeyEvent<Window> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ButtonEvent<Window> { pub struct ButtonEvent<Window> {
pub window: Window, pub window: Window,
pub state: KeyState, pub state: KeyState,
@ -157,7 +162,7 @@ impl<Window> ButtonEvent<Window> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct MotionEvent<Window> { pub struct MotionEvent<Window> {
pub position: Point<i32>, pub position: Point<i32>,
pub window: Window, pub window: Window,
@ -169,22 +174,22 @@ impl<Window> MotionEvent<Window> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct MapEvent<Window> { pub struct MapEvent<Window> {
pub window: Window, pub window: Window,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct UnmapEvent<Window> { pub struct UnmapEvent<Window> {
pub window: Window, pub window: Window,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct EnterEvent<Window> { pub struct EnterEvent<Window> {
pub window: Window, pub window: Window,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct DestroyEvent<Window> { pub struct DestroyEvent<Window> {
pub window: Window, pub window: Window,
} }
@ -195,7 +200,7 @@ impl<Window> DestroyEvent<Window> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct CreateEvent<Window> { pub struct CreateEvent<Window> {
pub window: Window, pub window: Window,
pub position: Point<i32>, pub position: Point<i32>,
@ -212,7 +217,7 @@ impl<Window> CreateEvent<Window> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ConfigureEvent<Window> { pub struct ConfigureEvent<Window> {
pub window: Window, pub window: Window,
pub position: Point<i32>, pub position: Point<i32>,
@ -229,7 +234,7 @@ impl<Window> ConfigureEvent<Window> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum FullscreenState { pub enum FullscreenState {
On, On,
Off, Off,
@ -245,7 +250,7 @@ impl From<bool> for FullscreenState {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct FullscreenEvent<Window> { pub struct FullscreenEvent<Window> {
pub window: Window, pub window: Window,
pub state: FullscreenState, pub state: FullscreenState,
@ -257,6 +262,33 @@ impl<Window> FullscreenEvent<Window> {
} }
} }
#[derive(Debug, Clone)]
pub struct WindowNameEvent<Window> {
pub window: Window,
pub name: String,
}
impl<Window> WindowNameEvent<Window> {
pub fn new(window: Window, name: String) -> Self {
Self { window, name }
}
}
#[derive(Debug, Clone)]
pub struct WindowTypeChangedEvent<Window> {
pub window: Window,
pub window_type: WindowType,
}
impl<Window> WindowTypeChangedEvent<Window> {
pub fn new(window: Window, window_type: WindowType) -> Self {
Self {
window,
window_type,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct KeyBind { pub struct KeyBind {
pub key: VirtualKeyCode, pub key: VirtualKeyCode,

File diff suppressed because it is too large Load diff

View file

@ -4,13 +4,17 @@ use indexmap::IndexMap;
use log::error; use log::error;
use num_traits::Zero; use num_traits::Zero;
use crate::backends::structs::WindowType;
use crate::util::BuildIdentityHasher; use crate::util::BuildIdentityHasher;
use crate::util::{Point, Size}; use crate::util::{Point, Size};
mod client { mod client {
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use crate::util::{Point, Size}; use crate::{
backends::structs::WindowType,
util::{Point, Size},
};
use x11::xlib::Window; use x11::xlib::Window;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -18,7 +22,8 @@ mod client {
pub(crate) window: Window, pub(crate) window: Window,
pub(crate) size: Size<i32>, pub(crate) size: Size<i32>,
pub(crate) position: Point<i32>, pub(crate) position: Point<i32>,
pub(crate) transient_for: Option<Window>, pub(crate) parent_window: Option<Window>,
pub(crate) window_type: WindowType,
pub(crate) fullscreen: bool, pub(crate) fullscreen: bool,
} }
@ -28,8 +33,9 @@ mod client {
window: 0, window: 0,
size: (100, 100).into(), size: (100, 100).into(),
position: (0, 0).into(), position: (0, 0).into(),
transient_for: None, parent_window: None,
fullscreen: false, fullscreen: false,
window_type: WindowType::Normal,
} }
} }
} }
@ -49,7 +55,7 @@ mod client {
} }
} }
pub fn new_transient( pub fn new_dialog(
window: Window, window: Window,
size: Size<i32>, size: Size<i32>,
transient: Window, transient: Window,
@ -57,7 +63,7 @@ mod client {
Self { Self {
window, window,
size, size,
transient_for: Some(transient), parent_window: Some(transient),
..Default::default() ..Default::default()
} }
} }
@ -69,6 +75,24 @@ mod client {
} }
} }
pub fn with_window_type(self, window_type: WindowType) -> Self {
Self {
window_type,
..self
}
}
pub fn with_parent_window(self, parent_window: Option<Window>) -> Self {
Self {
parent_window,
..self
}
}
pub fn with_size(self, size: Size<i32>) -> Self {
Self { size, ..self }
}
/// toggles the clients fullscreen flag. /// toggles the clients fullscreen flag.
/// returns `true` if the client is now fullscreen. /// returns `true` if the client is now fullscreen.
pub fn toggle_fullscreen(&mut self) -> bool { pub fn toggle_fullscreen(&mut self) -> bool {
@ -90,8 +114,8 @@ mod client {
self.fullscreen self.fullscreen
} }
pub fn is_transient(&self) -> bool { pub fn has_parent_window(&self) -> bool {
self.transient_for.is_some() self.parent_window.is_some()
} }
} }
@ -240,26 +264,41 @@ impl ClientState {
pub fn insert(&mut self, mut client: Client) -> Option<&Client> { pub fn insert(&mut self, mut client: Client) -> Option<&Client> {
let key = client.key(); let key = client.key();
if client.is_transient() match client.window_type {
&& self.contains(&client.transient_for.unwrap()) // idk how to handle docks and desktops, for now they float innit
{ WindowType::Splash
let transient = self.get(&client.transient_for.unwrap()).unwrap(); | WindowType::Dialog
| WindowType::Utility
| WindowType::Menu
| WindowType::Toolbar
| WindowType::Dock
| WindowType::Desktop => {
if let Some(parent) = client
.parent_window
.and_then(|window| self.get(&window).into_option())
{
client.position = {
(
parent.position.x
+ (parent.size.width - client.size.width) / 2,
parent.position.y
+ (parent.size.height - client.size.height) / 2,
)
.into()
};
}
client.position = { client.size = client.size.clamp(
( self.screen_size
transient.position.x - Size::new(self.border_size * 2, self.border_size * 2),
+ (transient.size.width - client.size.width) / 2, );
transient.position.y
+ (transient.size.height - client.size.height) / 2,
)
.into()
};
self.floating_clients.insert(key, client); self.floating_clients.insert(key, client);
} else { }
self.clients.insert(key, client); WindowType::Normal => {
self.clients.insert(key, client);
self.virtual_screens.get_mut_current().insert(&key); self.virtual_screens.get_mut_current().insert(&key);
}
} }
// adding a client changes the liling layout, rearrange // adding a client changes the liling layout, rearrange
@ -320,7 +359,15 @@ impl ClientState {
} }
pub fn iter_transient(&self) -> impl Iterator<Item = (&u64, &Client)> { pub fn iter_transient(&self) -> impl Iterator<Item = (&u64, &Client)> {
self.iter_floating().filter(|&(_, c)| c.is_transient()) self.iter_floating().filter(|&(_, c)| c.has_parent_window())
}
pub fn iter_by_window_type(
&self,
window_type: WindowType,
) -> impl Iterator<Item = (&u64, &Client)> {
self.iter_floating()
.filter(move |&(_, c)| c.window_type == window_type)
} }
pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> { pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> {
@ -357,7 +404,7 @@ impl ClientState {
{ {
match self.get(key) { match self.get(key) {
ClientEntry::Floating(c) => { ClientEntry::Floating(c) => {
if let Some(transient_for) = c.transient_for { if let Some(transient_for) = c.parent_window {
self.is_client_visible(&transient_for) self.is_client_visible(&transient_for)
} else { } else {
true true
@ -490,6 +537,23 @@ impl ClientState {
} }
} }
/**
Sets a floating client to tiled and returns true, does nothing for a tiled client and
returns false. If this function returns `true` you have to call `arrange_clients` after.
*/
pub fn set_tiled<K>(&mut self, key: &K) -> bool
where
K: ClientKey,
{
if self.get(key).is_floating() {
self.toggle_floating(key);
true
} else {
false
}
}
/** /**
This function invalidates the tiling, call `arrange_clients` to fix it again (it doesn't do it This function invalidates the tiling, call `arrange_clients` to fix it again (it doesn't do it
automatically since xlib has to move and resize all windows anyways). automatically since xlib has to move and resize all windows anyways).
@ -519,15 +583,15 @@ impl ClientState {
} }
(None, Some(floating_client)) => { (None, Some(floating_client)) => {
// transient clients cannot be tiled // transient clients cannot be tiled
match floating_client.is_transient() { // only normal windows can be tiled
true => { match floating_client.window_type {
self.floating_clients.insert(key, floating_client); WindowType::Normal => {
}
false => {
self.clients.insert(key, floating_client); self.clients.insert(key, floating_client);
self.virtual_screens.get_mut_current().insert(&key); self.virtual_screens.get_mut_current().insert(&key);
} }
_ => {
self.floating_clients.insert(key, floating_client);
}
} }
} }
_ => { _ => {
@ -542,6 +606,20 @@ impl ClientState {
} }
} }
pub fn update_window_type<K>(&mut self, key: &K, window_type: WindowType)
where
K: ClientKey,
{
if let Some(client) = self.get_mut(key).into_option() {
client.window_type = window_type;
match window_type {
WindowType::Normal => self.set_floating(key),
_ => self.set_tiled(key),
};
}
}
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,

View file

@ -4,7 +4,10 @@ use log::{error, info};
use x11::xlib::{self, Window}; use x11::xlib::{self, Window};
use crate::backends::window_event::{FullscreenEvent, FullscreenState}; use crate::backends::structs::WindowType;
use crate::backends::window_event::{
FullscreenEvent, FullscreenState, WindowNameEvent, WindowTypeChangedEvent,
};
use crate::util::{Point, Size}; use crate::util::{Point, Size};
use crate::{ use crate::{
backends::{ backends::{
@ -303,13 +306,6 @@ where
&self.config.inactive_window_border_color, &self.config.inactive_window_border_color,
); );
// add all already existing windows to the WM
if let Some(windows) = self.backend.all_windows() {
windows
.into_iter()
.for_each(|window| self.new_client(window));
}
self self
} }
@ -428,8 +424,6 @@ where
self.button_event(&event); self.button_event(&event);
} }
WindowEvent::MapRequestEvent(MapEvent { window }) => { WindowEvent::MapRequestEvent(MapEvent { window }) => {
self.backend.handle_event(event);
if !self.clients.contains(&window) { if !self.clients.contains(&window) {
self.new_client(window); self.new_client(window);
} }
@ -445,28 +439,27 @@ where
self.do_move_resize_window(&event); self.do_move_resize_window(&event);
} }
WindowEvent::ConfigureEvent(ConfigureEvent { WindowEvent::ConfigureEvent(ConfigureEvent {
window, .. window,
}) => { size,
match self.clients.get(&window) { position,
ClientEntry::Tiled(client) ..
| ClientEntry::Floating(client) => { }) => match self.clients.get(&window) {
self.backend.configure_window( ClientEntry::Tiled(client)
window, | ClientEntry::Floating(client) => {
Some(client.size), self.backend.configure_window(
Some(client.position), window,
None, Some(client.size),
) Some(client.position),
} None,
ClientEntry::Vacant => self.backend.handle_event(event), )
} }
// TODO ClientEntry::Vacant => self.backend.configure_window(
// match self.clients.get(&event.window).into_option() { window,
// Some(client) => self Some(size),
// .xlib Some(position),
// .configure_client(client, self.clients.get_border()), None,
// None => self.xlib.configure_window(event), ),
// } },
}
WindowEvent::FullscreenEvent(FullscreenEvent { WindowEvent::FullscreenEvent(FullscreenEvent {
window, window,
state, state,
@ -500,6 +493,17 @@ where
self.arrange_clients(); self.arrange_clients();
} }
} }
WindowEvent::WindowNameEvent(WindowNameEvent { .. }) => {
info!("{:#?}", event);
}
WindowEvent::WindowTypeChangedEvent(
WindowTypeChangedEvent {
window,
window_type,
},
) => {
self.clients.update_window_type(&window, window_type);
}
// i dont think i actually have to handle destroy notify events. // i dont think i actually have to handle destroy notify events.
// every window should be unmapped regardless // every window should be unmapped regardless
@ -743,19 +747,16 @@ where
} }
fn new_client(&mut self, window: Window) { fn new_client(&mut self, window: Window) {
info!("new client: {:?}", window); let client = match self.backend.get_window_type(window) {
let client = if let Some(transient_window) = WindowType::Normal => Client::new_default(window),
self.backend.get_parent_window(window) window_type @ _ => Client::new_default(window)
{ .with_window_type(window_type)
Client::new_transient( .with_size(
window, self.backend
self.backend .get_window_size(window)
.get_window_size(window) .unwrap_or((100, 100).into()),
.unwrap_or((100, 100).into()), )
transient_window, .with_parent_window(self.backend.get_parent_window(window)),
)
} else {
Client::new_default(window)
}; };
self.backend.configure_window( self.backend.configure_window(
@ -765,6 +766,8 @@ where
Some(self.clients.get_border()), Some(self.clients.get_border()),
); );
info!("new client: {:#?}", client);
self.clients.insert(client).unwrap(); self.clients.insert(client).unwrap();
self.arrange_clients(); self.arrange_clients();

View file

@ -123,6 +123,13 @@ mod size {
(self.width, self.height) (self.width, self.height)
} }
pub fn clamp(self, other: Self) -> Self {
Self::new(
self.width.min(other.width),
self.height.min(other.height),
)
}
pub fn map<F>(self, f: F) -> Self pub fn map<F>(self, f: F) -> Self
where where
F: FnOnce(I, I) -> Self, F: FnOnce(I, I) -> Self,