added fullscreen mechanics

This commit is contained in:
Janis 2021-12-02 20:22:21 +01:00
parent c9b926f5ba
commit 5dbfa6fbcf
2 changed files with 159 additions and 40 deletions

View file

@ -1,4 +1,3 @@
use std::num::NonZeroI32;
use std::{ops::Rem, usize};
use indexmap::IndexMap;
@ -20,6 +19,7 @@ mod client {
pub(crate) size: Point<i32>,
pub(crate) position: Point<i32>,
pub(crate) transient_for: Option<Window>,
pub(crate) fullscreen: bool,
}
impl Default for Client {
@ -29,6 +29,7 @@ mod client {
size: (100, 100).into(),
position: (0, 0).into(),
transient_for: None,
fullscreen: false,
}
}
}
@ -44,7 +45,7 @@ mod client {
window,
size,
position,
transient_for: None,
..Self::default()
}
}
@ -68,6 +69,27 @@ mod client {
}
}
/// toggles the clients fullscreen flag.
/// returns `true` if the client is now fullscreen.
pub fn toggle_fullscreen(&mut self) -> bool {
self.fullscreen = !self.fullscreen;
self.is_fullscreen()
}
pub fn set_fullscreen(&mut self, fullscreen: bool) -> bool {
if self.fullscreen == fullscreen {
false
} else {
self.fullscreen = fullscreen;
true
}
}
pub fn is_fullscreen(&self) -> bool {
self.fullscreen
}
pub fn is_transient(&self) -> bool {
self.transient_for.is_some()
}
@ -408,6 +430,43 @@ impl ClientState {
self.arrange_virtual_screen();
}
pub fn set_fullscreen<K>(&mut self, key: &K, fullscreen: bool) -> bool
where
K: ClientKey,
{
self.get(key)
.into_option()
.map(|client| client.is_fullscreen() != fullscreen)
.unwrap_or(false)
.then(|| self.toggle_fullscreen(key))
.unwrap_or(false)
}
pub fn toggle_fullscreen<K>(&mut self, key: &K) -> bool
where
K: ClientKey,
{
if self.inner_toggle_fullscreen(key) {
self.arrange_virtual_screen();
true
} else {
false
}
}
fn inner_toggle_fullscreen<K>(&mut self, key: &K) -> bool
where
K: ClientKey,
{
self.get_mut(key)
.into_option()
.map(|client| {
client.toggle_fullscreen();
true
})
.unwrap_or(false)
}
/**
Sets a tiled client to floating and returns true, does nothing for a floating client and
returns false. If this function returns `true` you have to call `arrange_clients` after.
@ -635,49 +694,87 @@ impl ClientState {
let vs = self.virtual_screens.get_mut_current();
// if aux is empty -> width : width / 2
let (master_width, aux_width) = {
let effective_width = width - gap * 2;
let vs_width = width - gap * 2;
let master_size = if vs.aux.is_empty() {
let master_position = Point::new(0, 0);
let master_window_size = {
let factor = if vs.aux.is_empty() {
1.0
} else {
self.master_size / 2.0
};
let master_width = (effective_width as f32 * master_size) as i32;
let aux_width = effective_width - master_width;
let width = (vs_width as f32 * factor) as i32;
(master_width, aux_width)
// make sure we dont devide by 0
// height is max height / number of clients in the stack
let height = match vs.master.len() as i32 {
0 => 1,
n => (height - gap * 2) / n,
};
Size::new(width, height)
};
// make sure we dont devide by 0
// height is max height / number of clients in the stack
let master_height = (height - gap * 2)
/ match NonZeroI32::new(vs.master.len() as i32) {
Some(i) => i.get(),
None => 1,
let aux_position = Point::new(master_window_size.width, 0);
let aux_window_size = {
let width = vs_width - master_window_size.width;
// make sure we dont devide by 0
// height is max height / number of clients in the stack
let height = match vs.aux.len() as i32 {
0 => 1,
n => (height - gap * 2) / n,
};
// height is max height / number of clients in the stack
let aux_height = (height - gap * 2)
/ match NonZeroI32::new(vs.aux.len() as i32) {
Some(i) => i.get(),
None => 1,
};
Size::new(width, height)
};
fn calculate_window_dimensions(
screen_size: Size<i32>,
stack_size: Size<i32>,
stack_position: Point<i32>,
fullscreen: bool,
nth: i32,
gap: i32,
border: i32,
) -> (Size<i32>, Point<i32>) {
if fullscreen {
let size = Size::new(
screen_size.width - border * 2,
screen_size.height - border * 2,
);
let pos = Point::new(0, 0);
(size, pos)
} else {
let size = Size::new(
stack_size.width - gap * 2 - border * 2,
stack_size.height - gap * 2 - border * 2,
);
let pos = Point::new(
stack_position.x + gap * 2,
stack_position.y + stack_size.height * nth + gap * 2,
);
(size, pos)
}
}
// Master
for (i, key) in vs.master.iter().enumerate() {
let size = (
master_width - gap * 2 - self.border_size * 2,
master_height - gap * 2 - self.border_size * 2,
);
let position = (gap * 2, master_height * i as i32 + gap * 2);
if let Some(client) = self.clients.get_mut(key) {
let (size, position) = calculate_window_dimensions(
self.screen_size.into(),
master_window_size,
master_position,
client.is_fullscreen(),
i as i32,
gap,
self.border_size,
);
*client = Client {
size: size.into(),
position: position.into(),
position,
..*client
};
}
@ -685,18 +782,20 @@ impl ClientState {
// Aux
for (i, key) in vs.aux.iter().enumerate() {
let size = (
aux_width - gap * 2 - self.border_size * 2,
aux_height - gap * 2 - self.border_size * 2,
);
let position =
(master_width + gap * 2, aux_height * i as i32 + gap * 2);
if let Some(client) = self.clients.get_mut(key) {
let (size, position) = calculate_window_dimensions(
self.screen_size.into(),
aux_window_size,
aux_position,
client.is_fullscreen(),
i as i32,
gap,
self.border_size,
);
*client = Client {
size: size.into(),
position: position.into(),
position,
..*client
};
}

View file

@ -8,9 +8,9 @@ use crate::{
backends::{
keycodes::{MouseButton, VirtualKeyCode},
window_event::{
ButtonEvent, ConfigureEvent, FullscreenEvent, KeyBind, KeyEvent,
KeyState, MapEvent, ModifierKey, ModifierState, MotionEvent,
MouseBind, Point, WindowEvent,
ButtonEvent, ConfigureEvent, FullscreenEvent, FullscreenState,
KeyBind, KeyEvent, KeyState, MapEvent, ModifierKey, ModifierState,
MotionEvent, MouseBind, Point, WindowEvent,
},
xlib::XLib,
WindowServerBackend,
@ -469,6 +469,20 @@ where
state,
}) => {
info!("FullscreenEvent for window {}: {:?}", window, state);
if match state {
FullscreenState::On => {
self.clients.set_fullscreen(&window, true)
}
FullscreenState::Off => {
self.clients.set_fullscreen(&window, false)
}
FullscreenState::Toggle => {
self.clients.toggle_fullscreen(&window)
}
} {
self.arrange_clients();
}
}
// i dont think i actually have to handle destroy notify events.
@ -658,6 +672,12 @@ where
self.clients
.iter_transient()
.for_each(|(_, c)| self.backend.raise_window(c.window));
//raise fullscreen windows
self.clients
.iter_current_screen()
.filter(|(_, c)| c.is_fullscreen())
.for_each(|(_, c)| self.backend.raise_window(c.window));
}
fn arrange_clients(&mut self) {