commit fb0dff8589d4206fcddf029ecbf8a9f8c76a7106
parent bb8f9a10811797b750b6e384a933dab052e31d7c
Author: deurzen <m.deurzen@tum.de>
Date: Sun, 28 Mar 2021 07:49:54 +0200
adds workspace and fullscreen rule parsing
Diffstat:
17 files changed, 2255 insertions(+), 2045 deletions(-)
diff --git a/src/core/binding.rs b/src/core/binding.rs
@@ -7,8 +7,8 @@ use winsys::window::Window;
use std::collections::HashMap;
-pub type Action = Box<dyn FnMut(&mut Model)>;
-pub type MouseEvents = Box<dyn FnMut(&mut Model, Option<Window>)>;
-pub type KeyEvents = Box<dyn FnMut(&mut Model)>;
+pub type Action = Box<dyn FnMut(&mut Model<'_>)>;
+pub type MouseEvents = Box<dyn FnMut(&mut Model<'_>, Option<Window>)>;
+pub type KeyEvents = Box<dyn FnMut(&mut Model<'_>)>;
pub type KeyBindings = HashMap<KeyCode, KeyEvents>;
pub type MouseBindings = HashMap<(MouseEventKey, MouseShortcut), (MouseEvents, bool)>;
diff --git a/src/core/change.rs b/src/core/change.rs
@@ -7,6 +7,37 @@ use std::ops::Mul;
use std::ops::Sub;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Toggle {
+ On,
+ Off,
+ Reverse,
+}
+
+impl From<bool> for Toggle {
+ #[inline(always)]
+ fn from(toggle: bool) -> Self {
+ match toggle {
+ true => Toggle::On,
+ false => Toggle::Off,
+ }
+ }
+}
+
+impl Toggle {
+ #[inline(always)]
+ pub fn eval(
+ self,
+ current: bool,
+ ) -> bool {
+ match self {
+ Toggle::On => true,
+ Toggle::Off => false,
+ Toggle::Reverse => !current,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Direction {
Forward,
Backward,
diff --git a/src/core/client.rs b/src/core/client.rs
@@ -1,4 +1,6 @@
+use crate::change::Toggle;
use crate::compare::MatchMethod;
+use crate::decoration::Color;
use crate::decoration::Decoration;
use crate::identify::Ident;
use crate::identify::Identify;
@@ -17,6 +19,33 @@ use std::cell::Cell;
use std::cell::RefCell;
use std::time::SystemTime;
+#[derive(Clone, Copy, Debug)]
+pub enum OutsideState {
+ Focused,
+ FocusedDisowned,
+ FocusedSticky,
+ Unfocused,
+ UnfocusedDisowned,
+ UnfocusedSticky,
+ Urgent,
+}
+
+impl std::ops::Not for OutsideState {
+ type Output = Self;
+
+ fn not(self) -> Self::Output {
+ match self {
+ Self::Focused => Self::Unfocused,
+ Self::FocusedDisowned => Self::UnfocusedDisowned,
+ Self::FocusedSticky => Self::UnfocusedSticky,
+ Self::Unfocused => Self::Focused,
+ Self::UnfocusedDisowned => Self::FocusedDisowned,
+ Self::UnfocusedSticky => Self::FocusedSticky,
+ other => other,
+ }
+ }
+}
+
pub struct Client {
zone: ZoneId,
window: Window,
@@ -43,16 +72,17 @@ pub struct Client {
focused: Cell<bool>,
mapped: Cell<bool>,
managed: Cell<bool>,
- in_window: Cell<bool>,
+ urgent: Cell<bool>,
floating: Cell<bool>,
fullscreen: Cell<bool>,
+ contained: Cell<bool>,
+ invincible: Cell<bool>,
+ sticky: Cell<bool>,
iconified: Cell<bool>,
disowned: Cell<bool>,
- sticky: Cell<bool>,
- invincible: Cell<bool>,
- urgent: Cell<bool>,
consuming: Cell<bool>,
producing: Cell<bool>,
+ outside_state: Cell<OutsideState>,
pid: Option<Pid>,
ppid: Option<Pid>,
last_focused: Cell<SystemTime>,
@@ -60,9 +90,17 @@ pub struct Client {
expected_unmap_count: Cell<u8>,
}
+impl Identify for Window {
+ #[inline(always)]
+ fn id(&self) -> Ident {
+ *self
+ }
+}
+
impl Identify for Client {
+ #[inline(always)]
fn id(&self) -> Ident {
- self.window as Ident
+ self.window
}
}
@@ -104,16 +142,17 @@ impl Client {
focused: Cell::new(false),
mapped: Cell::new(false),
managed: Cell::new(true),
- in_window: Cell::new(false),
+ urgent: Cell::new(false),
floating: Cell::new(false),
fullscreen: Cell::new(false),
+ contained: Cell::new(false),
+ invincible: Cell::new(false),
iconified: Cell::new(false),
- disowned: Cell::new(false),
sticky: Cell::new(false),
- invincible: Cell::new(false),
- urgent: Cell::new(false),
+ disowned: Cell::new(false),
consuming: Cell::new(false),
producing: Cell::new(true),
+ outside_state: Cell::new(OutsideState::Unfocused),
pid,
ppid,
last_focused: Cell::new(SystemTime::now()),
@@ -219,7 +258,7 @@ impl Client {
&self,
context: usize,
) {
- self.context.replace(context);
+ self.context.set(context);
}
#[inline]
@@ -232,7 +271,7 @@ impl Client {
&self,
workspace: usize,
) {
- self.workspace.replace(workspace);
+ self.workspace.set(workspace);
}
#[inline]
@@ -251,8 +290,8 @@ impl Client {
active_region: Region,
) {
self.set_inner_region(active_region);
- let active_region = self.active_region.replace(active_region);
- self.previous_region.replace(active_region);
+ self.previous_region
+ .set(self.active_region.replace(active_region));
}
#[inline]
@@ -271,7 +310,7 @@ impl Client {
active_region: Region,
) {
self.inner_region
- .replace(if let Some(frame) = self.decoration.get().frame {
+ .set(if let Some(frame) = self.decoration.get().frame {
let mut inner_region = active_region - frame.extents;
inner_region.pos.x = frame.extents.left;
@@ -298,11 +337,11 @@ impl Client {
) {
match region {
PlacementClass::Free(region) => {
- self.free_region.replace(region);
+ self.free_region.set(region);
self.set_active_region(region);
},
PlacementClass::Tile(region) => {
- self.tile_region.replace(region);
+ self.tile_region.set(region);
self.set_active_region(region);
},
}
@@ -328,7 +367,7 @@ impl Client {
&self,
decoration: Decoration,
) {
- self.decoration.replace(decoration);
+ self.decoration.set(decoration);
}
#[inline]
@@ -336,6 +375,57 @@ impl Client {
self.decoration.get().to_owned()
}
+ #[inline(always)]
+ pub fn decoration_colors(&self) -> (Option<(u32, Color)>, Option<Color>) {
+ let outside_state = self.outside_state();
+ let decoration = self.decoration.get();
+
+ match outside_state {
+ OutsideState::Focused => (
+ decoration
+ .border
+ .map(|border| (border.width, border.colors.focused)),
+ decoration.frame.map(|frame| frame.colors.focused),
+ ),
+ OutsideState::FocusedDisowned => (
+ decoration
+ .border
+ .map(|border| (border.width, border.colors.fdisowned)),
+ decoration.frame.map(|frame| frame.colors.fdisowned),
+ ),
+ OutsideState::FocusedSticky => (
+ decoration
+ .border
+ .map(|border| (border.width, border.colors.fsticky)),
+ decoration.frame.map(|frame| frame.colors.fsticky),
+ ),
+ OutsideState::Unfocused => (
+ decoration
+ .border
+ .map(|border| (border.width, border.colors.unfocused)),
+ decoration.frame.map(|frame| frame.colors.unfocused),
+ ),
+ OutsideState::UnfocusedDisowned => (
+ decoration
+ .border
+ .map(|border| (border.width, border.colors.udisowned)),
+ decoration.frame.map(|frame| frame.colors.udisowned),
+ ),
+ OutsideState::UnfocusedSticky => (
+ decoration
+ .border
+ .map(|border| (border.width, border.colors.usticky)),
+ decoration.frame.map(|frame| frame.colors.usticky),
+ ),
+ OutsideState::Urgent => (
+ decoration
+ .border
+ .map(|border| (border.width, border.colors.urgent)),
+ decoration.frame.map(|frame| frame.colors.urgent),
+ ),
+ }
+ }
+
#[inline]
pub fn frame_extents(&self) -> Extents {
Extents {
@@ -364,12 +454,12 @@ impl Client {
&self,
pointer_pos: Pos,
) {
- self.warp_pos.replace(Some(pointer_pos));
+ self.warp_pos.set(Some(pointer_pos));
}
#[inline]
pub fn unset_warp_pos(&self) {
- self.warp_pos.replace(None);
+ self.warp_pos.set(None);
}
#[inline]
@@ -465,16 +555,19 @@ impl Client {
}
#[inline]
- pub fn is_free(&self) -> bool {
- self.floating.get() || self.disowned.get() || !self.managed.get()
+ pub fn is_consuming(&self) -> bool {
+ self.producer.get().is_some()
}
#[inline]
pub fn set_focused(
&self,
- focused: bool,
+ toggle: Toggle,
) {
- self.focused.set(focused);
+ if Toggle::from(self.focused.get()) != toggle {
+ self.focused.set(toggle.eval(self.focused.get()));
+ self.outside_state.set(!self.outside_state.get());
+ }
}
#[inline]
@@ -485,9 +578,9 @@ impl Client {
#[inline]
pub fn set_mapped(
&self,
- mapped: bool,
+ toggle: Toggle,
) {
- self.mapped.set(mapped);
+ self.mapped.set(toggle.eval(self.mapped.get()));
}
#[inline]
@@ -498,9 +591,9 @@ impl Client {
#[inline]
pub fn set_managed(
&self,
- managed: bool,
+ toggle: Toggle,
) {
- self.managed.set(managed);
+ self.managed.set(toggle.eval(self.managed.get()));
}
#[inline]
@@ -509,24 +602,36 @@ impl Client {
}
#[inline]
- pub fn set_in_window(
+ pub fn set_urgent(
&self,
- in_window: bool,
+ toggle: Toggle,
) {
- self.in_window.set(in_window);
+ let urgent = toggle.eval(self.urgent.get());
+ self.urgent.set(urgent);
+
+ if urgent {
+ self.outside_state.set(OutsideState::Urgent);
+ }
}
#[inline]
- pub fn is_in_window(&self) -> bool {
- self.in_window.get()
+ pub fn is_urgent(&self) -> bool {
+ self.urgent.get()
+ }
+
+ #[inline]
+ pub fn is_free(&self) -> bool {
+ self.floating.get() && (!self.fullscreen.get() || self.contained.get())
+ || self.disowned.get()
+ || !self.managed.get()
}
#[inline]
pub fn set_floating(
&self,
- floating: bool,
+ toggle: Toggle,
) {
- self.floating.replace(floating);
+ self.floating.set(toggle.eval(self.floating.get()));
}
#[inline]
@@ -537,9 +642,9 @@ impl Client {
#[inline]
pub fn set_fullscreen(
&self,
- fullscreen: bool,
+ toggle: Toggle,
) {
- self.fullscreen.replace(fullscreen);
+ self.fullscreen.set(toggle.eval(self.fullscreen.get()));
}
#[inline]
@@ -548,94 +653,108 @@ impl Client {
}
#[inline]
- pub fn set_iconified(
+ pub fn set_contained(
&self,
- iconified: bool,
+ toggle: Toggle,
) {
- self.iconified.replace(iconified);
+ self.contained.set(toggle.eval(self.contained.get()));
}
#[inline]
- pub fn is_iconified(&self) -> bool {
- self.iconified.get()
+ pub fn is_contained(&self) -> bool {
+ self.contained.get()
}
#[inline]
- pub fn set_disowned(
+ pub fn set_invincible(
&self,
- disowned: bool,
+ toggle: Toggle,
) {
- self.disowned.replace(disowned);
+ self.invincible.set(toggle.eval(self.invincible.get()));
}
#[inline]
- pub fn is_disowned(&self) -> bool {
- self.disowned.get()
+ pub fn is_invincible(&self) -> bool {
+ self.invincible.get()
}
#[inline]
- pub fn set_sticky(
+ pub fn set_producing(
&self,
- sticky: bool,
+ toggle: Toggle,
) {
- self.sticky.replace(sticky);
+ self.producing.set(toggle.eval(self.producing.get()));
}
#[inline]
- pub fn is_sticky(&self) -> bool {
- self.sticky.get()
+ pub fn is_producing(&self) -> bool {
+ self.producing.get()
}
#[inline]
- pub fn set_invincible(
+ pub fn set_iconified(
&self,
- invincible: bool,
+ toggle: Toggle,
) {
- self.invincible.replace(invincible);
+ self.iconified.set(toggle.eval(self.iconified.get()));
}
#[inline]
- pub fn is_invincible(&self) -> bool {
- self.invincible.get()
+ pub fn is_iconified(&self) -> bool {
+ self.iconified.get()
}
#[inline]
- pub fn set_urgent(
+ pub fn set_sticky(
&self,
- urgent: bool,
+ toggle: Toggle,
) {
- self.urgent.replace(urgent);
+ let sticky = toggle.eval(self.sticky.get());
+ self.sticky.set(sticky);
+
+ self.outside_state.set(match self.outside_state.get() {
+ OutsideState::Focused if sticky => OutsideState::FocusedSticky,
+ OutsideState::Unfocused if sticky => OutsideState::UnfocusedSticky,
+ OutsideState::FocusedSticky if !sticky => OutsideState::Focused,
+ OutsideState::UnfocusedSticky if !sticky => OutsideState::Unfocused,
+ _ => return,
+ });
}
#[inline]
- pub fn is_urgent(&self) -> bool {
- self.urgent.get()
+ pub fn is_sticky(&self) -> bool {
+ self.sticky.get()
}
#[inline]
- pub fn set_consuming(
+ pub fn set_disowned(
&self,
- consuming: bool,
+ toggle: Toggle,
) {
- self.consuming.replace(consuming);
- }
+ let disowned = toggle.eval(self.disowned.get());
+ self.disowned.set(disowned);
- #[inline]
- pub fn is_consuming(&self) -> bool {
- self.consuming.get()
+ self.outside_state.set(match self.outside_state.get() {
+ OutsideState::Focused if disowned => OutsideState::FocusedDisowned,
+ OutsideState::Unfocused if disowned => OutsideState::UnfocusedDisowned,
+ OutsideState::FocusedDisowned if !disowned => OutsideState::Focused,
+ OutsideState::UnfocusedDisowned if !disowned => OutsideState::Unfocused,
+ _ => return,
+ });
}
#[inline]
- pub fn set_producing(
- &self,
- producing: bool,
- ) {
- self.producing.replace(producing);
+ pub fn is_disowned(&self) -> bool {
+ self.disowned.get()
}
#[inline]
- pub fn is_producing(&self) -> bool {
- self.producing.get()
+ pub fn outside_state(&self) -> OutsideState {
+ if self.urgent.get() {
+ OutsideState::Urgent
+ } else {
+ self.outside_state.get()
+ }
}
#[inline]
@@ -661,7 +780,7 @@ impl Client {
#[inline]
pub fn expect_unmap(&self) {
self.expected_unmap_count
- .replace(self.expected_unmap_count.get() + 1);
+ .set(self.expected_unmap_count.get() + 1);
}
#[inline]
@@ -670,7 +789,7 @@ impl Client {
let expecting = expected_unmap_count > 0;
if expecting {
- self.expected_unmap_count.replace(expected_unmap_count - 1);
+ self.expected_unmap_count.set(expected_unmap_count - 1);
}
expecting
@@ -724,7 +843,7 @@ impl std::fmt::Debug for Client {
.field("decoration", &self.decoration)
.field("size_hints", &self.size_hints)
.field("warp_pos", &self.warp_pos)
- .field("parent", &self.parent.map(|parent| Hex32(parent)))
+ .field("parent", &self.parent.map(Hex32))
.field(
"children",
&self
@@ -740,7 +859,7 @@ impl std::fmt::Debug for Client {
.field("focused", &self.focused)
.field("mapped", &self.mapped)
.field("managed", &self.managed)
- .field("in_window", &self.in_window)
+ .field("contained", &self.contained)
.field("floating", &self.floating)
.field("fullscreen", &self.fullscreen)
.field("iconified", &self.iconified)
diff --git a/src/core/cycle.rs b/src/core/cycle.rs
@@ -192,7 +192,7 @@ where
pub fn index_for(
&self,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) -> Option<Index> {
match sel {
Selector::AtActive => Some(self.index.get()),
@@ -238,7 +238,7 @@ where
self.indices.clear();
for (i, id) in self.elements.iter().enumerate().map(|(i, e)| (i, e.id())) {
- self.indices.insert(id as Ident, i as Index);
+ self.indices.insert(id, i);
}
}
}
@@ -340,12 +340,12 @@ where
}
#[inline]
- pub fn iter(&self) -> std::collections::vec_deque::Iter<T> {
+ pub fn iter(&self) -> std::collections::vec_deque::Iter<'_, T> {
self.elements.iter()
}
#[inline]
- pub fn iter_mut(&mut self) -> std::collections::vec_deque::IterMut<T> {
+ pub fn iter_mut(&mut self) -> std::collections::vec_deque::IterMut<'_, T> {
self.elements.iter_mut()
}
@@ -367,7 +367,7 @@ where
pub fn get_for(
&self,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) -> Option<&T> {
match sel {
Selector::AtActive => self.active_element(),
@@ -387,7 +387,7 @@ where
pub fn get_for_mut(
&mut self,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) -> Option<&mut T> {
match sel {
Selector::AtActive => self.active_element_mut(),
@@ -409,7 +409,7 @@ where
pub fn get_all_for(
&self,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) -> Vec<&T> {
match sel {
Selector::AtActive => self.active_element().into_iter().collect(),
@@ -433,7 +433,7 @@ where
pub fn get_all_for_mut(
&mut self,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) -> Vec<&mut T> {
match sel {
Selector::AtActive => self.active_element_mut().into_iter().collect(),
@@ -494,7 +494,7 @@ where
pub fn on_all_for<F: Fn(&T)>(
&self,
f: F,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) {
for element in self.get_all_for(sel) {
f(element);
@@ -504,7 +504,7 @@ where
pub fn on_all_for_mut<F: FnMut(&mut T)>(
&mut self,
mut f: F,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) {
for element in self.get_all_for_mut(sel) {
f(element);
@@ -513,7 +513,7 @@ where
pub fn activate_for(
&self,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) -> Option<&T> {
match sel {
Selector::AtActive => self.active_element(),
@@ -553,7 +553,7 @@ where
pub fn remove_for(
&mut self,
- sel: &Selector<T>,
+ sel: &Selector<'_, T>,
) -> Option<T> {
let (index, element) = match sel {
Selector::AtActive => (self.index.get(), self.elements.remove(self.index.get())),
@@ -585,8 +585,8 @@ where
pub fn swap(
&mut self,
- sel1: &Selector<T>,
- sel2: &Selector<T>,
+ sel1: &Selector<'_, T>,
+ sel2: &Selector<'_, T>,
) {
let index1 = self.index_for(sel1);
@@ -790,8 +790,8 @@ where
impl<T: PartialEq + Identify + std::fmt::Debug> Cycle<T> {
pub fn equivalent_selectors(
&self,
- sel1: &Selector<T>,
- sel2: &Selector<T>,
+ sel1: &Selector<'_, T>,
+ sel2: &Selector<'_, T>,
) -> bool {
match (self.index_for(&sel1), self.index_for(&sel2)) {
(Some(e), Some(f)) => e == f,
diff --git a/src/core/decoration.rs b/src/core/decoration.rs
@@ -7,24 +7,24 @@ pub type Color = u32;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ColorScheme {
- pub regular: Color,
pub focused: Color,
- pub urgent: Color,
- pub rdisowned: Color,
pub fdisowned: Color,
- pub rsticky: Color,
pub fsticky: Color,
+ pub unfocused: Color,
+ pub udisowned: Color,
+ pub usticky: Color,
+ pub urgent: Color,
}
impl ColorScheme {
pub const DEFAULT: Self = Self {
- regular: 0x333333,
focused: 0xe78a53,
- urgent: 0xfbcb97,
- rdisowned: 0x999999,
fdisowned: 0xc1c1c1,
- rsticky: 0x444444,
fsticky: 0x5f8787,
+ unfocused: 0x333333,
+ udisowned: 0x999999,
+ usticky: 0x444444,
+ urgent: 0xfbcb97,
};
}
diff --git a/src/core/identify.rs b/src/core/identify.rs
@@ -1,14 +1,6 @@
-use winsys::window::Window;
-
pub type Ident = u32;
pub type Index = usize;
pub trait Identify: PartialEq {
fn id(&self) -> Ident;
}
-
-impl Identify for Window {
- fn id(&self) -> Ident {
- *self as Ident
- }
-}
diff --git a/src/core/layout.rs b/src/core/layout.rs
@@ -805,8 +805,8 @@ impl Layout {
) -> Region {
Region {
pos: Pos {
- x: region.pos.x + extents.left as i32,
- y: region.pos.y + extents.top as i32,
+ x: region.pos.x + extents.left,
+ y: region.pos.y + extents.top,
},
dim: Dim {
w: region.dim.w - extents.left - extents.right,
@@ -926,7 +926,7 @@ impl Apply for Layout {
}
}
-impl std::cmp::PartialEq<Self> for Layout {
+impl PartialEq<Self> for Layout {
fn eq(
&self,
other: &Self,
@@ -936,6 +936,7 @@ impl std::cmp::PartialEq<Self> for Layout {
}
impl Identify for Layout {
+ #[inline(always)]
fn id(&self) -> Ident {
self.kind as Ident
}
diff --git a/src/core/macros.rs b/src/core/macros.rs
@@ -1,13 +1,20 @@
#[macro_export]
+macro_rules! call(
+ ($($method:tt)+) => {
+ |arg| $($method)+(arg)
+ };
+);
+
+#[macro_export]
macro_rules! do_internal(
($func:ident) => {
- Box::new(|model: &mut $crate::model::Model| {
+ Box::new(|model: &mut $crate::model::Model<'_>| {
drop(model.$func());
}) as $crate::binding::KeyEvents
};
($func:ident, $($arg:expr),+) => {
- Box::new(move |model: &mut $crate::model::Model| {
+ Box::new(move |model: &mut $crate::model::Model<'_>| {
drop(model.$func($($arg),+));
}) as $crate::binding::KeyEvents
};
@@ -16,7 +23,7 @@ macro_rules! do_internal(
#[macro_export]
macro_rules! do_internal_block(
($model:ident, $body:block) => {
- Box::new(|$model: &mut $crate::model::Model| {
+ Box::new(|$model: &mut $crate::model::Model<'_>| {
$body
}) as $crate::binding::KeyEvents
};
@@ -25,20 +32,20 @@ macro_rules! do_internal_block(
#[macro_export]
macro_rules! do_nothing(
() => {
- Box::new(|_: &mut $crate::model::Model, _| {}) as $crate::binding::MouseEvents
+ Box::new(|_: &mut $crate::model::Model<'_>, _| {}) as $crate::binding::MouseEvents
};
);
#[macro_export]
macro_rules! do_internal_mouse(
($func:ident) => {
- Box::new(|model: &mut $crate::model::Model, _| {
+ Box::new(|model: &mut $crate::model::Model<'_>, _| {
drop(model.$func());
}) as $crate::binding::MouseEvents
};
($func:ident, $($arg:expr),+) => {
- Box::new(|model: &mut $crate::model::Model, _| {
+ Box::new(|model: &mut $crate::model::Model<'_>, _| {
drop(model.$func($($arg),+));
}) as $crate::binding::MouseEvents
};
@@ -47,7 +54,7 @@ macro_rules! do_internal_mouse(
#[macro_export]
macro_rules! do_internal_mouse_block(
($model:ident, $window:ident, $body:block) => {
- Box::new(|$model: &mut $crate::model::Model, $window: Option<winsys::window::Window>| {
+ Box::new(|$model: &mut $crate::model::Model<'_>, $window: Option<winsys::window::Window>| {
$body
}) as $crate::binding::MouseEvents
};
@@ -57,7 +64,7 @@ macro_rules! do_internal_mouse_block(
macro_rules! spawn_external(
($cmd:expr) => {
{
- Box::new(move |_: &mut $crate::model::Model| {
+ Box::new(move |_: &mut $crate::model::Model<'_>| {
$crate::util::Util::spawn($cmd);
}) as $crate::binding::KeyEvents
}
@@ -68,7 +75,7 @@ macro_rules! spawn_external(
macro_rules! spawn_from_shell(
($cmd:expr) => {
{
- Box::new(move |_: &mut $crate::model::Model| {
+ Box::new(move |_: &mut $crate::model::Model<'_>| {
$crate::util::Util::spawn_shell($cmd);
}) as $crate::binding::KeyEvents
}
diff --git a/src/core/main.rs b/src/core/main.rs
@@ -1,4 +1,14 @@
-#![deny(clippy::all)]
+#![warn(clippy::all)]
+#![warn(missing_copy_implementations)]
+#![warn(missing_debug_implementations)]
+#![warn(missing_debug_implementations)]
+#![warn(rust_2018_idioms)]
+#![warn(trivial_numeric_casts)]
+#![warn(trivial_numeric_casts)]
+#![warn(unsafe_code)]
+#![warn(unused_extern_crates)]
+#![warn(unused_import_braces)]
+#![warn(unused_qualifications)]
#![allow(dead_code)]
#![recursion_limit = "256"]
@@ -44,6 +54,7 @@ use binding::KeyBindings;
use binding::MouseBindings;
use change::Change;
use change::Direction;
+use change::Toggle;
use compare::MatchMethod;
use jump::JumpCriterium;
use layout::LayoutKind;
@@ -74,13 +85,13 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
(Press, Client, true):
"1-C-Right" => do_internal_mouse_block!(model, window, {
if let Some(window) = window {
- model.toggle_float_client(window);
+ model.set_floating_window(window, Toggle::Reverse);
}
}),
(Press, Client, true):
"1-C-S-Middle" => do_internal_mouse_block!(model, window, {
if let Some(window) = window {
- model.toggle_fullscreen_client(window);
+ model.set_fullscreen_window(window, Toggle::Reverse);
}
}),
@@ -88,7 +99,7 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
(Press, Client, true):
"1-Middle" => do_internal_mouse_block!(model, window, {
if let Some(window) = window {
- model.center_client(window);
+ model.center_window(window);
}
}),
(Press, Client, true):
@@ -106,13 +117,13 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
(Press, Client, false):
"1-C-S-ScrollDown" => do_internal_mouse_block!(model, window, {
if let Some(window) = window {
- model.grow_ratio_client(window, -15);
+ model.grow_ratio_window(window, -15);
}
}),
(Press, Client, false):
"1-C-S-ScrollUp" => do_internal_mouse_block!(model, window, {
if let Some(window) = window {
- model.grow_ratio_client(window, 15);
+ model.grow_ratio_window(window, 15);
}
}),
@@ -124,21 +135,21 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
// workspace activators
(Press, Global, false):
- "1-S-ScrollDown" => do_internal_mouse!(activate_next_workspace),
+ "1-S-ScrollUp" => do_internal_mouse!(activate_next_workspace, Direction::Backward),
(Press, Global, false):
- "1-S-ScrollUp" => do_internal_mouse!(activate_prev_workspace),
+ "1-S-ScrollDown" => do_internal_mouse!(activate_next_workspace, Direction::Forward),
// workspace client movement
(Press, Client, false):
"1-Forward" => do_internal_mouse_block!(model, window, {
if let Some(window) = window {
- model.move_client_to_next_workspace(window);
+ model.move_window_to_next_workspace(window, Direction::Forward);
}
}),
(Press, Client, false):
"1-Backward" => do_internal_mouse_block!(model, window, {
if let Some(window) = window {
- model.move_client_to_prev_workspace(window);
+ model.move_window_to_next_workspace(window, Direction::Backward);
}
}),
@@ -155,17 +166,16 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
// client state modifiers
"1-c" => do_internal!(kill_focus),
- "1-S-space" => do_internal!(toggle_float_focus),
- "1-f" => do_internal!(toggle_fullscreen_focus),
- "1-x" => do_internal!(toggle_stick_focus),
- "1-2-C-f" => do_internal!(toggle_in_window_focus),
- "1-2-C-i" => do_internal!(toggle_invincible_focus),
- "1-2-C-p" => do_internal!(toggle_producing_focus),
- "1-y" => do_internal!(iconify_focus),
+ "1-S-space" => do_internal!(set_floating_focus, Toggle::Reverse),
+ "1-f" => do_internal!(set_fullscreen_focus, Toggle::Reverse),
+ "1-x" => do_internal!(set_stick_focus, Toggle::Reverse),
+ "1-2-C-f" => do_internal!(set_contained_focus, Toggle::Reverse),
+ "1-2-C-i" => do_internal!(set_invincible_focus, Toggle::Reverse),
+ "1-2-C-p" => do_internal!(set_producing_focus, Toggle::Reverse),
+ "1-y" => do_internal!(set_iconify_focus, Toggle::On),
"1-u" => do_internal!(pop_deiconify),
"1-2-u" => do_internal_block!(model, {
- let workspace_index = model.active_workspace();
- model.deiconify_all(workspace_index);
+ model.deiconify_all(model.active_workspace());
}),
// free client arrangers
@@ -201,8 +211,8 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
"1-C-C" => do_internal!(delete_zone),
// zone order modifiers
- "1-C-j" => do_internal!(cycle_zones, Direction::Forward),
- "1-C-k" => do_internal!(cycle_zones, Direction::Backward),
+ // "1-C-j" => do_internal!(cycle_zones, Direction::Forward),
+ // "1-C-k" => do_internal!(cycle_zones, Direction::Backward),
// active workspace layout setters
"1-S-f" => do_internal!(set_layout, LayoutKind::Float),
@@ -246,8 +256,8 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
// workspace activators
"1-Escape" => do_internal!(toggle_workspace),
- "1-bracketleft" => do_internal!(activate_prev_workspace),
- "1-bracketright" => do_internal!(activate_next_workspace),
+ "1-bracketleft" => do_internal!(activate_next_workspace, Direction::Backward),
+ "1-bracketright" => do_internal!(activate_next_workspace, Direction::Forward),
"1-1" => do_internal!(activate_workspace, 0),
"1-2" => do_internal!(activate_workspace, 1),
"1-3" => do_internal!(activate_workspace, 2),
@@ -260,8 +270,8 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
"1-0" => do_internal!(activate_workspace, 9),
// workspace client movement
- "1-S-bracketleft" => do_internal!(move_focus_to_prev_workspace),
- "1-S-bracketright" => do_internal!(move_focus_to_next_workspace),
+ "1-S-bracketleft" => do_internal!(move_focus_to_next_workspace, Direction::Backward),
+ "1-S-bracketright" => do_internal!(move_focus_to_next_workspace, Direction::Forward),
"1-S-1" => do_internal!(move_focus_to_workspace, 0),
"1-S-2" => do_internal!(move_focus_to_workspace, 1),
"1-S-3" => do_internal!(move_focus_to_workspace, 2),
@@ -278,51 +288,45 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
// client jump criteria
"1-b" => do_internal!(jump_client,
- &JumpCriterium::ByClass(MatchMethod::Equals("qutebrowser"))
+ JumpCriterium::ByClass(MatchMethod::Equals("qutebrowser"))
),
"1-S-b" => do_internal!(jump_client,
- &JumpCriterium::ByClass(MatchMethod::Equals("Firefox"))
+ JumpCriterium::ByClass(MatchMethod::Equals("Firefox"))
),
"1-C-b" => do_internal!(jump_client,
- &JumpCriterium::ByClass(MatchMethod::Equals("Chromium"))
+ JumpCriterium::ByClass(MatchMethod::Equals("Chromium"))
),
"1-2-space" => do_internal!(jump_client,
- &JumpCriterium::ByClass(MatchMethod::Equals("Spotify"))
+ JumpCriterium::ByClass(MatchMethod::Equals("Spotify"))
),
"1-e" => do_internal_block!(model, {
- model.jump_client(&JumpCriterium::ByName(
+ model.jump_client(JumpCriterium::ByName(
MatchMethod::Contains("[vim]"),
));
}),
"1-slash" => do_internal_block!(model, {
- let workspace_index = model.active_workspace();
-
- model.jump_client(&JumpCriterium::OnWorkspaceBySelector(
- workspace_index,
+ model.jump_client(JumpCriterium::OnWorkspaceBySelector(
+ model.active_workspace(),
&ClientSelector::Last,
));
}),
"1-period" => do_internal_block!(model, {
- let workspace_index = model.active_workspace();
-
- model.jump_client(&JumpCriterium::OnWorkspaceBySelector(
- workspace_index,
+ model.jump_client(JumpCriterium::OnWorkspaceBySelector(
+ model.active_workspace(),
&ClientSelector::AtMaster,
));
}),
"1-comma" => do_internal_block!(model, {
- let workspace_index = model.active_workspace();
-
- model.jump_client(&JumpCriterium::OnWorkspaceBySelector(
- workspace_index,
+ model.jump_client(JumpCriterium::OnWorkspaceBySelector(
+ model.active_workspace(),
&ClientSelector::First,
));
}),
// external spawn commands
- "XF86AudioPlay", "1-2-C-p" => spawn_external!("playerctl play-pause"),
- "XF86AudioPrev", "1-2-C-k" => spawn_external!("playerctl previous"),
- "XF86AudioNext", "1-2-C-j" => spawn_external!("playerctl next"),
+ "XF86AudioPlay", "1-2-p" => spawn_external!("playerctl play-pause"),
+ "XF86AudioPrev", "1-2-k" => spawn_external!("playerctl previous"),
+ "XF86AudioNext", "1-2-j" => spawn_external!("playerctl next"),
"1-2-BackSpace" => spawn_external!("playerctl stop"),
"XF86AudioMute" => spawn_external!("amixer -D pulse sset Master toggle"),
"XF86AudioLowerVolume" => spawn_external!("amixer -D pulse sset Master 5%-"),
diff --git a/src/core/model.rs b/src/core/model.rs
@@ -5,6 +5,7 @@ use crate::binding::KeyBindings;
use crate::binding::MouseBindings;
use crate::change::Change;
use crate::change::Direction;
+use crate::change::Toggle;
use crate::client::Client;
use crate::consume::get_spawner_pid;
use crate::cycle::Cycle;
@@ -52,6 +53,7 @@ use winsys::input::KeyCode;
use winsys::input::MouseEvent;
use winsys::input::MouseEventKey;
use winsys::input::MouseEventKind;
+use winsys::input::MouseShortcut;
use winsys::screen::Screen;
use winsys::window::IcccmWindowState;
use winsys::window::Window;
@@ -132,7 +134,6 @@ impl<'model> Model<'model> {
.partitions
.active_element()
.expect("no screen region found")
- .screen()
.placeable_region();
defaults::WORKSPACE_NAMES
@@ -162,14 +163,11 @@ impl<'model> Model<'model> {
.init_wm_properties(WM_NAME!(), &defaults::WORKSPACE_NAMES);
model.conn.grab_bindings(
- &key_bindings
- .keys()
- .into_iter()
- .collect::<Vec<&winsys::input::KeyCode>>(),
+ &key_bindings.keys().into_iter().collect::<Vec<&KeyCode>>(),
&mouse_bindings
.keys()
.into_iter()
- .collect::<Vec<&(winsys::input::MouseEventKey, winsys::input::MouseShortcut)>>(),
+ .collect::<Vec<&(MouseEventKey, MouseShortcut)>>(),
);
model
@@ -177,9 +175,7 @@ impl<'model> Model<'model> {
.top_level_windows()
.into_iter()
.for_each(|window| {
- if model.conn.must_manage_window(window) {
- model.manage(window, false);
- }
+ model.manage(window, !model.conn.must_manage_window(window));
});
if cfg!(not(debug_assertions)) {
@@ -194,114 +190,7 @@ impl<'model> Model<'model> {
model
}
- pub fn run(
- &mut self,
- mut key_bindings: KeyBindings,
- mut mouse_bindings: MouseBindings,
- ) {
- while self.running {
- if let Some(event) = self.conn.step() {
- trace!("received event: {:?}", event);
-
- match event {
- Event::Mouse {
- event,
- } => self.handle_mouse(event, &mut mouse_bindings),
- Event::Key {
- key_code,
- } => self.handle_key(key_code, &mut key_bindings),
- Event::MapRequest {
- window,
- ignore,
- } => self.handle_map_request(window, ignore),
- Event::Map {
- window,
- ignore,
- } => self.handle_map(window, ignore),
- Event::Enter {
- window,
- root_rpos,
- window_rpos,
- } => self.handle_enter(window, root_rpos, window_rpos),
- Event::Leave {
- window,
- root_rpos,
- window_rpos,
- } => self.handle_leave(window, root_rpos, window_rpos),
- Event::Destroy {
- window,
- } => self.handle_destroy(window),
- Event::Expose {
- window,
- } => self.handle_expose(window),
- Event::Unmap {
- window,
- ignore,
- } => self.handle_unmap(window, ignore),
- Event::Configure {
- window,
- region,
- on_root,
- } => self.handle_configure(window, region, on_root),
- Event::StateRequest {
- window,
- state,
- action,
- on_root,
- } => self.handle_state_request(window, state, action, on_root),
- Event::FocusRequest {
- window,
- on_root,
- } => self.handle_focus_request(window, on_root),
- Event::CloseRequest {
- window,
- on_root,
- } => self.handle_close_request(window, on_root),
- Event::WorkspaceRequest {
- window,
- index,
- on_root,
- } => self.handle_workspace_request(window, index, on_root),
- Event::PlacementRequest {
- window,
- pos,
- dim,
- on_root,
- } => self.handle_placement_request(window, pos, dim, on_root),
- Event::GripRequest {
- window,
- pos,
- grip,
- on_root,
- } => self.handle_grip_request(window, pos, grip, on_root),
- Event::RestackRequest {
- window,
- sibling,
- mode,
- on_root,
- } => self.handle_restack_request(window, sibling, mode, on_root),
- Event::Property {
- window,
- kind,
- on_root,
- } => self.handle_property(window, kind, on_root),
- Event::FrameExtentsRequest {
- window,
- on_root,
- } => self.handle_frame_extents_request(window, on_root),
- Event::Mapping {
- request,
- } => self.handle_mapping(request),
- Event::ScreenChange => self.handle_screen_change(),
- Event::Randr => self.handle_randr(),
- }
- }
-
- self.conn.flush();
- }
- }
-
- #[inline]
+ #[inline(always)]
fn window(
&self,
window: Window,
@@ -310,10 +199,10 @@ impl<'model> Model<'model> {
return Some(window);
}
- Some(self.frame_map.get(&window)?.to_owned())
+ self.frame_map.get(&window).map(|window| window.to_owned())
}
- #[inline]
+ #[inline(always)]
fn frame(
&self,
window: Window,
@@ -322,10 +211,10 @@ impl<'model> Model<'model> {
return Some(window);
}
- Some(self.window_map.get(&window)?.to_owned())
+ self.window_map.get(&window).map(|window| window.to_owned())
}
- #[inline]
+ #[inline(always)]
fn client_any(
&self,
mut window: Window,
@@ -337,7 +226,19 @@ impl<'model> Model<'model> {
self.client_map.get(&window)
}
- #[inline]
+ #[inline(always)]
+ fn client_any_unchecked(
+ &self,
+ mut window: Window,
+ ) -> &Client {
+ if let Some(&inside) = self.frame_map.get(&window) {
+ window = inside;
+ }
+
+ self.client_map.get(&window).unwrap()
+ }
+
+ #[inline(always)]
fn client(
&self,
window: Window,
@@ -345,12 +246,45 @@ impl<'model> Model<'model> {
self.client_any(window).filter(|client| client.is_managed())
}
- #[inline]
+ #[inline(always)]
+ fn client_unchecked(
+ &self,
+ window: Window,
+ ) -> &Client {
+ self.client_any(window)
+ .filter(|&client| client.is_managed())
+ .unwrap()
+ }
+
+ #[inline(always)]
+ fn active_partition(&self) -> usize {
+ self.partitions.active_index()
+ }
+
+ #[inline(always)]
+ fn active_screen(&self) -> &Screen {
+ self.partitions.active_element().unwrap().screen()
+ }
+
+ #[inline(always)]
+ pub fn active_workspace(&self) -> usize {
+ self.workspaces.active_index()
+ }
+
+ #[inline(always)]
+ fn focused_client(&self) -> Option<&Client> {
+ self.focus
+ .get()
+ .or_else(|| self.workspace(self.active_workspace()).focused_client())
+ .and_then(|focus| self.client_map.get(&focus))
+ }
+
+ #[inline(always)]
fn workspace(
&self,
index: Index,
) -> &Workspace {
- self.workspaces.get(index).unwrap()
+ &self.workspaces[index]
}
fn acquire_partitions(&mut self) {
@@ -359,20 +293,42 @@ impl<'model> Model<'model> {
.connected_outputs()
.into_iter()
.enumerate()
- .map(|(i, mut s)| {
+ .map(|(i, s)| {
s.compute_placeable_region();
Partition::new(s, i)
})
.collect();
- info!("acquired partitions: {:#?}", partitions);
- self.partitions = Cycle::new(partitions, false);
+ if partitions.is_empty() {
+ error!("no screen resources found, keeping old partitions");
+ } else {
+ info!("acquired partitions: {:#?}", partitions);
+ self.partitions = Cycle::new(partitions, false);
+ }
+ }
+
+ #[inline]
+ pub fn toggle_screen_struts(&self) {
+ let screen = self.active_screen();
+ let show = !screen.showing_struts();
+
+ screen
+ .show_and_yield_struts(show)
+ .iter()
+ .for_each(|&strut| {
+ if show {
+ self.conn.map_window(strut);
+ } else {
+ self.conn.unmap_window(strut);
+ }
+ });
+
+ self.apply_layout(self.active_workspace());
}
fn apply_layout(
&self,
index: Index,
- must_apply_stack: bool,
) {
if index != self.active_workspace() {
return;
@@ -389,7 +345,7 @@ impl<'model> Model<'model> {
.arrange(
&self.zone_manager,
&self.client_map,
- self.active_screen().placeable_region(),
+ self.partitions.active_element().unwrap().placeable_region(),
|client| !Self::is_applyable(client) || client.is_iconified(),
)
.into_iter()
@@ -398,9 +354,11 @@ impl<'model> Model<'model> {
show.iter().for_each(|placement| {
match placement.kind {
PlacementTarget::Client(window) => {
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
- self.map_client(self.client(window).unwrap());
+ let client = &self.client_map[&window];
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
+ self.map_client(client);
},
PlacementTarget::Tab(_) => {},
PlacementTarget::Layout => {},
@@ -410,16 +368,12 @@ impl<'model> Model<'model> {
hide.iter().for_each(|placement| {
match placement.kind {
PlacementTarget::Client(window) => {
- self.unmap_client(self.client(window).unwrap());
+ self.unmap_client(&self.client_map[&window]);
},
PlacementTarget::Tab(_) => {},
PlacementTarget::Layout => {},
};
});
-
- if must_apply_stack {
- self.apply_stack(index);
- }
}
fn apply_stack(
@@ -451,13 +405,13 @@ impl<'model> Model<'model> {
let (regular, fullscreen): (Vec<Window>, Vec<Window>) =
stack.iter().partition(|&&window| {
- let client = self.client(window).unwrap();
- !client.is_fullscreen() || client.is_in_window()
+ let client = self.client_unchecked(window);
+ !client.is_fullscreen() || client.is_contained()
});
let (free, regular): (Vec<Window>, Vec<Window>) = regular
.into_iter()
- .partition(|&window| self.is_free(self.client(window).unwrap()));
+ .partition(|&window| self.is_free(self.client_unchecked(window)));
let mut windows: Vec<Window> = desktop
.into_iter()
@@ -471,12 +425,16 @@ impl<'model> Model<'model> {
.into_iter()
.collect();
- // handle above-other relationships
- self.stack_manager.above_other().keys().for_each(|&window| {
- if let Some(index) = windows.iter().position(|&candidate| candidate == window) {
- windows.remove(index);
- }
- });
+ // handle {above,below}-other relationships
+ self.stack_manager
+ .above_other()
+ .keys()
+ .chain(self.stack_manager.below_other().keys())
+ .for_each(|&window| {
+ if let Some(index) = windows.iter().position(|&candidate| candidate == window) {
+ windows.remove(index);
+ }
+ });
self.stack_manager
.above_other()
@@ -489,13 +447,6 @@ impl<'model> Model<'model> {
}
});
- // handle below-other relationships
- self.stack_manager.below_other().keys().for_each(|&window| {
- if let Some(index) = windows.iter().position(|&candidate| candidate == window) {
- windows.remove(index);
- }
- });
-
self.stack_manager
.below_other()
.iter()
@@ -553,6 +504,7 @@ impl<'model> Model<'model> {
self.conn.update_client_list_stacking(&client_list_stacking);
}
+ #[inline]
fn detect_rules(
&self,
instance: &str,
@@ -563,25 +515,37 @@ impl<'model> Model<'model> {
let mut rules: Rules = Default::default();
match (instance.get(..PREFIX_LEN), instance.get(PREFIX_LEN..)) {
- (Some(PREFIX), flags) => {
- if let Some(flags) = flags {
- let mut invert = false;
-
- for i in 0..flags.len() {
- let flag = &flags[i..=i];
-
- match flag {
- "!" => {
- invert = true;
- continue;
- },
- "f" => rules.float = Some(!invert),
- "c" => rules.center = Some(!invert),
- _ => {},
- }
-
- invert = false;
+ (Some(PREFIX), Some(flags)) if !flags.is_empty() => {
+ let mut invert = false;
+ let mut workspace = false;
+
+ for i in 0..flags.len() {
+ let flag = &flags[i..=i];
+
+ match flag {
+ "!" => {
+ invert = true;
+ continue;
+ },
+ "w" => {
+ workspace = true;
+ continue;
+ },
+ number if workspace => {
+ if let Ok(number) = number.parse::<usize>() {
+ if number < self.workspaces.len() {
+ rules.workspace = Some(number);
+ }
+ }
+ },
+ "f" => rules.float = Some(!invert),
+ "F" => rules.fullscreen = Some(!invert),
+ "c" => rules.center = Some(!invert),
+ _ => {},
}
+
+ invert = false;
+ workspace = false;
}
},
_ => {},
@@ -607,14 +571,8 @@ impl<'model> Model<'model> {
}
let pid = self.conn.get_window_pid(window);
-
let ppid = pid.and_then(|pid| {
- get_spawner_pid(
- pid,
- std::process::id() as Pid,
- &self.pid_map,
- &self.client_map,
- )
+ get_spawner_pid(pid, std::process::id(), &self.pid_map, &self.client_map)
});
let name = self.conn.get_icccm_window_name(window);
@@ -624,64 +582,43 @@ impl<'model> Model<'model> {
let preferred_state = self.conn.get_window_preferred_state(window);
let preferred_type = self.conn.get_window_preferred_type(window);
- let geometry = self.conn.get_window_geometry(window);
-
- if geometry.is_err() {
- return;
- }
+ let mut geometry = match self.conn.get_window_geometry(window) {
+ Ok(geometry) => geometry,
+ Err(_) => return,
+ };
self.stop_moving();
self.stop_resizing();
- let original_geometry = geometry.unwrap();
- let mut geometry = original_geometry;
-
+ let at_origin = geometry.pos.is_origin();
let frame = self.conn.create_frame(geometry);
let rules = self.detect_rules(&instance);
let hints = self.conn.get_icccm_window_hints(window);
- let (_, size_hints) =
- self.conn
- .get_icccm_window_size_hints(window, Some(Client::MIN_CLIENT_DIM), &None);
-
- geometry = if size_hints.is_some() {
- geometry
- .with_size_hints(&size_hints)
- .with_extents(Decoration::FREE_DECORATION.extents())
- } else {
- geometry
+ let size_hints = self
+ .conn
+ .get_icccm_window_size_hints(window, Some(Client::MIN_CLIENT_DIM), &None)
+ .1;
+
+ geometry = match size_hints {
+ Some(size_hints) => geometry
+ .with_size_hints(&Some(size_hints))
+ .with_extents(Decoration::FREE_DECORATION.extents()),
+ None => geometry
.with_minimum_dim(&Client::MIN_CLIENT_DIM)
- .with_extents(Decoration::FREE_DECORATION.extents())
+ .with_extents(Decoration::FREE_DECORATION.extents()),
};
let parent = self.conn.get_icccm_window_transient_for(window);
-
- // TODO: startup sequence/notification
- // TODO: MOTIF decorations for old-style applications
-
- let context = 0;
- let workspace = self
- .conn
- .get_window_desktop(window)
- .map_or(self.active_workspace(), |d| {
- if d < self.workspaces.len() {
- d
- } else {
- self.active_workspace()
- }
- });
-
- let mut center = false;
-
- // TODO: retrieve screen of new client's workspace
let screen = self.active_screen();
+ let context = 0;
+ let workspace = rules.workspace.unwrap_or_else(|| {
+ self.conn
+ .get_window_desktop(window)
+ .filter(|&workspace| workspace < self.workspaces.len())
+ .unwrap_or_else(|| self.active_workspace())
+ });
- if rules.center(&mut center)
- || (size_hints.is_none() || !size_hints.unwrap().by_user)
- && original_geometry.pos
- == (Pos {
- x: 0,
- y: 0,
- })
+ if rules.center() || size_hints.map_or(true, |size_hints| !size_hints.by_user) && at_origin
{
geometry = screen
.full_region()
@@ -708,9 +645,9 @@ impl<'model> Model<'model> {
ppid,
);
- let fullscreen = self.conn.window_is_fullscreen(window);
+ let fullscreen = self.conn.window_is_fullscreen(window) | rules.fullscreen();
let sticky = self.conn.window_is_sticky(window);
- let mut floating = self.conn.must_free_window(window);
+ let mut floating = self.conn.must_free_window(window) | rules.float();
if let Some(parent) = parent {
floating = true;
@@ -724,6 +661,7 @@ impl<'model> Model<'model> {
if let Some(leader) = leader {
let leader_window = leader.window();
+
if leader_window != window {
floating = true;
client.set_leader(leader_window);
@@ -731,85 +669,82 @@ impl<'model> Model<'model> {
}
if let Some(hints) = hints {
- client.set_urgent(hints.urgent);
+ client.set_urgent(Toggle::from(hints.urgent));
}
- rules.float(&mut floating);
-
- client.set_floating(floating);
+ client.set_floating(Toggle::from(floating));
client.set_region(PlacementClass::Free(geometry));
client.set_size_hints(size_hints);
client.set_context(context);
client.set_workspace(workspace);
- let extents = Decoration::FREE_DECORATION.extents();
- self.conn.reparent_window(window, frame, Pos {
- x: extents.left as i32,
- y: extents.top as i32,
+ self.conn.reparent_window(window, frame, {
+ let extents = Decoration::FREE_DECORATION.extents();
+
+ Pos {
+ x: extents.left,
+ y: extents.top,
+ }
});
- self.workspaces[workspace].add_client(window, &InsertPos::Back);
+ if let Some(parent) = parent.and_then(|parent| self.client_any(parent)) {
+ let parent_frame = parent.frame();
- if let Some(parent) = parent {
- if let Some(parent) = self.client_any(parent) {
- let parent_frame = parent.frame();
- parent.add_child(window);
- self.stack_manager.add_above_other(frame, parent_frame);
- }
+ parent.add_child(window);
+ self.stack_manager.add_above_other(frame, parent_frame);
}
if let Some(pid) = pid {
self.pid_map.insert(pid, window);
}
- self.conn
- .set_icccm_window_state(window, IcccmWindowState::Normal);
+ self.workspaces[workspace].add_client(window, &InsertPos::AfterActive);
self.client_map.insert(window, client);
self.frame_map.insert(frame, window);
self.window_map.insert(window, frame);
self.conn.insert_window_in_save_set(window);
- self.conn.init_window(window, false); // TODO config.focus_follows_mouse
- self.conn.init_frame(frame, false); // TODO: config.focus_follows_mouse
+ self.conn.init_window(window, false);
+ self.conn.init_frame(frame, false);
self.conn.set_window_border_width(window, 0);
self.conn.set_window_desktop(window, workspace);
+ self.conn
+ .set_icccm_window_state(window, IcccmWindowState::Normal);
- self.apply_layout(workspace, false);
+ self.apply_layout(workspace);
self.focus_window(window);
- if let Some(ppid) = ppid {
- if let Some(ppid_window) = self.pid_map.get(&ppid) {
- let ppid_window = *ppid_window;
- if let Some(ppid_client) = self.client(ppid_window) {
- if ppid_client.is_producing() {
- self.consume_client(window, ppid_window);
- }
- }
- }
+ if let Some(WindowState::DemandsAttention) = preferred_state {
+ self.handle_state_request(
+ window,
+ WindowState::DemandsAttention,
+ ToggleAction::Add,
+ false,
+ );
}
- if let Some(state) = preferred_state {
- match state {
- WindowState::DemandsAttention => {
- self.handle_state_request(window, state, ToggleAction::Add, false)
- },
- _ => {},
- }
- }
+ let client = &self.client_map[&window];
if sticky {
- self.stick(window);
+ self.stick(client);
}
if fullscreen {
- self.fullscreen(window);
+ self.fullscreen(client);
}
- let client = self.client_any(window).unwrap();
- let active_region = client.active_region();
- let current_pos = self.conn.get_pointer_position();
+ if let Some(&ppid_window) = ppid.and_then(|ppid| self.pid_map.get(&ppid)) {
+ if let Some(ppid_client) = self.client(ppid_window) {
+ if ppid_client.is_producing() {
+ self.consume_client(client, ppid_client);
+ }
+ }
+ }
- if let Some(warp_pos) = active_region.quadrant_center_from_pos(current_pos) {
+ if let Some(warp_pos) = client
+ .active_region()
+ .quadrant_center_from_pos(self.conn.get_pointer_position())
+ {
self.conn.warp_pointer(warp_pos);
}
@@ -825,79 +760,61 @@ impl<'model> Model<'model> {
return;
}
- info!("remanaging client with window {:#0x}", client.window());
-
let window = client.window();
- let active_workspace = self.active_workspace();
- let mut workspace = active_workspace;
+ info!("remanaging client with window {:#0x}", window);
- if must_alter_workspace {
- let leader = client.leader();
+ client.set_managed(Toggle::On);
- if let Some(leader) = leader {
- if let Some(leader) = self.client(leader) {
- workspace = leader.workspace();
- }
- }
+ if must_alter_workspace {
+ let workspace = client
+ .leader()
+ .and_then(|leader| self.client(leader))
+ .map(|leader| {
+ let workspace = leader.workspace();
- {
- let workspace = self.workspace(workspace);
+ client.set_workspace(workspace);
+ self.workspace(leader.workspace())
+ });
+ if let Some(workspace) = workspace {
if !workspace.contains(window) {
workspace.add_client(window, &InsertPos::Back);
}
}
-
- let client = self.client_any(window).unwrap();
- client.set_workspace(workspace);
}
- let client = self.client_any(window).unwrap();
- client.set_managed(true);
-
- let client = self.client_any(window).unwrap();
if client.is_sticky() {
- let client = self.client_any(window).unwrap();
- client.set_sticky(false);
-
- self.stick(window);
+ client.set_sticky(Toggle::Off);
+ self.stick(client);
self.map_client(client);
}
+
+ self.focus(client);
}
fn unmanage(
- &mut self,
- window: Window,
+ &self,
+ client: &Client,
) {
- if let Some(client) = self.client(window) {
- info!("unmanaging client with window {:#0x}", client.window());
-
- if client.is_sticky() {
- self.unstick(window);
-
- let client = self.client(window).unwrap();
- client.set_sticky(true);
- }
-
- let client = self.client(window).unwrap();
- let window = client.window();
- let workspace = client.workspace();
-
- self.unmap_client(client);
+ if !client.is_managed() {
+ return;
+ }
- {
- let workspace = self.workspace(workspace);
+ let window = client.window();
+ info!("unmanaging client with window {:#0x}", window);
- if workspace.contains(window) {
- workspace.remove_client(window);
- }
- }
+ client.set_managed(Toggle::Off);
- let client = self.client(window).unwrap();
- client.set_managed(false);
+ if client.is_sticky() {
+ self.unstick(client);
+ client.set_sticky(Toggle::On);
}
+
+ self.unmap_client(client);
+ self.workspace(client.workspace()).remove_client(window);
}
+ // TODO: zones
pub fn create_layout_zone(&mut self) {
let workspace_index = self.active_workspace();
let workspace = self.workspace(workspace_index);
@@ -911,9 +828,11 @@ impl<'model> Model<'model> {
let workspace = self.workspace(workspace_index);
workspace.add_zone(id, &InsertPos::Back);
- self.apply_layout(workspace_index, true);
+ self.apply_layout(workspace_index);
+ self.apply_stack(workspace_index);
}
+ // TODO: zones
pub fn create_tab_zone(&mut self) {
let workspace_index = self.active_workspace();
let workspace = self.workspace(workspace_index);
@@ -926,9 +845,11 @@ impl<'model> Model<'model> {
let workspace = self.workspace(workspace_index);
workspace.add_zone(id, &InsertPos::Back);
- self.apply_layout(workspace_index, true);
+ self.apply_layout(workspace_index);
+ self.apply_stack(workspace_index);
}
+ // TODO: zones
pub fn delete_zone(&mut self) {
let workspace_index = self.active_workspace();
let workspace = self.workspace(workspace_index);
@@ -946,80 +867,79 @@ impl<'model> Model<'model> {
workspace.remove_zone(cycle);
}
+ #[inline]
fn is_applyable(client: &Client) -> bool {
!client.is_floating()
&& !client.is_disowned()
&& client.is_managed()
- && (!client.is_fullscreen() || client.is_in_window())
+ && (!client.is_fullscreen() || client.is_contained())
}
+ #[inline]
fn is_free(
&self,
client: &Client,
) -> bool {
- client.is_floating() && (!client.is_fullscreen() || client.is_in_window()) || {
- let id = client.zone();
- let zone = self.zone_manager.zone(id);
-
- zone.method() == PlacementMethod::Free
- }
+ client.is_free() || self.zone_manager.zone(client.zone()).method() == PlacementMethod::Free
}
+ #[inline]
fn is_focusable(
&self,
- window: Window,
+ client: &Client,
) -> bool {
- self.client(window).map_or(false, |client| {
- !client.is_disowned() && !client.is_iconified()
- })
+ !client.is_disowned() && !client.is_iconified()
}
fn remove_window(
&mut self,
window: Window,
) {
- let client = self.client(window);
-
- if client.is_none() {
- return;
- }
+ let client = match self.client_any(window) {
+ Some(client) if !client.consume_unmap_if_expecting() => client,
+ _ => return,
+ };
- let client = client.unwrap();
let (window, frame) = client.windows();
- let parent = client.parent();
- let producer = client.producer();
let workspace = client.workspace();
- let id = client.zone();
info!("removing client with window {:#0x}", window);
+ if !client.is_managed() {
+ self.remanage(client, true);
+ }
+
+ if let Ok(geometry) = self.conn.get_window_geometry(frame) {
+ self.conn.unparent_window(window, geometry.pos);
+ }
+
+ self.conn.cleanup_window(window);
+ self.conn.destroy_window(frame);
+
if client.is_sticky() {
- self.unstick(window);
+ self.unstick(client);
}
if Some(window) == self.jumped_from.get() {
self.jumped_from.set(None);
}
- if let Some(producer) = producer {
- let producer = self.client_any(producer);
- if let Some(producer) = producer {
- self.unconsume_client(producer);
- }
+ if client.producer().is_some() {
+ self.unconsume_client(client);
}
- if let Some(parent) = parent {
- if let Some(parent) = self.client(parent) {
- parent.remove_child(window);
- }
+ if let Some(parent) = client.parent().and_then(|parent| self.client(parent)) {
+ parent.remove_child(window);
}
+ let id = client.zone();
self.zone_manager.remove_zone(id);
- self.workspaces.get_mut(workspace).map(|w| {
- w.remove_client(window);
- w.remove_icon(window);
- });
+ {
+ let workspace = self.workspace(workspace);
+ workspace.remove_client(window);
+ workspace.remove_icon(window);
+ }
self.stack_manager.remove_window(window);
self.frame_map.remove(&frame);
@@ -1029,206 +949,145 @@ impl<'model> Model<'model> {
self.fullscreen_regions.borrow_mut().remove(&window);
self.sync_focus();
+ self.apply_layout(workspace);
}
- fn redraw_client(
+ #[inline(always)]
+ fn render_decoration(
&self,
- window: Window,
+ client: &Client,
) {
- if let Some(client) = self.client(window) {
- let decoration = client.decoration();
-
- if let Some(border) = decoration.border {
- self.conn
- .set_window_border_width(client.frame(), border.width);
-
- self.conn.set_window_border_color(
- client.frame(),
- if client.is_focused() {
- if client.is_sticky() {
- border.colors.fsticky
- } else {
- border.colors.focused
- }
- } else if client.is_urgent() {
- border.colors.urgent
- } else if client.is_sticky() {
- border.colors.rsticky
- } else {
- border.colors.regular
- },
- );
- }
+ let (border, frame_color) = client.decoration_colors();
- if let Some(frame) = decoration.frame {
- self.conn.set_window_background_color(
- client.frame(),
- if client.is_focused() {
- if client.is_sticky() {
- frame.colors.fsticky
- } else {
- frame.colors.focused
- }
- } else if client.is_urgent() {
- frame.colors.urgent
- } else if client.is_sticky() {
- frame.colors.rsticky
- } else {
- frame.colors.regular
- },
- );
- }
+ if let Some((width, color)) = border {
+ self.conn.set_window_border_width(client.frame(), width);
+ self.conn.set_window_border_color(client.frame(), color);
+ }
+
+ if let Some(color) = frame_color {
+ self.conn.set_window_background_color(client.frame(), color);
}
}
+ #[inline(always)]
fn update_client_placement(
&self,
+ client: &Client,
placement: &Placement,
) {
- match placement.kind {
- PlacementTarget::Client(window) => {
- let client = self.client(window).unwrap();
-
- let region = match placement.region {
- PlacementRegion::FreeRegion => client.free_region(),
- PlacementRegion::NewRegion(region) => region,
- PlacementRegion::NoRegion => return,
- };
-
- client.set_decoration(placement.decoration);
-
- match placement.method {
- PlacementMethod::Free => {
- let id = client.zone();
- client.set_region(PlacementClass::Free(region));
+ let region = match placement.region {
+ PlacementRegion::FreeRegion => client.free_region(),
+ PlacementRegion::NewRegion(region) => region,
+ PlacementRegion::NoRegion => return,
+ };
- let zone = self.zone_manager.zone(id);
- zone.set_region(region);
- zone.set_method(placement.method);
- },
- PlacementMethod::Tile => {
- let id = client.zone();
- client.set_region(PlacementClass::Tile(region));
+ let zone = self.zone_manager.zone(client.zone());
+ zone.set_method(placement.method);
- let zone = self.zone_manager.zone(id);
- zone.set_method(placement.method);
- },
- };
+ client.set_decoration(placement.decoration);
+ client.set_region(match placement.method {
+ PlacementMethod::Free => {
+ zone.set_region(region);
+ PlacementClass::Free(region)
},
- _ => panic!("attempting to update non-client placement"),
- }
+ PlacementMethod::Tile => PlacementClass::Tile(region),
+ });
}
+ #[inline(always)]
fn place_client(
&self,
- window: Window,
+ client: &Client,
method: PlacementMethod,
) {
- let client = self.client(window).unwrap();
-
let (window, frame) = client.windows();
- let inner_region = client.inner_region();
-
- self.conn.place_window(window, &inner_region);
+ self.conn.place_window(window, &client.inner_region());
self.conn.place_window(frame, &match method {
PlacementMethod::Free => client.free_region(),
PlacementMethod::Tile => client.tile_region(),
});
- self.redraw_client(window);
+ self.render_decoration(client);
self.conn.update_window_offset(window, frame);
}
+ #[inline(always)]
fn map_client(
&self,
client: &Client,
) {
if !client.is_mapped() {
let (window, frame) = client.windows();
-
info!("mapping client with window {:#0x}", window);
+
self.conn.map_window(window);
self.conn.map_window(frame);
- self.redraw_client(window);
- client.set_mapped(true);
+ self.render_decoration(client);
+ client.set_mapped(Toggle::On);
}
}
+ #[inline(always)]
fn unmap_client(
&self,
client: &Client,
) {
if client.is_mapped() {
let (window, frame) = client.windows();
-
info!("unmapping client with window {:#0x}", window);
+
self.conn.unmap_window(frame);
client.expect_unmap();
- client.set_mapped(false);
+ client.set_mapped(Toggle::Off);
}
}
fn consume_client(
- &mut self,
- consumer: Window,
- producer: Window,
+ &self,
+ consumer: &Client,
+ producer: &Client,
) {
- let consumer_window = consumer;
- let producer_window = producer;
-
- let consumer = self.client_any(consumer_window);
- let producer = self.client_any(producer_window);
-
- if consumer.is_none() || producer.is_none() {
+ if producer.is_iconified() || consumer.is_iconified() {
return;
}
+ let (cwindow, pwindow) = (consumer.window(), producer.window());
+ let (cworkspace, pworkspace) = (consumer.workspace(), producer.workspace());
+
info!(
"consuming client with window {:#0x} and producer window {:#0x}",
- consumer_window, producer_window
+ cwindow, pwindow
);
- let consumer = consumer.unwrap();
- let producer = producer.unwrap();
- let producer_workspace_index = producer.workspace();
-
- if producer.is_iconified() || consumer.is_iconified() {
- return;
- }
-
- let consumer_len = producer.consumer_len();
- let consumer_workspace_index = consumer.workspace();
- let consumer = self.client_any(consumer_window).unwrap();
- consumer.set_consuming(true);
- consumer.set_producer(producer_window);
+ consumer.set_producer(pwindow);
- if consumer_len == 0 {
- let producer_workspace = self.workspace(producer_workspace_index);
+ if producer.consumer_len() == 0 {
+ let workspace = self.workspace(pworkspace);
- if producer_workspace_index == consumer_workspace_index {
- producer_workspace.replace_client(producer_window, consumer_window);
+ if pworkspace == cworkspace {
+ workspace.replace_client(pwindow, cwindow);
} else {
- producer_workspace.remove_client(producer_window);
+ workspace.remove_client(pwindow);
}
- self.apply_layout(consumer_workspace_index, true);
+ self.apply_layout(cworkspace);
+ self.apply_stack(cworkspace);
}
- let producer = self.client_any(producer_window).unwrap();
- producer.add_consumer(consumer_window);
- self.unmanage(producer_window);
+ producer.add_consumer(cwindow);
+ self.unmanage(producer);
}
fn unconsume_client(
&self,
consumer: &Client,
) {
- let (producer, workspace) = match consumer
+ let producer = match consumer
.producer()
- .and_then(|window| self.client_any(window))
+ .and_then(|producer| self.client_any(producer))
{
- Some(producer) => (producer, consumer.workspace()),
+ Some(producer) => producer,
None => return,
};
@@ -1241,7 +1100,7 @@ impl<'model> Model<'model> {
producer.remove_consumer(consumer.window());
if producer.consumer_len() == 0 {
- producer.set_workspace(workspace);
+ let workspace = consumer.workspace();
{
let workspace = self.workspace(workspace);
@@ -1253,307 +1112,216 @@ impl<'model> Model<'model> {
}
}
+ producer.set_workspace(workspace);
self.remanage(producer, false);
-
- if workspace == self.active_workspace() {
- self.map_client(producer);
- }
-
- self.apply_layout(workspace, true);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
consumer.unset_producer();
- consumer.set_consuming(false);
}
+ #[inline(always)]
pub fn kill_focus(&self) {
if let Some(focus) = self.focus.get() {
- self.kill_client(focus);
+ self.kill_window(focus);
}
}
- pub fn kill_client(
+ #[inline]
+ pub fn kill_window(
&self,
- mut window: Window,
+ window: Window,
) {
- if let Some(client) = self.client_any(window) {
- window = client.window();
+ match self.client_any(window) {
+ Some(client) if !client.is_invincible() => {
+ info!("killing client with window {:#0x}", window);
- if client.is_invincible() {
- return;
- }
- } else {
- return;
+ self.conn.kill_window(window);
+ self.conn.flush();
+ },
+ _ => {},
}
-
- info!("killing client with window {:#0x}", window);
-
- self.conn.kill_window(window);
- self.conn.flush();
}
+ #[inline(always)]
pub fn cycle_zones(
- &mut self,
+ &self,
dir: Direction,
) {
- let workspace = self.active_workspace();
- let zone_manager = &self.zone_manager;
-
- self.workspaces
- .get_mut(workspace)
- .and_then(|ws| ws.cycle_zones(dir, zone_manager));
+ self.workspace(self.active_workspace())
+ .cycle_zones(dir, &self.zone_manager);
}
+ #[inline(always)]
pub fn cycle_focus(
- &mut self,
+ &self,
dir: Direction,
) {
- let workspace = self.active_workspace();
- let client_map = &self.client_map;
- let zone_manager = &self.zone_manager;
-
- let windows = self
- .workspaces
- .get_mut(workspace)
- .and_then(|ws| ws.cycle_focus(dir, client_map, zone_manager));
-
- if let Some((_, window)) = windows {
+ if let Some((_, window)) = self.workspace(self.active_workspace()).cycle_focus(
+ dir,
+ &self.client_map,
+ &self.zone_manager,
+ ) {
self.focus_window(window);
self.sync_focus();
}
}
+ #[inline(always)]
pub fn drag_focus(
- &mut self,
+ &self,
dir: Direction,
) {
if let Some(focus) = self.focus.get() {
- let workspace_index = self.active_workspace();
- self.workspaces
- .get_mut(workspace_index)
- .and_then(|ws| ws.drag_focus(dir));
+ let workspace = self.active_workspace();
- self.apply_layout(workspace_index, false);
+ self.workspace(workspace).drag_focus(dir);
+ self.apply_layout(workspace);
self.focus_window(focus);
}
}
+ #[inline(always)]
pub fn rotate_clients(
- &mut self,
+ &self,
dir: Direction,
) {
- let workspace_index = self.active_workspace();
- let workspace = self.workspace(workspace_index);
- let next_window = workspace.next_client(dir.rev());
+ let workspace = self.workspace(self.active_workspace());
- workspace.rotate_clients(dir);
- self.apply_layout(workspace_index, false);
-
- if let Some(window) = next_window {
- self.focus_window(window);
+ if let Some(next) = workspace.next_client(dir.rev()) {
+ workspace.rotate_clients(dir);
+ self.apply_layout(self.active_workspace());
+ self.focus_window(next);
}
}
- pub fn center_client(
- &mut self,
- window: Window,
+ #[inline]
+ pub fn move_focus_to_next_workspace(
+ &self,
+ dir: Direction,
) {
- if let Some(client) = self.client(window) {
- if self.is_free(client) {
- let screen = self.partitions.active_element().unwrap().screen();
-
- let center = screen
- .full_region()
- .from_absolute_inner_center(client.free_region().dim);
-
- let mut free_region = client.free_region();
- free_region.pos = center.pos;
-
- info!("centering client with window {:#0x}", client.window());
-
- self.conn.move_window(client.frame(), center.pos);
- self.client(window)
- .unwrap()
- .set_region(PlacementClass::Free(free_region));
- }
- }
- }
-
- pub fn center_focus(&mut self) {
if let Some(focus) = self.focus.get() {
- self.center_client(focus);
+ self.move_window_to_next_workspace(focus, dir);
}
}
- pub fn apply_float_retain_region(&mut self) {
- let workspace_index = self.active_workspace();
- let workspace = self.workspace(workspace_index);
- let windows = workspace.clients();
-
- windows.into_iter().for_each(|w| {
- let client = self.client(w).unwrap();
- let active_region = client.active_region();
-
- let client = self.client(w).unwrap();
- client.set_region(PlacementClass::Free(active_region));
- });
-
- drop(self.set_layout(LayoutKind::Float));
- self.apply_layout(workspace_index, false);
- }
-
- pub fn move_focus_to_next_workspace(&mut self) {
- if let Some(focus) = self.focus.get() {
- self.move_client_to_next_workspace(focus);
+ #[inline]
+ pub fn move_window_to_next_workspace(
+ &self,
+ window: Window,
+ dir: Direction,
+ ) {
+ if let Some(client) = self.client(window) {
+ self.move_client_to_next_workspace(client, dir);
}
}
- pub fn move_focus_to_prev_workspace(&mut self) {
- if let Some(focus) = self.focus.get() {
- self.move_client_to_prev_workspace(focus);
- }
+ #[inline]
+ pub fn move_client_to_next_workspace(
+ &self,
+ client: &Client,
+ dir: Direction,
+ ) {
+ self.move_client_to_workspace(
+ client,
+ Util::next_index(self.workspaces.iter(), self.active_workspace(), dir),
+ );
}
+ #[inline]
pub fn move_focus_to_workspace(
- &mut self,
- index: Index,
+ &self,
+ to: Index,
) {
if let Some(focus) = self.focus.get() {
- self.move_client_to_workspace(focus, index);
+ self.move_window_to_workspace(focus, to);
}
}
- pub fn move_client_to_next_workspace(
- &mut self,
- window: Window,
- ) {
- let index = self.active_workspace() + 1;
- let index = index % self.workspaces.len();
-
- self.move_client_to_workspace(window, index);
- }
-
- pub fn move_client_to_prev_workspace(
- &mut self,
+ #[inline]
+ fn move_window_to_workspace(
+ &self,
window: Window,
+ to: Index,
) {
- let index = if self.active_workspace() == 0 {
- self.workspaces.len() - 1
- } else {
- self.active_workspace() - 1
- };
-
- self.move_client_to_workspace(window, index);
+ if let Some(client) = self.client(window) {
+ self.move_client_to_workspace(client, to);
+ }
}
fn move_client_to_workspace(
- &mut self,
- window: Window,
- index: Index,
+ &self,
+ client: &Client,
+ to: Index,
) {
- if index == self.active_workspace() || index >= self.workspaces.len() {
- return;
- }
-
- let (window, current_index) = match self.client(window) {
- Some(client) => {
- if client.is_sticky() {
- return;
- } else {
- (client.window(), client.workspace())
- }
- },
- _ => return,
- };
+ let (window, from) =
+ if to != self.active_workspace() && to < self.workspaces.len() && !client.is_sticky() {
+ (client.window(), client.workspace())
+ } else {
+ return;
+ };
info!(
"moving client with window {:#0x} to workspace {}",
- window, index
+ window, to
);
- // add client to requested workspace
- let workspace = self.workspace(index);
- workspace.add_client(window, &InsertPos::Back);
-
- // remove client from current_index workspace
- let workspace = self.workspace(current_index);
- workspace.remove_client(window);
-
- let client = self.client(window).unwrap();
- client.set_workspace(index);
+ client.set_workspace(to);
self.unmap_client(client);
- self.apply_layout(current_index, true);
- self.sync_focus();
- }
-
- pub fn toggle_screen_struts(&mut self) {
- let screen = self.active_screen_mut();
-
- if screen.showing_struts() {
- let struts = screen.hide_and_yield_struts();
-
- for strut in struts {
- self.conn.unmap_window(strut);
- }
- } else {
- let struts = screen.show_and_yield_struts();
+ self.workspace(to).add_client(window, &InsertPos::Back);
+ self.apply_layout(to);
+ self.apply_stack(to);
- for strut in struts {
- self.conn.map_window(strut);
- }
- }
+ self.workspace(from).remove_client(window);
+ self.apply_layout(from);
+ self.apply_stack(from);
- // TODO: apply layout to workspace active on screen
- let workspace_index = self.active_workspace();
- self.apply_layout(workspace_index, false);
+ self.sync_focus();
}
+ #[inline(always)]
pub fn toggle_workspace(&self) {
self.activate_workspace(self.prev_workspace.get());
}
- pub fn activate_next_workspace(&self) {
- let index = self.active_workspace() + 1;
- let index = index % self.workspaces.len();
-
- self.activate_workspace(index);
- }
-
- pub fn activate_prev_workspace(&self) {
- let index = if self.active_workspace() == 0 {
- self.workspaces.len() - 1
- } else {
- self.active_workspace() - 1
- };
-
- self.activate_workspace(index);
+ #[inline(always)]
+ pub fn activate_next_workspace(
+ &self,
+ dir: Direction,
+ ) {
+ self.activate_workspace(Util::next_index(
+ self.workspaces.iter(),
+ self.active_workspace(),
+ dir,
+ ));
}
pub fn activate_workspace(
&self,
- index: Index,
+ to: Index,
) {
- if index == self.active_workspace() || index >= self.workspaces.len() {
+ if to == self.active_workspace() || to >= self.workspaces.len() {
return;
}
- info!("activating workspace {}", index);
+ info!("activating workspace {}", to);
self.stop_moving();
self.stop_resizing();
- let prev_workspace = self.workspaces.active_index();
- self.prev_workspace.set(prev_workspace);
+ let from = self.workspaces.active_index();
+ self.prev_workspace.set(from);
- self.workspace(index)
+ self.workspace(to)
.on_each_client(&self.client_map, |client| {
if !client.is_mapped() {
self.map_client(client);
}
});
- self.workspace(prev_workspace)
+ self.workspace(from)
.on_each_client(&self.client_map, |client| {
if client.is_mapped() && !client.is_sticky() {
self.unmap_client(client);
@@ -1561,13 +1329,16 @@ impl<'model> Model<'model> {
});
self.sticky_clients.borrow().iter().for_each(|&window| {
- self.client(window).unwrap().set_workspace(index);
+ self.client_unchecked(window).set_workspace(to);
});
- self.workspaces.activate_for(&Selector::AtIndex(index));
- self.apply_layout(index, true);
+ self.conn.set_current_desktop(to);
+
+ self.workspaces.activate_for(&Selector::AtIndex(to));
+ self.apply_layout(to);
+ self.apply_stack(to);
+
self.sync_focus();
- self.conn.set_current_desktop(index);
}
#[inline]
@@ -1575,49 +1346,45 @@ impl<'model> Model<'model> {
&mut self,
change: Change<u32>,
) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_gap_size(change, &mut self.zone_manager)?;
- }
+ self.workspaces[workspace].change_gap_size(change, &mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
#[inline]
pub fn copy_prev_layout_data(&mut self) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.copy_prev_layout_data(&mut self.zone_manager)?;
- }
+ self.workspaces[workspace].copy_prev_layout_data(&mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
#[inline]
pub fn reset_layout_data(&mut self) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.reset_layout_data(&mut self.zone_manager)?;
- }
+ self.workspaces[workspace].reset_layout_data(&mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
#[inline]
pub fn reset_gap_size(&mut self) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.reset_gap_size(&mut self.zone_manager)?;
- }
+ self.workspaces[workspace].reset_gap_size(&mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
@@ -1626,13 +1393,12 @@ impl<'model> Model<'model> {
&mut self,
change: Change<u32>,
) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_main_count(change, &mut self.zone_manager)?;
- }
+ self.workspaces[workspace].change_main_count(change, &mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
@@ -1641,13 +1407,12 @@ impl<'model> Model<'model> {
&mut self,
change: Change<f32>,
) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_main_factor(change, &mut self.zone_manager)?;
- }
+ self.workspaces[workspace].change_main_factor(change, &mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
@@ -1657,25 +1422,23 @@ impl<'model> Model<'model> {
edge: Edge,
change: Change<i32>,
) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_margin(edge, change, &mut self.zone_manager)?;
- }
+ self.workspaces[workspace].change_margin(edge, change, &mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
#[inline]
pub fn reset_margin(&mut self) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
+ let workspace = self.active_workspace();
- if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.reset_margin(&mut self.zone_manager)?;
- }
+ self.workspaces[workspace].reset_margin(&mut self.zone_manager)?;
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- self.apply_layout(workspace_index, true);
Ok(())
}
@@ -1684,17 +1447,14 @@ impl<'model> Model<'model> {
&mut self,
kind: LayoutKind,
) -> Result<(), StateChangeError> {
- let workspace_index = self.active_workspace();
- let workspace = self.workspace(workspace_index);
+ let workspace = self.active_workspace();
- if let Some(id) = workspace.active_focus_zone() {
- info!(
- "activating layout {:?} on workspace {}",
- kind, workspace_index
- );
+ if let Some(id) = self.workspaces[workspace].active_focus_zone() {
+ info!("activating layout {:?} on workspace {}", kind, workspace);
self.zone_manager.set_kind(id, kind)?;
- self.apply_layout(workspace_index, true);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
Ok(())
@@ -1702,858 +1462,1005 @@ impl<'model> Model<'model> {
#[inline]
pub fn toggle_layout(&mut self) {
- let workspace_index = self.active_workspace();
- let workspace = self.workspace(workspace_index);
+ let workspace = self.active_workspace();
- if let Some(id) = workspace.active_focus_zone() {
+ if let Some(id) = self.workspaces[workspace].active_focus_zone() {
let prev_kind = self.zone_manager.set_prev_kind(id);
info!(
"activating layout {:?} on workspace {}",
- prev_kind, workspace_index
+ prev_kind, workspace
);
- self.apply_layout(workspace_index, true);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
}
- #[inline]
- pub fn toggle_in_window_focus(&mut self) {
+ #[inline(always)]
+ pub fn set_floating_focus(
+ &self,
+ toggle: Toggle,
+ ) {
if let Some(focus) = self.focus.get() {
- if let Some(client) = self.client(focus) {
- let must_in_window = !client.is_in_window();
- client.set_in_window(must_in_window);
-
- if must_in_window {
- self.unfullscreen(focus);
- } else {
- self.fullscreen(focus);
- }
- }
+ self.set_floating_window(focus, toggle);
}
}
- #[inline]
- pub fn toggle_invincible_focus(&mut self) {
- if let Some(focus) = self.focus.get() {
- if let Some(client) = self.client(focus) {
- let must_invincible = !client.is_invincible();
- client.set_invincible(must_invincible);
- }
+ #[inline(always)]
+ pub fn set_floating_window(
+ &self,
+ window: Window,
+ toggle: Toggle,
+ ) {
+ if let Some(client) = self.client(window) {
+ self.set_floating_client(client, toggle);
}
}
#[inline]
- pub fn toggle_producing_focus(&mut self) {
- if let Some(focus) = self.focus.get() {
- if let Some(client) = self.client(focus) {
- let must_producing = !client.is_producing();
- client.set_producing(must_producing);
- }
- }
+ fn set_floating_client(
+ &self,
+ client: &Client,
+ toggle: Toggle,
+ ) {
+ info!(
+ "{}floating client with window {:#0x}",
+ if toggle.eval(client.is_floating()) {
+ ""
+ } else {
+ "un"
+ },
+ client.window()
+ );
+
+ let workspace = client.workspace();
+
+ client.set_floating(toggle);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
#[inline]
- pub fn toggle_float_focus(&mut self) {
+ pub fn set_fullscreen_focus(
+ &self,
+ toggle: Toggle,
+ ) {
if let Some(focus) = self.focus.get() {
- self.toggle_float_client(focus);
+ self.set_fullscreen_window(focus, toggle);
}
}
- pub fn toggle_float_client(
- &mut self,
+ #[inline]
+ pub fn set_fullscreen_window(
+ &self,
window: Window,
+ toggle: Toggle,
) {
if let Some(client) = self.client(window) {
- let active_workspace_index = client.workspace();
- let workspace_index = client.workspace();
+ self.set_fullscreen_client(client, toggle);
+ }
+ }
- let client = self.client(window).unwrap();
- let must_float = !client.is_floating();
+ fn set_fullscreen_client(
+ &self,
+ client: &Client,
+ toggle: Toggle,
+ ) {
+ if toggle.eval(client.is_fullscreen()) {
+ self.fullscreen(client);
+ } else {
+ self.unfullscreen(client);
+ }
+ }
- info!(
- "{}floating client with window {:#0x}",
- if must_float { "" } else { "un" },
- client.window()
- );
+ #[inline(always)]
+ fn fullscreen(
+ &self,
+ client: &Client,
+ ) {
+ if client.is_fullscreen() {
+ return;
+ }
- client.set_floating(must_float);
+ let window = client.window();
+ let workspace = client.workspace();
+ info!("enabling fullscreen for client with window {:#0x}", window);
- if active_workspace_index == workspace_index {
- self.apply_layout(workspace_index, true);
- }
- }
- }
+ self.conn
+ .set_window_state(window, WindowState::Fullscreen, true);
- #[inline]
- fn active_partition(&self) -> usize {
- self.partitions.active_index()
- }
+ client.set_fullscreen(Toggle::On);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- #[inline]
- fn active_screen(&self) -> &Screen {
- self.partitions.active_element().unwrap().screen()
+ self.fullscreen_regions
+ .borrow_mut()
+ .insert(window, client.free_region());
}
- #[inline]
- fn active_screen_mut(&mut self) -> &mut Screen {
- self.partitions.active_element_mut().unwrap().screen_mut()
- }
+ #[inline(always)]
+ fn unfullscreen(
+ &self,
+ client: &Client,
+ ) {
+ if !client.is_fullscreen() {
+ return;
+ }
- #[inline]
- pub fn active_workspace(&self) -> usize {
- self.workspaces.active_index()
+ let window = client.window();
+ let workspace = client.workspace();
+ info!("disabling fullscreen for client with window {:#0x}", window);
+
+ if let Some(free_region) = self.fullscreen_regions.borrow().get(&window).cloned() {
+ client.set_region(PlacementClass::Free(free_region));
+ }
+
+ self.conn
+ .set_window_state(window, WindowState::Fullscreen, false);
+
+ client.set_fullscreen(Toggle::Off);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
+
+ self.fullscreen_regions.borrow_mut().remove(&window);
}
- #[inline]
- fn focused_client(&self) -> Option<&Client> {
- self.focus
- .get()
- .or_else(|| self.workspace(self.active_workspace()).focused_client())
- .and_then(|id| self.client_map.get(&id))
+ #[inline(always)]
+ pub fn set_contained_focus(
+ &self,
+ toggle: Toggle,
+ ) {
+ if let Some(focus) = self.focus.get() {
+ self.set_contained_window(focus, toggle);
+ }
}
- #[inline]
- fn focus_window(
+ #[inline(always)]
+ pub fn set_contained_window(
&self,
window: Window,
+ toggle: Toggle,
) {
if let Some(client) = self.client(window) {
- self.focus(client);
+ self.set_contained_client(client, toggle);
}
}
- fn focus(
+ #[inline]
+ fn set_contained_client(
&self,
client: &Client,
+ toggle: Toggle,
) {
- let (window, frame) = client.windows();
+ client.set_contained(toggle);
+ self.set_fullscreen_client(client, Toggle::from(!client.is_contained()));
+ }
- if Some(window) == self.focus.get() {
- return;
+ #[inline(always)]
+ pub fn set_invincible_focus(
+ &self,
+ toggle: Toggle,
+ ) {
+ if let Some(focus) = self.focus.get() {
+ self.set_invincible_window(focus, toggle);
}
+ }
- info!("focusing client with window {:#0x}", window);
-
- let active_workspace_index = self.active_workspace();
- let client = self.client(window);
-
- if !self.is_focusable(window) {
- return;
+ #[inline(always)]
+ pub fn set_invincible_window(
+ &self,
+ window: Window,
+ toggle: Toggle,
+ ) {
+ if let Some(client) = self.client(window) {
+ self.set_invincible_client(client, toggle);
}
+ }
- let client = client.unwrap();
- let client_workspace_index = client.workspace();
- let id = client.zone();
-
- if client_workspace_index != active_workspace_index {
- self.activate_workspace(client_workspace_index);
- }
+ #[inline(always)]
+ fn set_invincible_client(
+ &self,
+ client: &Client,
+ toggle: Toggle,
+ ) {
+ client.set_invincible(toggle);
+ }
- if let Some(prev_focus) = self.focus.get() {
- self.unfocus(prev_focus);
+ #[inline(always)]
+ pub fn set_producing_focus(
+ &self,
+ toggle: Toggle,
+ ) {
+ if let Some(focus) = self.focus.get() {
+ self.set_producing_window(focus, toggle);
}
+ }
- self.conn.ungrab_buttons(frame);
-
+ #[inline(always)]
+ pub fn set_producing_window(
+ &self,
+ window: Window,
+ toggle: Toggle,
+ ) {
if let Some(client) = self.client(window) {
- client.set_focused(true);
- client.set_urgent(false);
+ self.set_producing_client(client, toggle);
}
+ }
- self.zone_manager.activate_zone(id);
- let cycle = self.zone_manager.nearest_cycle(id);
-
- let workspace = self.workspace(client_workspace_index);
- workspace.activate_zone(cycle);
- workspace.focus_client(window);
-
- if self.zone_manager.is_within_persisent(id) {
- self.apply_layout(client_workspace_index, false);
- }
+ #[inline(always)]
+ fn set_producing_client(
+ &self,
+ client: &Client,
+ toggle: Toggle,
+ ) {
+ client.set_producing(toggle);
+ }
- if self.conn.get_focused_window() != window {
- self.conn.focus_window(window);
+ #[inline]
+ pub fn set_iconify_focus(
+ &self,
+ toggle: Toggle,
+ ) {
+ if let Some(focus) = self.focus.get() {
+ self.set_iconify_window(focus, toggle);
}
-
- self.focus.set(Some(window));
- self.redraw_client(window);
- self.apply_stack(client_workspace_index);
}
- fn unfocus(
+ #[inline]
+ pub fn set_iconify_window(
&self,
window: Window,
+ toggle: Toggle,
) {
if let Some(client) = self.client(window) {
- let (window, frame) = client.windows();
- let current_pos = self.conn.get_pointer_position();
-
- info!("unfocusing client with window {:#0x}", window);
-
- self.conn.regrab_buttons(frame);
-
- let client = self.client(window).unwrap();
- client.set_warp_pos(current_pos);
- client.set_focused(false);
- self.redraw_client(window);
+ self.set_iconify_client(client, toggle);
}
}
- fn sync_focus(&self) {
- let workspace_index = self.active_workspace();
- let workspace = self.workspace(workspace_index);
-
- if !workspace.is_empty() {
- if let Some(ws_focus) = workspace.focused_client() {
- if Some(ws_focus) != self.focus.get() {
- self.focus_window(ws_focus);
- }
- }
+ fn set_iconify_client(
+ &self,
+ client: &Client,
+ toggle: Toggle,
+ ) {
+ if toggle.eval(client.is_iconified()) {
+ self.iconify(client);
} else {
- self.conn.unfocus();
- self.focus.set(None);
+ self.deiconify(client);
}
}
- pub fn toggle_fullscreen_focus(&mut self) {
- if let Some(focus) = self.focus.get() {
- self.toggle_fullscreen_client(focus);
+ #[inline]
+ pub fn pop_deiconify(&self) {
+ if let Some(icon) = self.workspaces[self.active_workspace()].focused_icon() {
+ self.set_iconify_window(icon, Toggle::Off);
}
}
- pub fn toggle_fullscreen_client(
- &mut self,
- window: Window,
+ #[inline]
+ pub fn deiconify_all(
+ &self,
+ index: Index,
) {
- if let Some(client) = self.client(window) {
- let must_fullscreen = !client.is_fullscreen();
+ if index >= self.workspaces.len() {
+ warn!(
+ "attempting to deicony_all from nonexistent workspace {}",
+ index
+ );
+ return;
+ }
- if must_fullscreen {
- self.fullscreen(window);
- } else {
- self.unfullscreen(window);
- }
+ let workspace = &self.workspaces[index];
+
+ while let Some(icon) = workspace.focused_icon() {
+ self.set_iconify_window(icon, Toggle::Off);
}
}
- pub fn jump_client(
- &mut self,
- criterium: &JumpCriterium,
+ #[inline(always)]
+ fn iconify(
+ &self,
+ client: &Client,
) {
- let mut window = match criterium {
- JumpCriterium::OnWorkspaceBySelector(index, sel) => {
- let index = *index;
+ if client.is_iconified() {
+ return;
+ }
- if index >= self.workspaces.len() {
- return;
- }
+ let window = client.window();
+ let workspace = client.workspace();
- let workspace = self.workspace(index);
- let window = workspace.get_client_for(sel, &self.zone_manager);
+ info!("iconifying client with window {:#0x}", window);
- if window.is_none() {
- return;
- }
+ self.workspaces[workspace].client_to_icon(window);
- window.unwrap()
- },
- JumpCriterium::ByName(match_method) => {
- let mut clients = self
- .client_map
- .iter()
- .filter(|&(_, client)| {
- client.is_managed() && client.name_matches(*match_method)
- })
- .map(|(_, client)| client)
- .collect::<Vec<&Client>>();
+ self.conn
+ .set_icccm_window_state(window, IcccmWindowState::Iconic);
- clients.sort_by_key(|&c| c.last_focused());
+ client.set_iconified(Toggle::On);
+ self.unmap_client(client);
- if let Some(client) = clients.last() {
- client.window()
- } else {
- return;
- }
- },
- JumpCriterium::ByClass(match_method) => {
- let mut clients = self
- .client_map
- .iter()
- .filter(|&(_, client)| {
- client.is_managed() && client.class_matches(*match_method)
- })
- .map(|(_, client)| client)
- .collect::<Vec<&Client>>();
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- clients.sort_by_key(|&c| c.last_focused());
+ self.sync_focus();
+ }
- if let Some(client) = clients.last() {
- client.window()
- } else {
- return;
- }
- },
- JumpCriterium::ByInstance(match_method) => {
- let mut clients = self
- .client_map
- .iter()
- .filter(|&(_, client)| {
- client.is_managed() && client.instance_matches(*match_method)
- })
- .map(|(_, client)| client)
- .collect::<Vec<&Client>>();
+ #[inline(always)]
+ fn deiconify(
+ &self,
+ client: &Client,
+ ) {
+ if !client.is_iconified() {
+ return;
+ }
- clients.sort_by_key(|&c| c.last_focused());
+ let window = client.window();
+ let workspace = client.workspace();
- if let Some(client) = clients.last() {
- client.window()
- } else {
- return;
- }
- },
- JumpCriterium::ForCond(cond) => {
- let mut clients = self
- .client_map
- .iter()
- .filter(|&(_, client)| client.is_managed() && cond(client))
- .map(|(_, client)| client)
- .collect::<Vec<&Client>>();
+ info!("deiconifying client with window {:#0x}", window);
- clients.sort_by_key(|&c| c.last_focused());
+ self.workspaces[workspace].icon_to_client(window);
- if let Some(client) = clients.last() {
- client.window()
- } else {
- return;
- }
- },
- };
+ self.conn
+ .set_icccm_window_state(window, IcccmWindowState::Normal);
- if let Some(focus) = self.focus.get() {
- if window == focus {
- let jumped_from = self.jumped_from.get();
+ client.set_iconified(Toggle::Off);
+ self.map_client(client);
- if jumped_from.is_none() || jumped_from == Some(focus) {
- return;
- }
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
- if let Some(jumped_from) = jumped_from {
- window = jumped_from;
- }
- }
+ self.sync_focus();
+ }
- self.jumped_from.set(Some(focus));
+ #[inline]
+ pub fn set_stick_focus(
+ &self,
+ toggle: Toggle,
+ ) {
+ if let Some(focus) = self.focus.get() {
+ self.set_stick_window(focus, toggle);
}
-
- info!("jumping to client with window {:#0x}", window);
- self.focus_window(window);
}
- fn fullscreen(
- &mut self,
+ #[inline]
+ pub fn set_stick_window(
+ &self,
window: Window,
+ toggle: Toggle,
) {
if let Some(client) = self.client(window) {
- let free_region = client.free_region();
- let window = client.window();
-
- info!("enabling fullscreen for client with window {:#0x}", window);
-
- self.conn
- .set_window_state(window, WindowState::Fullscreen, true);
- self.fullscreen_regions
- .borrow_mut()
- .insert(window, free_region);
-
- let client = self.client(window).unwrap();
- client.set_fullscreen(true);
-
- let workspace = client.workspace();
- if workspace == self.active_workspace() {
- self.apply_layout(workspace, true);
- }
+ self.set_stick_client(client, toggle);
}
}
- fn unfullscreen(
- &mut self,
- window: Window,
+ fn set_stick_client(
+ &self,
+ client: &Client,
+ toggle: Toggle,
) {
- if let Some(client) = self.client(window) {
- let window = client.window();
- let free_region = self
- .fullscreen_regions
- .borrow()
- .get(&window)
- .map(|®ion| region);
+ if toggle.eval(client.is_sticky()) {
+ self.stick(client);
+ } else {
+ self.unstick(client);
+ }
+ }
- info!("disabling fullscreen for client with window {:#0x}", window);
+ #[inline(always)]
+ fn stick(
+ &self,
+ client: &Client,
+ ) {
+ if client.is_sticky() {
+ return;
+ }
- self.conn
- .set_window_state(window, WindowState::Fullscreen, false);
+ let window = client.window();
+ info!("sticking client with window {:#0x}", window);
- let client = self.client(window).unwrap();
- client.set_fullscreen(false);
+ self.workspaces
+ .iter()
+ .filter(|workspace| workspace.number() as Index != client.workspace())
+ .for_each(|workspace| workspace.add_client(window, &InsertPos::Back));
- if let Some(free_region) = free_region {
- client.set_region(PlacementClass::Free(free_region));
- }
+ self.conn
+ .set_window_state(window, WindowState::Sticky, true);
- let workspace = client.workspace();
+ client.set_sticky(Toggle::On);
+ self.render_decoration(client);
- if workspace == self.active_workspace() {
- self.apply_layout(workspace, true);
- }
+ self.sticky_clients.borrow_mut().insert(window);
+ }
- self.fullscreen_regions.borrow_mut().remove(&window);
+ #[inline(always)]
+ fn unstick(
+ &self,
+ client: &Client,
+ ) {
+ if !client.is_sticky() {
+ return;
}
+
+ let window = client.window();
+ info!("unsticking client with window {:#0x}", window);
+
+ self.workspaces
+ .iter()
+ .filter(|workspace| workspace.number() as Index != client.workspace())
+ .for_each(|workspace| {
+ workspace.remove_client(window);
+ workspace.remove_icon(window);
+ });
+
+ self.conn
+ .set_window_state(window, WindowState::Sticky, false);
+
+ client.set_sticky(Toggle::Off);
+ self.render_decoration(client);
+
+ self.sticky_clients.borrow_mut().remove(&window);
}
- pub fn toggle_stick_focus(&mut self) {
- if let Some(focus) = self.focus.get() {
- if let Some(client) = self.client(focus) {
- if client.is_sticky() {
- self.unstick(focus);
- } else {
- self.stick(focus);
- }
- }
+ #[inline(always)]
+ fn focus_window(
+ &self,
+ window: Window,
+ ) {
+ if let Some(client) = self.client(window) {
+ self.focus(client);
}
}
- fn stick(
+ fn focus(
&self,
- window: Window,
+ client: &Client,
) {
- let client = self.client(window);
+ let (window, frame) = match client.windows() {
+ windows if self.is_focusable(client) && Some(windows.0) != self.focus.get() => windows,
+ _ => return,
+ };
- if client.is_none() {
- return;
+ info!("focusing client with window {:#0x}", window);
+
+ if self.active_workspace() != client.workspace() {
+ self.activate_workspace(client.workspace());
}
- let client = client.unwrap();
- let window = client.window();
- let workspace_index = client.workspace();
+ let workspace = client.workspace();
- info!("enabling sticky for client with window {:#0x}", window);
+ if let Some(prev_focus) = self.focus.get() {
+ self.unfocus_window(prev_focus);
+ }
- client.set_sticky(true);
- self.conn
- .set_window_state(window, WindowState::Sticky, true);
- self.sticky_clients.borrow_mut().insert(window);
+ self.conn.ungrab_buttons(frame);
- for workspace in self.workspaces.iter() {
- if workspace.number() as Index != workspace_index {
- workspace.add_client(window, &InsertPos::Back);
- }
+ if let Some(client) = self.client(window) {
+ client.set_focused(Toggle::On);
+ client.set_urgent(Toggle::Off);
+ }
+
+ let id = client.zone();
+ let cycle = self.zone_manager.nearest_cycle(id);
+ self.zone_manager.activate_zone(id);
+
+ {
+ let workspace = self.workspace(workspace);
+ workspace.activate_zone(cycle);
+ workspace.focus_client(window);
+ }
+
+ if self.zone_manager.is_within_persisent(id) {
+ self.apply_layout(workspace);
+ }
+
+ if self.conn.get_focused_window() != window {
+ self.conn.focus_window(window);
}
- self.redraw_client(window);
+ self.focus.set(Some(window));
+ self.render_decoration(client);
+ self.apply_stack(workspace);
}
- fn unstick(
+ #[inline]
+ fn unfocus_window(
&self,
window: Window,
) {
- let client = self.client(window);
-
- if client.is_none() {
- return;
+ if let Some(client) = self.client(window) {
+ self.unfocus(client);
}
+ }
- let client = client.unwrap();
- let window = client.window();
- let workspace_index = client.workspace();
+ #[inline]
+ fn unfocus(
+ &self,
+ client: &Client,
+ ) {
+ let (window, frame) = client.windows();
+ info!("unfocusing client with window {:#0x}", window);
- info!("disabling sticky for client with window {:#0x}", window);
+ client.set_warp_pos(self.conn.get_pointer_position());
+ client.set_focused(Toggle::Off);
- client.set_sticky(false);
- self.conn
- .set_window_state(window, WindowState::Sticky, false);
+ self.conn.regrab_buttons(frame);
+ self.render_decoration(client);
+ }
- self.sticky_clients.borrow_mut().remove(&window);
+ #[inline(always)]
+ fn sync_focus(&self) {
+ let workspace = self.workspace(self.active_workspace());
- for workspace in self.workspaces.iter() {
- if workspace.number() as Index != workspace_index {
- workspace.remove_client(window);
- workspace.remove_icon(window);
+ match workspace.focused_client() {
+ Some(focus) if Some(focus) != self.focus.get() => {
+ self.focus_window(focus);
+ },
+ _ if workspace.is_empty() => {
+ self.conn.unfocus();
+ self.focus.set(None);
+ },
+ _ => {},
+ }
+ }
+
+ pub fn jump_client(
+ &self,
+ criterium: JumpCriterium,
+ ) {
+ let mut window = match criterium {
+ JumpCriterium::OnWorkspaceBySelector(index, &sel) if index < self.workspaces.len() => {
+ match self.workspaces[index].get_client_for(sel, &self.zone_manager) {
+ Some(window) => window,
+ _ => return,
+ }
+ },
+ JumpCriterium::ByName(method) => {
+ match self
+ .client_map
+ .values()
+ .filter(|&client| client.is_managed() && client.name_matches(method))
+ .max_by_key(|client| client.last_focused())
+ {
+ Some(client) => client.window(),
+ None => return,
+ }
+ },
+ JumpCriterium::ByClass(method) => {
+ match self
+ .client_map
+ .values()
+ .filter(|&client| client.is_managed() && client.class_matches(method))
+ .max_by_key(|client| client.last_focused())
+ {
+ Some(client) => client.window(),
+ None => return,
+ }
+ },
+ JumpCriterium::ByInstance(method) => {
+ match self
+ .client_map
+ .values()
+ .filter(|&client| client.is_managed() && client.instance_matches(method))
+ .max_by_key(|client| client.last_focused())
+ {
+ Some(client) => client.window(),
+ None => return,
+ }
+ },
+ JumpCriterium::ForCond(cond) => {
+ match self
+ .client_map
+ .values()
+ .filter(|&client| client.is_managed() && cond(client))
+ .max_by_key(|client| client.last_focused())
+ {
+ Some(client) => client.window(),
+ None => return,
+ }
+ },
+ _ => return,
+ };
+
+ if let Some(focus) = self.focus.get() {
+ if window == focus {
+ match self.jumped_from.get() {
+ Some(jumped_from) if jumped_from != focus => {
+ window = jumped_from;
+ },
+ _ => {},
+ }
}
+
+ self.jumped_from.set(Some(focus));
}
- self.redraw_client(window);
+ info!("jumping to client with window {:#0x}", window);
+ self.focus_window(window);
}
- pub fn iconify_focus(&mut self) {
+ #[inline(always)]
+ pub fn center_focus(&self) {
if let Some(focus) = self.focus.get() {
- if let Some(client) = self.client(focus) {
- if !client.is_iconified() {
- self.iconify(focus);
- }
- }
+ self.center_window(focus);
}
}
- pub fn pop_deiconify(&mut self) {
- let workspace_index = self.active_workspace();
- let workspace = self.workspace(workspace_index);
-
- if let Some(icon) = workspace.focused_icon() {
- self.deiconify(icon);
+ #[inline(always)]
+ pub fn center_window(
+ &self,
+ window: Window,
+ ) {
+ if let Some(client) = self.client(window) {
+ self.center_client(client);
}
}
- pub fn deiconify_all(
- &mut self,
- index: Index,
+ pub fn center_client(
+ &self,
+ client: &Client,
) {
- if index >= self.workspaces.len() {
- warn!("attempting to deicony_all from nonexistent workspace");
+ if !self.is_free(client) {
return;
}
- let mut workspace = self.workspace(index);
-
- while let Some(icon) = workspace.focused_icon() {
- self.deiconify(icon);
- workspace = self.workspace(index);
- }
- }
+ info!("centering client with window {:#0x}", client.window());
- fn iconify(
- &mut self,
- window: Window,
- ) {
- let client = self.client(window);
+ let mut region = client.free_region();
+ region.pos = self
+ .active_screen()
+ .full_region()
+ .from_absolute_inner_center(region.dim)
+ .pos;
- if client.is_none() {
- return;
- }
+ self.conn.move_window(client.frame(), region.pos);
+ client.set_region(PlacementClass::Free(region));
+ }
- let client = self.client(window).unwrap();
- let window = client.window();
- let workspace_index = client.workspace();
+ pub fn apply_float_retain_region(&mut self) {
+ let workspace = self.active_workspace();
- info!("iconifying client with window {:#0x}", window);
+ self.workspace(workspace)
+ .clients()
+ .into_iter()
+ .map(|window| self.client_unchecked(window))
+ .for_each(|client| client.set_region(PlacementClass::Free(client.active_region())));
- client.set_iconified(true);
- self.unmap_client(client);
- self.conn
- .set_icccm_window_state(window, IcccmWindowState::Iconic);
+ self.set_layout(LayoutKind::Float).ok();
+ self.apply_layout(workspace);
+ }
- let workspace = self.workspace(workspace_index);
- workspace.client_to_icon(window);
- self.sync_focus();
- self.apply_layout(workspace_index, true);
+ #[inline(always)]
+ pub fn snap_focus(
+ &self,
+ edge: Edge,
+ ) {
+ if let Some(focus) = self.focus.get() {
+ self.snap_window(focus, edge);
+ }
}
- fn deiconify(
- &mut self,
+ #[inline(always)]
+ pub fn snap_window(
+ &self,
window: Window,
+ edge: Edge,
) {
- let client = self.client(window);
+ if let Some(client) = self.client(window) {
+ self.snap_client(client, edge);
+ }
+ }
- if client.is_none() {
+ fn snap_client(
+ &self,
+ client: &Client,
+ edge: Edge,
+ ) {
+ if !self.is_free(client) {
return;
}
- let client = self.client(window).unwrap();
let window = client.window();
- let workspace_index = client.workspace();
- info!("deiconifying client with window {:#0x}", window);
+ info!(
+ "snapping client with window {:#0x} to edge {:?}",
+ window, edge
+ );
- client.set_iconified(false);
- self.map_client(client);
- self.conn
- .set_icccm_window_state(window, IcccmWindowState::Normal);
+ let placeable_region = self.active_screen().placeable_region();
+ let mut region = client.free_region();
- let workspace = self.workspace(workspace_index);
- workspace.icon_to_client(window);
- self.sync_focus();
- self.apply_layout(workspace_index, true);
+ match edge {
+ Edge::Left => region.pos.x = placeable_region.pos.x,
+ Edge::Right => {
+ let x = placeable_region.dim.w + placeable_region.pos.x;
+ region.pos.x = std::cmp::max(0, x - region.dim.w)
+ },
+ Edge::Top => region.pos.y = placeable_region.pos.y,
+ Edge::Bottom => {
+ let y = placeable_region.dim.h + placeable_region.pos.y;
+ region.pos.y = std::cmp::max(0, y - region.dim.h)
+ },
+ }
+
+ client.set_region(PlacementClass::Free(region));
+
+ let placement = Placement {
+ method: PlacementMethod::Free,
+ kind: PlacementTarget::Client(window),
+ zone: client.zone(),
+ region: PlacementRegion::FreeRegion,
+ decoration: client.decoration(),
+ };
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
}
- pub fn snap_focus(
- &mut self,
+ #[inline(always)]
+ pub fn nudge_focus(
+ &self,
edge: Edge,
+ step: i32,
) {
if let Some(focus) = self.focus.get() {
- self.snap_client(focus, edge);
+ self.nudge_window(focus, edge, step);
}
}
- fn snap_client(
- &mut self,
+ #[inline(always)]
+ pub fn nudge_window(
+ &self,
window: Window,
edge: Edge,
+ step: i32,
) {
if let Some(client) = self.client(window) {
- if self.is_free(client) {
- let screen = self.active_screen();
- let placeable_region = screen.placeable_region();
- let mut region = client.free_region();
- let window = client.window();
-
- info!(
- "snapping client with window {:#0x} to edge {:?}",
- window, edge
- );
+ self.nudge_client(client, edge, step);
+ }
+ }
- match edge {
- Edge::Left => region.pos.x = placeable_region.pos.x,
- Edge::Right => {
- let x = placeable_region.dim.w as i32 + placeable_region.pos.x;
+ fn nudge_client(
+ &self,
+ client: &Client,
+ edge: Edge,
+ step: i32,
+ ) {
+ if !self.is_free(client) {
+ return;
+ }
- region.pos.x = std::cmp::max(0, x - region.dim.w as i32)
- },
- Edge::Top => region.pos.y = placeable_region.pos.y,
- Edge::Bottom => {
- let y = placeable_region.dim.h as i32 + placeable_region.pos.y;
+ let window = client.window();
- region.pos.y = std::cmp::max(0, y - region.dim.h as i32)
- },
- }
+ info!(
+ "nudging client with window {:#0x} at the {:?} by {}",
+ window, edge, step
+ );
- let placement = Placement {
- method: PlacementMethod::Free,
- kind: PlacementTarget::Client(window),
- zone: client.zone(),
- region: PlacementRegion::NewRegion(region),
- decoration: client.decoration(),
- };
+ let mut region = client.free_region();
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
- }
+ match edge {
+ Edge::Left => region.pos.x -= step,
+ Edge::Right => region.pos.x += step,
+ Edge::Top => region.pos.y -= step,
+ Edge::Bottom => region.pos.y += step,
}
+
+ client.set_region(PlacementClass::Free(region));
+
+ let placement = Placement {
+ method: PlacementMethod::Free,
+ kind: PlacementTarget::Client(window),
+ zone: client.zone(),
+ region: PlacementRegion::FreeRegion,
+ decoration: client.decoration(),
+ };
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
}
- pub fn nudge_focus(
- &mut self,
- edge: Edge,
+ #[inline(always)]
+ pub fn grow_ratio_focus(
+ &self,
step: i32,
) {
if let Some(focus) = self.focus.get() {
- self.nudge_client(focus, edge, step);
+ self.grow_ratio_window(focus, step);
}
}
- fn nudge_client(
- &mut self,
+ #[inline(always)]
+ pub fn grow_ratio_window(
+ &self,
window: Window,
- edge: Edge,
step: i32,
) {
if let Some(client) = self.client(window) {
- if self.is_free(client) {
- let mut region = client.free_region();
- let window = client.window();
+ self.grow_ratio_client(client, step);
+ }
+ }
- info!(
- "nudging client with window {:#0x} at the {:?} by {}",
- window, edge, step
- );
+ fn grow_ratio_client(
+ &self,
+ client: &Client,
+ step: i32,
+ ) {
+ if !self.is_free(client) {
+ return;
+ }
- match edge {
- Edge::Left => region.pos.x -= step,
- Edge::Right => region.pos.x += step,
- Edge::Top => region.pos.y -= step,
- Edge::Bottom => region.pos.y += step,
- }
+ let frame_extents = client.frame_extents();
- let placement = Placement {
- method: PlacementMethod::Free,
- kind: PlacementTarget::Client(window),
- zone: client.zone(),
- region: PlacementRegion::NewRegion(region),
- decoration: client.decoration(),
- };
+ let original_region = client.free_region();
+ let region = original_region;
+ let (width, height) = region.dim.values();
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
- }
+ let fraction = width as f64 / (width + height) as f64;
+ let width_inc = fraction * step as f64;
+ let height_inc = step as f64 - width_inc;
+ let width_inc = width_inc.round() as i32;
+ let height_inc = height_inc.round() as i32;
+
+ let mut region = region.without_extents(frame_extents);
+
+ if (width_inc.is_negative() && -width_inc >= region.dim.w)
+ || (height_inc.is_negative() && -height_inc >= region.dim.h)
+ || (region.dim.w + width_inc <= Client::MIN_CLIENT_DIM.w)
+ || (region.dim.h + height_inc <= Client::MIN_CLIENT_DIM.h)
+ {
+ return;
}
- }
- pub fn grow_ratio_client(
- &mut self,
- window: Window,
- step: i32,
- ) {
- if let Some(client) = self.client(window) {
- if self.is_free(client) {
- let frame_extents = client.frame_extents();
- let original_region = client.free_region();
- let region = original_region;
- let window = client.window();
- let (width, height) = region.dim.values();
-
- let fraction = width as f64 / (width + height) as f64;
- let width_inc = fraction * step as f64;
- let height_inc = step as f64 - width_inc;
- let width_inc = width_inc.round() as i32;
- let height_inc = height_inc.round() as i32;
-
- let mut region = region.without_extents(frame_extents);
-
- if (width_inc.is_negative() && -width_inc >= region.dim.w)
- || (height_inc.is_negative() && -height_inc >= region.dim.h)
- || (region.dim.w + width_inc <= Client::MIN_CLIENT_DIM.w)
- || (region.dim.h + height_inc <= Client::MIN_CLIENT_DIM.h)
- {
- return;
- }
+ let window = client.window();
- info!(
- "{} client with window {:#0x} by {}",
- if step >= 0 { "growing" } else { "shrinking" },
- window,
- step.abs()
- );
+ info!(
+ "{} client with window {:#0x} by {}",
+ if step >= 0 { "growing" } else { "shrinking" },
+ window,
+ step.abs()
+ );
- region.dim.w = region.dim.w + width_inc;
- region.dim.h = region.dim.h + height_inc;
+ region.dim.w += width_inc;
+ region.dim.h += height_inc;
- let mut region = region.with_extents(frame_extents);
- let dx = region.dim.w - original_region.dim.w;
- let dy = region.dim.h - original_region.dim.h;
+ region = region.with_extents(frame_extents);
+ let dx = region.dim.w - original_region.dim.w;
+ let dy = region.dim.h - original_region.dim.h;
- let width_shift = (dx as f64 / 2f64) as i32;
- let height_shift = (dy as f64 / 2f64) as i32;
+ let width_shift = (dx as f64 / 2f64) as i32;
+ let height_shift = (dy as f64 / 2f64) as i32;
- region.pos.x -= width_shift;
- region.pos.y -= height_shift;
+ region.pos.x -= width_shift;
+ region.pos.y -= height_shift;
- let placement = Placement {
- method: PlacementMethod::Free,
- kind: PlacementTarget::Client(window),
- zone: client.zone(),
- region: PlacementRegion::NewRegion(region),
- decoration: client.decoration(),
- };
+ client.set_region(PlacementClass::Free(region));
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
- }
- }
+ let placement = Placement {
+ method: PlacementMethod::Free,
+ kind: PlacementTarget::Client(window),
+ zone: client.zone(),
+ region: PlacementRegion::FreeRegion,
+ decoration: client.decoration(),
+ };
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
}
+ #[inline(always)]
pub fn stretch_focus(
- &mut self,
+ &self,
edge: Edge,
step: i32,
) {
if let Some(focus) = self.focus.get() {
- self.stretch_client(focus, edge, step);
+ self.stretch_window(focus, edge, step);
}
}
- fn stretch_client(
- &mut self,
+ #[inline(always)]
+ pub fn stretch_window(
+ &self,
window: Window,
edge: Edge,
step: i32,
) {
if let Some(client) = self.client(window) {
- if self.is_free(client) {
- let frame_extents = client.frame_extents();
- let window = client.window();
- let mut region = client.free_region().without_extents(frame_extents);
-
- info!(
- "stretching client with window {:#0x} at the {:?} by {}",
- window, edge, step
- );
+ self.stretch_client(client, edge, step);
+ }
+ }
- match edge {
- Edge::Left => {
- if step.is_negative() && -step >= region.dim.w {
- return;
- }
+ fn stretch_client(
+ &self,
+ client: &Client,
+ edge: Edge,
+ step: i32,
+ ) {
+ if !self.is_free(client) {
+ return;
+ }
- if region.dim.w + step <= Client::MIN_CLIENT_DIM.w {
- region.pos.x -= Client::MIN_CLIENT_DIM.w - region.dim.w;
- region.dim.w = Client::MIN_CLIENT_DIM.w;
- } else {
- region.pos.x -= step;
- region.dim.w = region.dim.w + step;
- }
- },
- Edge::Right => {
- if step.is_negative() && -step >= region.dim.w {
- return;
- }
+ let window = client.window();
- if region.dim.w + step <= Client::MIN_CLIENT_DIM.w {
- region.dim.w = Client::MIN_CLIENT_DIM.w;
- } else {
- region.dim.w = region.dim.w + step;
- }
- },
- Edge::Top => {
- if step.is_negative() && -step >= region.dim.h {
- return;
- }
+ info!(
+ "stretching client with window {:#0x} at the {:?} by {}",
+ window, edge, step
+ );
- if region.dim.h + step <= Client::MIN_CLIENT_DIM.h {
- region.pos.y -= Client::MIN_CLIENT_DIM.h - region.dim.h;
- region.dim.h = Client::MIN_CLIENT_DIM.h;
- } else {
- region.pos.y -= step;
- region.dim.h = region.dim.h + step;
- }
- },
- Edge::Bottom => {
- if step.is_negative() && -step >= region.dim.h {
- return;
- }
+ let frame_extents = client.frame_extents();
+ let mut region = client.free_region().without_extents(frame_extents);
- if region.dim.h + step <= Client::MIN_CLIENT_DIM.h {
- region.dim.h = Client::MIN_CLIENT_DIM.h;
- } else {
- region.dim.h = region.dim.h + step;
- }
- },
+ match edge {
+ Edge::Left if !(step.is_negative() && -step >= region.dim.w) => {
+ if region.dim.w + step <= Client::MIN_CLIENT_DIM.w {
+ region.pos.x -= Client::MIN_CLIENT_DIM.w - region.dim.w;
+ region.dim.w = Client::MIN_CLIENT_DIM.w;
+ } else {
+ region.pos.x -= step;
+ region.dim.w += step;
}
-
- let window = client.window();
- let region = region.with_extents(frame_extents);
- let placement = Placement {
- method: PlacementMethod::Free,
- kind: PlacementTarget::Client(window),
- zone: client.zone(),
- region: PlacementRegion::NewRegion(region),
- decoration: client.decoration(),
- };
-
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
- }
+ },
+ Edge::Right if !(step.is_negative() && -step >= region.dim.w) => {
+ if region.dim.w + step <= Client::MIN_CLIENT_DIM.w {
+ region.dim.w = Client::MIN_CLIENT_DIM.w;
+ } else {
+ region.dim.w += step;
+ }
+ },
+ Edge::Top if !(step.is_negative() && -step >= region.dim.h) => {
+ if region.dim.h + step <= Client::MIN_CLIENT_DIM.h {
+ region.pos.y -= Client::MIN_CLIENT_DIM.h - region.dim.h;
+ region.dim.h = Client::MIN_CLIENT_DIM.h;
+ } else {
+ region.pos.y -= step;
+ region.dim.h += step;
+ }
+ },
+ Edge::Bottom if (!step.is_negative() && -step >= region.dim.h) => {
+ if region.dim.h + step <= Client::MIN_CLIENT_DIM.h {
+ region.dim.h = Client::MIN_CLIENT_DIM.h;
+ } else {
+ region.dim.h += step;
+ }
+ },
+ _ => return,
}
+
+ client.set_region(PlacementClass::Free(region.with_extents(frame_extents)));
+
+ let placement = Placement {
+ method: PlacementMethod::Free,
+ kind: PlacementTarget::Client(window),
+ zone: client.zone(),
+ region: PlacementRegion::FreeRegion,
+ decoration: client.decoration(),
+ };
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
}
pub fn start_moving(
&self,
window: Window,
) {
- if !self.move_buffer.is_occupied() && !self.resize_buffer.is_occupied() {
- if let Some(client) = self.client(window) {
- let current_pos = self.conn.get_pointer_position();
- let client_region = client.free_region();
+ if self.move_buffer.is_occupied() || self.resize_buffer.is_occupied() {
+ return;
+ }
- self.move_buffer.set(
- window,
- Grip::Corner(Corner::TopLeft),
- current_pos,
- client_region,
- );
+ if let Some(client) = self.client(window) {
+ self.move_buffer.set(
+ client.window(),
+ Grip::Corner(Corner::TopLeft),
+ self.conn.get_pointer_position(),
+ client.free_region(),
+ );
- self.conn.confine_pointer(self.move_buffer.handle());
- }
+ self.conn.confine_pointer(self.move_buffer.handle());
}
}
+ #[inline(always)]
pub fn stop_moving(&self) {
if self.move_buffer.is_occupied() {
self.conn.release_pointer();
@@ -2561,51 +2468,58 @@ impl<'model> Model<'model> {
}
}
+ #[inline(always)]
pub fn handle_move(
- &mut self,
+ &self,
pos: &Pos,
) {
- if let Some(client) = self.client(self.move_buffer.window().unwrap()) {
- if self.is_free(client) {
- if let Some(grip_pos) = self.move_buffer.grip_pos() {
- if let Some(window_region) = self.move_buffer.window_region() {
- let window = client.window();
- let region = Region {
- pos: window_region.pos + grip_pos.dist(*pos),
- dim: client.free_region().dim,
- };
-
- let placement = Placement {
- method: PlacementMethod::Free,
- kind: PlacementTarget::Client(window),
- zone: client.zone(),
- region: PlacementRegion::NewRegion(region),
- decoration: client.decoration(),
- };
-
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
- }
- }
- }
+ let client = self
+ .move_buffer
+ .window()
+ .and_then(|window| self.client(window))
+ .unwrap();
+
+ if !self.is_free(client) {
+ return;
}
+
+ client.set_region(PlacementClass::Free(Region {
+ pos: self.move_buffer.window_region().unwrap().pos
+ + self.move_buffer.grip_pos().unwrap().dist(*pos),
+ dim: client.free_region().dim,
+ }));
+
+ let placement = Placement {
+ method: PlacementMethod::Free,
+ kind: PlacementTarget::Client(client.window()),
+ zone: client.zone(),
+ region: PlacementRegion::FreeRegion,
+ decoration: client.decoration(),
+ };
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
}
pub fn start_resizing(
&self,
window: Window,
) {
- if !self.move_buffer.is_occupied() && !self.resize_buffer.is_occupied() {
- if let Some(client) = self.client(window) {
- let current_pos = self.conn.get_pointer_position();
- let client_region = client.free_region();
- let corner = client.free_region().nearest_corner(current_pos);
+ if self.move_buffer.is_occupied() || self.resize_buffer.is_occupied() {
+ return;
+ }
- self.resize_buffer
- .set(window, Grip::Corner(corner), current_pos, client_region);
+ if let Some(client) = self.client(window) {
+ let pos = self.conn.get_pointer_position();
- self.conn.confine_pointer(self.resize_buffer.handle());
- }
+ self.resize_buffer.set(
+ client.window(),
+ Grip::Corner(client.free_region().nearest_corner(pos)),
+ pos,
+ client.free_region(),
+ );
+
+ self.conn.confine_pointer(self.resize_buffer.handle());
}
}
@@ -2616,82 +2530,183 @@ impl<'model> Model<'model> {
}
}
+ #[inline(always)]
pub fn handle_resize(
- &mut self,
+ &self,
pos: &Pos,
) {
- let window = self.resize_buffer.window().unwrap();
+ let client = self
+ .resize_buffer
+ .window()
+ .and_then(|window| self.client(window))
+ .unwrap();
- if let Some(client) = self.client(window) {
- if self.is_free(client) {
- let grip_pos = self.resize_buffer.grip_pos().unwrap();
- let window_region = self.resize_buffer.window_region().unwrap();
- let grip = self.resize_buffer.grip().unwrap();
-
- let current_pos = *pos;
- let previous_region = client.previous_region();
- let decoration = client.decoration();
- let (pos, mut dim) = client
- .free_region()
- .without_extents(decoration.extents())
- .values();
-
- let top_grip = grip.is_top_grip();
- let left_grip = grip.is_left_grip();
- let delta = grip_pos.dist(current_pos);
-
- let dest_w = if left_grip {
- window_region.dim.w - delta.dx
- } else {
- window_region.dim.w + delta.dx
- };
+ if !self.is_free(client) {
+ return;
+ }
- let dest_h = if top_grip {
- window_region.dim.h - delta.dy
- } else {
- window_region.dim.h + delta.dy
- };
+ let mut region = client.free_region().without_extents(client.frame_extents());
- dim.w = std::cmp::max(0, dest_w);
- dim.h = std::cmp::max(0, dest_h);
+ let window_region = self.resize_buffer.window_region().unwrap();
+ let grip = self.resize_buffer.grip().unwrap();
- if let Some(size_hints) = client.size_hints() {
- size_hints.apply(&mut dim);
- }
+ let top_grip = grip.is_top_grip();
+ let left_grip = grip.is_left_grip();
+ let delta = self.resize_buffer.grip_pos().unwrap().dist(pos.to_owned());
- let mut region = (Region {
- pos,
- dim,
- })
- .with_extents(decoration.extents());
+ let dest_w = if left_grip {
+ window_region.dim.w - delta.dx
+ } else {
+ window_region.dim.w + delta.dx
+ };
- if top_grip {
- region.pos.y = window_region.pos.y + (window_region.dim.h - region.dim.h);
- }
+ let dest_h = if top_grip {
+ window_region.dim.h - delta.dy
+ } else {
+ window_region.dim.h + delta.dy
+ };
- if left_grip {
- region.pos.x = window_region.pos.x + (window_region.dim.w - region.dim.w);
- }
+ region.dim.w = std::cmp::max(0, dest_w);
+ region.dim.h = std::cmp::max(0, dest_h);
+
+ if let Some(size_hints) = client.size_hints() {
+ size_hints.apply(&mut region.dim);
+ }
+
+ region = region.with_extents(client.frame_extents());
+
+ if top_grip {
+ region.pos.y = window_region.pos.y + (window_region.dim.h - region.dim.h);
+ }
+
+ if left_grip {
+ region.pos.x = window_region.pos.x + (window_region.dim.w - region.dim.w);
+ }
+
+ if region == client.previous_region() {
+ return;
+ }
+
+ let placement = Placement {
+ method: PlacementMethod::Free,
+ kind: PlacementTarget::Client(client.window()),
+ zone: client.zone(),
+ region: PlacementRegion::NewRegion(region),
+ decoration: client.decoration(),
+ };
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
+ }
+
+ pub fn run(
+ &mut self,
+ mut key_bindings: KeyBindings,
+ mut mouse_bindings: MouseBindings,
+ ) {
+ while self.running {
+ if let Some(event) = self.conn.step() {
+ trace!("received event: {:?}", event);
- if region == previous_region {
- return;
+ match event {
+ Event::Mouse {
+ event,
+ } => self.handle_mouse(event, &mut mouse_bindings),
+ Event::Key {
+ key_code,
+ } => self.handle_key(key_code, &mut key_bindings),
+ Event::MapRequest {
+ window,
+ ignore,
+ } => self.handle_map_request(window, ignore),
+ Event::Map {
+ window,
+ ignore,
+ } => self.handle_map(window, ignore),
+ Event::Enter {
+ window,
+ root_rpos,
+ window_rpos,
+ } => self.handle_enter(window, root_rpos, window_rpos),
+ Event::Leave {
+ window,
+ root_rpos,
+ window_rpos,
+ } => self.handle_leave(window, root_rpos, window_rpos),
+ Event::Destroy {
+ window,
+ } => self.handle_destroy(window),
+ Event::Expose {
+ window,
+ } => self.handle_expose(window),
+ Event::Unmap {
+ window,
+ ignore,
+ } => self.handle_unmap(window, ignore),
+ Event::Configure {
+ window,
+ region,
+ on_root,
+ } => self.handle_configure(window, region, on_root),
+ Event::StateRequest {
+ window,
+ state,
+ action,
+ on_root,
+ } => self.handle_state_request(window, state, action, on_root),
+ Event::FocusRequest {
+ window,
+ on_root,
+ } => self.handle_focus_request(window, on_root),
+ Event::CloseRequest {
+ window,
+ on_root,
+ } => self.handle_close_request(window, on_root),
+ Event::WorkspaceRequest {
+ window,
+ index,
+ on_root,
+ } => self.handle_workspace_request(window, index, on_root),
+ Event::PlacementRequest {
+ window,
+ pos,
+ dim,
+ on_root,
+ } => self.handle_placement_request(window, pos, dim, on_root),
+ Event::GripRequest {
+ window,
+ pos,
+ grip,
+ on_root,
+ } => self.handle_grip_request(window, pos, grip, on_root),
+ Event::RestackRequest {
+ window,
+ sibling,
+ mode,
+ on_root,
+ } => self.handle_restack_request(window, sibling, mode, on_root),
+ Event::Property {
+ window,
+ kind,
+ on_root,
+ } => self.handle_property(window, kind, on_root),
+ Event::FrameExtentsRequest {
+ window,
+ on_root,
+ } => self.handle_frame_extents_request(window, on_root),
+ Event::Mapping {
+ request,
+ } => self.handle_mapping(request),
+ Event::ScreenChange => self.handle_screen_change(),
+ Event::Randr => self.handle_randr(),
}
-
- let window = client.window();
- let placement = Placement {
- method: PlacementMethod::Free,
- kind: PlacementTarget::Client(window),
- zone: client.zone(),
- region: PlacementRegion::NewRegion(region),
- decoration,
- };
-
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
}
+
+ self.conn.flush();
}
}
+ #[inline(always)]
fn handle_mouse(
&mut self,
event: MouseEvent,
@@ -2758,7 +2773,7 @@ impl<'model> Model<'model> {
kind: event.kind,
target: EventTarget::Root,
},
- event.shortcut.clone(),
+ event.shortcut,
));
if let Some((action, _)) = binding {
@@ -2805,6 +2820,7 @@ impl<'model> Model<'model> {
}
}
+ #[inline(always)]
fn handle_key(
&mut self,
key_code: KeyCode,
@@ -2816,6 +2832,7 @@ impl<'model> Model<'model> {
}
}
+ #[inline(always)]
fn handle_map_request(
&mut self,
window: Window,
@@ -2823,16 +2840,19 @@ impl<'model> Model<'model> {
) {
debug!("MAP_REQUEST for window {:#0x}", window);
+ let workspace = self.active_workspace();
+
if ignore {
if let Some(struts) = self.conn.get_window_strut(window) {
- let screen = self.active_screen_mut();
+ let screen = self.active_screen();
screen.add_struts(struts);
if !screen.showing_struts() {
self.conn.unmap_window(window);
} else {
screen.compute_placeable_region();
- self.apply_layout(self.active_workspace(), true);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
}
@@ -2840,30 +2860,27 @@ impl<'model> Model<'model> {
let preferred_type = self.conn.get_window_preferred_type(window);
let geometry = self.conn.get_window_geometry(window);
- match (preferred_state, preferred_type) {
+ if let Some(layer) = match (preferred_state, preferred_type) {
(Some(WindowState::Below), _) => Some(StackLayer::Below),
(_, WindowType::Desktop) => Some(StackLayer::Desktop),
(_, WindowType::Dock) => {
if let Ok(geometry) = geometry {
- let screen = self.active_screen_mut();
+ let screen = self.active_screen();
+ let full_region = screen.full_region();
if !screen.contains_window(window) {
let strut = match (
(geometry.pos.x, geometry.pos.y),
(geometry.dim.w, geometry.dim.h),
) {
- ((0, 0), (w, h)) if w == screen.full_region().dim.w => {
- Some((Edge::Top, h))
- },
- ((0, 0), (w, h)) if h == screen.full_region().dim.h => {
- Some((Edge::Left, w))
- },
+ ((0, 0), (w, h)) if w == full_region.dim.w => Some((Edge::Top, h)),
+ ((0, 0), (w, h)) if h == full_region.dim.h => Some((Edge::Left, w)),
((0, 0), (w, h)) if w > h => Some((Edge::Top, h)),
((0, 0), (w, h)) if w < h => Some((Edge::Left, w)),
- ((_, y), (_, h)) if y == screen.full_region().dim.h - h => {
+ ((_, y), (_, h)) if y == full_region.dim.h - h => {
Some((Edge::Bottom, h))
},
- ((x, _), (w, _)) if x == screen.full_region().dim.w - w => {
+ ((x, _), (w, _)) if x == full_region.dim.w - w => {
Some((Edge::Right, w))
},
_ => None,
@@ -2876,7 +2893,8 @@ impl<'model> Model<'model> {
self.conn.unmap_window(window);
} else {
screen.compute_placeable_region();
- self.apply_layout(self.active_workspace(), true);
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
}
}
@@ -2887,8 +2905,9 @@ impl<'model> Model<'model> {
(_, WindowType::Notification) => Some(StackLayer::Notification),
(Some(WindowState::Above), _) => Some(StackLayer::Above),
(..) => None,
- }
- .map(|layer| self.stack_manager.add_window(window, layer));
+ } {
+ self.stack_manager.add_window(window, layer)
+ };
self.apply_stack(self.active_workspace());
}
@@ -2900,102 +2919,78 @@ impl<'model> Model<'model> {
self.manage(window, ignore);
}
+ #[inline]
fn handle_map(
- &mut self,
+ &self,
window: Window,
_ignore: bool,
) {
debug!("MAP for window {:#0x}", window);
}
+ #[inline]
fn handle_enter(
- &mut self,
+ &self,
window: Window,
_root_rpos: Pos,
_window_rpos: Pos,
) {
debug!("ENTER for window {:#0x}", window);
- if let Some(window) = self.window(window) {
+ if let Some(client) = self.client(window) {
if let Some(focus) = self.focus.get() {
- if focus != window {
- self.unfocus(focus);
+ if client.window() != focus {
+ self.unfocus_window(focus);
+ } else {
+ return;
}
}
- self.focus_window(window);
+ self.focus(client);
}
}
+ #[inline]
fn handle_leave(
- &mut self,
+ &self,
window: Window,
_root_rpos: Pos,
_window_rpos: Pos,
) {
debug!("LEAVE for window {:#0x}", window);
- self.unfocus(window);
+ self.unfocus_window(window);
}
+ #[inline]
fn handle_destroy(
&mut self,
window: Window,
) {
debug!("DESTROY for window {:#0x}", window);
- let active_workspace = self.active_workspace();
- let screen = self.active_screen_mut();
+ let screen = self.active_screen();
if screen.has_strut_window(window) {
screen.remove_window_strut(window);
screen.compute_placeable_region();
- self.apply_layout(active_workspace, true);
- }
-
- self.unmanaged_windows.borrow_mut().remove(&window);
- let client = self.client_any(window);
-
- if client.is_none() {
- return;
- }
-
- let client = client.unwrap();
- let is_managed = client.is_managed();
- let (window, frame) = client.windows();
-
- let client = self.client_any(window).unwrap();
- if client.consume_unmap_if_expecting() {
- return;
- }
-
- if !is_managed {
- self.remanage(client, true);
- }
-
- let client = self.client_any(window).unwrap();
- let workspace = client.workspace();
-
- if let Ok(geometry) = self.conn.get_window_geometry(frame) {
- self.conn.unparent_window(window, geometry.pos);
+ let workspace = self.active_workspace();
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
- self.conn.cleanup_window(window);
- self.conn.destroy_window(frame);
-
+ self.unmanaged_windows.borrow_mut().remove(&window);
self.remove_window(window);
-
- if workspace == active_workspace {
- self.apply_layout(workspace, false);
- }
}
+ #[inline]
fn handle_expose(
- &mut self,
+ &self,
_window: Window,
) {
}
+ #[inline]
fn handle_unmap(
&mut self,
window: Window,
@@ -3010,6 +3005,7 @@ impl<'model> Model<'model> {
self.handle_destroy(window);
}
+ #[inline]
fn handle_configure(
&mut self,
window: Window,
@@ -3022,63 +3018,57 @@ impl<'model> Model<'model> {
}
}
+ #[inline]
fn handle_state_request(
- &mut self,
+ &self,
window: Window,
state: WindowState,
action: ToggleAction,
on_root: bool,
) {
+ let client = match self.client_any(window) {
+ Some(client) => client,
+ _ => return,
+ };
+
debug!(
"STATE_REQUEST for window {:#0x}, with state {:?} and action {:?}",
window, state, action
);
- let client = self.client_any(window);
-
- if client.is_none() {
- return;
- }
-
- let client = client.unwrap();
-
match action {
ToggleAction::Add => match state {
- WindowState::Fullscreen => self.fullscreen(window),
- WindowState::Sticky => self.stick(window),
+ WindowState::Fullscreen => self.fullscreen(client),
+ WindowState::Sticky => self.stick(client),
WindowState::DemandsAttention => {
- let hints = Hints {
+ self.conn.set_icccm_window_hints(window, Hints {
urgent: true,
input: None,
initial_state: None,
group: None,
- };
-
- self.conn.set_icccm_window_hints(window, hints);
+ });
if let Some(client) = self.client_any(window) {
- client.set_urgent(true);
- self.redraw_client(window);
+ client.set_urgent(Toggle::On);
+ self.render_decoration(client);
}
},
_ => {},
},
ToggleAction::Remove => match state {
- WindowState::Fullscreen => self.unfullscreen(window),
- WindowState::Sticky => self.unstick(window),
+ WindowState::Fullscreen => self.unfullscreen(client),
+ WindowState::Sticky => self.unstick(client),
WindowState::DemandsAttention => {
- let hints = Hints {
+ self.conn.set_icccm_window_hints(window, Hints {
urgent: false,
input: None,
initial_state: None,
group: None,
- };
-
- self.conn.set_icccm_window_hints(window, hints);
+ });
if let Some(client) = self.client_any(window) {
- client.set_urgent(false);
- self.redraw_client(window);
+ client.set_urgent(Toggle::Off);
+ self.render_decoration(client);
}
},
_ => {},
@@ -3100,8 +3090,9 @@ impl<'model> Model<'model> {
}
}
+ #[inline]
fn handle_focus_request(
- &mut self,
+ &self,
window: Window,
on_root: bool,
) {
@@ -3112,8 +3103,9 @@ impl<'model> Model<'model> {
}
}
+ #[inline]
fn handle_close_request(
- &mut self,
+ &self,
window: Window,
on_root: bool,
) {
@@ -3124,103 +3116,45 @@ impl<'model> Model<'model> {
}
}
+ #[inline]
fn handle_workspace_request(
- &mut self,
- _window: Option<Window>,
+ &self,
+ window: Option<Window>,
index: usize,
on_root: bool,
) {
- debug!("WORKSPACE_REQUEST for workspace {}", index);
+ debug!(
+ "WORKSPACE_REQUEST for workspace {} by window {:?}",
+ index,
+ window.map(|window| format!("{:#0x}", window))
+ );
if on_root {
self.activate_workspace(index);
}
}
+ #[inline]
fn handle_placement_request(
- &mut self,
+ &self,
window: Window,
pos: Option<Pos>,
dim: Option<Dim>,
_on_root: bool,
) {
+ if pos.is_none() && dim.is_none() {
+ return;
+ }
+
debug!(
"PLACEMENT_REQUEST for window {:#0x} with pos {:?} and dim {:?}",
window, pos, dim
);
- if pos.is_some() || dim.is_some() {
- let event_window = window;
-
- if let Some(client) = self.client(window) {
- if self.is_free(client) {
- let window = client.window();
- let frame_extents = client.frame_extents();
-
- let region = if event_window == window {
- Some(Region {
- pos: if let Some(pos) = pos {
- Pos {
- x: pos.x - frame_extents.left as i32,
- y: pos.y - frame_extents.top as i32,
- }
- } else {
- client.free_region().pos
- },
- dim: if let Some(dim) = dim {
- Dim {
- w: dim.w + frame_extents.left + frame_extents.right,
- h: dim.h + frame_extents.top + frame_extents.bottom,
- }
- } else {
- client.free_region().dim
- },
- })
- } else {
- Some(Region {
- pos: if let Some(pos) = pos {
- pos
- } else {
- client.free_region().pos
- },
- dim: if let Some(dim) = dim {
- dim
- } else {
- client.free_region().dim
- },
- })
- }
- .map(|region| {
- if client.size_hints().is_some() {
- region
- .without_extents(frame_extents)
- .with_size_hints(&client.size_hints())
- .with_extents(frame_extents)
- } else {
- region
- .without_extents(frame_extents)
- .with_minimum_dim(&Client::MIN_CLIENT_DIM)
- .with_extents(frame_extents)
- }
- });
-
- if let Some(region) = region {
- let placement = Placement {
- method: PlacementMethod::Free,
- kind: PlacementTarget::Client(window),
- zone: client.zone(),
- region: PlacementRegion::NewRegion(region),
- decoration: client.decoration(),
- };
-
- self.update_client_placement(&placement);
- self.place_client(window, placement.method);
- }
- }
- } else {
- let geometry = self.conn.get_window_geometry(window);
-
- if let Ok(mut geometry) = geometry {
+ let client = match self.client(window) {
+ Some(client) if self.is_free(client) => client,
+ None => {
+ if let Ok(mut geometry) = self.conn.get_window_geometry(window) {
if let Some(pos) = pos {
geometry.pos = pos;
}
@@ -3231,12 +3165,65 @@ impl<'model> Model<'model> {
self.conn.place_window(window, &geometry);
}
- }
+
+ return;
+ },
+ _ => return,
+ };
+
+ let extents = client.frame_extents();
+ let region = if window == client.window() {
+ Some(Region {
+ pos: if let Some(pos) = pos {
+ Pos {
+ x: pos.x - extents.left,
+ y: pos.y - extents.top,
+ }
+ } else {
+ client.free_region().pos
+ },
+ dim: if let Some(dim) = dim {
+ Dim {
+ w: dim.w + extents.left + extents.right,
+ h: dim.h + extents.top + extents.bottom,
+ }
+ } else {
+ client.free_region().dim
+ },
+ })
+ } else {
+ Some(Region {
+ pos: pos.unwrap_or(client.free_region().pos),
+ dim: dim.unwrap_or(client.free_region().dim),
+ })
+ }
+ .map(|region| {
+ region
+ .without_extents(extents)
+ .with_size_hints(&client.size_hints())
+ .with_minimum_dim(&Client::MIN_CLIENT_DIM)
+ .with_extents(extents)
+ });
+
+ if let Some(region) = region {
+ client.set_region(PlacementClass::Free(region));
+
+ let placement = Placement {
+ method: PlacementMethod::Free,
+ kind: PlacementTarget::Client(window),
+ zone: client.zone(),
+ region: PlacementRegion::FreeRegion,
+ decoration: client.decoration(),
+ };
+
+ self.update_client_placement(client, &placement);
+ self.place_client(client, placement.method);
}
}
+ #[inline]
fn handle_grip_request(
- &mut self,
+ &self,
window: Window,
pos: Pos,
grip: Option<Grip>,
@@ -3248,25 +3235,25 @@ impl<'model> Model<'model> {
);
if let Some(grip) = grip {
- // initiate resize from grip
self.move_buffer.unset();
self.resize_buffer.unset();
if let Some(client) = self.client(window) {
- let current_pos = self.conn.get_pointer_position();
- let client_region = client.free_region();
-
- self.resize_buffer
- .set(window, grip, current_pos, client_region);
+ self.resize_buffer.set(
+ client.window(),
+ grip,
+ self.conn.get_pointer_position(),
+ client.free_region(),
+ );
self.conn.confine_pointer(self.resize_buffer.handle());
}
} else {
- // initiate move
self.start_moving(window);
}
}
+ #[inline]
fn handle_restack_request(
&mut self,
window: Window,
@@ -3287,8 +3274,9 @@ impl<'model> Model<'model> {
self.apply_stack(self.active_workspace());
}
+ #[inline]
fn handle_property(
- &mut self,
+ &self,
window: Window,
kind: PropertyKind,
_on_root: bool,
@@ -3297,73 +3285,67 @@ impl<'model> Model<'model> {
match kind {
PropertyKind::Name => {
- let name = self.conn.get_icccm_window_name(window);
-
if let Some(client) = self.client_any(window) {
- client.set_name(name);
+ client.set_name(self.conn.get_icccm_window_name(window));
}
},
PropertyKind::Class => {
- let class = self.conn.get_icccm_window_class(window);
- let instance = self.conn.get_icccm_window_instance(window);
-
if let Some(client) = self.client_any(window) {
- client.set_class(class);
- client.set_instance(instance);
+ client.set_class(self.conn.get_icccm_window_class(window));
+ client.set_instance(self.conn.get_icccm_window_instance(window));
}
},
PropertyKind::Size => {
if let Some(client) = self.client_any(window) {
let window = client.window();
- let workspace = client.workspace();
- let geometry = self.conn.get_window_geometry(window);
- if geometry.is_err() {
- return;
+ let size_hints = self
+ .conn
+ .get_icccm_window_size_hints(
+ window,
+ Some(Client::MIN_CLIENT_DIM),
+ &client.size_hints(),
+ )
+ .1;
+
+ let mut geometry = match self.conn.get_window_geometry(window) {
+ Ok(geometry) => geometry,
+ Err(_) => return,
}
+ .with_size_hints(&size_hints)
+ .with_minimum_dim(&Client::MIN_CLIENT_DIM);
- let frame_extents = client.frame_extents();
- let mut geometry = geometry.unwrap();
- let (_, size_hints) = self.conn.get_icccm_window_size_hints(
- window,
- Some(Client::MIN_CLIENT_DIM),
- &client.size_hints(),
- );
-
- geometry = if size_hints.is_some() {
- geometry.with_size_hints(&size_hints)
- } else {
- geometry.with_minimum_dim(&Client::MIN_CLIENT_DIM)
- };
-
+ let extents = client.frame_extents();
geometry.pos = client.free_region().pos;
- geometry.dim.w += frame_extents.left + frame_extents.right;
- geometry.dim.h += frame_extents.top + frame_extents.bottom;
+ geometry.dim.w += extents.left + extents.right;
+ geometry.dim.h += extents.top + extents.bottom;
- let client = self.client_any(window).unwrap();
client.set_size_hints(size_hints);
client.set_region(PlacementClass::Free(geometry));
- if client.is_managed() && workspace == self.active_workspace() {
- self.apply_layout(workspace, true);
+ if client.is_managed() {
+ let workspace = client.workspace();
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
}
},
PropertyKind::Strut => {
if let Some(struts) = self.conn.get_window_strut(window) {
- // TODO: screen of window
- let screen = self.active_screen_mut();
-
+ let screen = self.active_screen();
screen.remove_window_strut(window);
screen.add_struts(struts);
screen.compute_placeable_region();
- self.apply_layout(self.active_workspace(), true);
+ let workspace = self.active_workspace();
+ self.apply_layout(workspace);
+ self.apply_stack(workspace);
}
},
}
}
+ #[inline]
fn handle_frame_extents_request(
&self,
window: Window,
@@ -3376,30 +3358,25 @@ impl<'model> Model<'model> {
if let Some(client) = self.client_any(window) {
client.frame_extents()
} else {
- if self.conn.must_manage_window(window) {
- Decoration::FREE_DECORATION
- } else {
- Decoration::NO_DECORATION
- }
- .extents()
+ Decoration::NO_DECORATION.extents()
},
);
}
+ #[inline]
fn handle_mapping(
- &mut self,
+ &self,
request: u8,
) {
debug!("MAPPING with request {}", request);
- if self.conn.is_mapping_request(request) {} // TODO
+ if self.conn.is_mapping_request(request) {}
}
#[cold]
- fn handle_screen_change(&mut self) {
+ fn handle_screen_change(&self) {
debug!("SCREEN_CHANGE");
-
- let workspace = self.partitions.active_element().unwrap().screen().number();
- self.workspaces.activate_for(&Selector::AtIndex(workspace));
+ self.workspaces
+ .activate_for(&Selector::AtIndex(self.active_screen().number()));
}
#[cold]
@@ -3410,19 +3387,19 @@ impl<'model> Model<'model> {
#[cold]
pub fn exit(&mut self) {
- info!("exit called, shutting down window manager");
+ info!("exit called, shutting down {}", WM_NAME!());
- for index in 0..self.workspaces.len() {
- self.deiconify_all(index);
- }
+ (0..self.workspaces.len()).for_each(|workspace| {
+ self.deiconify_all(workspace);
+ });
- for (window, client) in self.client_map.drain() {
+ self.client_map.iter().for_each(|(&window, client)| {
self.conn.unparent_window(window, client.free_region().pos);
- }
-
- self.running = false;
+ });
self.conn.cleanup();
self.conn.flush();
+
+ self.running = false;
}
}
diff --git a/src/core/partition.rs b/src/core/partition.rs
@@ -2,6 +2,7 @@ use crate::identify::Ident;
use crate::identify::Identify;
use crate::identify::Index;
+use winsys::geometry::Region;
use winsys::screen::Screen;
#[derive(Clone)]
@@ -21,20 +22,29 @@ impl Partition {
}
}
+ #[inline]
pub fn screen(&self) -> &Screen {
&self.screen
}
- pub fn screen_mut(&mut self) -> &mut Screen {
- &mut self.screen
- }
-
+ #[inline]
pub fn index(&self) -> Index {
self.index
}
+
+ #[inline]
+ pub fn full_region(&self) -> Region {
+ self.screen.full_region()
+ }
+
+ #[inline]
+ pub fn placeable_region(&self) -> Region {
+ self.screen.placeable_region()
+ }
}
impl Identify for Partition {
+ #[inline(always)]
fn id(&self) -> Ident {
self.screen.number() as Ident
}
diff --git a/src/core/rule.rs b/src/core/rule.rs
@@ -1,5 +1,7 @@
+use crate::change::Toggle;
use crate::client::Client;
+#[derive(Debug)]
pub struct Rules {
pub float: Option<bool>,
pub center: Option<bool>,
@@ -11,14 +13,14 @@ pub struct Rules {
impl Rules {
pub fn propagate(
&self,
- client: &mut Client,
+ client: &Client,
) {
if let Some(float) = self.float {
- client.set_floating(float);
+ client.set_floating(Toggle::from(float));
}
if let Some(fullscreen) = self.fullscreen {
- client.set_fullscreen(fullscreen);
+ client.set_fullscreen(Toggle::from(fullscreen));
}
if let Some(workspace) = self.workspace {
@@ -30,40 +32,16 @@ impl Rules {
}
}
- pub fn float(
- &self,
- must_float: &mut bool,
- ) -> bool {
- if let Some(float) = self.float {
- *must_float = float;
- return float;
- }
-
- false
+ pub fn float(&self) -> bool {
+ self.float.map_or(false, |float| float)
}
- pub fn center(
- &self,
- must_center: &mut bool,
- ) -> bool {
- if let Some(center) = self.center {
- *must_center = center;
- return center;
- }
-
- false
+ pub fn center(&self) -> bool {
+ self.center.map_or(false, |center| center)
}
- pub fn fullscreen(
- &self,
- must_fullscreen: &mut bool,
- ) -> bool {
- if let Some(fullscreen) = self.fullscreen {
- *must_fullscreen = fullscreen;
- return fullscreen;
- }
-
- false
+ pub fn fullscreen(&self) -> bool {
+ self.fullscreen.map_or(false, |fullscreen| fullscreen)
}
}
diff --git a/src/core/util.rs b/src/core/util.rs
@@ -1,4 +1,5 @@
use crate::change::Change;
+use crate::change::Direction;
use crate::identify::Index;
use winsys::input::Button;
@@ -57,7 +58,7 @@ impl BuildHasher for BuildIdHasher {
}
}
-pub struct Util {}
+pub struct Util;
impl Util {
#[inline]
@@ -70,6 +71,24 @@ impl Util {
}
#[inline]
+ pub fn next_index(
+ iter: impl ExactSizeIterator,
+ index: Index,
+ dir: Direction,
+ ) -> Index {
+ match dir {
+ Direction::Forward => (index + 1) % iter.len(),
+ Direction::Backward => {
+ if index == 0 {
+ iter.len() - 1
+ } else {
+ index - 1
+ }
+ },
+ }
+ }
+
+ #[inline]
pub fn change_within_range<T>(
min: T,
max: T,
@@ -163,7 +182,7 @@ impl Util {
let mut constituents: Vec<&str> = s.split('-').collect();
match keycodes.get(constituents.remove(constituents.len() - 1)) {
- Some(code) => {
+ Some(&code) => {
let mask = constituents
.iter()
.map(|&modifier| match modifier {
@@ -186,8 +205,8 @@ impl Util {
.fold(0, |acc, modifier| acc | modifier);
Some(KeyCode {
- mask: mask as u16,
- code: *code,
+ mask,
+ code,
})
},
None => None,
diff --git a/src/core/workspace.rs b/src/core/workspace.rs
@@ -71,6 +71,7 @@ impl Buffer {
}
}
+ #[inline(always)]
pub fn set(
&self,
window: Window,
@@ -84,6 +85,7 @@ impl Buffer {
self.window_region.set(Some(region));
}
+ #[inline(always)]
pub fn unset(&self) {
self.window.set(None);
self.grip.set(None);
@@ -91,26 +93,32 @@ impl Buffer {
self.window_region.set(None);
}
+ #[inline(always)]
pub fn is_occupied(&self) -> bool {
self.window.get().is_some()
}
+ #[inline(always)]
pub fn handle(&self) -> Window {
self.handle
}
+ #[inline(always)]
pub fn window(&self) -> Option<Window> {
self.window.get()
}
+ #[inline(always)]
pub fn grip(&self) -> Option<Grip> {
self.grip.get()
}
+ #[inline(always)]
pub fn grip_pos(&self) -> Option<Pos> {
self.grip_pos.get()
}
+ #[inline(always)]
pub fn set_grip_pos(
&self,
pos: Pos,
@@ -118,10 +126,12 @@ impl Buffer {
self.grip_pos.set(Some(pos));
}
+ #[inline(always)]
pub fn window_region(&self) -> Option<Region> {
self.window_region.get()
}
+ #[inline(always)]
pub fn set_window_region(
&self,
region: Region,
@@ -165,22 +175,27 @@ impl Workspace {
}
}
+ #[inline(always)]
pub fn number(&self) -> Ident {
self.number
}
+ #[inline(always)]
pub fn name(&self) -> &str {
&self.name
}
+ #[inline(always)]
pub fn root_zone(&self) -> ZoneId {
self.root_zone
}
+ #[inline(always)]
pub fn len(&self) -> usize {
self.clients.borrow().len()
}
+ #[inline(always)]
pub fn contains(
&self,
window: Window,
@@ -188,10 +203,12 @@ impl Workspace {
self.clients.borrow().contains(&window)
}
+ #[inline(always)]
pub fn is_empty(&self) -> bool {
self.clients.borrow().is_empty()
}
+ #[inline(always)]
pub fn clients(&self) -> Vec<Window> {
self.clients
.borrow()
@@ -200,6 +217,7 @@ impl Workspace {
.collect::<Vec<Window>>()
}
+ #[inline(always)]
pub fn on_each_client<F>(
&self,
client_map: &HashMap<Window, Client, BuildIdHasher>,
@@ -213,6 +231,7 @@ impl Workspace {
.for_each(|window| func(client_map.get(window).unwrap()));
}
+ #[inline(always)]
pub fn on_each_client_mut<F>(
&self,
client_map: &HashMap<Window, Client, BuildIdHasher>,
@@ -226,55 +245,61 @@ impl Workspace {
.for_each(|window| func(client_map.get(window).unwrap()));
}
+ #[inline(always)]
pub fn stack(&self) -> VecDeque<Window> {
self.clients.borrow().stack().clone()
}
+ #[inline(always)]
pub fn stack_after_focus(&self) -> Vec<Window> {
self.clients.borrow().stack_after_focus()
}
+ #[inline(always)]
pub fn active_focus_zone(&self) -> Option<ZoneId> {
self.focus_zones.borrow().active_element().copied()
}
+ #[inline(always)]
pub fn active_spawn_zone(&self) -> Option<ZoneId> {
self.spawn_zones.borrow().active_element().copied()
}
+ #[inline(always)]
pub fn focused_client(&self) -> Option<Window> {
self.clients.borrow().active_element().copied()
}
+ #[inline(always)]
pub fn get_client_for(
&self,
- sel: &ClientSelector,
+ sel: ClientSelector,
zone_manager: &ZoneManager,
) -> Option<Window> {
- let sel = match sel {
- ClientSelector::AtActive => Selector::AtActive,
- ClientSelector::AtMaster => {
- if let Some(&id) = self.focus_zones.borrow().active_element() {
- let cycle = zone_manager.nearest_cycle(id);
- let cycle = zone_manager.zone(cycle);
-
- Selector::AtIndex(std::cmp::min(
- cycle.data().unwrap().main_count as usize,
- self.clients.borrow().len(),
- ))
- } else {
- return None;
- }
- },
- ClientSelector::AtIndex(index) => Selector::AtIndex(*index),
- ClientSelector::AtIdent(window) => Selector::AtIdent(*window as Ident),
- ClientSelector::First => Selector::First,
- ClientSelector::Last => Selector::Last,
- };
-
- self.clients.borrow().get_for(&sel).cloned()
+ self.clients
+ .borrow()
+ .get_for(&match sel {
+ ClientSelector::AtActive => Selector::AtActive,
+ ClientSelector::AtMaster => {
+ self.focus_zones.borrow().active_element().map(|&id| {
+ let cycle = zone_manager.nearest_cycle(id);
+ let cycle = zone_manager.zone(cycle);
+
+ Selector::AtIndex(std::cmp::min(
+ cycle.data().unwrap().main_count as usize,
+ self.clients.borrow().len(),
+ ))
+ })?
+ },
+ ClientSelector::AtIndex(index) => Selector::AtIndex(index),
+ ClientSelector::AtIdent(window) => Selector::AtIdent(window),
+ ClientSelector::First => Selector::First,
+ ClientSelector::Last => Selector::Last,
+ })
+ .cloned()
}
+ #[inline(always)]
pub fn next_client(
&self,
dir: Direction,
@@ -282,6 +307,7 @@ impl Workspace {
self.clients.borrow().next_element(dir).copied()
}
+ #[inline(always)]
pub fn add_zone(
&self,
id: ZoneId,
@@ -291,6 +317,7 @@ impl Workspace {
self.spawn_zones.borrow_mut().insert_at(insert, id);
}
+ #[inline(always)]
pub fn add_client(
&self,
window: Window,
@@ -299,6 +326,7 @@ impl Workspace {
self.clients.borrow_mut().insert_at(insert, window);
}
+ #[inline(always)]
pub fn replace_client(
&self,
window: Window,
@@ -307,44 +335,45 @@ impl Workspace {
self.clients
.borrow_mut()
.remove_for(&Selector::AtIdent(replacement));
+
self.clients
.borrow_mut()
.insert_at(&InsertPos::BeforeIdent(window), replacement);
+
self.clients
.borrow_mut()
.remove_for(&Selector::AtIdent(window));
}
+ #[inline(always)]
pub fn activate_zone(
&self,
id: ZoneId,
) -> Option<ZoneId> {
- let prev_active = match self.focus_zones.borrow().active_element() {
- Some(z) => *z,
- None => return None,
- };
+ let prev_active = self.focus_zones.borrow().active_element()?.to_owned();
self.focus_zones
.borrow_mut()
.activate_for(&Selector::AtIdent(id));
+
Some(prev_active)
}
+ #[inline(always)]
pub fn focus_client(
&self,
window: Window,
) -> Option<Window> {
- let prev_active = match self.clients.borrow().active_element() {
- Some(c) => *c,
- None => return None,
- };
+ let prev_active = self.clients.borrow().active_element()?.to_owned();
self.clients
.borrow_mut()
.activate_for(&Selector::AtIdent(window));
+
Some(prev_active)
}
+ #[inline(always)]
pub fn remove_zone(
&self,
id: ZoneId,
@@ -352,11 +381,13 @@ impl Workspace {
self.focus_zones
.borrow_mut()
.remove_for(&Selector::AtIdent(id));
+
self.spawn_zones
.borrow_mut()
.remove_for(&Selector::AtIdent(id));
}
+ #[inline(always)]
pub fn remove_client(
&self,
window: Window,
@@ -366,6 +397,7 @@ impl Workspace {
.remove_for(&Selector::AtIdent(window))
}
+ #[inline(always)]
pub fn remove_focused_client(&self) -> Option<Window> {
self.clients.borrow_mut().remove_for(&Selector::AtActive)
}
@@ -380,59 +412,59 @@ impl Workspace {
where
F: Fn(&Client) -> bool,
{
- if !self.clients.borrow().is_empty() {
- let zone = zone_manager.zone(self.root_zone);
- zone.set_region(screen_region);
-
- let (to_ignore_ids, to_ignore_clients): (Vec<_>, Vec<_>) = self
- .clients
- .borrow()
- .iter()
- .chain(self.icons.borrow().iter())
- .map(|window| client_map.get(window).unwrap())
- .filter(|&client| ignore_filter(client))
- .map(|client| (client.zone(), client))
- .unzip();
-
- zone_manager
- .arrange(self.root_zone, &to_ignore_ids)
- .into_iter()
- .chain(to_ignore_clients.into_iter().map(|client| {
- let (method, region, decoration) =
- if client.is_fullscreen() && !client.is_in_window() {
- (
- PlacementMethod::Tile,
- PlacementRegion::NewRegion(screen_region),
- Decoration::NO_DECORATION,
- )
- } else if client.is_iconified() {
- (
- PlacementMethod::Tile,
- PlacementRegion::NoRegion,
- Decoration::NO_DECORATION,
- )
- } else {
- (
- PlacementMethod::Free,
- PlacementRegion::FreeRegion,
- Decoration::FREE_DECORATION,
- )
- };
-
- Placement {
- method,
- kind: PlacementTarget::Client(client.window()),
- zone: client.zone(),
- region,
- decoration,
- }
- }))
- .collect()
- } else {
- Vec::with_capacity(0)
+ if self.clients.borrow().is_empty() {
+ return Vec::with_capacity(0);
}
+
+ zone_manager.zone(self.root_zone).set_region(screen_region);
+
+ let (to_ignore_ids, to_ignore_clients): (Vec<_>, Vec<_>) = self
+ .clients
+ .borrow()
+ .iter()
+ .chain(self.icons.borrow().iter())
+ .map(|window| client_map.get(window).unwrap())
+ .filter(|&client| ignore_filter(client))
+ .map(|client| (client.zone(), client))
+ .unzip();
+
+ zone_manager
+ .arrange(self.root_zone, &to_ignore_ids)
+ .into_iter()
+ .chain(to_ignore_clients.into_iter().map(|client| {
+ let (method, region, decoration) =
+ if client.is_fullscreen() && !client.is_contained() {
+ (
+ PlacementMethod::Tile,
+ PlacementRegion::NewRegion(screen_region),
+ Decoration::NO_DECORATION,
+ )
+ } else if client.is_iconified() {
+ (
+ PlacementMethod::Tile,
+ PlacementRegion::NoRegion,
+ Decoration::NO_DECORATION,
+ )
+ } else {
+ (
+ PlacementMethod::Free,
+ PlacementRegion::FreeRegion,
+ Decoration::FREE_DECORATION,
+ )
+ };
+
+ Placement {
+ method,
+ kind: PlacementTarget::Client(client.window()),
+ zone: client.zone(),
+ region,
+ decoration,
+ }
+ }))
+ .collect()
}
+ #[inline(always)]
pub fn cycle_zones(
&self,
dir: Direction,
@@ -442,18 +474,19 @@ impl Workspace {
return None;
}
- let prev_active = *self.spawn_zones.borrow().active_element()?;
- let mut now_active = *self.spawn_zones.borrow_mut().cycle_active(dir)?;
+ let prev_active = self.spawn_zones.borrow().active_element()?.to_owned();
+ let mut now_active = self.spawn_zones.borrow_mut().cycle_active(dir)?.to_owned();
loop {
if zone_manager.is_cycle(now_active) {
return Some((prev_active, now_active));
}
- now_active = *self.spawn_zones.borrow_mut().cycle_active(dir)?;
+ now_active = self.spawn_zones.borrow_mut().cycle_active(dir)?.to_owned();
}
}
+ #[inline(always)]
pub fn cycle_focus(
&self,
dir: Direction,
@@ -464,7 +497,7 @@ impl Workspace {
return None;
}
- let prev_active = *self.clients.borrow().active_element()?;
+ let prev_active = self.clients.borrow().active_element()?.to_owned();
let id = client_map.get(&prev_active).unwrap().zone();
let config = zone_manager.active_layoutconfig(id);
@@ -474,7 +507,7 @@ impl Workspace {
}
}
- let now_active = *self.clients.borrow_mut().cycle_active(dir)?;
+ let now_active = self.clients.borrow_mut().cycle_active(dir)?.to_owned();
if prev_active != now_active {
Some((prev_active, now_active))
@@ -483,6 +516,7 @@ impl Workspace {
}
}
+ #[inline(always)]
pub fn drag_focus(
&self,
dir: Direction,
@@ -490,6 +524,7 @@ impl Workspace {
self.clients.borrow_mut().drag_active(dir).copied()
}
+ #[inline(always)]
pub fn rotate_clients(
&self,
dir: Direction,
@@ -498,9 +533,9 @@ impl Workspace {
return None;
}
- let prev_active = *self.clients.borrow().active_element()?;
+ let prev_active = self.clients.borrow().active_element()?.to_owned();
self.clients.borrow_mut().rotate(dir);
- let now_active = *self.clients.borrow().active_element()?;
+ let now_active = self.clients.borrow().active_element()?.to_owned();
if prev_active != now_active {
Some((prev_active, now_active))
@@ -509,6 +544,7 @@ impl Workspace {
}
}
+ #[inline(always)]
pub fn copy_prev_layout_data(
&self,
zone_manager: &mut ZoneManager,
@@ -519,9 +555,10 @@ impl Workspace {
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
- let prev_data = *zone_manager
+ let prev_data = zone_manager
.active_prev_data(id)
- .ok_or(StateChangeError::EarlyStop)?;
+ .ok_or(StateChangeError::EarlyStop)?
+ .to_owned();
let data = zone_manager
.active_data_mut(id)
@@ -530,6 +567,7 @@ impl Workspace {
Ok(*data = prev_data)
}
+ #[inline(always)]
pub fn reset_layout_data(
&self,
zone_manager: &mut ZoneManager,
@@ -551,6 +589,7 @@ impl Workspace {
Ok(*data = default_data)
}
+ #[inline(always)]
pub fn change_gap_size(
&self,
change: Change<u32>,
@@ -578,6 +617,7 @@ impl Workspace {
Ok(data.gap_size = new_gap_size)
}
+ #[inline(always)]
pub fn reset_gap_size(
&self,
zone_manager: &mut ZoneManager,
@@ -599,6 +639,7 @@ impl Workspace {
Ok(data.gap_size = default_data.gap_size)
}
+ #[inline(always)]
pub fn change_main_count(
&self,
change: Change<u32>,
@@ -626,6 +667,7 @@ impl Workspace {
}
}
+ #[inline(always)]
pub fn change_main_factor(
&self,
change: Change<f32>,
@@ -655,6 +697,7 @@ impl Workspace {
Ok(())
}
+ #[inline(always)]
pub fn change_margin(
&self,
edge: Edge,
@@ -683,7 +726,7 @@ impl Workspace {
Edge::Bottom => (&mut data.margin.bottom, Layout::MAX_MARGIN.bottom),
};
- let edge_changed = *edge_value + delta_change as i32;
+ let edge_changed = *edge_value + delta_change;
let edge_changed = std::cmp::max(edge_changed, 0);
let edge_changed = std::cmp::min(edge_changed, edge_max);
@@ -694,6 +737,7 @@ impl Workspace {
}
}
+ #[inline(always)]
pub fn reset_margin(
&self,
zone_manager: &mut ZoneManager,
@@ -715,10 +759,12 @@ impl Workspace {
Ok(data.margin = default_data.margin)
}
+ #[inline(always)]
pub fn focused_icon(&self) -> Option<Window> {
self.icons.borrow().active_element().copied()
}
+ #[inline(always)]
pub fn icon_to_client(
&self,
window: Window,
@@ -728,6 +774,7 @@ impl Workspace {
}
}
+ #[inline(always)]
pub fn client_to_icon(
&self,
window: Window,
@@ -737,6 +784,7 @@ impl Workspace {
}
}
+ #[inline(always)]
pub fn add_icon(
&self,
window: Window,
@@ -744,6 +792,7 @@ impl Workspace {
self.icons.borrow_mut().insert_at(&InsertPos::Back, window);
}
+ #[inline(always)]
pub fn remove_icon(
&self,
window: Window,
@@ -755,6 +804,7 @@ impl Workspace {
}
impl Identify for Workspace {
+ #[inline(always)]
fn id(&self) -> Ident {
self.number
}
diff --git a/src/core/zone.rs b/src/core/zone.rs
@@ -49,7 +49,7 @@ pub struct Zone {
impl Zone {
fn next_id() -> ZoneId {
- INSTANCE_COUNT.fetch_add(1, atomic::Ordering::Relaxed) as ZoneId
+ INSTANCE_COUNT.fetch_add(1, atomic::Ordering::Relaxed)
}
fn new(
@@ -674,7 +674,7 @@ impl ZoneManager {
}
}
-impl std::cmp::PartialEq<Self> for Zone {
+impl PartialEq<Self> for Zone {
fn eq(
&self,
other: &Self,
@@ -685,6 +685,6 @@ impl std::cmp::PartialEq<Self> for Zone {
impl Identify for Zone {
fn id(&self) -> Ident {
- self.id as Ident
+ self.id
}
}
diff --git a/src/winsys/geometry.rs b/src/winsys/geometry.rs
@@ -77,6 +77,14 @@ impl Pos {
y: self.y - pos.y,
}
}
+
+ pub fn is_origin(&self) -> bool {
+ *self
+ == Pos {
+ x: 0,
+ y: 0,
+ }
+ }
}
impl Add<Pos> for Pos {
@@ -408,14 +416,18 @@ impl Region {
self,
dim: Dim,
) -> Self {
- if dim.w > self.dim.w || dim.h > self.dim.h {
- return self;
- }
-
Self {
pos: Pos {
- x: self.pos.x + ((self.dim.w - dim.w) as f32 / 2f32) as i32,
- y: self.pos.y + ((self.dim.h - dim.h) as f32 / 2f32) as i32,
+ x: if dim.w > self.dim.w {
+ self.pos.x
+ } else {
+ self.pos.x + ((self.dim.w - dim.w) as f32 / 2f32) as i32
+ },
+ y: if dim.h > self.dim.h {
+ self.pos.y
+ } else {
+ self.pos.y + ((self.dim.h - dim.h) as f32 / 2f32) as i32
+ },
},
dim,
}
diff --git a/src/winsys/screen.rs b/src/winsys/screen.rs
@@ -5,20 +5,21 @@ use crate::geometry::Region;
use crate::geometry::Strut;
use crate::window::Window;
-use std::{
- collections::HashMap,
- sync::atomic::{AtomicUsize, Ordering},
- vec::Vec,
-};
+use std::cell::Cell;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+use std::vec::Vec;
#[derive(Debug, Clone)]
pub struct Screen {
- number: usize,
- full_region: Region,
- placeable_region: Region,
- windows: HashMap<Window, Vec<Edge>>,
- struts: HashMap<Edge, Vec<Strut>>,
- showing_struts: bool,
+ number: Cell<usize>,
+ full_region: Cell<Region>,
+ placeable_region: Cell<Region>,
+ windows: RefCell<HashMap<Window, Vec<Edge>>>,
+ struts: RefCell<HashMap<Edge, Vec<Strut>>>,
+ showing_struts: Cell<bool>,
}
impl std::cmp::PartialEq<Self> for Screen {
@@ -36,109 +37,126 @@ impl Screen {
number: usize,
) -> Self {
Screen::init(Self {
- number,
- full_region: region,
- placeable_region: region,
- windows: HashMap::new(),
- struts: HashMap::with_capacity(4),
- showing_struts: true,
+ number: Cell::new(number),
+ full_region: Cell::new(region),
+ placeable_region: Cell::new(region),
+ windows: RefCell::new(HashMap::new()),
+ struts: RefCell::new(HashMap::with_capacity(4)),
+ showing_struts: Cell::new(true),
})
}
- fn init(mut self) -> Self {
- self.struts.insert(Edge::Left, Vec::with_capacity(1));
- self.struts.insert(Edge::Right, Vec::with_capacity(1));
- self.struts.insert(Edge::Top, Vec::with_capacity(1));
- self.struts.insert(Edge::Bottom, Vec::with_capacity(1));
+ fn init(self) -> Self {
+ let mut struts = self.struts.borrow_mut();
+ struts.insert(Edge::Left, Vec::with_capacity(1));
+ struts.insert(Edge::Right, Vec::with_capacity(1));
+ struts.insert(Edge::Top, Vec::with_capacity(1));
+ struts.insert(Edge::Bottom, Vec::with_capacity(1));
+
+ drop(struts);
self
}
+ #[inline]
pub fn showing_struts(&self) -> bool {
- self.showing_struts
+ self.showing_struts.get()
}
+ #[inline]
pub fn number(&self) -> usize {
- self.number
+ self.number.get()
}
+ #[inline]
pub fn set_number(
- &mut self,
+ &self,
number: usize,
) {
- self.number = number
- }
-
- pub fn show_and_yield_struts(&mut self) -> Vec<Window> {
- self.showing_struts = true;
- self.compute_placeable_region();
-
- self.windows.keys().cloned().collect()
+ self.number.set(number)
}
- pub fn hide_and_yield_struts(&mut self) -> Vec<Window> {
- self.showing_struts = false;
+ #[inline]
+ pub fn show_and_yield_struts(
+ &self,
+ show: bool,
+ ) -> Vec<Window> {
+ self.showing_struts.set(show);
self.compute_placeable_region();
- self.windows.keys().cloned().collect()
+ self.windows.borrow().keys().cloned().collect()
}
+ #[inline]
pub fn full_region(&self) -> Region {
- self.full_region
+ self.full_region.get()
}
+ #[inline]
pub fn placeable_region(&self) -> Region {
- self.placeable_region
+ self.placeable_region.get()
}
+ #[inline]
pub fn contains_window(
&self,
window: Window,
) -> bool {
- self.windows.contains_key(&window)
+ self.windows.borrow().contains_key(&window)
}
- pub fn compute_placeable_region(&mut self) {
- let mut region = self.full_region;
+ #[inline]
+ pub fn compute_placeable_region(&self) {
+ let mut region = self.full_region.get();
+
+ if self.showing_struts.get() {
+ let struts = self.struts.borrow();
- if self.showing_struts {
- if let Some(strut) = self.struts.get(&Edge::Left).unwrap().last() {
+ if let Some(strut) = struts.get(&Edge::Left).unwrap().last() {
region.pos.x += strut.width as i32;
region.dim.w -= strut.width as i32;
}
- if let Some(strut) = self.struts.get(&Edge::Right).unwrap().last() {
+ if let Some(strut) = struts.get(&Edge::Right).unwrap().last() {
region.dim.w -= strut.width as i32;
}
- if let Some(strut) = self.struts.get(&Edge::Top).unwrap().last() {
+ if let Some(strut) = struts.get(&Edge::Top).unwrap().last() {
region.pos.y += strut.width as i32;
region.dim.h -= strut.width as i32;
}
- if let Some(strut) = self.struts.get(&Edge::Bottom).unwrap().last() {
+ if let Some(strut) = struts.get(&Edge::Bottom).unwrap().last() {
region.dim.h -= strut.width as i32;
}
}
- self.placeable_region = region;
+ self.placeable_region.set(region);
}
+ #[inline]
pub fn add_strut(
- &mut self,
+ &self,
edge: Edge,
window: Window,
width: u32,
) {
- let strut = self.struts.get_mut(&edge).unwrap();
- let index = strut.binary_search_by(|s| s.width.cmp(&width));
+ let mut struts = self.struts.borrow_mut();
+ let strut = struts.get_mut(&edge).unwrap();
+ let index = strut.binary_search_by(|s| s.width.cmp(&width));
strut.insert(index.unwrap_or_else(|e| e), Strut::new(window, width));
- self.windows.entry(window).or_insert(vec![edge]).push(edge);
+
+ self.windows
+ .borrow_mut()
+ .entry(window)
+ .or_insert(vec![edge])
+ .push(edge);
}
+ #[inline]
pub fn add_struts(
- &mut self,
+ &self,
struts: Vec<Option<Strut>>,
) {
if let Some(left_strut) = struts[0] {
@@ -158,20 +176,22 @@ impl Screen {
}
}
+ #[inline]
pub fn remove_window_strut(
- &mut self,
+ &self,
window: Window,
) {
- for (_, struts) in &mut self.struts {
+ self.struts.borrow_mut().iter_mut().for_each(|(_, struts)| {
// a window may have strut at multiple screen edges
struts.retain(|s| s.window != window);
- }
+ });
- self.windows.remove(&window);
+ self.windows.borrow_mut().remove(&window);
}
+ #[inline]
pub fn update_strut(
- &mut self,
+ &self,
edge: Edge,
window: Window,
width: u32,
@@ -180,82 +200,72 @@ impl Screen {
self.add_strut(edge, window, width);
}
+ #[inline]
pub fn max_strut_val(
&self,
edge: Edge,
) -> Option<u32> {
- match edge {
- Edge::Left => {
- if let Some(strut) = self.struts.get(&Edge::Left).unwrap().last() {
- return Some(strut.width);
- }
- },
- Edge::Right => {
- if let Some(strut) = self.struts.get(&Edge::Right).unwrap().last() {
- return Some(strut.width);
- }
- },
- Edge::Top => {
- if let Some(strut) = self.struts.get(&Edge::Top).unwrap().last() {
- return Some(strut.width);
- }
- },
- Edge::Bottom => {
- if let Some(strut) = self.struts.get(&Edge::Bottom).unwrap().last() {
- return Some(strut.width);
- }
- },
- };
-
- None
+ self.struts
+ .borrow()
+ .get(&edge)
+ .unwrap()
+ .last()
+ .map(|strut| strut.width)
}
+ #[inline]
pub fn has_strut_window(
&self,
window: Window,
) -> bool {
- self.windows.contains_key(&window)
+ self.windows.borrow().contains_key(&window)
}
+ #[inline]
pub fn full_encompasses(
&self,
pos: Pos,
) -> bool {
- self.full_region.encompasses(pos)
+ self.full_region.get().encompasses(pos)
}
+ #[inline]
pub fn placeable_encompasses(
&self,
pos: Pos,
) -> bool {
- self.placeable_region.encompasses(pos)
+ self.placeable_region.get().encompasses(pos)
}
+ #[inline]
pub fn full_contains(
&self,
region: Region,
) -> bool {
- self.full_region.contains(region)
+ self.full_region.get().contains(region)
}
+ #[inline]
pub fn placeable_contains(
&self,
region: Region,
) -> bool {
- self.placeable_region.contains(region)
+ self.placeable_region.get().contains(region)
}
+ #[inline]
pub fn full_occludes(
&self,
region: Region,
) -> bool {
- self.full_region.occludes(region)
+ self.full_region.get().occludes(region)
}
+ #[inline]
pub fn placeable_occludes(
&self,
region: Region,
) -> bool {
- self.placeable_region.occludes(region)
+ self.placeable_region.get().occludes(region)
}
}