changed rustfmt to max 80 chars per line, added better ways to switch virtual screens

This commit is contained in:
NoOneBtw 2021-05-03 12:34:48 +02:00
parent ef63004242
commit 5b37a86a58
5 changed files with 308 additions and 77 deletions

View file

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

View file

@ -32,7 +32,11 @@ mod client {
}
impl Client {
pub fn new(window: Window, size: (i32, i32), position: (i32, i32)) -> Self {
pub fn new(
window: Window,
size: (i32, i32),
position: (i32, i32),
) -> Self {
Self {
window,
size,
@ -41,7 +45,11 @@ mod client {
}
}
pub fn new_transient(window: Window, size: (i32, i32), transient: Window) -> Self {
pub fn new_transient(
window: Window,
size: (i32, i32),
transient: Window,
) -> Self {
Self {
window,
size,
@ -300,13 +308,17 @@ impl ClientState {
pub fn insert(&mut self, mut client: Client) -> Option<&Client> {
let key = client.key();
if client.is_transient() && self.contains(&client.transient_for.unwrap()) {
if client.is_transient()
&& self.contains(&client.transient_for.unwrap())
{
let transient = self.get(&client.transient_for.unwrap()).unwrap();
client.position = {
(
transient.position.0 + (transient.size.0 - client.size.0) / 2,
transient.position.1 + (transient.size.1 - client.size.1) / 2,
transient.position.0
+ (transient.size.0 - client.size.0) / 2,
transient.position.1
+ (transient.size.1 - client.size.1) / 2,
)
};
@ -347,7 +359,8 @@ impl ClientState {
{
let key = key.key();
self.clients.contains_key(&key) || self.floating_clients.contains_key(&key)
self.clients.contains_key(&key)
|| self.floating_clients.contains_key(&key)
}
pub fn iter_floating(&self) -> impl Iterator<Item = (&u64, &Client)> {
@ -378,6 +391,18 @@ impl ClientState {
.filter(move |&(k, _)| self.current_vs().contains(k))
}
pub fn iter_master_stack(&self) -> impl Iterator<Item = (&u64, &Client)> {
self.clients
.iter()
.filter(move |&(k, _)| self.current_vs().is_in_master(k))
}
pub fn iter_aux_stack(&self) -> impl Iterator<Item = (&u64, &Client)> {
self.clients
.iter()
.filter(move |&(k, _)| self.current_vs().is_in_aux(k))
}
/// Returns reference to the current `VirtualScreen`.
fn current_vs(&self) -> &VirtualScreen {
// there is always at least one (1) virtual screen.
@ -510,31 +535,39 @@ impl ClientState {
where
K: ClientKey,
{
self.virtual_screens
.iter()
.find_map(|vs| if vs.contains(key) { Some(vs) } else { None })
self.virtual_screens.iter().find_map(|vs| {
if vs.contains(key) {
Some(vs)
} else {
None
}
})
}
fn get_mut_virtualscreen_for_client<K>(&mut self, key: &K) -> Option<&mut VirtualScreen>
fn get_mut_virtualscreen_for_client<K>(
&mut self,
key: &K,
) -> Option<&mut VirtualScreen>
where
K: ClientKey,
{
self.virtual_screens.iter_mut().find_map(
|vs| {
if vs.contains(key) {
Some(vs)
} else {
None
}
},
)
self.virtual_screens.iter_mut().find_map(|vs| {
if vs.contains(key) {
Some(vs)
} else {
None
}
})
}
/**
focuses client `key` if it contains `key` and returns a reference to the newly and the previously
focused clients if any.
*/
pub fn focus_client<K>(&mut self, key: &K) -> (ClientEntry<&Client>, ClientEntry<&Client>)
pub fn focus_client<K>(
&mut self,
key: &K,
) -> (ClientEntry<&Client>, ClientEntry<&Client>)
where
K: ClientKey,
{
@ -613,7 +646,12 @@ 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>) {
pub fn arrange_virtual_screen(
&mut self,
width: i32,
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
@ -687,6 +725,20 @@ impl VirtualScreen {
self.master.contains(&key.key()) || self.aux.contains(&key.key())
}
fn is_in_master<K>(&self, key: &K) -> bool
where
K: ClientKey,
{
self.master.contains(&key.key())
}
fn is_in_aux<K>(&self, key: &K) -> bool
where
K: ClientKey,
{
self.aux.contains(&key.key())
}
fn insert<K>(&mut self, key: &K)
where
K: ClientKey,
@ -716,7 +768,8 @@ impl VirtualScreen {
self.aux.extend(self.master.drain(index..=index));
}
None => {
let index = self.aux.iter().position(|&k| k == key.key()).unwrap();
let index =
self.aux.iter().position(|&k| k == key.key()).unwrap();
self.master.extend(self.aux.drain(index..=index));
}
}

View file

@ -5,6 +5,7 @@ use log4rs::{
encode::pattern::PatternEncoder,
Config,
};
use state::WMConfig;
mod clients;
mod state;
@ -44,7 +45,7 @@ fn main() {
log_prologue();
state::WindowManager::new().init().run();
state::WindowManager::new(WMConfig::default()).init().run();
}
fn log_prologue() {

View file

@ -2,10 +2,14 @@ use std::rc::Rc;
use log::{error, info};
use x11::xlib::{self, ShiftMask, Window, XButtonEvent, XEvent, XKeyEvent, XMotionEvent};
use x11::xlib::{
self, Mod4Mask, ShiftMask, Window, XButtonEvent, XEvent, XKeyEvent,
XMotionEvent,
};
use xlib::{
ButtonPressMask, ButtonReleaseMask, Mod1Mask, PointerMotionMask, XConfigureRequestEvent,
XCrossingEvent, XDestroyWindowEvent, XMapRequestEvent, XUnmapEvent,
ButtonPressMask, ButtonReleaseMask, PointerMotionMask,
XConfigureRequestEvent, XCrossingEvent, XDestroyWindowEvent,
XMapRequestEvent, XUnmapEvent,
};
use crate::{
@ -14,15 +18,28 @@ use crate::{
xlib::XLib,
};
/**
Contains static config data for the window manager, the sort of stuff you might want to
be able to configure in a config file.
*/
pub struct WMConfig {
num_virtualscreens: usize,
mod_key: u32,
gap: Option<i32>,
}
pub struct WindowManager {
clients: ClientState,
move_window: Option<MoveWindow>,
resize_window: Option<MoveWindow>,
keybinds: Vec<KeyBinding>,
xlib: XLib,
last_rotation: Option<Direction>,
config: WMConfig,
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum Direction {
Left,
Right,
@ -40,8 +57,9 @@ struct KeyBinding {
}
impl WindowManager {
pub fn new() -> Self {
let clients = ClientState::with_virtualscreens(3);
pub fn new(config: WMConfig) -> Self {
let clients =
ClientState::with_virtualscreens(config.num_virtualscreens);
let xlib = XLib::new();
Self {
@ -50,28 +68,30 @@ impl WindowManager {
resize_window: None,
keybinds: Vec::new(),
xlib,
last_rotation: None,
config,
}
}
pub fn init(mut self) -> Self {
self.xlib.add_global_keybind(KeyOrButton::button(
1,
Mod1Mask,
self.config.mod_key,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
));
self.xlib.add_global_keybind(KeyOrButton::button(
2,
Mod1Mask,
self.config.mod_key,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
));
self.xlib.add_global_keybind(KeyOrButton::button(
3,
Mod1Mask,
self.config.mod_key,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("P", Mod1Mask),
self.xlib.make_key("P", self.config.mod_key),
|wm, _| {
wm.spawn(
"dmenu_run",
@ -94,37 +114,63 @@ impl WindowManager {
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("M", Mod1Mask),
self.xlib.make_key("M", self.config.mod_key),
Self::handle_switch_stack,
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("Q", Mod1Mask),
self.xlib.make_key("Q", self.config.mod_key),
Self::kill_client,
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("Q", Mod1Mask | ShiftMask),
self.xlib.make_key("Q", self.config.mod_key | ShiftMask),
|wm, _| wm.quit(),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("T", Mod1Mask),
self.xlib.make_key("T", self.config.mod_key),
|wm, _| wm.spawn("alacritty", &[]),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("Return", Mod1Mask | ShiftMask),
self.xlib
.make_key("Return", self.config.mod_key | ShiftMask),
|wm, _| wm.spawn("alacritty", &[]),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("Left", Mod1Mask),
self.xlib.make_key("Left", self.config.mod_key),
|wm, _| wm.rotate_virtual_screen(Direction::Left),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("Right", Mod1Mask),
self.xlib.make_key("Right", self.config.mod_key),
|wm, _| wm.rotate_virtual_screen(Direction::Right),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("Tab", self.config.mod_key),
|wm, _| wm.rotate_virtual_screen_back(),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("J", self.config.mod_key),
|wm, _| wm.focus_master_stack(),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("K", self.config.mod_key),
|wm, _| wm.focus_aux_stack(),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("J", self.config.mod_key | ShiftMask),
|wm, _| wm.rotate_virtual_screen(Direction::Left),
));
self.add_keybind(KeyBinding::new(
self.xlib.make_key("K", self.config.mod_key | ShiftMask),
|wm, _| wm.rotate_virtual_screen(Direction::Right),
));
@ -192,7 +238,9 @@ impl WindowManager {
let event: &XButtonEvent = event.as_ref();
let clean_mask = self.xlib.get_clean_mask();
if event.button == 2 && event.state & clean_mask == Mod1Mask & clean_mask {
if event.button == 2
&& event.state & clean_mask == self.config.mod_key & clean_mask
{
if self.clients.contains(&event.subwindow) {
info!("toggleing floating for {:?}", event.subwindow);
@ -221,7 +269,8 @@ impl WindowManager {
if self.move_window.is_none()
&& event.button == 1
&& event.state & clean_mask == Mod1Mask & clean_mask
&& event.state & clean_mask
== self.config.mod_key & clean_mask
&& self.clients.contains(&event.subwindow)
{
// if client is tiled, set to floating
@ -257,7 +306,9 @@ impl WindowManager {
move_window.cached_cursor_position = (event.x, event.y);
if let Some(client) = self.clients.get_mut(&move_window.key).into_option() {
if let Some(client) =
self.clients.get_mut(&move_window.key).into_option()
{
let position = &mut client.position;
position.0 += x;
position.1 += y;
@ -279,7 +330,8 @@ impl WindowManager {
if self.resize_window.is_none()
&& event.button == 3
&& event.state & clean_mask == Mod1Mask & clean_mask
&& event.state & clean_mask
== self.config.mod_key & clean_mask
&& self.clients.contains(&event.subwindow)
{
// if client is tiled, set to floating
@ -329,7 +381,9 @@ impl WindowManager {
resize_window.cached_cursor_position = (event.x, event.y);
if let Some(client) = self.clients.get_mut(&resize_window.key).into_option() {
if let Some(client) =
self.clients.get_mut(&resize_window.key).into_option()
{
let size = &mut client.size;
size.0 = std::cmp::max(1, size.0 + x);
@ -343,9 +397,17 @@ impl WindowManager {
}
}
fn rotate_virtual_screen_back(&mut self) {
if let Some(dir) = self.last_rotation {
self.rotate_virtual_screen(!dir);
}
}
fn rotate_virtual_screen(&mut self, dir: Direction) {
info!("rotateing VS: {:?}", dir);
self.last_rotation = Some(dir);
match dir {
Direction::Left => self.clients.rotate_left(),
Direction::Right => self.clients.rotate_right(),
@ -354,13 +416,40 @@ impl WindowManager {
self.arrange_clients();
// focus first client in all visible clients
let to_focus = self.clients.iter_visible().next().map(|(k, _)| k).cloned();
let to_focus =
self.clients.iter_visible().next().map(|(k, _)| k).cloned();
if let Some(key) = to_focus {
self.focus_client(&key);
}
}
fn focus_master_stack(&mut self) {
let k = self
.clients
.iter_master_stack()
.map(|(k, _)| k)
.next()
.cloned();
if let Some(k) = k {
self.focus_client(&k);
}
}
fn focus_aux_stack(&mut self) {
let k = self
.clients
.iter_aux_stack()
.map(|(k, _)| k)
.next()
.cloned();
if let Some(k) = k {
self.focus_client(&k);
}
}
fn hide_hidden_clients(&self) {
self.clients
.iter_hidden()
@ -379,14 +468,15 @@ impl WindowManager {
fn arrange_clients(&mut self) {
let (width, height) = self.xlib.dimensions();
self.clients.arrange_virtual_screen(width, height, Some(2));
self.hide_hidden_clients();
self.clients
.arrange_virtual_screen(width, height, self.config.gap);
self.clients
.iter_visible()
.for_each(|(_, c)| self.xlib.move_resize_client(c));
self.hide_hidden_clients();
self.raise_floating_clients();
}
@ -410,7 +500,9 @@ impl WindowManager {
fn new_client(&mut self, window: Window) {
info!("new client: {:?}", window);
let client = if let Some(transient_window) = self.xlib.get_transient_for_window(window) {
let client = if let Some(transient_window) =
self.xlib.get_transient_for_window(window)
{
Client::new_transient(
window,
self.xlib.get_window_size(window).unwrap_or((100, 100)),
@ -502,3 +594,24 @@ impl KeyBinding {
}
}
}
impl Default for WMConfig {
fn default() -> Self {
Self {
num_virtualscreens: 5,
mod_key: Mod4Mask,
gap: Some(2),
}
}
}
impl std::ops::Not for Direction {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Direction::Left => Direction::Right,
Direction::Right => Direction::Left,
}
}
}

View file

@ -3,12 +3,14 @@ use std::ptr::{null, null_mut};
use std::{ffi::CString, rc::Rc};
use x11::xlib::{
self, Atom, ButtonPressMask, ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime,
EnterWindowMask, FocusChangeMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask,
PointerMotionMask, PropertyChangeMask, ShiftMask, StructureNotifyMask, SubstructureNotifyMask,
SubstructureRedirectMask, Window, XCloseDisplay, XConfigureRequestEvent, XDefaultScreen,
XEvent, XGetTransientForHint, XGrabPointer, XInternAtom, XKillClient, XMapWindow, XOpenDisplay,
XRaiseWindow, XRootWindow, XSetErrorHandler, XSync, XUngrabPointer, XWarpPointer,
self, Atom, ButtonPressMask, ButtonReleaseMask, CWEventMask, ControlMask,
CurrentTime, EnterWindowMask, FocusChangeMask, LockMask, Mod1Mask,
Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, PointerMotionMask,
PropertyChangeMask, ShiftMask, StructureNotifyMask, SubstructureNotifyMask,
SubstructureRedirectMask, Window, XCloseDisplay, XConfigureRequestEvent,
XDefaultScreen, XEvent, XGetTransientForHint, XGrabPointer, XInternAtom,
XKillClient, XMapWindow, XOpenDisplay, XRaiseWindow, XRootWindow,
XSetErrorHandler, XSync, XUngrabPointer, XWarpPointer,
};
use xlib::GrabModeAsync;
@ -76,7 +78,8 @@ impl XLib {
pub fn init(&mut self) {
unsafe {
let mut window_attributes =
std::mem::MaybeUninit::<xlib::XSetWindowAttributes>::zeroed().assume_init();
std::mem::MaybeUninit::<xlib::XSetWindowAttributes>::zeroed()
.assume_init();
window_attributes.event_mask = SubstructureRedirectMask
| StructureNotifyMask
@ -92,7 +95,11 @@ impl XLib {
&mut window_attributes,
);
xlib::XSelectInput(self.dpy(), self.root, window_attributes.event_mask);
xlib::XSelectInput(
self.dpy(),
self.root,
window_attributes.event_mask,
);
XSetErrorHandler(Some(xlib_error_handler));
}
@ -123,9 +130,12 @@ impl XLib {
pub fn squash_event(&self, event_type: i32) -> XEvent {
unsafe {
let mut event = std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
let mut event =
std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
while xlib::XCheckTypedEvent(self.dpy(), event_type, &mut event) != 0 {}
while xlib::XCheckTypedEvent(self.dpy(), event_type, &mut event)
!= 0
{}
event
}
@ -133,7 +143,8 @@ impl XLib {
pub fn next_event(&self) -> XEvent {
unsafe {
let mut event = std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
let mut event =
std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
xlib::XNextEvent(self.dpy(), &mut event);
event
@ -142,7 +153,8 @@ impl XLib {
pub fn grab_key_or_button(&self, window: Window, key: &KeyOrButton) {
let numlock_mask = self.get_numlock_mask();
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
let modifiers =
vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
for modifier in modifiers.iter() {
match key {
@ -215,7 +227,11 @@ impl XLib {
xlib::CurrentTime,
);
xlib::XDeleteProperty(self.dpy(), self.root, self.atoms.active_window);
xlib::XDeleteProperty(
self.dpy(),
self.root,
self.atoms.active_window,
);
}
}
@ -237,7 +253,8 @@ impl XLib {
xlib::XConfigureWindow(
self.dpy(),
client.window,
(xlib::CWY | xlib::CWX | xlib::CWHeight | xlib::CWWidth) as u32,
(xlib::CWY | xlib::CWX | xlib::CWHeight | xlib::CWWidth)
as u32,
&mut windowchanges,
);
@ -338,10 +355,14 @@ impl XLib {
}
pub fn get_window_size(&self, window: Window) -> Option<(i32, i32)> {
let mut wa =
unsafe { std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed().assume_init() };
let mut wa = unsafe {
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed()
.assume_init()
};
if unsafe { xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0 } {
if unsafe {
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0
} {
Some((wa.width, wa.height))
} else {
None
@ -351,7 +372,9 @@ impl XLib {
pub fn get_transient_for_window(&self, window: Window) -> Option<Window> {
let mut transient_for: Window = 0;
if unsafe { XGetTransientForHint(self.dpy(), window, &mut transient_for) != 0 } {
if unsafe {
XGetTransientForHint(self.dpy(), window, &mut transient_for) != 0
} {
Some(transient_for)
} else {
None
@ -370,7 +393,12 @@ impl XLib {
};
unsafe {
xlib::XConfigureWindow(self.dpy(), event.window, event.value_mask as u32, &mut wc);
xlib::XConfigureWindow(
self.dpy(),
event.window,
event.value_mask as u32,
&mut wc,
);
}
}
@ -409,7 +437,10 @@ impl XLib {
xlib::XSelectInput(
self.dpy(),
window,
EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask,
EnterWindowMask
| FocusChangeMask
| PropertyChangeMask
| StructureNotifyMask,
);
}
@ -445,7 +476,8 @@ impl XLib {
self.dpy(),
self.root,
0,
(ButtonPressMask | ButtonReleaseMask | PointerMotionMask) as u32,
(ButtonPressMask | ButtonReleaseMask | PointerMotionMask)
as u32,
GrabModeAsync,
GrabModeAsync,
0,
@ -463,7 +495,17 @@ impl XLib {
pub fn move_cursor(&self, window: Window, position: (i32, i32)) {
unsafe {
XWarpPointer(self.dpy(), 0, window, 0, 0, 0, 0, position.0, position.1);
XWarpPointer(
self.dpy(),
0,
window,
0,
0,
0,
0,
position.0,
position.1,
);
}
}
@ -472,7 +514,13 @@ impl XLib {
let mut num_protos: i32 = 0;
unsafe {
if xlib::XGetWMProtocols(self.dpy(), client.window, &mut protos, &mut num_protos) != 0 {
if xlib::XGetWMProtocols(
self.dpy(),
client.window,
&mut protos,
&mut num_protos,
) != 0
{
for i in 0..num_protos {
if *protos.offset(i as isize) == proto {
return true;
@ -503,7 +551,13 @@ impl XLib {
};
unsafe {
xlib::XSendEvent(self.dpy(), client.window, 0, xlib::NoEventMask, &mut event);
xlib::XSendEvent(
self.dpy(),
client.window,
0,
xlib::NoEventMask,
&mut event,
);
}
true
@ -543,7 +597,10 @@ impl XLib {
if *(*modmap)
.modifiermap
.offset((i * max_keypermod + j) as isize)
== xlib::XKeysymToKeycode(self.dpy(), x11::keysym::XK_Num_Lock as u64)
== xlib::XKeysymToKeycode(
self.dpy(),
x11::keysym::XK_Num_Lock as u64,
)
{
return 1 << i;
}
@ -556,7 +613,13 @@ impl XLib {
pub fn get_clean_mask(&self) -> u32 {
!(self.get_numlock_mask() | LockMask)
& (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
& (ShiftMask
| ControlMask
| Mod1Mask
| Mod2Mask
| Mod3Mask
| Mod4Mask
| Mod5Mask)
}
}