commit 986b9e3e483242fbdb6e3d34f9d395a5782d721e
parent 5405ebc2e12856ed1fef241aad3c076a8ba76e43
Author: deurzen <m.deurzen@tum.de>
Date: Mon, 15 Mar 2021 08:53:06 +0100
implements state change layout reapplication check
Diffstat:
5 files changed, 221 insertions(+), 116 deletions(-)
diff --git a/src/core/common.rs b/src/core/common.rs
@@ -33,6 +33,12 @@ pub const FREE_DECORATION: Decoration = Decoration {
}),
};
+pub enum StateChangeError {
+ EarlyStop,
+ LimitReached,
+ StateUnchanged,
+}
+
pub type Color = u32;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
diff --git a/src/core/macros.rs b/src/core/macros.rs
@@ -2,13 +2,13 @@
macro_rules! do_internal(
($func:ident) => {
Box::new(|model: &mut $crate::model::Model| {
- model.$func();
+ drop(model.$func());
}) as $crate::binding::KeyEvents
};
($func:ident, $($arg:expr),+) => {
Box::new(move |model: &mut $crate::model::Model| {
- model.$func($($arg),+);
+ drop(model.$func($($arg),+));
}) as $crate::binding::KeyEvents
};
);
@@ -33,13 +33,13 @@ macro_rules! do_nothing(
macro_rules! do_internal_mouse(
($func:ident) => {
Box::new(|model: &mut $crate::model::Model, _| {
- model.$func();
+ drop(model.$func());
}) as $crate::binding::MouseEvents
};
($func:ident, $($arg:expr),+) => {
Box::new(|model: &mut $crate::model::Model, _| {
- model.$func($($arg),+);
+ drop(model.$func($($arg),+));
}) as $crate::binding::MouseEvents
};
);
diff --git a/src/core/model.rs b/src/core/model.rs
@@ -4,6 +4,7 @@ use crate::client::Client;
use crate::common::Change;
use crate::common::Direction;
use crate::common::Index;
+use crate::common::StateChangeError;
use crate::common::FREE_DECORATION;
use crate::common::MIN_WINDOW_DIM;
use crate::common::NO_DECORATION;
@@ -1579,84 +1580,91 @@ impl<'a> Model<'a> {
pub fn change_gap_size(
&mut self,
change: Change,
- ) {
+ ) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_gap_size(change, 5, &mut self.zone_manager);
+ workspace.change_gap_size(change, 5, &mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
+ Ok(())
}
- pub fn reset_layout(&mut self) {
+ pub fn reset_layout(&mut self) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.reset_layout(&mut self.zone_manager);
+ workspace.reset_layout(&mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
+ Ok(())
}
- pub fn reset_gap_size(&mut self) {
+ pub fn reset_gap_size(&mut self) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.reset_gap_size(&mut self.zone_manager);
+ workspace.reset_gap_size(&mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
+ Ok(())
}
pub fn change_main_count(
&mut self,
change: Change,
- ) {
+ ) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_main_count(change, &mut self.zone_manager);
+ workspace.change_main_count(change, &mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
+ Ok(())
}
pub fn change_main_factor(
&mut self,
change: Change,
- ) {
+ ) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_main_factor(change, 0.05f32, &mut self.zone_manager);
+ workspace.change_main_factor(change, 0.05f32, &mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
+ Ok(())
}
pub fn change_margin(
&mut self,
edge: Edge,
change: Change,
- ) {
+ ) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_margin(edge, change, 5, &mut self.zone_manager);
+ workspace.change_margin(edge, change, 5, &mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
+ Ok(())
}
- pub fn reset_margin(&mut self) {
+ pub fn reset_margin(&mut self) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.reset_margin(&mut self.zone_manager);
+ workspace.reset_margin(&mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
+ Ok(())
}
pub fn set_layout(
diff --git a/src/core/workspace.rs b/src/core/workspace.rs
@@ -4,6 +4,7 @@ use crate::common::Direction;
use crate::common::Ident;
use crate::common::Identify;
use crate::common::Index;
+use crate::common::StateChangeError;
use crate::common::FREE_DECORATION;
use crate::common::NO_DECORATION;
use crate::cycle::Cycle;
@@ -437,14 +438,21 @@ impl Workspace {
pub fn reset_layout(
&self,
zone_manager: &mut ZoneManager,
- ) {
- if let Some(&id) = self.zones.active_element() {
- if let Some(default_data) = zone_manager.active_default_data(id) {
- if let Some(data) = zone_manager.active_data_mut(id) {
- *data = default_data;
- }
- }
- }
+ ) -> Result<(), StateChangeError> {
+ let &id = self
+ .zones
+ .active_element()
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let default_data = zone_manager
+ .active_default_data(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let data = zone_manager
+ .active_data_mut(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ Ok(*data = default_data)
}
pub fn change_gap_size(
@@ -452,42 +460,71 @@ impl Workspace {
change: Change,
delta: u32,
zone_manager: &mut ZoneManager,
- ) {
- if let Some(&id) = self.zones.active_element() {
- if let Some(data) = zone_manager.active_data_mut(id) {
- data.gap_size = match change {
- Change::Inc => std::cmp::min(data.gap_size + delta, MAX_GAP_SIZE),
- Change::Dec => std::cmp::max(data.gap_size as i32 - delta as i32, 0) as u32,
- };
- }
+ ) -> Result<(), StateChangeError> {
+ let &id = self
+ .zones
+ .active_element()
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let data = zone_manager
+ .active_data_mut(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let new_gap_size = match change {
+ Change::Inc => std::cmp::min(data.gap_size + delta, MAX_GAP_SIZE),
+ Change::Dec => std::cmp::max(data.gap_size as i32 - delta as i32, 0) as u32,
+ };
+
+ if new_gap_size == data.gap_size {
+ return Err(StateChangeError::LimitReached);
}
+
+ Ok(data.gap_size = new_gap_size)
}
pub fn reset_gap_size(
&self,
zone_manager: &mut ZoneManager,
- ) {
- if let Some(&id) = self.zones.active_element() {
- if let Some(default_data) = zone_manager.active_default_data(id) {
- if let Some(data) = zone_manager.active_data_mut(id) {
- data.gap_size = default_data.gap_size;
- }
- }
- }
+ ) -> Result<(), StateChangeError> {
+ let &id = self
+ .zones
+ .active_element()
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let default_data = zone_manager
+ .active_default_data(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let data = zone_manager
+ .active_data_mut(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ Ok(data.gap_size = default_data.gap_size)
}
pub fn change_main_count(
&self,
change: Change,
zone_manager: &mut ZoneManager,
- ) {
- if let Some(&id) = self.zones.active_element() {
- if let Some(data) = zone_manager.active_data_mut(id) {
- data.main_count = match change {
- Change::Inc => std::cmp::min(data.main_count + 1, MAX_MAIN_COUNT),
- Change::Dec => std::cmp::max(data.main_count as i32 - 1, 0) as u32,
- };
- }
+ ) -> Result<(), StateChangeError> {
+ let &id = self
+ .zones
+ .active_element()
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let data = zone_manager
+ .active_data_mut(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let new_main_count = match change {
+ Change::Inc => std::cmp::min(data.main_count + 1, MAX_MAIN_COUNT),
+ Change::Dec => std::cmp::max(data.main_count as i32 - 1, 0) as u32,
+ };
+
+ if data.main_count == new_main_count {
+ Err(StateChangeError::LimitReached)
+ } else {
+ Ok(data.main_count = new_main_count)
}
}
@@ -496,21 +533,28 @@ impl Workspace {
change: Change,
delta: f32,
zone_manager: &mut ZoneManager,
- ) {
- if let Some(&id) = self.zones.active_element() {
- if let Some(data) = zone_manager.active_data_mut(id) {
- match change {
- Change::Inc => data.main_factor += delta,
- Change::Dec => data.main_factor -= delta,
- }
+ ) -> Result<(), StateChangeError> {
+ let &id = self
+ .zones
+ .active_element()
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let data = zone_manager
+ .active_data_mut(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ match change {
+ Change::Inc => data.main_factor += delta,
+ Change::Dec => data.main_factor -= delta,
+ }
- if data.main_factor < 0.05f32 {
- data.main_factor = 0.05f32;
- } else if data.main_factor > 0.95f32 {
- data.main_factor = 0.95f32;
- }
- }
+ if data.main_factor < 0.05f32 {
+ data.main_factor = 0.05f32;
+ } else if data.main_factor > 0.95f32 {
+ data.main_factor = 0.95f32;
}
+
+ Ok(())
}
pub fn change_margin(
@@ -519,40 +563,57 @@ impl Workspace {
change: Change,
delta: u32,
zone_manager: &mut ZoneManager,
- ) {
- if let Some(&id) = self.zones.active_element() {
- if let Some(data) = zone_manager.active_data_mut(id) {
- let delta_change = match change {
- Change::Inc => delta as i32,
- Change::Dec => -(delta as i32),
- };
-
- let (edge_value, edge_max) = match edge {
- Edge::Left => (&mut data.margin.left, MAX_MARGIN.left),
- Edge::Right => (&mut data.margin.right, MAX_MARGIN.right),
- Edge::Top => (&mut data.margin.top, MAX_MARGIN.top),
- Edge::Bottom => (&mut data.margin.bottom, MAX_MARGIN.bottom),
- };
-
- let edge_changed = *edge_value as i32 + delta_change;
- let edge_changed = std::cmp::max(edge_changed, 0);
- let edge_changed = std::cmp::min(edge_changed, edge_max as i32);
- *edge_value = edge_changed as u32;
- }
+ ) -> Result<(), StateChangeError> {
+ let &id = self
+ .zones
+ .active_element()
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let data = zone_manager
+ .active_data_mut(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let delta_change = match change {
+ Change::Inc => delta as i32,
+ Change::Dec => -(delta as i32),
+ };
+
+ let (edge_value, edge_max) = match edge {
+ Edge::Left => (&mut data.margin.left, MAX_MARGIN.left),
+ Edge::Right => (&mut data.margin.right, MAX_MARGIN.right),
+ Edge::Top => (&mut data.margin.top, MAX_MARGIN.top),
+ Edge::Bottom => (&mut data.margin.bottom, MAX_MARGIN.bottom),
+ };
+
+ let edge_changed = *edge_value as i32 + delta_change;
+ let edge_changed = std::cmp::max(edge_changed, 0);
+ let edge_changed = std::cmp::min(edge_changed, edge_max as i32);
+
+ if *edge_value == edge_changed as u32 {
+ Err(StateChangeError::LimitReached)
+ } else {
+ Ok(*edge_value = edge_changed as u32)
}
}
pub fn reset_margin(
&self,
zone_manager: &mut ZoneManager,
- ) {
- if let Some(&id) = self.zones.active_element() {
- if let Some(default_data) = zone_manager.active_default_data(id) {
- if let Some(data) = zone_manager.active_data_mut(id) {
- data.margin = default_data.margin;
- }
- }
- }
+ ) -> Result<(), StateChangeError> {
+ let &id = self
+ .zones
+ .active_element()
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let default_data = zone_manager
+ .active_default_data(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ let data = zone_manager
+ .active_data_mut(id)
+ .ok_or(StateChangeError::EarlyStop)?;
+
+ Ok(data.margin = default_data.margin)
}
pub fn focused_icon(&self) -> Option<Window> {
diff --git a/src/core/zone.rs b/src/core/zone.rs
@@ -36,6 +36,11 @@ pub const MAX_MARGIN: Padding = Padding {
bottom: 400,
};
+const MIN_ZONE_DIM: Dim = Dim {
+ w: 25,
+ h: 25,
+};
+
static INSTANCE_COUNT: atomic::AtomicU32 = atomic::AtomicU32::new(1);
fn next_id() -> ZoneId {
INSTANCE_COUNT.fetch_add(1, atomic::Ordering::Relaxed) as ZoneId
@@ -133,20 +138,6 @@ pub enum LayoutKind {
Vert = b'V',
}
-#[inline]
-fn stack_split(
- n: usize,
- n_main: u32,
-) -> (u32, u32) {
- let n = n as u32;
-
- if n <= n_main {
- (n, 0)
- } else {
- (n_main, n - n_main)
- }
-}
-
impl LayoutKind {
pub fn symbol(&self) -> char {
(*self as u8) as char
@@ -329,6 +320,20 @@ impl LayoutKind {
}
}
+ #[inline]
+ fn stack_split(
+ n: usize,
+ n_main: u32,
+ ) -> (u32, u32) {
+ let n = n as u32;
+
+ if n <= n_main {
+ (n, 0)
+ } else {
+ (n_main, n - n_main)
+ }
+ }
+
fn func(&self) -> LayoutFn {
match *self {
LayoutKind::Float => {
@@ -348,7 +353,7 @@ impl LayoutKind {
return vec![(Disposition::Changed(*region, NO_DECORATION), true)];
}
- let (n_main, n_stack) = stack_split(n, data.main_count);
+ let (n_main, n_stack) = Self::stack_split(n, data.main_count);
let h_stack = if n_stack > 0 { dim.h / n_stack } else { 0 };
let h_main = if n_main > 0 { dim.h / n_main } else { 0 };
@@ -559,6 +564,7 @@ pub struct Layout {
}
impl Layout {
+ #[inline]
pub fn new() -> Self {
let kind = LayoutKind::Stack;
let mut data = HashMap::with_capacity(LayoutKind::COUNT);
@@ -574,6 +580,7 @@ impl Layout {
}
}
+ #[inline]
pub fn with_kind(kind: LayoutKind) -> Self {
let mut data = HashMap::with_capacity(LayoutKind::COUNT);
@@ -588,22 +595,27 @@ impl Layout {
}
}
+ #[inline]
fn get_config(&self) -> LayoutConfig {
self.kind.config()
}
+ #[inline]
fn get_data(&self) -> &LayoutData {
self.data.get(&self.kind).unwrap()
}
+ #[inline]
fn get_data_mut(&mut self) -> &mut LayoutData {
self.data.get_mut(&self.kind).unwrap()
}
+ #[inline]
fn get_default_data(&self) -> LayoutData {
self.kind.default_data()
}
+ #[inline]
fn set_kind(
&mut self,
kind: LayoutKind,
@@ -612,6 +624,7 @@ impl Layout {
self.kind = kind;
}
+ #[inline]
fn adjust_for_margin(
region: Region,
extents: &Extents,
@@ -628,14 +641,31 @@ impl Layout {
}
}
+ #[inline]
fn adjust_for_gap_size(
region: &mut Region,
gap_size: u32,
+ min_dim: &Dim,
) {
- region.pos.x += gap_size as i32;
- region.pos.y += gap_size as i32;
- region.dim.w -= 2 * gap_size;
- region.dim.h -= 2 * gap_size;
+ let dim_gap = 2 * gap_size as i32;
+
+ let new_w = region.dim.w as i32 - dim_gap;
+ if new_w < min_dim.w as i32 {
+ region.pos.x += ((region.dim.w as i32 - min_dim.w as i32) as f32 / 2f32) as i32;
+ region.dim.w = min_dim.w;
+ } else {
+ region.dim.w = new_w as u32;
+ region.pos.x += gap_size as i32;
+ }
+
+ let new_h = region.dim.h as i32 - dim_gap;
+ if new_h < min_dim.h as i32 {
+ region.pos.y += ((region.dim.h as i32 - min_dim.h as i32) as f32 / 2f32) as i32;
+ region.dim.h = min_dim.h;
+ } else {
+ region.dim.h = new_h as u32;
+ region.pos.y += gap_size as i32;
+ }
}
}
@@ -653,24 +683,24 @@ impl Apply for Layout {
region: Region,
active_map: Vec<bool>,
) -> (PlacementMethod, Vec<(Disposition, bool)>) {
- let method = self.kind.config().method;
+ let config = self.kind.config();
let data = self.get_data();
- let region = if method == PlacementMethod::Free {
- region
- } else {
+ let region = if config.gap {
Self::adjust_for_margin(region, &data.margin)
+ } else {
+ region
};
(
- method,
+ config.method,
(self.kind.func())(®ion, &data, active_map)
.into_iter()
.map(|(mut disposition, is_visible)| {
match disposition {
Disposition::Unchanged => {},
Disposition::Changed(ref mut region, _) => {
- Self::adjust_for_gap_size(region, data.gap_size);
+ Self::adjust_for_gap_size(region, data.gap_size, &MIN_ZONE_DIM);
},
}