commit e2101e4f7f1472c31d871f482ac4275ebec61d7c
parent 7c99b99a80114faf46f4a93b5c3e6cd1099d8e3f
Author: deurzen <m.deurzen@tum.de>
Date: Sat, 20 Mar 2021 02:05:56 +0100
layout handling refactoring
Diffstat:
34 files changed, 3762 insertions(+), 2982 deletions(-)
diff --git a/src/core/binding.rs b/src/core/binding.rs
@@ -1,9 +1,9 @@
use crate::model::Model;
-use winsys::common::Window;
use winsys::input::KeyCode;
use winsys::input::MouseEventKey;
use winsys::input::MouseShortcut;
+use winsys::window::Window;
use std::collections::HashMap;
diff --git a/src/core/change.rs b/src/core/change.rs
@@ -0,0 +1,37 @@
+use crate::decoration::Decoration;
+
+use winsys::geometry::Region;
+
+use std::ops::Add;
+use std::ops::Mul;
+use std::ops::Sub;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Direction {
+ Forward,
+ Backward,
+}
+
+impl Direction {
+ pub fn rev(&self) -> Self {
+ match self {
+ Self::Forward => Self::Backward,
+ Self::Backward => Self::Forward,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Change<T>
+where
+ T: Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
+{
+ Inc(T),
+ Dec(T),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Disposition {
+ Unchanged(Decoration),
+ Changed(Region, Decoration),
+}
diff --git a/src/core/client.rs b/src/core/client.rs
@@ -1,17 +1,19 @@
-use crate::common::Decoration;
-use crate::common::Ident;
-use crate::common::Identify;
+use crate::decoration::Decoration;
+use crate::identify::Ident;
+use crate::identify::Identify;
+use crate::placement::PlacementClass;
use crate::zone::ZoneId;
-use winsys::common::Extents;
-use winsys::common::Hex32;
-use winsys::common::Pid;
-use winsys::common::Pos;
-use winsys::common::Region;
-use winsys::common::SizeHints;
-use winsys::common::Window;
-use winsys::common::WindowType;
+use winsys::connection::Pid;
+use winsys::geometry::Extents;
+use winsys::geometry::Pos;
+use winsys::geometry::Region;
+use winsys::hints::SizeHints;
+use winsys::window::Window;
+use winsys::window::WindowType;
+use std::cell::Ref;
+use std::cell::RefCell;
use std::time::SystemTime;
pub struct Client {
@@ -681,6 +683,17 @@ impl PartialEq for Client {
}
}
+pub struct Hex32(pub u32);
+
+impl std::fmt::Debug for Hex32 {
+ fn fmt(
+ &self,
+ f: &mut std::fmt::Formatter<'_>,
+ ) -> std::fmt::Result {
+ write!(f, "{:#0x}", &self.0)
+ }
+}
+
impl std::fmt::Debug for Client {
fn fmt(
&self,
@@ -735,3 +748,703 @@ impl std::fmt::Debug for Client {
.finish()
}
}
+
+// -----------------------------------------------------------
+
+pub struct Client2 {
+ zone: ZoneId,
+ window: Window,
+ frame: Window,
+ name: RefCell<String>,
+ class: RefCell<String>,
+ instance: RefCell<String>,
+ context: RefCell<usize>,
+ workspace: RefCell<usize>,
+ window_type: WindowType,
+ active_region: RefCell<Region>,
+ previous_region: RefCell<Region>,
+ inner_region: RefCell<Region>,
+ free_region: RefCell<Region>,
+ tile_region: RefCell<Region>,
+ decoration: RefCell<Decoration>,
+ size_hints: RefCell<Option<SizeHints>>,
+ warp_pos: RefCell<Option<Pos>>,
+ parent: Option<Window>,
+ children: RefCell<Vec<Window>>,
+ leader: Option<Window>,
+ producer: Option<Window>,
+ consumers: RefCell<Vec<Window>>,
+ focused: RefCell<bool>,
+ mapped: RefCell<bool>,
+ managed: RefCell<bool>,
+ in_window: RefCell<bool>,
+ floating: RefCell<bool>,
+ fullscreen: RefCell<bool>,
+ iconified: RefCell<bool>,
+ disowned: RefCell<bool>,
+ sticky: RefCell<bool>,
+ invincible: RefCell<bool>,
+ urgent: RefCell<bool>,
+ consuming: RefCell<bool>,
+ producing: RefCell<bool>,
+ pid: Option<Pid>,
+ ppid: Option<Pid>,
+ last_focused: RefCell<SystemTime>,
+ managed_since: SystemTime,
+ expected_unmap_count: RefCell<u8>,
+}
+
+impl<'client> Identify for Client2 {
+ fn id(&self) -> Ident {
+ self.window as Ident
+ }
+}
+
+impl<'client> Client2 {
+ pub fn new(
+ zone: ZoneId,
+ window: Window,
+ frame: Window,
+ name: impl Into<String>,
+ class: impl Into<String>,
+ instance: impl Into<String>,
+ window_type: WindowType,
+ pid: Option<Pid>,
+ ppid: Option<Pid>,
+ ) -> Self {
+ Self {
+ zone,
+ window,
+ frame,
+ name: RefCell::new(name.into()),
+ class: RefCell::new(class.into()),
+ instance: RefCell::new(instance.into()),
+ context: RefCell::new(0),
+ workspace: RefCell::new(0),
+ window_type,
+ active_region: RefCell::new(Default::default()),
+ previous_region: RefCell::new(Default::default()),
+ inner_region: RefCell::new(Default::default()),
+ free_region: RefCell::new(Default::default()),
+ tile_region: RefCell::new(Default::default()),
+ decoration: RefCell::new(Default::default()),
+ size_hints: RefCell::new(None),
+ warp_pos: RefCell::new(None),
+ parent: None,
+ children: RefCell::new(Vec::new()),
+ leader: None,
+ producer: None,
+ consumers: RefCell::new(Vec::new()),
+ focused: RefCell::new(false),
+ mapped: RefCell::new(false),
+ managed: RefCell::new(true),
+ in_window: RefCell::new(false),
+ floating: RefCell::new(false),
+ fullscreen: RefCell::new(false),
+ iconified: RefCell::new(false),
+ disowned: RefCell::new(false),
+ sticky: RefCell::new(false),
+ invincible: RefCell::new(false),
+ urgent: RefCell::new(false),
+ consuming: RefCell::new(false),
+ producing: RefCell::new(true),
+ pid,
+ ppid,
+ last_focused: RefCell::new(SystemTime::now()),
+ managed_since: SystemTime::now(),
+ expected_unmap_count: RefCell::new(0),
+ }
+ }
+
+ #[inline]
+ pub fn zone(&self) -> ZoneId {
+ self.zone
+ }
+
+ #[inline]
+ pub fn windows(&self) -> (Window, Window) {
+ (self.window, self.frame)
+ }
+
+ #[inline]
+ pub fn window(&self) -> Window {
+ self.window
+ }
+
+ #[inline]
+ pub fn frame(&self) -> Window {
+ self.frame
+ }
+
+ #[inline]
+ pub fn name(&'client self) -> Ref<'client, String> {
+ self.name.borrow()
+ }
+
+ #[inline]
+ pub fn set_name(
+ &self,
+ name: impl Into<String>,
+ ) {
+ self.name.replace(name.into());
+ }
+
+ #[inline]
+ pub fn class(&'client self) -> Ref<'client, String> {
+ self.class.borrow()
+ }
+
+ #[inline]
+ pub fn set_class(
+ &self,
+ class: impl Into<String>,
+ ) {
+ self.class.replace(class.into());
+ }
+
+ #[inline]
+ pub fn instance(&'client self) -> Ref<'client, String> {
+ self.instance.borrow()
+ }
+
+ #[inline]
+ pub fn set_instance(
+ &self,
+ instance: impl Into<String>,
+ ) {
+ self.instance.replace(instance.into());
+ }
+
+ #[inline]
+ pub fn context(&self) -> usize {
+ self.context.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_context(
+ &self,
+ context: usize,
+ ) {
+ self.context.replace(context);
+ }
+
+ #[inline]
+ pub fn workspace(&self) -> usize {
+ self.workspace.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_workspace(
+ &self,
+ workspace: usize,
+ ) {
+ self.workspace.replace(workspace);
+ }
+
+ #[inline]
+ pub fn window_type(&self) -> WindowType {
+ self.window_type
+ }
+
+ #[inline]
+ pub fn free_region(&self) -> Region {
+ self.free_region.borrow().clone()
+ }
+
+ #[inline]
+ pub fn tile_region(&self) -> Region {
+ self.tile_region.borrow().clone()
+ }
+
+ #[inline]
+ pub fn active_region(&self) -> Region {
+ self.active_region.borrow().clone()
+ }
+
+ #[inline]
+ pub fn previous_region(&self) -> Region {
+ self.previous_region.borrow().clone()
+ }
+
+ #[inline]
+ pub fn inner_region(&self) -> Region {
+ self.inner_region.borrow().clone()
+ }
+
+ #[inline]
+ fn set_active_region(
+ &self,
+ active_region: Region,
+ ) {
+ self.previous_region
+ .replace(self.active_region.borrow().clone());
+ self.active_region.replace(active_region);
+ self.set_inner_region(active_region);
+ }
+
+ #[inline]
+ fn set_inner_region(
+ &self,
+ active_region: Region,
+ ) {
+ self.inner_region.replace(
+ if let Some(frame) = self.decoration.borrow().clone().frame {
+ let mut inner_region = active_region - frame.extents;
+
+ inner_region.pos.x = frame.extents.left;
+ inner_region.pos.y = frame.extents.top;
+
+ inner_region.dim.w = active_region.dim.w - frame.extents.left - frame.extents.right;
+ inner_region.dim.h = active_region.dim.h - frame.extents.top - frame.extents.bottom;
+
+ inner_region
+ } else {
+ let mut inner_region = active_region;
+
+ inner_region.pos.x = 0;
+ inner_region.pos.y = 0;
+
+ inner_region
+ },
+ );
+ }
+
+ #[inline]
+ pub fn set_region(
+ &self,
+ region: PlacementClass<Region>,
+ ) {
+ match region {
+ PlacementClass::Free(region) => {
+ self.free_region.replace(region);
+ },
+ PlacementClass::Tile(region) => {
+ self.tile_region.replace(region);
+ },
+ }
+ }
+
+ #[inline]
+ pub fn decoration(&self) -> Decoration {
+ self.decoration.borrow().clone()
+ }
+
+ #[inline]
+ pub fn frame_extents(&self) -> Extents {
+ Extents {
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ } + self.decoration.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_decoration(
+ &self,
+ decoration: Decoration,
+ ) {
+ self.decoration.replace(decoration);
+ }
+
+ #[inline]
+ pub fn size_hints(&self) -> Option<SizeHints> {
+ self.size_hints.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_size_hints(
+ &self,
+ size_hints: Option<SizeHints>,
+ ) {
+ self.size_hints.replace(size_hints);
+ }
+
+ #[inline]
+ pub fn warp_pos(&self) -> Option<Pos> {
+ self.warp_pos.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_warp_pos(
+ &self,
+ pointer_pos: Pos,
+ ) {
+ self.warp_pos.replace(Some(pointer_pos));
+ }
+
+ #[inline]
+ pub fn unset_warp_pos(&self) {
+ self.warp_pos.replace(None);
+ }
+
+ #[inline]
+ pub fn set_parent(
+ &mut self,
+ parent: Window,
+ ) {
+ self.parent = Some(parent);
+ }
+
+ #[inline]
+ pub fn parent(&self) -> Option<Window> {
+ self.parent
+ }
+
+ #[inline]
+ pub fn add_child(
+ &self,
+ child: Window,
+ ) {
+ self.children.borrow_mut().push(child);
+ }
+
+ #[inline]
+ pub fn remove_child(
+ &self,
+ child: Window,
+ ) {
+ let mut children = self.children.borrow_mut();
+
+ if let Some(index) = children.iter().rposition(|&c| c == child) {
+ children.remove(index);
+ }
+ }
+
+ #[inline]
+ pub fn set_leader(
+ &mut self,
+ leader: Window,
+ ) {
+ self.leader = Some(leader);
+ }
+
+ #[inline]
+ pub fn leader(&self) -> Option<Window> {
+ self.leader
+ }
+
+ #[inline]
+ pub fn set_producer(
+ &mut self,
+ producer: Window,
+ ) {
+ self.producer = Some(producer);
+ }
+
+ #[inline]
+ pub fn unset_producer(&mut self) {
+ self.producer = None;
+ }
+
+ #[inline]
+ pub fn producer(&self) -> Option<Window> {
+ self.producer
+ }
+
+ #[inline]
+ pub fn consumer_len(&self) -> usize {
+ self.consumers.borrow().len()
+ }
+
+ #[inline]
+ pub fn add_consumer(
+ &self,
+ consumer: Window,
+ ) {
+ self.consumers.borrow_mut().push(consumer);
+ }
+
+ #[inline]
+ pub fn remove_consumer(
+ &self,
+ consumer: Window,
+ ) {
+ let mut consumers = self.consumers.borrow_mut();
+
+ if let Some(index) = consumers.iter().rposition(|&c| c == consumer) {
+ consumers.remove(index);
+ }
+ }
+
+ #[inline]
+ pub fn is_free(&self) -> bool {
+ self.floating.borrow().clone() || self.disowned.borrow().clone() || !self.managed.borrow().clone()
+ }
+
+ #[inline]
+ pub fn is_focused(&self) -> bool {
+ self.focused.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_focused(
+ &self,
+ focused: bool,
+ ) {
+ self.focused.replace(focused);
+ }
+
+ #[inline]
+ pub fn is_mapped(&self) -> bool {
+ self.mapped.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_mapped(
+ &self,
+ mapped: bool,
+ ) {
+ self.mapped.replace(mapped);
+ }
+
+ #[inline]
+ pub fn is_managed(&self) -> bool {
+ self.managed.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_managed(
+ &self,
+ managed: bool,
+ ) {
+ self.managed.replace(managed);
+ }
+
+ #[inline]
+ pub fn is_in_window(&self) -> bool {
+ self.in_window.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_in_window(
+ &self,
+ in_window: bool,
+ ) {
+ self.in_window.replace(in_window);
+ }
+
+ #[inline]
+ pub fn is_floating(&self) -> bool {
+ self.floating.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_floating(
+ &self,
+ floating: bool,
+ ) {
+ self.floating.replace(floating);
+ }
+
+ #[inline]
+ pub fn is_fullscreen(&self) -> bool {
+ self.fullscreen.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_fullscreen(
+ &self,
+ fullscreen: bool,
+ ) {
+ self.fullscreen.replace(fullscreen);
+ }
+
+ #[inline]
+ pub fn is_iconified(&self) -> bool {
+ self.iconified.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_iconified(
+ &self,
+ iconified: bool,
+ ) {
+ self.iconified.replace(iconified);
+ }
+
+ #[inline]
+ pub fn is_disowned(&self) -> bool {
+ self.disowned.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_disowned(
+ &self,
+ disowned: bool,
+ ) {
+ self.disowned.replace(disowned);
+ }
+
+ #[inline]
+ pub fn is_sticky(&self) -> bool {
+ self.sticky.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_sticky(
+ &self,
+ sticky: bool,
+ ) {
+ self.sticky.replace(sticky);
+ }
+
+ #[inline]
+ pub fn is_invincible(&self) -> bool {
+ self.invincible.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_invincible(
+ &self,
+ invincible: bool,
+ ) {
+ self.invincible.replace(invincible);
+ }
+
+ #[inline]
+ pub fn is_urgent(&self) -> bool {
+ self.urgent.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_urgent(
+ &self,
+ urgent: bool,
+ ) {
+ self.urgent.replace(urgent);
+ }
+
+ #[inline]
+ pub fn is_consuming(&self) -> bool {
+ self.consuming.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_consuming(
+ &self,
+ consuming: bool,
+ ) {
+ self.consuming.replace(consuming);
+ }
+
+ #[inline]
+ pub fn is_producing(&self) -> bool {
+ self.producing.borrow().clone()
+ }
+
+ #[inline]
+ pub fn set_producing(
+ &self,
+ producing: bool,
+ ) {
+ self.producing.replace(producing);
+ }
+
+ #[inline]
+ pub fn pid(&self) -> Option<Pid> {
+ self.pid
+ }
+
+ #[inline]
+ pub fn ppid(&self) -> Option<Pid> {
+ self.ppid
+ }
+
+ #[inline]
+ pub fn last_focused(&self) -> SystemTime {
+ self.last_focused.borrow().clone()
+ }
+
+ #[inline]
+ pub fn managed_since(&self) -> SystemTime {
+ self.managed_since
+ }
+
+ #[inline]
+ pub fn expect_unmap(&self) {
+ self.expected_unmap_count.replace(self.expected_unmap_count.borrow().clone() + 1);
+ }
+
+ #[inline]
+ pub fn is_expecting_unmap(&self) -> bool {
+ self.expected_unmap_count.borrow().clone() > 0
+ }
+
+ #[inline]
+ pub fn consume_unmap_if_expecting(&self) -> bool {
+ let expected_unmap_count = self.expected_unmap_count.borrow().clone();
+ let expecting = expected_unmap_count > 0;
+
+ if expecting {
+ self.expected_unmap_count.replace(expected_unmap_count - 1);
+ }
+
+ expecting
+ }
+}
+
+impl<'client> PartialEq for Client2 {
+ fn eq(
+ &self,
+ other: &Self,
+ ) -> bool {
+ self.window == other.window
+ }
+}
+
+impl<'client> std::fmt::Debug for Client2 {
+ fn fmt(
+ &self,
+ f: &mut std::fmt::Formatter<'_>,
+ ) -> std::fmt::Result {
+ f.debug_struct("Client2")
+ .field("window", &Hex32(self.window))
+ .field("frame", &Hex32(self.frame))
+ .field("name", &self.name)
+ .field("class", &self.class)
+ .field("instance", &self.instance)
+ .field("context", &self.context)
+ .field("workspace", &self.workspace)
+ .field("window_type", &self.window_type)
+ .field("active_region", &self.active_region)
+ .field("previous_region", &self.previous_region)
+ .field("inner_region", &self.inner_region)
+ .field("free_region", &self.free_region)
+ .field("tile_region", &self.tile_region)
+ .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(
+ "children",
+ &self
+ .children
+ .borrow()
+ .iter()
+ .map(|&child| Hex32(child))
+ .collect::<Vec<Hex32>>(),
+ )
+ .field("leader", &self.leader)
+ .field("producer", &self.producer)
+ .field("consumers", &self.consumers)
+ .field("focused", &self.focused)
+ .field("mapped", &self.mapped)
+ .field("managed", &self.managed)
+ .field("in_window", &self.in_window)
+ .field("floating", &self.floating)
+ .field("fullscreen", &self.fullscreen)
+ .field("iconified", &self.iconified)
+ .field("disowned", &self.disowned)
+ .field("sticky", &self.sticky)
+ .field("invincible", &self.invincible)
+ .field("urgent", &self.urgent)
+ .field("consuming", &self.consuming)
+ .field("pid", &self.pid)
+ .field("ppid", &self.ppid)
+ .field("last_focused", &self.last_focused)
+ .field("managed_since", &self.managed_since)
+ .field("expected_unmap_count", &self.expected_unmap_count)
+ .finish()
+ }
+}
diff --git a/src/core/common.rs b/src/core/common.rs
@@ -1,213 +0,0 @@
-use winsys::common::Dim;
-use winsys::common::Extents;
-use winsys::common::Padding;
-use winsys::common::Window;
-
-use std::ops::Add;
-
-#[macro_export]
-macro_rules! WM_NAME (
- () => { "wzrd" };
-);
-
-pub const MIN_WINDOW_DIM: Dim = Dim {
- w: 75,
- h: 50,
-};
-
-pub const NO_DECORATION: Decoration = Decoration {
- border: None,
- frame: None,
-};
-
-pub const FREE_DECORATION: Decoration = Decoration {
- border: None,
- frame: Some(Frame {
- extents: Extents {
- left: 3,
- right: 1,
- top: 1,
- bottom: 1,
- },
- colors: ColorScheme::DEFAULT,
- }),
-};
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum StateChangeError {
- EarlyStop,
- LimitReached,
- StateUnchanged,
- InvalidCaller,
-}
-
-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,
-}
-
-impl ColorScheme {
- const DEFAULT: Self = Self {
- regular: 0x333333,
- focused: 0xe78a53,
- urgent: 0xfbcb97,
- rdisowned: 0x999999,
- fdisowned: 0xc1c1c1,
- rsticky: 0x444444,
- fsticky: 0x5f8787,
- };
-}
-
-impl Default for ColorScheme {
- fn default() -> Self {
- Self::DEFAULT
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Border {
- pub width: u32,
- pub colors: ColorScheme,
-}
-
-impl Add<Border> for Padding {
- type Output = Self;
-
- fn add(
- self,
- _: Border,
- ) -> Self::Output {
- Self::Output {
- left: self.left + 1,
- right: self.right + 1,
- top: self.top + 1,
- bottom: self.bottom + 1,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Frame {
- pub extents: Extents,
- pub colors: ColorScheme,
-}
-
-impl Add<Frame> for Padding {
- type Output = Self;
-
- fn add(
- self,
- frame: Frame,
- ) -> Self::Output {
- Self::Output {
- left: self.left + frame.extents.left,
- right: self.right + frame.extents.right,
- top: self.top + frame.extents.top,
- bottom: self.bottom + frame.extents.bottom,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Decoration {
- pub border: Option<Border>,
- pub frame: Option<Frame>,
-}
-
-impl Default for Decoration {
- fn default() -> Self {
- Self {
- border: None,
- frame: None,
- }
- }
-}
-
-impl Decoration {
- pub fn extents(&self) -> Extents {
- Extents {
- left: 0,
- right: 0,
- top: 0,
- bottom: 0,
- } + *self
- }
-}
-
-impl Add<Decoration> for Padding {
- type Output = Self;
-
- fn add(
- mut self,
- decoration: Decoration,
- ) -> Self::Output {
- if let Some(border) = decoration.border {
- self = self + border;
- }
-
- if let Some(frame) = decoration.frame {
- self = self + frame;
- }
-
- self
- }
-}
-
-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
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum Direction {
- Forward,
- Backward,
-}
-
-impl Direction {
- pub fn rev(&self) -> Self {
- match self {
- Self::Forward => Self::Backward,
- Self::Backward => Self::Forward,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum Change {
- Inc,
- Dec,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum BorderState {
- Urgent,
- Focused,
- Unfocused,
- Disowned,
- Sticky,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct BorderSize {
- pub left: u32,
- pub right: u32,
- pub top: u32,
- pub bottom: u32,
-}
diff --git a/src/core/consume.rs b/src/core/consume.rs
@@ -1,6 +1,7 @@
use crate::client::Client;
-use winsys::common::Pid;
-use winsys::common::Window;
+
+use winsys::connection::Pid;
+use winsys::window::Window;
use std::collections::HashMap;
use std::fs;
diff --git a/src/core/cycle.rs b/src/core/cycle.rs
@@ -1,7 +1,7 @@
-use crate::common::Direction;
-use crate::common::Ident;
-use crate::common::Identify;
-use crate::common::Index;
+use crate::change::Direction;
+use crate::identify::Ident;
+use crate::identify::Identify;
+use crate::identify::Index;
use crate::util::BuildIdHasher;
use crate::util::Util;
diff --git a/src/core/decoration.rs b/src/core/decoration.rs
@@ -0,0 +1,124 @@
+use winsys::geometry::Extents;
+use winsys::geometry::Padding;
+
+use std::ops::Add;
+
+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,
+}
+
+impl ColorScheme {
+ pub const DEFAULT: Self = Self {
+ regular: 0x333333,
+ focused: 0xe78a53,
+ urgent: 0xfbcb97,
+ rdisowned: 0x999999,
+ fdisowned: 0xc1c1c1,
+ rsticky: 0x444444,
+ fsticky: 0x5f8787,
+ };
+}
+
+impl Default for ColorScheme {
+ fn default() -> Self {
+ Self::DEFAULT
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Border {
+ pub width: u32,
+ pub colors: ColorScheme,
+}
+
+impl Add<Border> for Padding {
+ type Output = Self;
+
+ fn add(
+ self,
+ _: Border,
+ ) -> Self::Output {
+ Self::Output {
+ left: self.left + 1,
+ right: self.right + 1,
+ top: self.top + 1,
+ bottom: self.bottom + 1,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Frame {
+ pub extents: Extents,
+ pub colors: ColorScheme,
+}
+
+impl Add<Frame> for Padding {
+ type Output = Self;
+
+ fn add(
+ self,
+ frame: Frame,
+ ) -> Self::Output {
+ Self::Output {
+ left: self.left + frame.extents.left,
+ right: self.right + frame.extents.right,
+ top: self.top + frame.extents.top,
+ bottom: self.bottom + frame.extents.bottom,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Decoration {
+ pub border: Option<Border>,
+ pub frame: Option<Frame>,
+}
+
+impl Default for Decoration {
+ fn default() -> Self {
+ Self {
+ border: None,
+ frame: None,
+ }
+ }
+}
+
+impl Decoration {
+ pub fn extents(&self) -> Extents {
+ Extents {
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ } + *self
+ }
+}
+
+impl Add<Decoration> for Padding {
+ type Output = Self;
+
+ fn add(
+ mut self,
+ decoration: Decoration,
+ ) -> Self::Output {
+ if let Some(border) = decoration.border {
+ self = self + border;
+ }
+
+ if let Some(frame) = decoration.frame {
+ self = self + frame;
+ }
+
+ self
+ }
+}
diff --git a/src/core/defaults.rs b/src/core/defaults.rs
@@ -0,0 +1,65 @@
+use crate::client::Client;
+use crate::decoration::ColorScheme;
+use crate::decoration::Decoration;
+use crate::decoration::Frame;
+use crate::layout::Layout;
+use crate::zone::Zone;
+
+use winsys::geometry::Dim;
+use winsys::geometry::Extents;
+use winsys::geometry::Padding;
+
+#[macro_export]
+macro_rules! WM_NAME (
+ () => { "wzrd" };
+);
+
+impl Client {
+ pub const MIN_CLIENT_DIM: Dim = Dim {
+ w: 75,
+ h: 50,
+ };
+
+ pub const PREFERRED_CLIENT_DIM: Dim = Dim {
+ w: 480,
+ h: 260,
+ };
+}
+
+impl Decoration {
+ pub const NO_DECORATION: Self = Self {
+ border: None,
+ frame: None,
+ };
+
+ pub const FREE_DECORATION: Self = Self {
+ border: None,
+ frame: Some(Frame {
+ extents: Extents {
+ left: 3,
+ right: 1,
+ top: 1,
+ bottom: 1,
+ },
+ colors: ColorScheme::DEFAULT,
+ }),
+ };
+}
+
+impl Layout {
+ pub const MAX_MAIN_COUNT: u32 = 15;
+ pub const MAX_GAP_SIZE: u32 = 300;
+ pub const MAX_MARGIN: Padding = Padding {
+ left: 700,
+ right: 700,
+ top: 400,
+ bottom: 400,
+ };
+}
+
+impl Zone {
+ pub const MIN_ZONE_DIM: Dim = Dim {
+ w: 25,
+ h: 25,
+ };
+}
diff --git a/src/core/error.rs b/src/core/error.rs
@@ -0,0 +1,7 @@
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum StateChangeError {
+ EarlyStop,
+ LimitReached,
+ StateUnchanged,
+ InvalidCaller,
+}
diff --git a/src/core/identify.rs b/src/core/identify.rs
@@ -0,0 +1,14 @@
+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/jump.rs b/src/core/jump.rs
@@ -1,5 +1,5 @@
use crate::client::Client;
-use crate::common::Index;
+use crate::identify::Index;
use crate::workspace::ClientSelector;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
diff --git a/src/core/layout.rs b/src/core/layout.rs
@@ -0,0 +1,955 @@
+use crate::change::Disposition;
+use crate::decoration::Decoration;
+use crate::decoration::Frame;
+use crate::error::StateChangeError;
+use crate::identify::Ident;
+use crate::identify::Identify;
+use crate::placement::PlacementMethod;
+use crate::zone::Zone;
+
+use winsys::geometry::Dim;
+use winsys::geometry::Extents;
+use winsys::geometry::Padding;
+use winsys::geometry::Pos;
+use winsys::geometry::Region;
+
+use strum::EnumCount;
+use strum::IntoEnumIterator;
+use strum_macros::EnumIter;
+use strum_macros::ToString;
+
+use std::collections::HashMap;
+use std::string::ToString;
+use std::vec::Vec;
+
+type LayoutFn = fn(&Region, &LayoutData, Vec<bool>) -> Vec<(Disposition, bool)>;
+
+#[non_exhaustive]
+#[derive(Debug, PartialEq, Clone, Copy)]
+pub struct LayoutConfig {
+ pub method: PlacementMethod,
+ pub decoration: Decoration,
+ pub root_only: bool,
+ pub margin: bool,
+ pub gap: bool,
+ pub persistent: bool,
+ pub single: bool,
+ pub wraps: bool,
+}
+
+impl Default for LayoutConfig {
+ fn default() -> Self {
+ Self {
+ method: PlacementMethod::Free,
+ decoration: Default::default(),
+ root_only: true,
+ margin: false,
+ gap: false,
+ persistent: false,
+ single: false,
+ wraps: true,
+ }
+ }
+}
+
+#[non_exhaustive]
+#[derive(Debug, PartialEq, Clone, Copy)]
+pub struct LayoutData {
+ /// Generic layout data
+ pub margin: Padding,
+ pub gap_size: u32,
+
+ /// Tiled layout data
+ pub main_count: u32,
+ pub main_factor: f32,
+}
+
+impl Default for LayoutData {
+ fn default() -> Self {
+ Self {
+ margin: Default::default(),
+ gap_size: 0u32,
+
+ main_count: 1u32,
+ main_factor: 0.50f32,
+ }
+ }
+}
+
+#[non_exhaustive]
+#[repr(u8)]
+#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, EnumIter, EnumCount, ToString)]
+pub enum LayoutKind {
+ /// Free layouts
+ Float = b'f',
+ BLFloat = b'F',
+ SingleFloat = b'z',
+ BLSingleFloat = b'Z',
+
+ /// Tiled layouts
+ // Overlapping
+ Center = b';',
+ Monocle = b'%',
+ // Non-overlapping
+ Paper = b'p',
+ SPaper = b'P',
+ Stack = b's',
+ SStack = b'S',
+ BStack = b'b',
+ SBStack = b'B',
+ Horz = b'h',
+ SHorz = b'H',
+ Vert = b'v',
+ SVert = b'V',
+}
+
+impl LayoutKind {
+ pub fn symbol(&self) -> char {
+ (*self as u8) as char
+ }
+
+ pub fn name(&self) -> String {
+ self.to_string()
+ }
+
+ pub fn config(&self) -> LayoutConfig {
+ match *self {
+ LayoutKind::Float => LayoutConfig {
+ method: PlacementMethod::Free,
+ decoration: Decoration::FREE_DECORATION,
+ root_only: true,
+ margin: false,
+ gap: false,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::BLFloat => LayoutConfig {
+ method: PlacementMethod::Free,
+ decoration: Decoration::NO_DECORATION,
+ root_only: true,
+ margin: false,
+ gap: false,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::SingleFloat => LayoutConfig {
+ method: PlacementMethod::Free,
+ decoration: Decoration::FREE_DECORATION,
+ root_only: true,
+ margin: false,
+ gap: false,
+ persistent: true,
+ single: true,
+ wraps: true,
+ },
+ LayoutKind::BLSingleFloat => LayoutConfig {
+ method: PlacementMethod::Free,
+ decoration: Decoration::NO_DECORATION,
+ root_only: true,
+ margin: false,
+ gap: false,
+ persistent: true,
+ single: true,
+ wraps: true,
+ },
+ LayoutKind::Center => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration::NO_DECORATION,
+ root_only: false,
+ margin: true,
+ gap: true,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::Monocle => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration::NO_DECORATION,
+ root_only: false,
+ margin: true,
+ gap: true,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::Paper => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 1,
+ right: 1,
+ top: 0,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: true,
+ persistent: true,
+ single: false,
+ wraps: false,
+ },
+ LayoutKind::SPaper => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 1,
+ right: 1,
+ top: 0,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: false,
+ persistent: true,
+ single: false,
+ wraps: false,
+ },
+ LayoutKind::Stack => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: true,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::SStack => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: false,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::BStack => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: true,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::SBStack => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: false,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::Horz => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: true,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::SHorz => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: false,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::Vert => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: true,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+ LayoutKind::SVert => LayoutConfig {
+ method: PlacementMethod::Tile,
+ decoration: Decoration {
+ frame: Some(Frame {
+ extents: Extents {
+ left: 0,
+ right: 0,
+ top: 3,
+ bottom: 0,
+ },
+ colors: Default::default(),
+ }),
+ border: None,
+ },
+ root_only: false,
+ margin: true,
+ gap: false,
+ persistent: false,
+ single: false,
+ wraps: true,
+ },
+
+ #[allow(unreachable_patterns)]
+ _ => unimplemented!("{:?} does not have an associated configuration", self),
+ }
+ }
+
+ fn default_data(&self) -> LayoutData {
+ match *self {
+ LayoutKind::Float => Default::default(),
+ LayoutKind::BLFloat => Default::default(),
+ LayoutKind::SingleFloat => Default::default(),
+ LayoutKind::BLSingleFloat => Default::default(),
+ LayoutKind::Center => LayoutData {
+ main_count: 5u32,
+ main_factor: 0.40f32,
+ ..Default::default()
+ },
+ LayoutKind::Monocle => Default::default(),
+ LayoutKind::Paper => Default::default(),
+ LayoutKind::SPaper => Default::default(),
+ LayoutKind::Stack => LayoutData {
+ main_count: 1u32,
+ main_factor: 0.50f32,
+ ..Default::default()
+ },
+ LayoutKind::SStack => LayoutData {
+ main_count: 1u32,
+ main_factor: 0.50f32,
+ ..Default::default()
+ },
+ LayoutKind::BStack => LayoutData {
+ main_count: 1u32,
+ main_factor: 0.50f32,
+ ..Default::default()
+ },
+ LayoutKind::SBStack => LayoutData {
+ main_count: 1u32,
+ main_factor: 0.50f32,
+ ..Default::default()
+ },
+ LayoutKind::Horz => Default::default(),
+ LayoutKind::SHorz => Default::default(),
+ LayoutKind::Vert => Default::default(),
+ LayoutKind::SVert => Default::default(),
+
+ #[allow(unreachable_patterns)]
+ _ => unimplemented!("{:?} does not have associated default data", self),
+ }
+ }
+
+ #[inline]
+ fn stack_split(
+ n: usize,
+ n_main: u32,
+ ) -> (i32, i32) {
+ let n_main = n_main as i32;
+ let n = n as i32;
+
+ if n <= n_main {
+ (n, 0i32)
+ } else {
+ (n_main, n - n_main)
+ }
+ }
+
+ fn func(&self) -> LayoutFn {
+ match *self {
+ LayoutKind::Float => |_, _, active_map| {
+ let config = &LayoutKind::Float.config();
+ vec![(Disposition::Unchanged(config.decoration), true); active_map.len()]
+ },
+ LayoutKind::BLFloat => |_, _, active_map| {
+ let config = &LayoutKind::BLFloat.config();
+ vec![(Disposition::Unchanged(config.decoration), true); active_map.len()]
+ },
+ LayoutKind::SingleFloat => |_, _, active_map| {
+ let config = &LayoutKind::SingleFloat.config();
+ active_map
+ .into_iter()
+ .map(|b| (Disposition::Unchanged(config.decoration), b))
+ .collect()
+ },
+ LayoutKind::BLSingleFloat => |_, _, active_map| {
+ let config = &LayoutKind::BLSingleFloat.config();
+ active_map
+ .into_iter()
+ .map(|b| (Disposition::Unchanged(config.decoration), b))
+ .collect()
+ },
+ LayoutKind::Center => |region, data, active_map| {
+ let config = &LayoutKind::Center.config();
+ let (pos, dim) = region.values();
+
+ let h_comp = Layout::MAX_MAIN_COUNT + 1;
+ let w_ratio: f32 = data.main_factor / 0.95;
+ let h_ratio: f32 = (h_comp - data.main_count) as f32 / h_comp as f32;
+
+ active_map
+ .into_iter()
+ .map(|_| {
+ (
+ Disposition::Changed(
+ Region {
+ pos,
+ dim,
+ }
+ .from_absolute_inner_center(&Dim {
+ w: (dim.w as f32 * w_ratio) as i32,
+ h: (dim.h as f32 * h_ratio) as i32,
+ }),
+ config.decoration,
+ ),
+ true,
+ )
+ })
+ .collect()
+ },
+ LayoutKind::Monocle => |region, _, active_map| {
+ let config = &LayoutKind::Monocle.config();
+ let (pos, dim) = region.values();
+
+ active_map
+ .into_iter()
+ .map(|_| {
+ (
+ Disposition::Changed(
+ Region {
+ pos,
+ dim,
+ },
+ config.decoration,
+ ),
+ true,
+ )
+ })
+ .collect()
+ },
+ LayoutKind::Paper => |region, data, active_map| {
+ const MIN_W_RATIO: f32 = 0.5;
+
+ let config = &LayoutKind::Paper.config();
+ let (pos, dim) = region.values();
+ let n = active_map.len();
+
+ if n == 1 {
+ return vec![(
+ Disposition::Changed(*region, Decoration::NO_DECORATION),
+ true,
+ )];
+ }
+
+ let cw = (dim.w as f32
+ * if data.main_factor > MIN_W_RATIO {
+ data.main_factor
+ } else {
+ MIN_W_RATIO
+ }) as i32;
+
+ let w = ((dim.w - cw) as usize / (n - 1)) as i32;
+ let mut after_active = false;
+
+ active_map
+ .into_iter()
+ .enumerate()
+ .map(|(i, active)| {
+ let i = i as i32;
+
+ (
+ Disposition::Changed(
+ if active {
+ after_active = true;
+ Region::new(pos.x + i * w, pos.y, cw, dim.h)
+ } else {
+ let mut x = pos.x + i * w;
+
+ if after_active {
+ x += cw - w;
+ }
+
+ Region::new(x, pos.y, w, dim.h)
+ },
+ config.decoration,
+ ),
+ true,
+ )
+ })
+ .collect()
+ },
+ LayoutKind::SPaper => |region, data, active_map| {
+ let mut region = region.clone();
+ Layout::adjust_for_gap_size(&mut region, data.gap_size, &Zone::MIN_ZONE_DIM);
+
+ (Self::Paper.func())(®ion, data, active_map)
+ },
+ LayoutKind::Stack => |region, data, active_map| {
+ let (pos, dim) = region.values();
+ let n = active_map.len();
+
+ if n == 1 {
+ return vec![(
+ Disposition::Changed(*region, Decoration::NO_DECORATION),
+ true,
+ )];
+ }
+
+ let (n_main, n_stack) = Self::stack_split(n, data.main_count);
+ let h_stack = if n_stack > 0 { dim.h / n_stack } else { 0 };
+ let h_main = if n_main > 0 { dim.h / n_main } else { 0 };
+
+ let div = if data.main_count > 0 {
+ (dim.w as f32 * data.main_factor) as i32
+ } else {
+ 0
+ };
+
+ let config = &LayoutKind::Stack.config();
+ let main_count = data.main_count as i32;
+
+ active_map
+ .into_iter()
+ .enumerate()
+ .map(|(i, _)| {
+ let i = i as i32;
+
+ (
+ Disposition::Changed(
+ if i < main_count {
+ Region::new(
+ pos.x,
+ pos.y + (i * h_main),
+ if n_stack == 0 { dim.w } else { div },
+ h_main,
+ )
+ } else {
+ Region::new(
+ pos.x + div,
+ pos.y + (i - main_count) * h_stack,
+ dim.w - div,
+ h_stack,
+ )
+ },
+ config.decoration,
+ ),
+ true,
+ )
+ })
+ .collect()
+ },
+ LayoutKind::SStack => |region, data, active_map| {
+ let mut region = region.clone();
+ Layout::adjust_for_gap_size(&mut region, data.gap_size, &Zone::MIN_ZONE_DIM);
+
+ (Self::Stack.func())(®ion, data, active_map)
+ },
+ LayoutKind::BStack => |region, data, active_map| {
+ let (pos, dim) = region.values();
+ let n = active_map.len();
+
+ if n == 1 {
+ return vec![(
+ Disposition::Changed(*region, Decoration::NO_DECORATION),
+ true,
+ )];
+ }
+
+ let (n_main, n_stack) = Self::stack_split(n, data.main_count);
+
+ let div = if data.main_count > 0 {
+ (dim.w as f32 * data.main_factor) as i32
+ } else {
+ 0
+ };
+
+ let h_main = if n_main > 0 {
+ (if n_stack > 0 { div } else { dim.h }) / n_main
+ } else {
+ 0
+ };
+
+ let w_stack = if n_stack > 0 { dim.w / n_stack } else { 0 };
+
+ let config = &LayoutKind::Stack.config();
+ let main_count = data.main_count as i32;
+
+ active_map
+ .into_iter()
+ .enumerate()
+ .map(|(i, _)| {
+ let i = i as i32;
+
+ (
+ Disposition::Changed(
+ if i < main_count {
+ Region::new(pos.x, pos.y + (i * h_main), dim.w, h_main)
+ } else {
+ Region::new(
+ pos.x + ((i - main_count) * w_stack),
+ pos.y + div,
+ w_stack,
+ dim.h - div,
+ )
+ },
+ config.decoration,
+ ),
+ true,
+ )
+ })
+ .collect()
+ },
+ LayoutKind::SBStack => |region, data, active_map| {
+ let mut region = region.clone();
+ Layout::adjust_for_gap_size(&mut region, data.gap_size, &Zone::MIN_ZONE_DIM);
+
+ (Self::BStack.func())(®ion, data, active_map)
+ },
+ LayoutKind::Horz => |_region, _data, _active_map| todo!(),
+ LayoutKind::SHorz => |_region, _data, _active_map| todo!(),
+ LayoutKind::Vert => |_region, _data, _active_map| todo!(),
+ LayoutKind::SVert => |_region, _data, _active_map| todo!(),
+
+ #[allow(unreachable_patterns)]
+ _ => unimplemented!("{:?} does not have an associated function", self),
+ }
+ }
+}
+
+pub struct Layout {
+ kind: LayoutKind,
+ prev_kind: LayoutKind,
+ data: HashMap<LayoutKind, LayoutData>,
+}
+
+impl Layout {
+ #[inline]
+ pub fn new() -> Self {
+ let kind = LayoutKind::Stack;
+ let mut data = HashMap::with_capacity(LayoutKind::COUNT);
+
+ for kind in LayoutKind::iter() {
+ data.insert(kind, kind.default_data());
+ }
+
+ Self {
+ kind,
+ prev_kind: kind,
+ data,
+ }
+ }
+
+ #[inline]
+ pub fn with_kind(kind: LayoutKind) -> Self {
+ let mut data = HashMap::with_capacity(LayoutKind::COUNT);
+
+ for kind in LayoutKind::iter() {
+ data.insert(kind, kind.default_data());
+ }
+
+ Self {
+ kind,
+ prev_kind: kind,
+ data,
+ }
+ }
+
+ #[inline]
+ pub fn kind(&self) -> LayoutKind {
+ self.kind
+ }
+
+ #[inline]
+ pub fn prev_kind(&self) -> LayoutKind {
+ self.prev_kind
+ }
+
+ #[inline]
+ pub fn config(&self) -> LayoutConfig {
+ self.kind.config()
+ }
+
+ #[inline]
+ pub fn prev_data(&self) -> &LayoutData {
+ self.data.get(&self.prev_kind).unwrap()
+ }
+
+ #[inline]
+ pub fn data(&self) -> &LayoutData {
+ self.data.get(&self.kind).unwrap()
+ }
+
+ #[inline]
+ pub fn data_mut(&mut self) -> &mut LayoutData {
+ self.data.get_mut(&self.kind).unwrap()
+ }
+
+ #[inline]
+ pub fn default_data(&self) -> LayoutData {
+ self.kind.default_data()
+ }
+
+ #[inline]
+ pub fn set_kind(
+ &mut self,
+ kind: LayoutKind,
+ ) -> Result<LayoutKind, StateChangeError> {
+ if kind == self.kind {
+ return Err(StateChangeError::EarlyStop);
+ }
+
+ self.prev_kind = self.kind;
+ self.kind = kind;
+
+ Ok(self.prev_kind)
+ }
+
+ #[inline]
+ pub fn adjust_for_margin(
+ region: Region,
+ extents: &Extents,
+ ) -> Region {
+ Region {
+ pos: Pos {
+ x: region.pos.x + extents.left as i32,
+ y: region.pos.y + extents.top as i32,
+ },
+ dim: Dim {
+ w: region.dim.w - extents.left - extents.right,
+ h: region.dim.h - extents.top - extents.bottom,
+ },
+ }
+ }
+
+ #[inline]
+ pub fn adjust_for_gap_size(
+ region: &mut Region,
+ gap_size: u32,
+ min_dim: &Dim,
+ ) {
+ let gap_size = gap_size as i32;
+ let dim_gap = 2 * gap_size;
+
+ let new_w = region.dim.w - dim_gap;
+ if new_w < min_dim.w {
+ region.pos.x += ((region.dim.w - min_dim.w) as f32 / 2f32) as i32;
+ region.dim.w = min_dim.w;
+ } else {
+ region.dim.w = new_w;
+ region.pos.x += gap_size;
+ }
+
+ let new_h = region.dim.h - dim_gap;
+ if new_h < min_dim.h {
+ region.pos.y += ((region.dim.h - min_dim.h) as f32 / 2f32) as i32;
+ region.dim.h = min_dim.h;
+ } else {
+ region.dim.h = new_h;
+ region.pos.y += gap_size;
+ }
+ }
+
+ #[inline]
+ pub fn adjust_for_border(
+ region: &mut Region,
+ border_width: u32,
+ min_dim: &Dim,
+ ) {
+ let border_padding = 2 * border_width as i32;
+
+ let new_w = region.dim.w - border_padding;
+ region.dim.w = std::cmp::max(min_dim.w, new_w);
+
+ let new_h = region.dim.h - border_padding;
+ region.dim.h = std::cmp::max(min_dim.h, new_h);
+ }
+}
+
+impl Default for Layout {
+ fn default() -> Self {
+ Self {
+ kind: LayoutKind::Stack,
+ prev_kind: LayoutKind::Stack,
+ data: HashMap::new(),
+ }
+ }
+}
+
+pub trait Apply {
+ fn apply(
+ &self,
+ region: Region,
+ active_map: Vec<bool>,
+ ) -> (PlacementMethod, Vec<(Disposition, bool)>);
+}
+
+impl Apply for Layout {
+ #[inline]
+ fn apply(
+ &self,
+ region: Region,
+ active_map: Vec<bool>,
+ ) -> (PlacementMethod, Vec<(Disposition, bool)>) {
+ let config = self.kind.config();
+ let data = self.data();
+
+ let region = if config.margin {
+ Self::adjust_for_margin(region, &data.margin)
+ } else {
+ region
+ };
+
+ (
+ config.method,
+ (self.kind.func())(®ion, &data, active_map)
+ .into_iter()
+ .map(|(mut disposition, is_visible)| {
+ match disposition {
+ Disposition::Unchanged(_) => {},
+ Disposition::Changed(ref mut region, decoration) => {
+ if let Some(border) = decoration.border {
+ Self::adjust_for_gap_size(
+ region,
+ border.width,
+ &Zone::MIN_ZONE_DIM,
+ );
+ }
+
+ if config.gap {
+ Self::adjust_for_gap_size(
+ region,
+ data.gap_size,
+ &Zone::MIN_ZONE_DIM,
+ );
+ }
+ },
+ }
+
+ (disposition, is_visible)
+ })
+ .collect(),
+ )
+ }
+}
+
+impl std::cmp::PartialEq<Self> for Layout {
+ fn eq(
+ &self,
+ other: &Self,
+ ) -> bool {
+ self.kind == other.kind && self.data.get(&self.kind) == other.data.get(&other.kind)
+ }
+}
+
+impl Identify for Layout {
+ fn id(&self) -> Ident {
+ self.kind as Ident
+ }
+}
+
+impl std::fmt::Debug for Layout {
+ fn fmt(
+ &self,
+ f: &mut std::fmt::Formatter<'_>,
+ ) -> std::fmt::Result {
+ f.debug_struct("Layout")
+ .field("kind", &self.kind)
+ .field("prev_kind", &self.prev_kind)
+ .field("data", &self.data.get(&self.kind))
+ .finish()
+ }
+}
diff --git a/src/core/macros.rs b/src/core/macros.rs
@@ -47,7 +47,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::common::Window>| {
+ Box::new(|$model: &mut $crate::model::Model, $window: Option<winsys::window::Window>| {
$body
}) as $crate::binding::MouseEvents
};
diff --git a/src/core/main.rs b/src/core/main.rs
@@ -1,5 +1,6 @@
#![deny(clippy::all)]
#![allow(dead_code)]
+#![recursion_limit = "256"]
#[macro_use]
extern crate log;
@@ -9,7 +10,7 @@ use simplelog::LevelFilter;
#[allow(unused_imports)]
use simplelog::SimpleLogger;
-use winsys::common::Edge;
+use winsys::geometry::Edge;
use winsys::xdata::xconnection::XConnection;
pub use winsys::Result;
@@ -17,15 +18,21 @@ pub use winsys::Result;
mod macros;
#[macro_use]
-mod common;
+mod defaults;
mod binding;
+mod change;
mod client;
mod consume;
mod cycle;
+mod decoration;
+mod error;
+mod identify;
mod jump;
+mod layout;
mod model;
mod partition;
+mod placement;
mod rule;
mod stack;
mod util;
@@ -34,13 +41,13 @@ mod zone;
use binding::KeyBindings;
use binding::MouseBindings;
-use common::Change;
-use common::Direction;
+use change::Change;
+use change::Direction;
use jump::JumpCriterium;
use jump::MatchMethod;
+use layout::LayoutKind;
use model::Model;
use workspace::ClientSelector;
-use zone::LayoutKind;
pub fn main() -> Result<()> {
#[cfg(debug_assertions)]
@@ -48,9 +55,13 @@ pub fn main() -> Result<()> {
let (conn, screen_num) = x11rb::connect(None)?;
let (mouse_bindings, key_bindings) = init_bindings();
- let mut xconn = XConnection::new(&conn, screen_num)?;
- Model::new(&mut xconn, &key_bindings, &mouse_bindings).run(key_bindings, mouse_bindings);
+ Model::new(
+ &mut XConnection::new(&conn, screen_num)?,
+ &key_bindings,
+ &mouse_bindings,
+ )
+ .run(key_bindings, mouse_bindings);
Ok(())
}
@@ -193,34 +204,41 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
"1-C-k" => do_internal!(cycle_zones, Direction::Backward),
// active workspace layout setters
- "1-m" => do_internal!(set_layout, LayoutKind::Monocle),
- "1-t" => do_internal!(set_layout, LayoutKind::Stack),
- "1-g" => do_internal!(set_layout, LayoutKind::Center),
"1-S-f" => do_internal!(set_layout, LayoutKind::Float),
"1-S-l" => do_internal!(set_layout, LayoutKind::BLFloat),
"1-z" => do_internal!(set_layout, LayoutKind::SingleFloat),
"1-S-z" => do_internal!(set_layout, LayoutKind::BLSingleFloat),
- "1-C-S-f" => do_internal!(apply_float_retain_region),
+ "1-m" => do_internal!(set_layout, LayoutKind::Monocle),
+ "1-g" => do_internal!(set_layout, LayoutKind::Center),
+ "1-t" => do_internal!(set_layout, LayoutKind::Stack),
"1-S-t" => do_internal!(set_layout, LayoutKind::SStack),
"1-C-S-p" => do_internal!(set_layout, LayoutKind::Paper),
+ "1-2-C-S-p" => do_internal!(set_layout, LayoutKind::SPaper),
+ "1-C-S-b" => do_internal!(set_layout, LayoutKind::BStack),
+ "1-2-C-S-b" => do_internal!(set_layout, LayoutKind::SBStack),
+ "1-S-y" => do_internal!(set_layout, LayoutKind::Horz),
+ "1-C-y" => do_internal!(set_layout, LayoutKind::SHorz),
+ "1-S-v" => do_internal!(set_layout, LayoutKind::Vert),
+ "1-C-v" => do_internal!(set_layout, LayoutKind::SVert),
+ "1-C-S-f" => do_internal!(apply_float_retain_region),
"1-space" => do_internal!(toggle_layout),
// active workspace layout-data modifiers
- "1-plus" => do_internal!(change_gap_size, Change::Inc),
- "1-minus" => do_internal!(change_gap_size, Change::Dec),
+ "1-plus" => do_internal!(change_gap_size, Change::Inc(5u32)),
+ "1-minus" => do_internal!(change_gap_size, Change::Dec(5u32)),
"1-S-equal" => do_internal!(reset_gap_size),
- "1-i" => do_internal!(change_main_count, Change::Inc),
- "1-d" => do_internal!(change_main_count, Change::Dec),
- "1-l" => do_internal!(change_main_factor, Change::Inc),
- "1-h" => do_internal!(change_main_factor, Change::Dec),
- "1-S-Left" => do_internal!(change_margin, Edge::Left, Change::Inc),
- "1-C-S-Left" => do_internal!(change_margin, Edge::Left, Change::Dec),
- "1-S-Up" => do_internal!(change_margin, Edge::Top, Change::Inc),
- "1-C-S-Up" => do_internal!(change_margin, Edge::Top, Change::Dec),
- "1-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Inc),
- "1-C-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Dec),
- "1-S-Right" => do_internal!(change_margin, Edge::Right, Change::Inc),
- "1-C-S-Right" => do_internal!(change_margin, Edge::Right, Change::Dec),
+ "1-i" => do_internal!(change_main_count, Change::Inc(1u32)),
+ "1-d" => do_internal!(change_main_count, Change::Dec(1u32)),
+ "1-l" => do_internal!(change_main_factor, Change::Inc(0.05f32)),
+ "1-h" => do_internal!(change_main_factor, Change::Dec(0.05f32)),
+ "1-S-Left" => do_internal!(change_margin, Edge::Left, Change::Inc(5i32)),
+ "1-C-S-Left" => do_internal!(change_margin, Edge::Left, Change::Dec(5i32)),
+ "1-S-Up" => do_internal!(change_margin, Edge::Top, Change::Inc(5i32)),
+ "1-C-S-Up" => do_internal!(change_margin, Edge::Top, Change::Dec(5i32)),
+ "1-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Inc(5i32)),
+ "1-C-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Dec(5i32)),
+ "1-S-Right" => do_internal!(change_margin, Edge::Right, Change::Inc(5i32)),
+ "1-C-S-Right" => do_internal!(change_margin, Edge::Right, Change::Dec(5i32)),
"1-C-S-equal" => do_internal!(reset_margin),
"1-2-C-S-l" => do_internal!(copy_prev_layout_data),
"1-2-C-S-equal" => do_internal!(reset_layout_data),
diff --git a/src/core/model.rs b/src/core/model.rs
@@ -1,61 +1,59 @@
use crate::binding::KeyBindings;
use crate::binding::MouseBindings;
+use crate::change::Change;
+use crate::change::Direction;
use crate::client::Client;
-use crate::common::Change;
-use crate::common::Direction;
-use crate::common::Index;
-use crate::common::StateChangeError;
-use crate::common::FREE_DECORATION;
-use crate::common::MIN_WINDOW_DIM;
-use crate::common::NO_DECORATION;
use crate::consume::get_spawner_pid;
use crate::cycle::Cycle;
use crate::cycle::InsertPos;
use crate::cycle::Selector;
+use crate::decoration::Decoration;
+use crate::error::StateChangeError;
+use crate::identify::Index;
use crate::jump::JumpCriterium;
use crate::jump::MatchMethod;
+use crate::layout::Layout;
+use crate::layout::LayoutKind;
use crate::partition::Partition;
+use crate::placement::Placement;
+use crate::placement::PlacementMethod;
+use crate::placement::PlacementRegion;
+use crate::placement::PlacementTarget;
use crate::rule::Rules;
use crate::stack::StackLayer;
use crate::stack::StackManager;
use crate::workspace::Buffer;
use crate::workspace::BufferKind;
use crate::workspace::Workspace;
-use crate::zone::Layout;
-use crate::zone::LayoutKind;
-use crate::zone::Placement;
-use crate::zone::PlacementKind;
-use crate::zone::PlacementMethod;
-use crate::zone::PlacementRegion;
use crate::zone::ZoneContent;
use crate::zone::ZoneManager;
#[allow(unused_imports)]
use crate::util::Util;
-use winsys::common::Corner;
-use winsys::common::Dim;
-use winsys::common::Edge;
-use winsys::common::Grip;
-use winsys::common::Hints;
-use winsys::common::IcccmWindowState;
-use winsys::common::Pid;
-use winsys::common::Pos;
-use winsys::common::Region;
-use winsys::common::Window;
-use winsys::common::WindowState;
-use winsys::common::WindowType;
use winsys::connection::Connection;
+use winsys::connection::Pid;
use winsys::event::Event;
use winsys::event::PropertyKind;
use winsys::event::StackMode;
use winsys::event::ToggleAction;
+use winsys::geometry::Corner;
+use winsys::geometry::Dim;
+use winsys::geometry::Edge;
+use winsys::geometry::Pos;
+use winsys::geometry::Region;
+use winsys::hints::Hints;
use winsys::input::EventTarget;
+use winsys::input::Grip;
use winsys::input::KeyCode;
use winsys::input::MouseEvent;
use winsys::input::MouseEventKey;
use winsys::input::MouseEventKind;
use winsys::screen::Screen;
+use winsys::window::IcccmWindowState;
+use winsys::window::Window;
+use winsys::window::WindowState;
+use winsys::window::WindowType;
use std::collections::HashMap;
@@ -345,26 +343,26 @@ impl<'a> Model<'a> {
for placement in show {
match placement.kind {
- PlacementKind::Client(window) => {
+ PlacementTarget::Client(window) => {
let frame = self.frame(window).unwrap();
self.update_client_placement(&placement);
self.place_client(window, placement.method);
self.map_client(frame);
},
- PlacementKind::Tab(_) => {},
- PlacementKind::Layout => {},
+ PlacementTarget::Tab(_) => {},
+ PlacementTarget::Layout => {},
};
}
for placement in hide {
match placement.kind {
- PlacementKind::Client(window) => {
+ PlacementTarget::Client(window) => {
let frame = self.frame(window).unwrap();
self.unmap_client(frame);
},
- PlacementKind::Tab(_) => {},
- PlacementKind::Layout => {},
+ PlacementTarget::Tab(_) => {},
+ PlacementTarget::Layout => {},
};
}
@@ -679,16 +677,16 @@ impl<'a> Model<'a> {
let hints = self.conn.get_icccm_window_hints(window);
let (_, size_hints) =
self.conn
- .get_icccm_window_size_hints(window, Some(MIN_WINDOW_DIM), &None);
+ .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(&FREE_DECORATION.extents())
+ .with_extents(&Decoration::FREE_DECORATION.extents())
} else {
geometry
- .with_minimum_dim(&MIN_WINDOW_DIM)
- .with_extents(&FREE_DECORATION.extents())
+ .with_minimum_dim(&Client::MIN_CLIENT_DIM)
+ .with_extents(&Decoration::FREE_DECORATION.extents())
};
let parent = self.conn.get_icccm_window_transient_for(window);
@@ -771,7 +769,7 @@ impl<'a> Model<'a> {
client.set_context(context);
client.set_workspace(workspace);
- let extents = FREE_DECORATION.extents();
+ let extents = Decoration::FREE_DECORATION.extents();
self.conn.reparent_window(window, frame, Pos {
x: extents.left as i32,
y: extents.top as i32,
@@ -782,7 +780,7 @@ impl<'a> Model<'a> {
if let Some(current_workspace) = self.workspaces.get(workspace) {
let parent_zone = current_workspace
- .active_zone()
+ .active_spawn_zone()
.map(|id| self.zone_manager.nearest_cycle(id));
let id = self
@@ -947,10 +945,12 @@ impl<'a> Model<'a> {
let workspace_index = self.active_workspace();
let workspace = self.workspace(workspace_index);
- let cycle = workspace.active_zone().unwrap();
+ let cycle = workspace.active_focus_zone().unwrap();
let cycle = self.zone_manager.nearest_cycle(cycle);
- let id = self.zone_manager.new_zone(Some(cycle),
- ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)));
+ let id = self.zone_manager.new_zone(
+ Some(cycle),
+ ZoneContent::Layout(Layout::new(), Cycle::new(Vec::new(), true)),
+ );
let workspace = self.workspace_mut(workspace_index);
workspace.add_zone(id, &InsertPos::Back);
@@ -961,10 +961,11 @@ impl<'a> Model<'a> {
let workspace_index = self.active_workspace();
let workspace = self.workspace(workspace_index);
- let cycle = workspace.active_zone().unwrap();
+ let cycle = workspace.active_focus_zone().unwrap();
let cycle = self.zone_manager.nearest_cycle(cycle);
- let id = self.zone_manager.new_zone(Some(cycle),
- ZoneContent::Tab(Cycle::new(Vec::new(), true)));
+ let id = self
+ .zone_manager
+ .new_zone(Some(cycle), ZoneContent::Tab(Cycle::new(Vec::new(), true)));
let workspace = self.workspace_mut(workspace_index);
workspace.add_zone(id, &InsertPos::Back);
@@ -975,7 +976,7 @@ impl<'a> Model<'a> {
let workspace_index = self.active_workspace();
let workspace = self.workspace(workspace_index);
- let cycle = workspace.active_zone().unwrap();
+ let cycle = workspace.active_spawn_zone().unwrap();
let cycle = self.zone_manager.nearest_cycle(cycle);
if cycle == workspace.root_zone() {
@@ -1125,7 +1126,7 @@ impl<'a> Model<'a> {
placement: &Placement,
) {
match placement.kind {
- PlacementKind::Client(window) => {
+ PlacementTarget::Client(window) => {
let client = self.client_mut(window).unwrap();
let region = match placement.region {
PlacementRegion::FreeRegion => *client.free_region(),
@@ -1651,12 +1652,12 @@ impl<'a> Model<'a> {
pub fn change_gap_size(
&mut self,
- change: Change,
+ change: Change<u32>,
) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_gap_size(change, 5, &mut self.zone_manager)?;
+ workspace.change_gap_size(change, &mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
@@ -1698,7 +1699,7 @@ impl<'a> Model<'a> {
pub fn change_main_count(
&mut self,
- change: Change,
+ change: Change<u32>,
) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
@@ -1712,12 +1713,12 @@ impl<'a> Model<'a> {
pub fn change_main_factor(
&mut self,
- change: Change,
+ change: Change<f32>,
) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_main_factor(change, 0.05f32, &mut self.zone_manager)?;
+ workspace.change_main_factor(change, &mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
@@ -1727,12 +1728,12 @@ impl<'a> Model<'a> {
pub fn change_margin(
&mut self,
edge: Edge,
- change: Change,
+ change: Change<i32>,
) -> Result<(), StateChangeError> {
let workspace_index = self.active_workspace();
if let Some(workspace) = self.workspaces.get(workspace_index) {
- workspace.change_margin(edge, change, 5, &mut self.zone_manager)?;
+ workspace.change_margin(edge, change, &mut self.zone_manager)?;
}
self.apply_layout(workspace_index, true);
@@ -1757,7 +1758,7 @@ impl<'a> Model<'a> {
let workspace_index = self.active_workspace();
let workspace = self.workspace_mut(workspace_index);
- if let Some(id) = workspace.active_zone() {
+ if let Some(id) = workspace.active_focus_zone() {
info!(
"activating layout {:?} on workspace {}",
kind, workspace_index
@@ -1774,7 +1775,7 @@ impl<'a> Model<'a> {
let workspace_index = self.active_workspace();
let workspace = self.workspace_mut(workspace_index);
- if let Some(id) = workspace.active_zone() {
+ if let Some(id) = workspace.active_focus_zone() {
let prev_kind = self.zone_manager.set_prev_kind(id);
info!(
@@ -1924,15 +1925,15 @@ impl<'a> Model<'a> {
}
self.zone_manager.activate_zone(id);
+ let cycle = self.zone_manager.nearest_cycle(id);
- self.workspaces
- .get_mut(client_workspace_index)
- .and_then(|ws| ws.focus_client(window));
+ self.workspaces.get_mut(client_workspace_index).map(|ws| {
+ ws.activate_zone(cycle);
+ ws.focus_client(window);
+ });
- if let Some(config) = self.zone_manager.cycle_config(id) {
- if config.persistent {
- self.apply_layout(client_workspace_index, false);
- }
+ if self.zone_manager.is_within_persisent(id) {
+ self.apply_layout(client_workspace_index, false);
}
if self.conn.get_focused_window() != window {
@@ -2390,7 +2391,7 @@ impl<'a> Model<'a> {
let placement = Placement {
method: PlacementMethod::Free,
- kind: PlacementKind::Client(window),
+ kind: PlacementTarget::Client(window),
zone: client.zone(),
region: PlacementRegion::NewRegion(region),
decoration: *client.decoration(),
@@ -2437,7 +2438,7 @@ impl<'a> Model<'a> {
let placement = Placement {
method: PlacementMethod::Free,
- kind: PlacementKind::Client(window),
+ kind: PlacementTarget::Client(window),
zone: client.zone(),
region: PlacementRegion::NewRegion(region),
decoration: *client.decoration(),
@@ -2470,10 +2471,10 @@ impl<'a> Model<'a> {
let mut region = region.without_extents(&frame_extents);
- if (width_inc.is_negative() && -width_inc >= region.dim.w as i32)
- || (height_inc.is_negative() && -height_inc >= region.dim.h as i32)
- || (region.dim.w as i32 + width_inc <= MIN_WINDOW_DIM.w as i32)
- || (region.dim.h as i32 + height_inc <= MIN_WINDOW_DIM.h as i32)
+ 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;
}
@@ -2485,12 +2486,12 @@ impl<'a> Model<'a> {
step.abs()
);
- region.dim.w = (region.dim.w as i32 + width_inc) as u32;
- region.dim.h = (region.dim.h as i32 + height_inc) as u32;
+ region.dim.w = region.dim.w + width_inc;
+ region.dim.h = region.dim.h + height_inc;
let mut region = region.with_extents(&frame_extents);
- let dx = region.dim.w as i32 - original_region.dim.w as i32;
- let dy = region.dim.h as i32 - original_region.dim.h as i32;
+ 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;
@@ -2500,7 +2501,7 @@ impl<'a> Model<'a> {
let placement = Placement {
method: PlacementMethod::Free,
- kind: PlacementKind::Client(window),
+ kind: PlacementTarget::Client(window),
zone: client.zone(),
region: PlacementRegion::NewRegion(region),
decoration: *client.decoration(),
@@ -2541,51 +2542,51 @@ impl<'a> Model<'a> {
match edge {
Edge::Left => {
- if step.is_negative() && -step >= region.dim.w as i32 {
+ if step.is_negative() && -step >= region.dim.w {
return;
}
- if region.dim.w as i32 + step <= MIN_WINDOW_DIM.w as i32 {
- region.pos.x -= MIN_WINDOW_DIM.w as i32 - region.dim.w as i32;
- region.dim.w = MIN_WINDOW_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 = (region.dim.w as i32 + step) as u32;
+ region.dim.w = region.dim.w + step;
}
},
Edge::Right => {
- if step.is_negative() && -step >= region.dim.w as i32 {
+ if step.is_negative() && -step >= region.dim.w {
return;
}
- if region.dim.w as i32 + step <= MIN_WINDOW_DIM.w as i32 {
- region.dim.w = MIN_WINDOW_DIM.w;
+ 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 as i32 + step) as u32;
+ region.dim.w = region.dim.w + step;
}
},
Edge::Top => {
- if step.is_negative() && -step >= region.dim.h as i32 {
+ if step.is_negative() && -step >= region.dim.h {
return;
}
- if region.dim.h as i32 + step <= MIN_WINDOW_DIM.h as i32 {
- region.pos.y -= MIN_WINDOW_DIM.h as i32 - region.dim.h as i32;
- region.dim.h = MIN_WINDOW_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 = (region.dim.h as i32 + step) as u32;
+ region.dim.h = region.dim.h + step;
}
},
Edge::Bottom => {
- if step.is_negative() && -step >= region.dim.h as i32 {
+ if step.is_negative() && -step >= region.dim.h {
return;
}
- if region.dim.h as i32 + step <= MIN_WINDOW_DIM.h as i32 {
- region.dim.h = MIN_WINDOW_DIM.h;
+ 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 as i32 + step) as u32;
+ region.dim.h = region.dim.h + step;
}
},
}
@@ -2594,7 +2595,7 @@ impl<'a> Model<'a> {
let region = region.with_extents(&frame_extents);
let placement = Placement {
method: PlacementMethod::Free,
- kind: PlacementKind::Client(window),
+ kind: PlacementTarget::Client(window),
zone: client.zone(),
region: PlacementRegion::NewRegion(region),
decoration: *client.decoration(),
@@ -2650,7 +2651,7 @@ impl<'a> Model<'a> {
let placement = Placement {
method: PlacementMethod::Free,
- kind: PlacementKind::Client(window),
+ kind: PlacementTarget::Client(window),
zone: client.zone(),
region: PlacementRegion::NewRegion(region),
decoration: *client.decoration(),
@@ -2714,19 +2715,19 @@ impl<'a> Model<'a> {
let delta = grip_pos.dist(current_pos);
let dest_w = if left_grip {
- window_region.dim.w as i32 - delta.dx
+ window_region.dim.w - delta.dx
} else {
- window_region.dim.w as i32 + delta.dx
+ window_region.dim.w + delta.dx
};
let dest_h = if top_grip {
- window_region.dim.h as i32 - delta.dy
+ window_region.dim.h - delta.dy
} else {
- window_region.dim.h as i32 + delta.dy
+ window_region.dim.h + delta.dy
};
- dim.w = std::cmp::max(0, dest_w) as u32;
- dim.h = std::cmp::max(0, dest_h) as u32;
+ dim.w = std::cmp::max(0, dest_w);
+ dim.h = std::cmp::max(0, dest_h);
if let Some(size_hints) = client.size_hints() {
size_hints.apply(&mut dim);
@@ -2739,13 +2740,11 @@ impl<'a> Model<'a> {
.with_extents(&decoration.extents());
if top_grip {
- region.pos.y =
- window_region.pos.y + (window_region.dim.h as i32 - region.dim.h as i32);
+ 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 as i32 - region.dim.w as i32);
+ region.pos.x = window_region.pos.x + (window_region.dim.w - region.dim.w);
}
if region == previous_region {
@@ -2755,7 +2754,7 @@ impl<'a> Model<'a> {
let window = client.window();
let placement = Placement {
method: PlacementMethod::Free,
- kind: PlacementKind::Client(window),
+ kind: PlacementTarget::Client(window),
zone: client.zone(),
region: PlacementRegion::NewRegion(region),
decoration: *decoration,
@@ -2935,21 +2934,17 @@ impl<'a> Model<'a> {
},
((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 as i32 - h as i32 =>
- {
+ ((_, y), (_, h)) if y == screen.full_region().dim.h - h => {
Some((Edge::Bottom, h))
},
- ((x, _), (w, _))
- if x == screen.full_region().dim.w as i32 - w as i32 =>
- {
+ ((x, _), (w, _)) if x == screen.full_region().dim.w - w => {
Some((Edge::Right, w))
},
_ => None,
};
if let Some((edge, width)) = strut {
- screen.add_strut(edge, window, width);
+ screen.add_strut(edge, window, width as u32);
if !screen.showing_struts() {
self.conn.unmap_window(window);
@@ -3280,7 +3275,7 @@ impl<'a> Model<'a> {
} else {
region
.without_extents(&frame_extents)
- .with_minimum_dim(&MIN_WINDOW_DIM)
+ .with_minimum_dim(&Client::MIN_CLIENT_DIM)
.with_extents(&frame_extents)
}
});
@@ -3288,7 +3283,7 @@ impl<'a> Model<'a> {
if let Some(region) = region {
let placement = Placement {
method: PlacementMethod::Free,
- kind: PlacementKind::Client(window),
+ kind: PlacementTarget::Client(window),
zone: client.zone(),
region: PlacementRegion::NewRegion(region),
decoration: *client.decoration(),
@@ -3407,14 +3402,14 @@ impl<'a> Model<'a> {
let mut geometry = geometry.unwrap();
let (_, size_hints) = self.conn.get_icccm_window_size_hints(
window,
- Some(MIN_WINDOW_DIM),
+ 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(&MIN_WINDOW_DIM)
+ geometry.with_minimum_dim(&Client::MIN_CLIENT_DIM)
};
geometry.pos = client.free_region().pos;
@@ -3458,9 +3453,9 @@ impl<'a> Model<'a> {
client.frame_extents()
} else {
if self.conn.must_manage_window(window) {
- FREE_DECORATION.extents()
+ Decoration::FREE_DECORATION.extents()
} else {
- NO_DECORATION.extents()
+ Decoration::NO_DECORATION.extents()
}
},
);
diff --git a/src/core/partition.rs b/src/core/partition.rs
@@ -1,6 +1,6 @@
-use crate::common::Ident;
-use crate::common::Identify;
-use crate::common::Index;
+use crate::identify::Ident;
+use crate::identify::Identify;
+use crate::identify::Index;
use winsys::screen::Screen;
diff --git a/src/core/placement.rs b/src/core/placement.rs
@@ -0,0 +1,51 @@
+use crate::decoration::Decoration;
+use crate::zone::ZoneContent;
+use crate::zone::ZoneId;
+
+use winsys::geometry::Region;
+use winsys::window::Window;
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum PlacementMethod {
+ Free,
+ Tile,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum PlacementClass<T> {
+ Free(T),
+ Tile(T),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum PlacementTarget {
+ Client(Window),
+ Tab(usize),
+ Layout,
+}
+
+impl PlacementTarget {
+ pub fn from_zone_content(content: &ZoneContent) -> Self {
+ match content {
+ ZoneContent::Client(window) => PlacementTarget::Client(*window),
+ ZoneContent::Tab(zones) => PlacementTarget::Tab(zones.len()),
+ ZoneContent::Layout(..) => PlacementTarget::Layout,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum PlacementRegion {
+ NoRegion,
+ FreeRegion,
+ NewRegion(Region),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Placement {
+ pub method: PlacementMethod,
+ pub kind: PlacementTarget,
+ pub zone: ZoneId,
+ pub region: PlacementRegion,
+ pub decoration: Decoration,
+}
diff --git a/src/core/stack.rs b/src/core/stack.rs
@@ -1,4 +1,4 @@
-use winsys::common::Window;
+use winsys::window::Window;
use std::collections::HashMap;
use std::vec::Vec;
diff --git a/src/core/util.rs b/src/core/util.rs
@@ -1,5 +1,5 @@
-use crate::common::Change;
-use crate::common::Index;
+use crate::change::Change;
+use crate::identify::Index;
use winsys::input::Button;
use winsys::input::CodeMap;
@@ -12,6 +12,8 @@ use std::hash::BuildHasherDefault;
use std::hash::Hasher;
use std::ops::Add;
use std::ops::AddAssign;
+use std::ops::Mul;
+use std::ops::MulAssign;
use std::ops::Sub;
use std::ops::SubAssign;
use std::process::Command;
@@ -60,14 +62,20 @@ impl Util {
min: T,
max: T,
mut base: T,
- change: Change,
- delta: T,
+ change: Change<T>,
) -> T
where
- T: Ord + Add<Output = T> + AddAssign + Sub<Output = T> + SubAssign + Copy,
+ T: Ord
+ + Add<Output = T>
+ + AddAssign
+ + Mul<Output = T>
+ + MulAssign
+ + Sub<Output = T>
+ + SubAssign
+ + Copy,
{
match change {
- Change::Inc => {
+ Change::Inc(delta) => {
base += delta;
if base > max {
max
@@ -75,7 +83,7 @@ impl Util {
base
}
},
- Change::Dec => {
+ Change::Dec(delta) => {
if base >= min + delta {
base - delta
} else {
diff --git a/src/core/workspace.rs b/src/core/workspace.rs
@@ -1,30 +1,27 @@
+use crate::change::Change;
+use crate::change::Direction;
use crate::client::Client;
-use crate::common::Change;
-use crate::common::Direction;
-use crate::common::Ident;
-use crate::common::Identify;
-use crate::common::Index;
-use crate::common::StateChangeError;
-use crate::common::FREE_DECORATION;
-use crate::common::NO_DECORATION;
use crate::cycle::Cycle;
use crate::cycle::InsertPos;
use crate::cycle::Selector;
-use crate::zone::Placement;
-use crate::zone::PlacementKind;
-use crate::zone::PlacementMethod;
-use crate::zone::PlacementRegion;
+use crate::decoration::Decoration;
+use crate::error::StateChangeError;
+use crate::identify::Ident;
+use crate::identify::Identify;
+use crate::identify::Index;
+use crate::layout::Layout;
+use crate::placement::Placement;
+use crate::placement::PlacementMethod;
+use crate::placement::PlacementRegion;
+use crate::placement::PlacementTarget;
use crate::zone::ZoneId;
use crate::zone::ZoneManager;
-use crate::zone::MAX_GAP_SIZE;
-use crate::zone::MAX_MAIN_COUNT;
-use crate::zone::MAX_MARGIN;
-use winsys::common::Edge;
-use winsys::common::Grip;
-use winsys::common::Pos;
-use winsys::common::Region;
-use winsys::common::Window;
+use winsys::geometry::Edge;
+use winsys::geometry::Pos;
+use winsys::geometry::Region;
+use winsys::input::Grip;
+use winsys::window::Window;
use std::collections::HashMap;
use std::collections::VecDeque;
@@ -142,7 +139,8 @@ pub struct Workspace {
number: Ident,
name: String,
root_zone: ZoneId,
- zones: Cycle<ZoneId>,
+ focus_zones: Cycle<ZoneId>,
+ spawn_zones: Cycle<ZoneId>,
clients: Cycle<Window>,
icons: Cycle<Window>,
}
@@ -157,7 +155,8 @@ impl Workspace {
number,
name: name.into(),
root_zone,
- zones: Cycle::new(vec![root_zone], true),
+ focus_zones: Cycle::new(vec![root_zone], true),
+ spawn_zones: Cycle::new(vec![root_zone], true),
clients: Cycle::new(Vec::new(), true),
icons: Cycle::new(Vec::new(), true),
}
@@ -213,8 +212,12 @@ impl Workspace {
self.clients.stack_after_focus()
}
- pub fn active_zone(&self) -> Option<ZoneId> {
- self.zones.active_element().copied()
+ pub fn active_focus_zone(&self) -> Option<ZoneId> {
+ self.focus_zones.active_element().copied()
+ }
+
+ pub fn active_spawn_zone(&self) -> Option<ZoneId> {
+ self.spawn_zones.active_element().copied()
}
pub fn focused_client(&self) -> Option<Window> {
@@ -229,7 +232,7 @@ impl Workspace {
let sel = match sel {
ClientSelector::AtActive => Selector::AtActive,
ClientSelector::AtMaster => {
- if let Some(&id) = self.zones.active_element() {
+ if let Some(&id) = self.focus_zones.active_element() {
let cycle = zone_manager.nearest_cycle(id);
let cycle = zone_manager.zone(cycle);
@@ -262,7 +265,8 @@ impl Workspace {
id: ZoneId,
insert: &InsertPos,
) {
- self.zones.insert_at(insert, id);
+ self.focus_zones.insert_at(insert, id);
+ self.spawn_zones.insert_at(insert, id);
}
pub fn add_client(
@@ -288,12 +292,12 @@ impl Workspace {
&mut self,
id: ZoneId,
) -> Option<ZoneId> {
- let prev_active = match self.zones.active_element() {
+ let prev_active = match self.focus_zones.active_element() {
Some(z) => *z,
None => return None,
};
- self.zones.activate_for(&Selector::AtIdent(id));
+ self.focus_zones.activate_for(&Selector::AtIdent(id));
Some(prev_active)
}
@@ -313,8 +317,9 @@ impl Workspace {
pub fn remove_zone(
&mut self,
id: ZoneId,
- ) -> Option<Window> {
- self.zones.remove_for(&Selector::AtIdent(id))
+ ) {
+ self.focus_zones.remove_for(&Selector::AtIdent(id));
+ self.spawn_zones.remove_for(&Selector::AtIdent(id));
}
pub fn remove_client(
@@ -360,25 +365,25 @@ impl Workspace {
(
PlacementMethod::Tile,
PlacementRegion::NewRegion(screen_region),
- NO_DECORATION,
+ Decoration::NO_DECORATION,
)
} else if client.is_iconified() {
(
PlacementMethod::Tile,
PlacementRegion::NoRegion,
- NO_DECORATION,
+ Decoration::NO_DECORATION,
)
- }else {
+ } else {
(
PlacementMethod::Free,
PlacementRegion::FreeRegion,
- FREE_DECORATION,
+ Decoration::FREE_DECORATION,
)
};
Placement {
method,
- kind: PlacementKind::Client(client.window()),
+ kind: PlacementTarget::Client(client.window()),
zone: client.zone(),
region,
decoration,
@@ -395,19 +400,19 @@ impl Workspace {
dir: Direction,
zone_manager: &ZoneManager,
) -> Option<(ZoneId, ZoneId)> {
- if self.zones.len() < 2 {
+ if self.spawn_zones.len() < 2 {
return None;
}
- let prev_active = *self.zones.active_element()?;
- let mut now_active = *self.zones.cycle_active(dir)?;
+ let prev_active = *self.spawn_zones.active_element()?;
+ let mut now_active = *self.spawn_zones.cycle_active(dir)?;
loop {
if zone_manager.is_cycle(now_active) {
return Some((prev_active, now_active));
}
- now_active = *self.zones.cycle_active(dir)?;
+ now_active = *self.spawn_zones.cycle_active(dir)?;
}
}
@@ -473,7 +478,7 @@ impl Workspace {
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
@@ -493,7 +498,7 @@ impl Workspace {
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
@@ -510,12 +515,11 @@ impl Workspace {
pub fn change_gap_size(
&self,
- change: Change,
- delta: u32,
+ change: Change<u32>,
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
@@ -524,8 +528,8 @@ impl Workspace {
.ok_or(StateChangeError::EarlyStop)?;
let new_gap_size = match change {
- Change::Inc => std::cmp::min(data.gap_size + delta, MAX_GAP_SIZE),
- Change::Dec => std::cmp::max(data.gap_size as i32 - delta as i32, 0) as u32,
+ Change::Inc(delta) => std::cmp::min(data.gap_size + delta, Layout::MAX_GAP_SIZE),
+ Change::Dec(delta) => std::cmp::max(data.gap_size as i32 - delta as i32, 0) as u32,
};
if new_gap_size == data.gap_size {
@@ -540,7 +544,7 @@ impl Workspace {
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
@@ -557,11 +561,11 @@ impl Workspace {
pub fn change_main_count(
&self,
- change: Change,
+ change: Change<u32>,
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
@@ -570,8 +574,8 @@ impl Workspace {
.ok_or(StateChangeError::EarlyStop)?;
let new_main_count = match change {
- Change::Inc => std::cmp::min(data.main_count + 1, MAX_MAIN_COUNT),
- Change::Dec => std::cmp::max(data.main_count as i32 - 1, 0) as u32,
+ Change::Inc(delta) => std::cmp::min(data.main_count + delta, Layout::MAX_MAIN_COUNT),
+ Change::Dec(delta) => std::cmp::max(data.main_count - delta, 0),
};
if data.main_count == new_main_count {
@@ -583,12 +587,11 @@ impl Workspace {
pub fn change_main_factor(
&self,
- change: Change,
- delta: f32,
+ change: Change<f32>,
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
@@ -597,8 +600,8 @@ impl Workspace {
.ok_or(StateChangeError::EarlyStop)?;
match change {
- Change::Inc => data.main_factor += delta,
- Change::Dec => data.main_factor -= delta,
+ Change::Inc(delta) => data.main_factor += delta,
+ Change::Dec(delta) => data.main_factor -= delta,
}
if data.main_factor < 0.05f32 {
@@ -613,12 +616,11 @@ impl Workspace {
pub fn change_margin(
&self,
edge: Edge,
- change: Change,
- delta: u32,
+ change: Change<i32>,
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
@@ -627,25 +629,25 @@ impl Workspace {
.ok_or(StateChangeError::EarlyStop)?;
let delta_change = match change {
- Change::Inc => delta as i32,
- Change::Dec => -(delta as i32),
+ Change::Inc(delta) => delta,
+ Change::Dec(delta) => -delta,
};
let (edge_value, edge_max) = match edge {
- Edge::Left => (&mut data.margin.left, MAX_MARGIN.left),
- Edge::Right => (&mut data.margin.right, MAX_MARGIN.right),
- Edge::Top => (&mut data.margin.top, MAX_MARGIN.top),
- Edge::Bottom => (&mut data.margin.bottom, MAX_MARGIN.bottom),
+ Edge::Left => (&mut data.margin.left, Layout::MAX_MARGIN.left),
+ Edge::Right => (&mut data.margin.right, Layout::MAX_MARGIN.right),
+ Edge::Top => (&mut data.margin.top, Layout::MAX_MARGIN.top),
+ Edge::Bottom => (&mut data.margin.bottom, Layout::MAX_MARGIN.bottom),
};
- let edge_changed = *edge_value as i32 + delta_change;
+ let edge_changed = *edge_value + delta_change as i32;
let edge_changed = std::cmp::max(edge_changed, 0);
- let edge_changed = std::cmp::min(edge_changed, edge_max as i32);
+ let edge_changed = std::cmp::min(edge_changed, edge_max);
- if *edge_value == edge_changed as u32 {
+ if *edge_value == edge_changed {
Err(StateChangeError::LimitReached)
} else {
- Ok(*edge_value = edge_changed as u32)
+ Ok(*edge_value = edge_changed)
}
}
@@ -654,7 +656,7 @@ impl Workspace {
zone_manager: &mut ZoneManager,
) -> Result<(), StateChangeError> {
let &id = self
- .zones
+ .focus_zones
.active_element()
.ok_or(StateChangeError::EarlyStop)?;
diff --git a/src/core/zone.rs b/src/core/zone.rs
@@ -1,930 +1,35 @@
-use crate::common::Border;
-use crate::common::Decoration;
-use crate::common::Frame;
-use crate::common::Ident;
-use crate::common::Identify;
-use crate::common::StateChangeError;
-use crate::common::FREE_DECORATION;
-use crate::common::NO_DECORATION;
+use crate::change::Disposition;
use crate::cycle::Cycle;
use crate::cycle::InsertPos;
use crate::cycle::Selector;
-
-use winsys::common::Dim;
-use winsys::common::Extents;
-use winsys::common::Padding;
-use winsys::common::Pos;
-use winsys::common::Region;
-use winsys::common::Window;
-
-use strum::EnumCount;
-use strum::IntoEnumIterator;
-use strum_macros::EnumIter;
-use strum_macros::ToString;
+use crate::decoration::Border;
+use crate::decoration::Decoration;
+use crate::error::StateChangeError;
+use crate::identify::Ident;
+use crate::identify::Identify;
+use crate::layout::Apply;
+use crate::layout::Layout;
+use crate::layout::LayoutConfig;
+use crate::layout::LayoutData;
+use crate::layout::LayoutKind;
+use crate::placement::Placement;
+use crate::placement::PlacementMethod;
+use crate::placement::PlacementRegion;
+use crate::placement::PlacementTarget;
+
+use winsys::geometry::Region;
+use winsys::window::Window;
use std::collections::HashMap;
-use std::string::ToString;
use std::sync::atomic;
use std::vec::Vec;
pub type ZoneId = u32;
-pub const MAX_MAIN_COUNT: u32 = 15;
-pub const MAX_GAP_SIZE: u32 = 300;
-pub const MAX_MARGIN: Padding = Padding {
- left: 700,
- right: 700,
- top: 400,
- bottom: 400,
-};
-
-const MIN_ZONE_DIM: Dim = Dim {
- w: 25,
- h: 25,
-};
-
static INSTANCE_COUNT: atomic::AtomicU32 = atomic::AtomicU32::new(1);
fn next_id() -> ZoneId {
INSTANCE_COUNT.fetch_add(1, atomic::Ordering::Relaxed) as ZoneId
}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-enum Disposition {
- Unchanged(Decoration),
- Changed(Region, Decoration),
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum PlacementMethod {
- /// Does not inhibit free placement of clients
- Free,
-
- /// Arranges clients along a predefined layout
- Tile,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum PlacementKind {
- Client(Window),
- Tab(usize),
- Layout,
-}
-
-impl PlacementKind {
- pub fn from_zone_content(content: &ZoneContent) -> Self {
- match content {
- ZoneContent::Client(window) => PlacementKind::Client(*window),
- ZoneContent::Tab(zones) => PlacementKind::Tab(zones.len()),
- ZoneContent::Layout(..) => PlacementKind::Layout,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum PlacementRegion {
- NoRegion,
- FreeRegion,
- NewRegion(Region),
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Placement {
- pub method: PlacementMethod,
- pub kind: PlacementKind,
- pub zone: ZoneId,
- pub region: PlacementRegion,
- pub decoration: Decoration,
-}
-
-type LayoutFn = fn(&Region, &LayoutData, Vec<bool>) -> Vec<(Disposition, bool)>;
-
-#[non_exhaustive]
-#[derive(Debug, PartialEq, Clone, Copy)]
-pub struct LayoutConfig {
- pub method: PlacementMethod,
- pub decoration: Decoration,
- pub root_only: bool,
- pub margin: bool,
- pub gap: bool,
- pub persistent: bool,
- pub single: bool,
- pub wraps: bool,
-}
-
-impl Default for LayoutConfig {
- fn default() -> Self {
- Self {
- method: PlacementMethod::Free,
- decoration: Default::default(),
- root_only: true,
- margin: false,
- gap: false,
- persistent: false,
- single: false,
- wraps: true,
- }
- }
-}
-
-#[non_exhaustive]
-#[derive(Debug, PartialEq, Clone, Copy)]
-pub struct LayoutData {
- /// Generic layout data
- pub margin: Padding,
- pub gap_size: u32,
-
- /// Tiled layout data
- pub main_count: u32,
- pub main_factor: f32,
-}
-
-impl Default for LayoutData {
- fn default() -> Self {
- Self {
- margin: Default::default(),
- gap_size: 0u32,
-
- main_count: 1u32,
- main_factor: 0.50f32,
- }
- }
-}
-
-#[non_exhaustive]
-#[repr(u8)]
-#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, EnumIter, EnumCount, ToString)]
-pub enum LayoutKind {
- /// Free layouts
- Float = b'f',
- BLFloat = b'F',
- SingleFloat = b'z',
- BLSingleFloat = b'Z',
-
- /// Tiled layouts
- // Overlapping
- Center = b';',
- Monocle = b'%',
- // Non-overlapping
- Paper = b'p',
- SPaper = b'P',
- Stack = b's',
- SStack = b'S',
- BStack = b'b',
- BSStack = b'B',
- Horz = b'h',
- SHorz = b'H',
- Vert = b'v',
- SVert = b'V',
-}
-
-impl LayoutKind {
- pub fn symbol(&self) -> char {
- (*self as u8) as char
- }
-
- pub fn name(&self) -> String {
- self.to_string()
- }
-
- fn config(&self) -> LayoutConfig {
- match *self {
- LayoutKind::Float => LayoutConfig {
- method: PlacementMethod::Free,
- decoration: FREE_DECORATION,
- root_only: true,
- margin: false,
- gap: false,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::BLFloat => LayoutConfig {
- method: PlacementMethod::Free,
- decoration: NO_DECORATION,
- root_only: true,
- margin: false,
- gap: false,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::SingleFloat => LayoutConfig {
- method: PlacementMethod::Free,
- decoration: FREE_DECORATION,
- root_only: true,
- margin: false,
- gap: false,
- persistent: true,
- single: true,
- wraps: true,
- },
- LayoutKind::BLSingleFloat => LayoutConfig {
- method: PlacementMethod::Free,
- decoration: NO_DECORATION,
- root_only: true,
- margin: false,
- gap: false,
- persistent: true,
- single: true,
- wraps: true,
- },
- LayoutKind::Center => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: NO_DECORATION,
- root_only: false,
- margin: true,
- gap: true,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::Monocle => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: NO_DECORATION,
- root_only: false,
- margin: true,
- gap: true,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::Paper => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 1,
- right: 1,
- top: 0,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: true,
- persistent: true,
- single: false,
- wraps: false,
- },
- LayoutKind::SPaper => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 1,
- right: 1,
- top: 0,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: false,
- persistent: true,
- single: false,
- wraps: false,
- },
- LayoutKind::Stack => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: true,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::SStack => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: false,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::BStack => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: true,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::BSStack => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: false,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::Horz => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: true,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::SHorz => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: false,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::Vert => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: true,
- persistent: false,
- single: false,
- wraps: true,
- },
- LayoutKind::SVert => LayoutConfig {
- method: PlacementMethod::Tile,
- decoration: Decoration {
- frame: Some(Frame {
- extents: Extents {
- left: 0,
- right: 0,
- top: 3,
- bottom: 0,
- },
- colors: Default::default(),
- }),
- border: None,
- },
- root_only: false,
- margin: true,
- gap: false,
- persistent: false,
- single: false,
- wraps: true,
- },
-
- #[allow(unreachable_patterns)]
- _ => unimplemented!("{:?} does not have an associated configuration", self),
- }
- }
-
- fn default_data(&self) -> LayoutData {
- match *self {
- LayoutKind::Float => Default::default(),
- LayoutKind::BLFloat => Default::default(),
- LayoutKind::SingleFloat => Default::default(),
- LayoutKind::BLSingleFloat => Default::default(),
- LayoutKind::Center => LayoutData {
- main_count: 5u32,
- main_factor: 0.40f32,
- ..Default::default()
- },
- LayoutKind::Monocle => Default::default(),
- LayoutKind::Paper => Default::default(),
- LayoutKind::SPaper => Default::default(),
- LayoutKind::Stack => LayoutData {
- main_count: 1u32,
- main_factor: 0.50f32,
- ..Default::default()
- },
- LayoutKind::SStack => LayoutData {
- main_count: 1u32,
- main_factor: 0.50f32,
- ..Default::default()
- },
- LayoutKind::BStack => LayoutData {
- main_count: 1u32,
- main_factor: 0.50f32,
- ..Default::default()
- },
- LayoutKind::BSStack => LayoutData {
- main_count: 1u32,
- main_factor: 0.50f32,
- ..Default::default()
- },
- LayoutKind::Horz => Default::default(),
- LayoutKind::SHorz => Default::default(),
- LayoutKind::Vert => Default::default(),
- LayoutKind::SVert => Default::default(),
-
- #[allow(unreachable_patterns)]
- _ => unimplemented!("{:?} does not have associated default data", self),
- }
- }
-
- #[inline]
- fn stack_split(
- n: usize,
- n_main: u32,
- ) -> (u32, u32) {
- let n = n as u32;
-
- if n <= n_main {
- (n, 0)
- } else {
- (n_main, n - n_main)
- }
- }
-
- fn func(&self) -> LayoutFn {
- match *self {
- LayoutKind::Float => |_, _, active_map| {
- let config = &LayoutKind::Float.config();
- vec![(Disposition::Unchanged(config.decoration), true); active_map.len()]
- },
- LayoutKind::BLFloat => |_, _, active_map| {
- let config = &LayoutKind::BLFloat.config();
- vec![(Disposition::Unchanged(config.decoration), true); active_map.len()]
- },
- LayoutKind::SingleFloat => |_, _, active_map| {
- let config = &LayoutKind::SingleFloat.config();
- active_map
- .into_iter()
- .map(|b| (Disposition::Unchanged(config.decoration), b))
- .collect()
- },
- LayoutKind::BLSingleFloat => |_, _, active_map| {
- let config = &LayoutKind::BLSingleFloat.config();
- active_map
- .into_iter()
- .map(|b| (Disposition::Unchanged(config.decoration), b))
- .collect()
- },
- LayoutKind::Center => |region, data, active_map| {
- let config = &LayoutKind::Center.config();
- let (pos, dim) = region.values();
-
- let h_comp = MAX_MAIN_COUNT + 1;
- let w_ratio: f32 = data.main_factor / 0.95;
- let h_ratio: f32 = (h_comp - data.main_count) as f32 / h_comp as f32;
-
- active_map
- .into_iter()
- .map(|_| {
- (
- Disposition::Changed(
- Region {
- pos,
- dim,
- }
- .from_absolute_inner_center(&Dim {
- w: (dim.w as f32 * w_ratio) as u32,
- h: (dim.h as f32 * h_ratio) as u32,
- }),
- config.decoration,
- ),
- true,
- )
- })
- .collect()
- },
- LayoutKind::Monocle => |region, _, active_map| {
- let config = &LayoutKind::Monocle.config();
- let (pos, dim) = region.values();
-
- active_map
- .into_iter()
- .map(|_| {
- (
- Disposition::Changed(
- Region {
- pos,
- dim,
- },
- config.decoration,
- ),
- true,
- )
- })
- .collect()
- },
- LayoutKind::Paper => |region, data, active_map| {
- const MIN_W_RATIO: f32 = 0.5;
-
- let config = &LayoutKind::Paper.config();
- let (pos, dim) = region.values();
- let n = active_map.len();
-
- if n == 1 {
- return vec![(Disposition::Changed(*region, NO_DECORATION), true)];
- }
-
- let cw = (dim.w as f32
- * if data.main_factor > MIN_W_RATIO {
- data.main_factor
- } else {
- MIN_W_RATIO
- }) as u32;
-
- let w = ((dim.w - cw) as usize / (n - 1)) as i32;
- let mut after_active = false;
-
- active_map
- .into_iter()
- .enumerate()
- .map(|(i, active)| {
- if active {
- after_active = true;
-
- (
- Disposition::Changed(
- Region::new(pos.x + i as i32 * w, pos.y, cw, dim.h),
- config.decoration,
- ),
- true,
- )
- } else {
- let mut x = pos.x + i as i32 * w;
-
- if after_active {
- x += cw as i32 - w;
- }
-
- (
- Disposition::Changed(
- Region::new(x, pos.y, w as u32, dim.h),
- config.decoration,
- ),
- true,
- )
- }
- })
- .collect()
- },
- LayoutKind::SPaper => |region, data, active_map| {
- let mut region = region.clone();
- Layout::adjust_for_gap_size(&mut region, data.gap_size, &MIN_ZONE_DIM);
-
- (Self::Paper.func())(®ion, data, active_map)
- },
- LayoutKind::Stack => |region, data, active_map| {
- let (pos, dim) = region.values();
- let n = active_map.len();
-
- if n == 1 {
- return vec![(Disposition::Changed(*region, NO_DECORATION), true)];
- }
-
- let (n_main, n_stack) = Self::stack_split(n, data.main_count);
- let h_stack = if n_stack > 0 { dim.h / n_stack } else { 0 };
- let h_main = if n_main > 0 { dim.h / n_main } else { 0 };
-
- let div = if data.main_count > 0 {
- (dim.w as f32 * data.main_factor) as i32
- } else {
- 0
- };
-
- let config = &LayoutKind::Stack.config();
- active_map
- .into_iter()
- .enumerate()
- .map(|(i, _)| {
- let i = i as u32;
-
- if i < data.main_count {
- let w = if n_stack == 0 { dim.w } else { div as u32 };
-
- (
- Disposition::Changed(
- Region::new(pos.x, pos.y + (i * h_main) as i32, w, h_main),
- config.decoration,
- ),
- true,
- )
- } else {
- let sn = (i - data.main_count) as i32;
-
- (
- Disposition::Changed(
- Region::new(
- pos.x + div,
- pos.y + sn * h_stack as i32,
- dim.w - div as u32,
- h_stack,
- ),
- config.decoration,
- ),
- true,
- )
- }
- })
- .collect()
- },
- LayoutKind::SStack => |region, data, active_map| {
- let mut region = region.clone();
- Layout::adjust_for_gap_size(&mut region, data.gap_size, &MIN_ZONE_DIM);
-
- (Self::Stack.func())(®ion, data, active_map)
- },
- LayoutKind::BStack => |region, _data, active_map| {
- let (_pos, _dim) = region.values();
- let n = active_map.len();
-
- if n == 1 {
- return vec![(Disposition::Changed(*region, NO_DECORATION), true)];
- }
-
- todo!()
- },
- LayoutKind::BSStack => |region, data, active_map| {
- let mut region = region.clone();
- Layout::adjust_for_gap_size(&mut region, data.gap_size, &MIN_ZONE_DIM);
-
- (Self::BStack.func())(®ion, data, active_map)
- },
- LayoutKind::Horz => |_region, _data, _active_map| {
- todo!()
- },
- LayoutKind::SHorz => |_region, _data, _active_map| {
- todo!()
- },
- LayoutKind::Vert => |_region, _data, _active_map| {
- todo!()
- },
- LayoutKind::SVert => |_region, _data, _active_map| {
- todo!()
- },
-
- #[allow(unreachable_patterns)]
- _ => unimplemented!("{:?} does not have an associated function", self),
- }
- }
-}
-
-pub struct Layout {
- kind: LayoutKind,
- prev_kind: LayoutKind,
- data: HashMap<LayoutKind, LayoutData>,
-}
-
-impl Layout {
- #[inline]
- pub fn new() -> Self {
- let kind = LayoutKind::Stack;
- let mut data = HashMap::with_capacity(LayoutKind::COUNT);
-
- for kind in LayoutKind::iter() {
- data.insert(kind, kind.default_data());
- }
-
- Self {
- kind,
- prev_kind: kind,
- data,
- }
- }
-
- #[inline]
- pub fn with_kind(kind: LayoutKind) -> Self {
- let mut data = HashMap::with_capacity(LayoutKind::COUNT);
-
- for kind in LayoutKind::iter() {
- data.insert(kind, kind.default_data());
- }
-
- Self {
- kind,
- prev_kind: kind,
- data,
- }
- }
-
- #[inline]
- fn config(&self) -> LayoutConfig {
- self.kind.config()
- }
-
- #[inline]
- fn prev_data(&self) -> &LayoutData {
- self.data.get(&self.prev_kind).unwrap()
- }
-
- #[inline]
- fn data(&self) -> &LayoutData {
- self.data.get(&self.kind).unwrap()
- }
-
- #[inline]
- fn data_mut(&mut self) -> &mut LayoutData {
- self.data.get_mut(&self.kind).unwrap()
- }
-
- #[inline]
- fn default_data(&self) -> LayoutData {
- self.kind.default_data()
- }
-
- #[inline]
- fn set_kind(
- &mut self,
- kind: LayoutKind,
- ) -> Result<LayoutKind, StateChangeError> {
- if kind == self.kind {
- return Err(StateChangeError::EarlyStop);
- }
-
- self.prev_kind = self.kind;
- self.kind = kind;
-
- Ok(self.prev_kind)
- }
-
- #[inline]
- fn adjust_for_margin(
- region: Region,
- extents: &Extents,
- ) -> Region {
- Region {
- pos: Pos {
- x: region.pos.x + extents.left as i32,
- y: region.pos.y + extents.top as i32,
- },
- dim: Dim {
- w: region.dim.w - extents.left - extents.right,
- h: region.dim.h - extents.top - extents.bottom,
- },
- }
- }
-
- #[inline]
- fn adjust_for_gap_size(
- region: &mut Region,
- gap_size: u32,
- min_dim: &Dim,
- ) {
- let dim_gap = 2 * gap_size as i32;
-
- let new_w = region.dim.w as i32 - dim_gap;
- if new_w < min_dim.w as i32 {
- region.pos.x += ((region.dim.w as i32 - min_dim.w as i32) as f32 / 2f32) as i32;
- region.dim.w = min_dim.w;
- } else {
- region.dim.w = new_w as u32;
- region.pos.x += gap_size as i32;
- }
-
- let new_h = region.dim.h as i32 - dim_gap;
- if new_h < min_dim.h as i32 {
- region.pos.y += ((region.dim.h as i32 - min_dim.h as i32) as f32 / 2f32) as i32;
- region.dim.h = min_dim.h;
- } else {
- region.dim.h = new_h as u32;
- region.pos.y += gap_size as i32;
- }
- }
-}
-
-impl Default for Layout {
- fn default() -> Self {
- Self {
- kind: LayoutKind::Stack,
- prev_kind: LayoutKind::Stack,
- data: HashMap::new(),
- }
- }
-}
-
-trait Apply {
- fn apply(
- &self,
- region: Region,
- active_map: Vec<bool>,
- ) -> (PlacementMethod, Vec<(Disposition, bool)>);
-}
-
-impl Apply for Layout {
- fn apply(
- &self,
- region: Region,
- active_map: Vec<bool>,
- ) -> (PlacementMethod, Vec<(Disposition, bool)>) {
- let config = self.kind.config();
- let data = self.data();
-
- let region = if config.margin {
- Self::adjust_for_margin(region, &data.margin)
- } else {
- region
- };
-
- (
- config.method,
- (self.kind.func())(®ion, &data, active_map)
- .into_iter()
- .map(|(mut disposition, is_visible)| {
- if config.gap {
- match disposition {
- Disposition::Unchanged(_) => {},
- Disposition::Changed(ref mut region, _) => {
- Self::adjust_for_gap_size(region, data.gap_size, &MIN_ZONE_DIM);
- },
- }
- }
-
- (disposition, is_visible)
- })
- .collect(),
- )
- }
-}
-
#[derive(Debug, PartialEq)]
pub enum ZoneContent {
Client(Window),
@@ -957,7 +62,7 @@ impl Zone {
method: PlacementMethod::Free,
content,
region,
- decoration: NO_DECORATION,
+ decoration: Decoration::NO_DECORATION,
is_visible: true,
})
}
@@ -981,14 +86,14 @@ impl Zone {
pub fn prev_kind(&self) -> Result<LayoutKind, StateChangeError> {
match &self.content {
- ZoneContent::Layout(layout, _) => Ok(layout.prev_kind),
+ ZoneContent::Layout(layout, _) => Ok(layout.prev_kind()),
_ => Err(StateChangeError::InvalidCaller),
}
}
pub fn kind(&self) -> Result<LayoutKind, StateChangeError> {
match &self.content {
- ZoneContent::Layout(layout, _) => Ok(layout.kind),
+ ZoneContent::Layout(layout, _) => Ok(layout.kind()),
_ => Err(StateChangeError::InvalidCaller),
}
}
@@ -1037,7 +142,7 @@ impl Zone {
pub fn config(&self) -> Option<LayoutConfig> {
match self.content {
- ZoneContent::Layout(ref layout, _) => Some(layout.kind.config()),
+ ZoneContent::Layout(ref layout, _) => Some(layout.config()),
_ => None,
}
}
@@ -1238,11 +343,11 @@ impl ZoneManager {
pub fn cycle_config(
&self,
id: ZoneId,
- ) -> Option<LayoutConfig> {
- let cycle = self.nearest_cycle(id);
+ ) -> Option<(ZoneId, Option<LayoutConfig>)> {
+ let cycle = self.next_cycle(id)?;
let zone = self.zone(cycle);
- zone.config()
+ Some((cycle, zone.config()))
}
pub fn is_cycle(
@@ -1299,6 +404,31 @@ impl ZoneManager {
None
}
+ pub fn is_within_persisent(
+ &self,
+ mut id: ZoneId,
+ ) -> bool {
+ while let Some(next_id) = self.parent_id(id) {
+ let zone = self.zone_map.get(&next_id).unwrap();
+
+ match zone.content {
+ ZoneContent::Tab(_) => {
+ return true;
+ },
+ ZoneContent::Layout(ref layout, _) => {
+ if layout.config().persistent {
+ return true;
+ }
+ },
+ _ => {},
+ }
+
+ id = next_id;
+ }
+
+ false
+ }
+
fn gather_subzones(
&self,
zone: ZoneId,
@@ -1342,7 +472,7 @@ impl ZoneManager {
let method = match &zone.content {
ZoneContent::Tab(_) => PlacementMethod::Tile,
- ZoneContent::Layout(layout, _) => layout.kind.config().method,
+ ZoneContent::Layout(layout, _) => layout.config().method,
_ => panic!("attempting to derive method from non-cycle"),
};
@@ -1366,7 +496,7 @@ impl ZoneManager {
ZoneContent::Client(window) => {
return vec![Placement {
method,
- kind: PlacementKind::Client(*window),
+ kind: PlacementTarget::Client(*window),
zone: id,
region: if method == PlacementMethod::Free {
PlacementRegion::FreeRegion
@@ -1379,7 +509,7 @@ impl ZoneManager {
ZoneContent::Tab(zones) => {
let mut placements = vec![Placement {
method,
- kind: PlacementKind::Tab(zones.len()),
+ kind: PlacementTarget::Tab(zones.len()),
zone: id,
region: if method == PlacementMethod::Free {
PlacementRegion::FreeRegion
@@ -1390,62 +520,50 @@ impl ZoneManager {
decoration,
}];
- let active_element = zones.active_element();
- active_element.into_iter().for_each(|&id| {
- zone_changes.push((id, ZoneChange::Visible(true)));
-
- self.gather_subzones(id, true).into_iter().for_each(|id| {
- zone_changes.push((id, ZoneChange::Visible(true)));
- });
- });
+ let mut region = region;
+ Layout::adjust_for_border(&mut region, 1, &Zone::MIN_ZONE_DIM);
- zones
+ let active_element = zones.active_element().copied();
+ let zones: Vec<ZoneId> = zones
.iter()
- .filter(|&id| Some(id) != active_element)
- .for_each(|&id| {
- zone_changes.push((id, ZoneChange::Visible(false)));
-
- self.gather_subzones(id, true).into_iter().for_each(|id| {
- zone_changes.push((id, ZoneChange::Visible(false)));
- });
- });
+ .filter(|&id| !to_ignore.contains(id))
+ .copied()
+ .collect();
- match active_element {
- None => placements,
- Some(&id) => {
- let subzones = self.gather_subzones(id, true);
- let method = PlacementMethod::Tile;
+ zones.into_iter().for_each(|id| {
+ let is_active_element = Some(id) == active_element;
+ let subzones = self.gather_subzones(id, !is_active_element);
+ let method = PlacementMethod::Tile;
- subzones.into_iter().for_each(|id| {
- zone_changes.push((id, ZoneChange::Visible(true)));
- zone_changes.push((id, ZoneChange::Region(region)));
- zone_changes.push((id, ZoneChange::Method(method)));
- });
+ subzones.into_iter().for_each(|id| {
+ zone_changes.push((id, ZoneChange::Visible(is_active_element)));
+ zone_changes.push((id, ZoneChange::Region(region)));
+ zone_changes.push((id, ZoneChange::Method(method)));
+ });
- placements.extend(self.arrange_subzones(
- id,
- region,
- Decoration {
- frame: None,
- border: Some(Border {
- width: 1,
- colors: Default::default(),
- }),
- },
- method,
- to_ignore,
- ));
+ placements.extend(self.arrange_subzones(
+ id,
+ region,
+ Decoration {
+ frame: None,
+ border: Some(Border {
+ width: 1,
+ colors: Default::default(),
+ }),
+ },
+ method,
+ to_ignore,
+ ));
+ });
- placements
- },
- }
+ placements
},
ZoneContent::Layout(layout, zones) => {
let active_element = zones.active_element();
let mut subplacements = Vec::new();
let mut placements = vec![Placement {
method,
- kind: PlacementKind::Layout,
+ kind: PlacementTarget::Layout,
zone: id,
region: if method == PlacementMethod::Free {
PlacementRegion::FreeRegion
@@ -1458,7 +576,7 @@ impl ZoneManager {
let zones: Vec<ZoneId> = zones
.iter()
.filter(|&id| layout.config().single || !to_ignore.contains(id))
- .map(|&id| id)
+ .copied()
.collect();
let (method, application) = layout.apply(
@@ -1481,7 +599,7 @@ impl ZoneManager {
placements.push(Placement {
method,
- kind: PlacementKind::from_zone_content(&self.zone(id).content),
+ kind: PlacementTarget::from_zone_content(&self.zone(id).content),
zone: id,
region: PlacementRegion::NoRegion,
decoration,
@@ -1493,7 +611,7 @@ impl ZoneManager {
.map(|id| {
placements.push(Placement {
method,
- kind: PlacementKind::from_zone_content(
+ kind: PlacementTarget::from_zone_content(
&self.zone(id).content,
),
zone: id,
@@ -1567,31 +685,3 @@ impl Identify for Zone {
self.id as Ident
}
}
-
-impl std::cmp::PartialEq<Self> for Layout {
- fn eq(
- &self,
- other: &Self,
- ) -> bool {
- self.kind == other.kind && self.data.get(&self.kind) == other.data.get(&other.kind)
- }
-}
-
-impl Identify for Layout {
- fn id(&self) -> Ident {
- self.kind as Ident
- }
-}
-
-impl std::fmt::Debug for Layout {
- fn fmt(
- &self,
- f: &mut std::fmt::Formatter<'_>,
- ) -> std::fmt::Result {
- f.debug_struct("Layout")
- .field("kind", &self.kind)
- .field("prev_kind", &self.prev_kind)
- .field("data", &self.data.get(&self.kind))
- .finish()
- }
-}
diff --git a/src/winsys/common.rs b/src/winsys/common.rs
@@ -1,1073 +0,0 @@
-use std::default::Default;
-use std::ops::Add;
-use std::ops::AddAssign;
-use std::ops::Sub;
-use std::ops::SubAssign;
-
-pub type Atom = u32;
-pub type Window = u32;
-pub type Pid = u32;
-pub type Extents = Padding;
-
-pub struct Hex32(pub u32);
-
-impl std::fmt::Debug for Hex32 {
- fn fmt(
- &self,
- f: &mut std::fmt::Formatter<'_>,
- ) -> std::fmt::Result {
- write!(f, "{:#0x}", &self.0)
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub enum IcccmWindowState {
- Withdrawn,
- Normal,
- Iconic,
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub enum WindowState {
- Modal,
- Sticky,
- MaximizedVert,
- MaximizedHorz,
- Shaded,
- SkipTaskbar,
- SkipPager,
- Hidden,
- Fullscreen,
- Above,
- Below,
- DemandsAttention,
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub enum WindowType {
- Desktop,
- Dock,
- Toolbar,
- Menu,
- Utility,
- Splash,
- Dialog,
- DropdownMenu,
- PopupMenu,
- Tooltip,
- Notification,
- Combo,
- Dnd,
- Normal,
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub enum Grip {
- Edge(Edge),
- Corner(Corner),
-}
-
-impl Grip {
- pub fn is_top_grip(&self) -> bool {
- *self == Grip::Edge(Edge::Top)
- || *self == Grip::Corner(Corner::TopLeft)
- || *self == Grip::Corner(Corner::TopRight)
- }
-
- pub fn is_left_grip(&self) -> bool {
- *self == Grip::Edge(Edge::Left)
- || *self == Grip::Corner(Corner::TopLeft)
- || *self == Grip::Corner(Corner::BottomLeft)
- }
-}
-
-#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
-pub enum Edge {
- Left,
- Right,
- Top,
- Bottom,
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub enum Corner {
- TopLeft,
- TopRight,
- BottomLeft,
- BottomRight,
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Region {
- pub pos: Pos,
- pub dim: Dim,
-}
-
-impl Default for Region {
- fn default() -> Self {
- Self {
- pos: Default::default(),
- dim: Default::default(),
- }
- }
-}
-
-impl Region {
- pub fn new(
- x: i32,
- y: i32,
- w: u32,
- h: u32,
- ) -> Self {
- Self {
- pos: Pos {
- x,
- y,
- },
- dim: Dim {
- w,
- h,
- },
- }
- }
-
- pub fn values(&self) -> (Pos, Dim) {
- (self.pos, self.dim)
- }
-
- pub fn with_size_hints(
- self,
- size_hints: &Option<SizeHints>,
- ) -> Self {
- let mut geometry = self;
-
- if let Some(size_hints) = size_hints {
- size_hints.apply(&mut geometry.dim);
- }
-
- geometry
- }
-
- pub fn encompasses(
- &self,
- pos: Pos,
- ) -> bool {
- pos.x >= self.pos.x
- && pos.y >= self.pos.y
- && pos.x <= self.pos.x + self.dim.w as i32
- && pos.y <= self.pos.y + self.dim.h as i32
- }
-
- pub fn contains(
- &self,
- region: Region,
- ) -> bool {
- self.encompasses(region.pos) && self.encompasses(region.bottom_right())
- }
-
- pub fn occludes(
- &self,
- region: Region,
- ) -> bool {
- self.encompasses(region.pos) || region.encompasses(self.pos)
- }
-
- pub fn nearest_corner(
- &self,
- mut pos: Pos,
- ) -> Corner {
- pos += self.pos.dist(Pos {
- x: 0,
- y: 0,
- });
- self.dim.nearest_corner(pos)
- }
-
- pub fn quadrant_center_from_pos(
- &self,
- pos: Pos,
- ) -> Option<Pos> {
- if self.encompasses(pos) {
- return None;
- }
-
- let mut dists = vec![
- (Corner::TopLeft, self.pos.dist(pos).pythagorean()),
- (Corner::TopRight, self.top_right().dist(pos).pythagorean()),
- (
- Corner::BottomLeft,
- self.bottom_left().dist(pos).pythagorean(),
- ),
- (
- Corner::BottomRight,
- self.bottom_right().dist(pos).pythagorean(),
- ),
- ];
-
- dists.sort_by_key(|&(corner, dist)| dist);
-
- match dists.first().unwrap() {
- (Corner::TopLeft, _) => {
- let (left, _) = self.split_at_width((self.dim.w as f64 / 2f64).round() as u32);
- let (topleft, _) = left.split_at_height((left.dim.h as f64 / 2f64).round() as u32);
-
- Some(Pos::from_center_of_region(topleft))
- },
- (Corner::TopRight, _) => {
- let (_, right) = self.split_at_width((self.dim.w as f64 / 2f64).round() as u32);
- let (topright, _) =
- right.split_at_height((right.dim.h as f64 / 2f64).round() as u32);
-
- Some(Pos::from_center_of_region(topright))
- },
- (Corner::BottomLeft, _) => {
- let (left, _) = self.split_at_width((self.dim.w as f64 / 2f64).round() as u32);
- let (_, bottomleft) =
- left.split_at_height((left.dim.h as f64 / 2f64).round() as u32);
-
- Some(Pos::from_center_of_region(bottomleft))
- },
- (Corner::BottomRight, _) => {
- let (_, right) = self.split_at_width((self.dim.w as f64 / 2f64).round() as u32);
- let (_, bottomright) =
- right.split_at_height((right.dim.h as f64 / 2f64).round() as u32);
-
- Some(Pos::from_center_of_region(bottomright))
- },
- }
- }
-
- pub fn split_at_width(
- &self,
- width: u32,
- ) -> (Self, Self) {
- assert!(width < self.dim.w, "desired width exceeds divisible width.");
-
- (
- Self {
- dim: Dim {
- w: width,
- ..self.dim
- },
- ..*self
- },
- Self {
- pos: Pos {
- x: self.pos.x + width as i32,
- ..self.pos
- },
- dim: Dim {
- w: self.dim.w - width,
- ..self.dim
- },
- },
- )
- }
-
- pub fn split_at_height(
- &self,
- height: u32,
- ) -> (Self, Self) {
- assert!(
- height < self.dim.h,
- "desired height exceeds divisible height."
- );
-
- (
- Self {
- dim: Dim {
- h: height,
- ..self.dim
- },
- ..*self
- },
- Self {
- pos: Pos {
- y: self.pos.y + height as i32,
- ..self.pos
- },
- dim: Dim {
- h: self.dim.h - height,
- ..self.dim
- },
- },
- )
- }
-
- pub fn with_minimum_dim(
- self,
- minimum_dim: &Dim,
- ) -> Self {
- Self {
- pos: self.pos,
- dim: Dim {
- w: std::cmp::max(minimum_dim.w, self.dim.w),
- h: std::cmp::max(minimum_dim.h, self.dim.h),
- },
- }
- }
-
- pub fn with_maximum_dim(
- self,
- maximum_dim: &Dim,
- ) -> Self {
- Self {
- pos: self.pos,
- dim: Dim {
- w: std::cmp::min(maximum_dim.w, self.dim.w),
- h: std::cmp::min(maximum_dim.h, self.dim.h),
- },
- }
- }
-
- pub fn from_absolute_inner_center(
- 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,
- },
- dim: *dim,
- }
- }
-
- pub fn without_extents(
- mut self,
- extents: &Extents,
- ) -> Self {
- self.pos.x += extents.left as i32;
- self.pos.y += extents.top as i32;
- self.dim.w -= extents.left + extents.right;
- self.dim.h -= extents.top + extents.bottom;
- self
- }
-
- pub fn with_extents(
- mut self,
- extents: &Extents,
- ) -> Self {
- self.pos.x -= extents.left as i32;
- self.pos.y -= extents.top as i32;
- self.dim.w += extents.left + extents.right;
- self.dim.h += extents.top + extents.bottom;
- self
- }
-
- pub fn top_right(&self) -> Pos {
- Pos {
- x: self.pos.x + self.dim.w as i32,
- y: self.pos.y,
- }
- }
-
- pub fn bottom_left(&self) -> Pos {
- Pos {
- x: self.pos.x,
- y: self.pos.y + self.dim.h as i32,
- }
- }
-
- pub fn bottom_right(&self) -> Pos {
- Pos {
- x: self.pos.x + self.dim.w as i32,
- y: self.pos.y + self.dim.h as i32,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Pos {
- pub x: i32,
- pub y: i32,
-}
-
-impl Default for Pos {
- fn default() -> Self {
- Self {
- x: 0,
- y: 0,
- }
- }
-}
-
-impl Pos {
- pub fn from_center_of_region(region: Region) -> Self {
- Self {
- x: region.pos.x + (region.dim.w as f32 / 2f32) as i32,
- y: region.pos.y + (region.dim.h as f32 / 2f32) as i32,
- }
- }
-
- pub fn from_center_of_dim(dim: Dim) -> Self {
- Self {
- x: dim.w as i32 / 2,
- y: dim.h as i32 / 2,
- }
- }
-
- pub fn values(&self) -> (i32, i32) {
- (self.x, self.y)
- }
-
- pub fn dist(
- &self,
- pos: Self,
- ) -> Distance {
- Distance {
- dx: (pos.x - self.x),
- dy: (pos.y - self.y),
- }
- }
-
- pub fn relative_to(
- &self,
- pos: Self,
- ) -> Self {
- Pos {
- x: self.x - pos.x,
- y: self.y - pos.y,
- }
- }
-}
-
-impl Add<Pos> for Pos {
- type Output = Self;
-
- fn add(
- self,
- other: Pos,
- ) -> Self::Output {
- Self::Output {
- x: self.x + other.x,
- y: self.y + other.y,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Dim {
- pub w: u32,
- pub h: u32,
-}
-
-impl Default for Dim {
- fn default() -> Self {
- Self {
- w: 480,
- h: 260,
- }
- }
-}
-
-impl Dim {
- pub fn values(&self) -> (u32, u32) {
- (self.w, self.h)
- }
-
- pub fn center(&self) -> Pos {
- Pos {
- x: (self.w as f32 / 2f32) as i32,
- y: (self.h as f32 / 2f32) as i32,
- }
- }
-
- pub fn nearest_corner(
- &self,
- pos: Pos,
- ) -> Corner {
- let center = self.center();
-
- if pos.x >= center.x {
- if pos.y >= center.y {
- Corner::BottomRight
- } else {
- Corner::TopRight
- }
- } else {
- if pos.y >= center.y {
- Corner::BottomLeft
- } else {
- Corner::TopLeft
- }
- }
- }
-}
-
-impl Add<Dim> for Pos {
- type Output = Self;
-
- fn add(
- self,
- other: Dim,
- ) -> Self::Output {
- Self::Output {
- x: self.x + other.w as i32,
- y: self.y + other.h as i32,
- }
- }
-}
-
-impl Sub<Dim> for Pos {
- type Output = Self;
-
- fn sub(
- self,
- other: Dim,
- ) -> Self::Output {
- Self::Output {
- x: self.x - other.w as i32,
- y: self.y - other.h as i32,
- }
- }
-}
-
-impl Sub for Pos {
- type Output = Dim;
-
- fn sub(
- self,
- other: Self,
- ) -> Self::Output {
- Self::Output {
- w: (self.x as i32 - other.x) as u32,
- h: (self.y as i32 - other.y) as u32,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Distance {
- pub dx: i32,
- pub dy: i32,
-}
-
-impl Distance {
- pub fn values(&self) -> (i32, i32) {
- (self.dx, self.dy)
- }
-
- pub fn pythagorean(&self) -> u32 {
- let dx = self.dx.pow(2) as f64;
- let dy = self.dy.pow(2) as f64;
-
- (dx + dy).sqrt().round() as u32
- }
-}
-
-impl Add<Distance> for Pos {
- type Output = Self;
-
- fn add(
- self,
- dist: Distance,
- ) -> Self::Output {
- Self::Output {
- x: self.x + dist.dx,
- y: self.y + dist.dy,
- }
- }
-}
-
-impl AddAssign<Distance> for Pos {
- fn add_assign(
- &mut self,
- dist: Distance,
- ) {
- *self = Self {
- x: self.x + dist.dx,
- y: self.y + dist.dy,
- };
- }
-}
-
-impl Sub<Distance> for Pos {
- type Output = Self;
-
- fn sub(
- self,
- dist: Distance,
- ) -> Self::Output {
- Self::Output {
- x: self.x - dist.dx,
- y: self.y - dist.dy,
- }
- }
-}
-
-impl SubAssign<Distance> for Pos {
- fn sub_assign(
- &mut self,
- dist: Distance,
- ) {
- *self = Self {
- x: self.x - dist.dx,
- y: self.y - dist.dy,
- };
- }
-}
-
-impl Add<Distance> for Dim {
- type Output = Self;
-
- fn add(
- self,
- dist: Distance,
- ) -> Self::Output {
- Self::Output {
- w: (self.w as i32 + dist.dx).abs() as u32,
- h: (self.h as i32 + dist.dy).abs() as u32,
- }
- }
-}
-
-impl AddAssign<Distance> for Dim {
- fn add_assign(
- &mut self,
- dist: Distance,
- ) {
- *self = Self {
- w: (self.w as i32 + dist.dx).abs() as u32,
- h: (self.h as i32 + dist.dy).abs() as u32,
- };
- }
-}
-
-impl Sub<Distance> for Dim {
- type Output = Self;
-
- fn sub(
- self,
- dist: Distance,
- ) -> Self::Output {
- Self::Output {
- w: (self.w as i32 - dist.dx).abs() as u32,
- h: (self.h as i32 - dist.dy).abs() as u32,
- }
- }
-}
-
-impl SubAssign<Distance> for Dim {
- fn sub_assign(
- &mut self,
- dist: Distance,
- ) {
- *self = Self {
- w: (self.w as i32 - dist.dx).abs() as u32,
- h: (self.h as i32 - dist.dy).abs() as u32,
- };
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Ratio {
- pub numerator: i32,
- pub denominator: i32,
-}
-
-impl Ratio {
- pub fn new(
- numerator: i32,
- denominator: i32,
- ) -> Self {
- Self {
- numerator,
- denominator,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialOrd)]
-pub struct SizeHints {
- pub by_user: bool,
- pub pos: Option<Pos>,
- pub min_width: Option<u32>,
- pub min_height: Option<u32>,
- pub max_width: Option<u32>,
- pub max_height: Option<u32>,
- pub base_width: Option<u32>,
- pub base_height: Option<u32>,
- pub inc_width: Option<u32>,
- pub inc_height: Option<u32>,
- pub min_ratio: Option<f64>,
- pub max_ratio: Option<f64>,
- pub min_ratio_vulgar: Option<Ratio>,
- pub max_ratio_vulgar: Option<Ratio>,
-}
-
-impl SizeHints {
- fn new(
- by_user: bool,
- pos: Option<Pos>,
- min_width: Option<u32>,
- min_height: Option<u32>,
- max_width: Option<u32>,
- max_height: Option<u32>,
- base_width: Option<u32>,
- base_height: Option<u32>,
- inc_width: Option<u32>,
- inc_height: Option<u32>,
- min_ratio: Option<f64>,
- max_ratio: Option<f64>,
- min_ratio_vulgar: Option<Ratio>,
- max_ratio_vulgar: Option<Ratio>,
- ) -> Self {
- Self {
- by_user,
- pos,
- min_width,
- min_height,
- max_width,
- max_height,
- base_width,
- base_height,
- inc_width,
- inc_height,
- min_ratio,
- max_ratio,
- min_ratio_vulgar,
- max_ratio_vulgar,
- }
- }
-
- pub fn apply(
- &self,
- dim: &mut Dim,
- ) {
- let mut dest_width = dim.w as i32;
- let mut dest_height = dim.h as i32;
-
- if let Some(min_width) = self.min_width {
- dest_width = std::cmp::max(dest_width, min_width as i32);
- }
-
- if let Some(min_height) = self.min_height {
- dest_height = std::cmp::max(dest_height, min_height as i32);
- }
-
- if let Some(max_width) = self.max_width {
- dest_width = std::cmp::min(dest_width, max_width as i32);
- }
-
- if let Some(max_height) = self.max_height {
- dest_height = std::cmp::min(dest_height, max_height as i32);
- }
-
- let base_width = if let Some(base_width) = self.base_width {
- base_width as i32
- } else {
- 0
- };
-
- let base_height = if let Some(base_height) = self.base_height {
- base_height as i32
- } else {
- 0
- };
-
- let mut width = if base_width < dest_width {
- dest_width - base_width as i32
- } else {
- dest_width
- };
-
- let mut height = if base_height < dest_height {
- dest_height - base_height as i32
- } else {
- dest_height
- };
-
- if self.min_ratio.is_some() || self.max_ratio.is_some() {
- if height == 0 {
- height = 1;
- }
-
- let current_ratio = width as f64 / height as f64;
- let mut new_ratio = None;
-
- if let Some(min_ratio) = self.min_ratio {
- if current_ratio < min_ratio {
- new_ratio = Some(min_ratio);
- }
- }
-
- if new_ratio.is_none() {
- if let Some(max_ratio) = self.max_ratio {
- if current_ratio > max_ratio {
- new_ratio = Some(max_ratio);
- }
- }
- }
-
- if let Some(new_ratio) = new_ratio {
- height = (width as f64 / new_ratio).round() as i32;
- width = (height as f64 * new_ratio).round() as i32;
-
- dest_width = width + base_width as i32;
- dest_height = height + base_height as i32;
- }
- }
-
- if let Some(inc_height) = self.inc_height {
- if dest_height >= base_height {
- dest_height -= base_height as i32;
- dest_height -= dest_height % inc_height as i32;
- dest_height += base_height as i32;
- }
- }
-
- if let Some(inc_width) = self.inc_width {
- if dest_width >= base_width {
- dest_width -= base_width as i32;
- dest_width -= dest_width % inc_width as i32;
- dest_width += base_width as i32;
- }
- }
-
- dim.w = std::cmp::max(dest_width, 0) as u32;
- dim.h = std::cmp::max(dest_height, 0) as u32;
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Padding {
- pub left: u32,
- pub right: u32,
- pub top: u32,
- pub bottom: u32,
-}
-
-impl Default for Padding {
- fn default() -> Self {
- Self {
- left: 0,
- right: 0,
- top: 0,
- bottom: 0,
- }
- }
-}
-
-impl Padding {
- pub fn with_each_edge(size: u32) -> Self {
- Self {
- left: size,
- right: size,
- top: size,
- bottom: size,
- }
- }
-}
-
-impl Add<Padding> for Region {
- type Output = Self;
-
- fn add(
- self,
- padding: Padding,
- ) -> Self::Output {
- Self::Output {
- pos: Pos {
- x: self.pos.x - padding.left as i32,
- y: self.pos.y - padding.top as i32,
- },
- dim: Dim {
- w: self.dim.w + padding.left + padding.right,
- h: self.dim.h + padding.top + padding.bottom,
- },
- }
- }
-}
-
-impl Sub<Padding> for Region {
- type Output = Self;
-
- fn sub(
- self,
- padding: Padding,
- ) -> Self::Output {
- Self::Output {
- pos: Pos {
- x: self.pos.x + padding.left as i32,
- y: self.pos.y + padding.top as i32,
- },
- dim: Dim {
- w: self.dim.w - padding.left - padding.right,
- h: self.dim.h - padding.top - padding.bottom,
- },
- }
- }
-}
-
-impl AddAssign<Padding> for Region {
- fn add_assign(
- &mut self,
- padding: Padding,
- ) {
- *self = Self {
- pos: Pos {
- x: self.pos.x - padding.left as i32,
- y: self.pos.y - padding.top as i32,
- },
- dim: Dim {
- w: self.dim.w + padding.left + padding.right,
- h: self.dim.h + padding.top + padding.bottom,
- },
- };
- }
-}
-
-impl SubAssign<Padding> for Region {
- fn sub_assign(
- &mut self,
- padding: Padding,
- ) {
- *self = Self {
- pos: Pos {
- x: self.pos.x + padding.left as i32,
- y: self.pos.y + padding.top as i32,
- },
- dim: Dim {
- w: self.dim.w - padding.left - padding.right,
- h: self.dim.h - padding.top - padding.bottom,
- },
- };
- }
-}
-
-impl Add<Padding> for Dim {
- type Output = Self;
-
- fn add(
- self,
- padding: Padding,
- ) -> Self::Output {
- Self::Output {
- w: self.w + padding.left + padding.right,
- h: self.h + padding.top + padding.bottom,
- }
- }
-}
-
-impl Sub<Padding> for Dim {
- type Output = Self;
-
- fn sub(
- self,
- padding: Padding,
- ) -> Self::Output {
- Self::Output {
- w: self.w - padding.left - padding.right,
- h: self.h - padding.top - padding.bottom,
- }
- }
-}
-
-impl AddAssign<Padding> for Dim {
- fn add_assign(
- &mut self,
- padding: Padding,
- ) {
- *self = Self {
- w: self.w + padding.left + padding.right,
- h: self.h + padding.top + padding.bottom,
- };
- }
-}
-
-impl SubAssign<Padding> for Dim {
- fn sub_assign(
- &mut self,
- padding: Padding,
- ) {
- *self = Self {
- w: self.w - padding.left - padding.right,
- h: self.h - padding.top - padding.bottom,
- };
- }
-}
-
-impl PartialEq for SizeHints {
- fn eq(
- &self,
- other: &Self,
- ) -> bool {
- self.min_width == other.min_width
- && self.min_height == other.min_height
- && self.max_width == other.max_width
- && self.max_height == other.max_height
- && self.base_width == other.base_width
- && self.base_height == other.base_height
- && self.inc_width == other.inc_width
- && self.inc_height == other.inc_height
- && self.min_ratio_vulgar == other.min_ratio_vulgar
- && self.max_ratio_vulgar == other.max_ratio_vulgar
- }
-}
-
-impl Eq for SizeHints {}
-
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
-pub struct Hints {
- pub urgent: bool,
- pub input: Option<bool>,
- pub initial_state: Option<IcccmWindowState>,
- pub group: Option<Window>,
-}
-
-impl Hints {
- fn new(
- urgent: bool,
- input: Option<bool>,
- initial_state: Option<IcccmWindowState>,
- group: Option<Window>,
- ) -> Self {
- Self {
- urgent,
- input,
- initial_state,
- group,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Strut {
- pub window: Window,
- pub width: u32,
-}
-
-impl Strut {
- pub fn new(
- window: Window,
- width: u32,
- ) -> Self {
- Self {
- window,
- width,
- }
- }
-}
-
-impl PartialOrd for Strut {
- fn partial_cmp(
- &self,
- other: &Self,
- ) -> Option<std::cmp::Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for Strut {
- fn cmp(
- &self,
- other: &Self,
- ) -> std::cmp::Ordering {
- other.width.cmp(&self.width)
- }
-}
diff --git a/src/winsys/connection.rs b/src/winsys/connection.rs
@@ -1,22 +1,23 @@
-use crate::common::Dim;
-use crate::common::Extents;
-use crate::common::Hints;
-use crate::common::IcccmWindowState;
-use crate::common::Pid;
-use crate::common::Pos;
-use crate::common::Region;
-use crate::common::SizeHints;
-use crate::common::Strut;
-use crate::common::Window;
-use crate::common::WindowState;
-use crate::common::WindowType;
use crate::event::Event;
+use crate::geometry::Dim;
+use crate::geometry::Extents;
+use crate::geometry::Pos;
+use crate::geometry::Region;
+use crate::geometry::Strut;
+use crate::hints::Hints;
+use crate::hints::SizeHints;
use crate::input::*;
use crate::screen::Screen;
+use crate::window::IcccmWindowState;
+use crate::window::Window;
+use crate::window::WindowState;
+use crate::window::WindowType;
use crate::Result;
use std::collections::HashMap;
+pub type Pid = u32;
+
pub trait Connection {
fn flush(&self) -> bool;
fn step(&self) -> Option<Event>;
@@ -253,21 +254,6 @@ pub trait Connection {
window: Window,
index: usize,
);
- fn set_window_fullscreen(
- &self,
- window: Window,
- on: bool,
- );
- fn set_window_above(
- &self,
- window: Window,
- on: bool,
- );
- fn set_window_below(
- &self,
- window: Window,
- on: bool,
- );
fn set_window_state(
&self,
window: Window,
diff --git a/src/winsys/event.rs b/src/winsys/event.rs
@@ -1,15 +1,15 @@
pub use crate::Result;
-use crate::common::Dim;
-use crate::common::Grip;
-use crate::common::Pos;
-use crate::common::Region;
-use crate::common::Window;
-use crate::common::WindowState;
-use crate::common::WindowType;
+use crate::geometry::Dim;
+use crate::geometry::Pos;
+use crate::geometry::Region;
+use crate::input::Grip;
use crate::input::KeyCode;
use crate::input::MouseEvent;
use crate::screen::Screen;
+use crate::window::Window;
+use crate::window::WindowState;
+use crate::window::WindowType;
#[derive(Debug, Clone)]
pub enum Event {
diff --git a/src/winsys/geometry.rs b/src/winsys/geometry.rs
@@ -0,0 +1,801 @@
+use crate::hints::SizeHints;
+use crate::window::Window;
+
+use std::ops::Add;
+use std::ops::AddAssign;
+use std::ops::Sub;
+use std::ops::SubAssign;
+
+pub type Extents = Padding;
+
+#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)]
+pub enum Edge {
+ Left,
+ Right,
+ Top,
+ Bottom,
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub enum Corner {
+ TopLeft,
+ TopRight,
+ BottomLeft,
+ BottomRight,
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Pos {
+ pub x: i32,
+ pub y: i32,
+}
+
+impl Default for Pos {
+ fn default() -> Self {
+ Self {
+ x: 0,
+ y: 0,
+ }
+ }
+}
+
+impl Pos {
+ pub fn from_center_of_region(region: Region) -> Self {
+ Self {
+ x: region.pos.x + (region.dim.w as f32 / 2f32) as i32,
+ y: region.pos.y + (region.dim.h as f32 / 2f32) as i32,
+ }
+ }
+
+ pub fn from_center_of_dim(dim: Dim) -> Self {
+ Self {
+ x: dim.w / 2,
+ y: dim.h / 2,
+ }
+ }
+
+ pub fn values(&self) -> (i32, i32) {
+ (self.x, self.y)
+ }
+
+ pub fn dist(
+ &self,
+ pos: Self,
+ ) -> Distance {
+ Distance {
+ dx: (pos.x - self.x),
+ dy: (pos.y - self.y),
+ }
+ }
+
+ pub fn relative_to(
+ &self,
+ pos: Self,
+ ) -> Self {
+ Pos {
+ x: self.x - pos.x,
+ y: self.y - pos.y,
+ }
+ }
+}
+
+impl Add<Pos> for Pos {
+ type Output = Self;
+
+ fn add(
+ self,
+ other: Pos,
+ ) -> Self::Output {
+ Self::Output {
+ x: self.x + other.x,
+ y: self.y + other.y,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Dim {
+ pub w: i32,
+ pub h: i32,
+}
+
+impl Default for Dim {
+ fn default() -> Self {
+ Self {
+ w: 0,
+ h: 0,
+ }
+ }
+}
+
+impl Dim {
+ pub fn values(&self) -> (i32, i32) {
+ (self.w, self.h)
+ }
+
+ pub fn center(&self) -> Pos {
+ Pos {
+ x: (self.w as f32 / 2f32) as i32,
+ y: (self.h as f32 / 2f32) as i32,
+ }
+ }
+
+ pub fn nearest_corner(
+ &self,
+ pos: Pos,
+ ) -> Corner {
+ let center = self.center();
+
+ if pos.x >= center.x {
+ if pos.y >= center.y {
+ Corner::BottomRight
+ } else {
+ Corner::TopRight
+ }
+ } else {
+ if pos.y >= center.y {
+ Corner::BottomLeft
+ } else {
+ Corner::TopLeft
+ }
+ }
+ }
+}
+
+impl Add<Dim> for Pos {
+ type Output = Self;
+
+ fn add(
+ self,
+ other: Dim,
+ ) -> Self::Output {
+ Self::Output {
+ x: self.x + other.w,
+ y: self.y + other.h,
+ }
+ }
+}
+
+impl Sub<Dim> for Pos {
+ type Output = Self;
+
+ fn sub(
+ self,
+ other: Dim,
+ ) -> Self::Output {
+ Self::Output {
+ x: self.x - other.w,
+ y: self.y - other.h,
+ }
+ }
+}
+
+impl Sub for Pos {
+ type Output = Dim;
+
+ fn sub(
+ self,
+ other: Self,
+ ) -> Self::Output {
+ Self::Output {
+ w: self.x - other.x,
+ h: self.y - other.y,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Region {
+ pub pos: Pos,
+ pub dim: Dim,
+}
+
+impl Default for Region {
+ fn default() -> Self {
+ Self {
+ pos: Default::default(),
+ dim: Default::default(),
+ }
+ }
+}
+
+impl Region {
+ pub fn new(
+ x: i32,
+ y: i32,
+ w: i32,
+ h: i32,
+ ) -> Self {
+ Self {
+ pos: Pos {
+ x,
+ y,
+ },
+ dim: Dim {
+ w,
+ h,
+ },
+ }
+ }
+
+ pub fn values(&self) -> (Pos, Dim) {
+ (self.pos, self.dim)
+ }
+
+ pub fn with_size_hints(
+ self,
+ size_hints: &Option<SizeHints>,
+ ) -> Self {
+ let mut geometry = self;
+
+ if let Some(size_hints) = size_hints {
+ size_hints.apply(&mut geometry.dim);
+ }
+
+ geometry
+ }
+
+ pub fn encompasses(
+ &self,
+ pos: Pos,
+ ) -> bool {
+ pos.x >= self.pos.x
+ && pos.y >= self.pos.y
+ && pos.x <= self.pos.x + self.dim.w
+ && pos.y <= self.pos.y + self.dim.h
+ }
+
+ pub fn contains(
+ &self,
+ region: Region,
+ ) -> bool {
+ self.encompasses(region.pos) && self.encompasses(region.bottom_right())
+ }
+
+ pub fn occludes(
+ &self,
+ region: Region,
+ ) -> bool {
+ self.encompasses(region.pos) || region.encompasses(self.pos)
+ }
+
+ pub fn nearest_corner(
+ &self,
+ mut pos: Pos,
+ ) -> Corner {
+ pos += self.pos.dist(Pos {
+ x: 0,
+ y: 0,
+ });
+ self.dim.nearest_corner(pos)
+ }
+
+ pub fn quadrant_center_from_pos(
+ &self,
+ pos: Pos,
+ ) -> Option<Pos> {
+ if self.encompasses(pos) {
+ return None;
+ }
+
+ let mut dists = vec![
+ (Corner::TopLeft, self.pos.dist(pos).pythagorean()),
+ (Corner::TopRight, self.top_right().dist(pos).pythagorean()),
+ (
+ Corner::BottomLeft,
+ self.bottom_left().dist(pos).pythagorean(),
+ ),
+ (
+ Corner::BottomRight,
+ self.bottom_right().dist(pos).pythagorean(),
+ ),
+ ];
+
+ dists.sort_by_key(|&(corner, dist)| dist);
+
+ match dists.first().unwrap() {
+ (Corner::TopLeft, _) => {
+ let (left, _) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
+ let (topleft, _) = left.split_at_height((left.dim.h as f64 / 2f64).round() as i32);
+
+ Some(Pos::from_center_of_region(topleft))
+ },
+ (Corner::TopRight, _) => {
+ let (_, right) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
+ let (topright, _) =
+ right.split_at_height((right.dim.h as f64 / 2f64).round() as i32);
+
+ Some(Pos::from_center_of_region(topright))
+ },
+ (Corner::BottomLeft, _) => {
+ let (left, _) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
+ let (_, bottomleft) =
+ left.split_at_height((left.dim.h as f64 / 2f64).round() as i32);
+
+ Some(Pos::from_center_of_region(bottomleft))
+ },
+ (Corner::BottomRight, _) => {
+ let (_, right) = self.split_at_width((self.dim.w as f64 / 2f64).round() as i32);
+ let (_, bottomright) =
+ right.split_at_height((right.dim.h as f64 / 2f64).round() as i32);
+
+ Some(Pos::from_center_of_region(bottomright))
+ },
+ }
+ }
+
+ pub fn split_at_width(
+ &self,
+ width: i32,
+ ) -> (Self, Self) {
+ let width = std::cmp::min(width, self.dim.w);
+
+ (
+ Self {
+ dim: Dim {
+ w: width,
+ ..self.dim
+ },
+ ..*self
+ },
+ Self {
+ pos: Pos {
+ x: self.pos.x + width,
+ ..self.pos
+ },
+ dim: Dim {
+ w: self.dim.w - width,
+ ..self.dim
+ },
+ },
+ )
+ }
+
+ pub fn split_at_height(
+ &self,
+ height: i32,
+ ) -> (Self, Self) {
+ let height = std::cmp::min(height, self.dim.h);
+
+ (
+ Self {
+ dim: Dim {
+ h: height,
+ ..self.dim
+ },
+ ..*self
+ },
+ Self {
+ pos: Pos {
+ y: self.pos.y + height,
+ ..self.pos
+ },
+ dim: Dim {
+ h: self.dim.h - height,
+ ..self.dim
+ },
+ },
+ )
+ }
+
+ pub fn with_minimum_dim(
+ self,
+ minimum_dim: &Dim,
+ ) -> Self {
+ Self {
+ pos: self.pos,
+ dim: Dim {
+ w: std::cmp::max(minimum_dim.w, self.dim.w),
+ h: std::cmp::max(minimum_dim.h, self.dim.h),
+ },
+ }
+ }
+
+ pub fn with_maximum_dim(
+ self,
+ maximum_dim: &Dim,
+ ) -> Self {
+ Self {
+ pos: self.pos,
+ dim: Dim {
+ w: std::cmp::min(maximum_dim.w, self.dim.w),
+ h: std::cmp::min(maximum_dim.h, self.dim.h),
+ },
+ }
+ }
+
+ pub fn from_absolute_inner_center(
+ 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,
+ },
+ dim: *dim,
+ }
+ }
+
+ pub fn without_extents(
+ mut self,
+ extents: &Extents,
+ ) -> Self {
+ self.pos.x += extents.left;
+ self.pos.y += extents.top;
+ self.dim.w -= extents.left + extents.right;
+ self.dim.h -= extents.top + extents.bottom;
+ self
+ }
+
+ pub fn with_extents(
+ mut self,
+ extents: &Extents,
+ ) -> Self {
+ self.pos.x -= extents.left;
+ self.pos.y -= extents.top;
+ self.dim.w += extents.left + extents.right;
+ self.dim.h += extents.top + extents.bottom;
+ self
+ }
+
+ pub fn top_right(&self) -> Pos {
+ Pos {
+ x: self.pos.x + self.dim.w,
+ y: self.pos.y,
+ }
+ }
+
+ pub fn bottom_left(&self) -> Pos {
+ Pos {
+ x: self.pos.x,
+ y: self.pos.y + self.dim.h,
+ }
+ }
+
+ pub fn bottom_right(&self) -> Pos {
+ Pos {
+ x: self.pos.x + self.dim.w,
+ y: self.pos.y + self.dim.h,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Padding {
+ pub left: i32,
+ pub right: i32,
+ pub top: i32,
+ pub bottom: i32,
+}
+
+impl Default for Padding {
+ fn default() -> Self {
+ Self {
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ }
+ }
+}
+
+impl Padding {
+ pub fn with_each_edge(size: i32) -> Self {
+ Self {
+ left: size,
+ right: size,
+ top: size,
+ bottom: size,
+ }
+ }
+}
+
+impl Add<Padding> for Region {
+ type Output = Self;
+
+ fn add(
+ self,
+ padding: Padding,
+ ) -> Self::Output {
+ Self::Output {
+ pos: Pos {
+ x: self.pos.x - padding.left,
+ y: self.pos.y - padding.top,
+ },
+ dim: Dim {
+ w: self.dim.w + padding.left + padding.right,
+ h: self.dim.h + padding.top + padding.bottom,
+ },
+ }
+ }
+}
+
+impl Sub<Padding> for Region {
+ type Output = Self;
+
+ fn sub(
+ self,
+ padding: Padding,
+ ) -> Self::Output {
+ Self::Output {
+ pos: Pos {
+ x: self.pos.x + padding.left,
+ y: self.pos.y + padding.top,
+ },
+ dim: Dim {
+ w: self.dim.w - padding.left - padding.right,
+ h: self.dim.h - padding.top - padding.bottom,
+ },
+ }
+ }
+}
+
+impl AddAssign<Padding> for Region {
+ fn add_assign(
+ &mut self,
+ padding: Padding,
+ ) {
+ *self = Self {
+ pos: Pos {
+ x: self.pos.x - padding.left,
+ y: self.pos.y - padding.top,
+ },
+ dim: Dim {
+ w: self.dim.w + padding.left + padding.right,
+ h: self.dim.h + padding.top + padding.bottom,
+ },
+ };
+ }
+}
+
+impl SubAssign<Padding> for Region {
+ fn sub_assign(
+ &mut self,
+ padding: Padding,
+ ) {
+ *self = Self {
+ pos: Pos {
+ x: self.pos.x + padding.left,
+ y: self.pos.y + padding.top,
+ },
+ dim: Dim {
+ w: self.dim.w - padding.left - padding.right,
+ h: self.dim.h - padding.top - padding.bottom,
+ },
+ };
+ }
+}
+
+impl Add<Padding> for Dim {
+ type Output = Self;
+
+ fn add(
+ self,
+ padding: Padding,
+ ) -> Self::Output {
+ Self::Output {
+ w: self.w + padding.left + padding.right,
+ h: self.h + padding.top + padding.bottom,
+ }
+ }
+}
+
+impl Sub<Padding> for Dim {
+ type Output = Self;
+
+ fn sub(
+ self,
+ padding: Padding,
+ ) -> Self::Output {
+ Self::Output {
+ w: self.w - padding.left - padding.right,
+ h: self.h - padding.top - padding.bottom,
+ }
+ }
+}
+
+impl AddAssign<Padding> for Dim {
+ fn add_assign(
+ &mut self,
+ padding: Padding,
+ ) {
+ *self = Self {
+ w: self.w + padding.left + padding.right,
+ h: self.h + padding.top + padding.bottom,
+ };
+ }
+}
+
+impl SubAssign<Padding> for Dim {
+ fn sub_assign(
+ &mut self,
+ padding: Padding,
+ ) {
+ *self = Self {
+ w: self.w - padding.left - padding.right,
+ h: self.h - padding.top - padding.bottom,
+ };
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Distance {
+ pub dx: i32,
+ pub dy: i32,
+}
+
+impl Distance {
+ pub fn values(&self) -> (i32, i32) {
+ (self.dx, self.dy)
+ }
+
+ pub fn pythagorean(&self) -> i32 {
+ let dx = self.dx.pow(2) as f64;
+ let dy = self.dy.pow(2) as f64;
+
+ (dx + dy).sqrt().round() as i32
+ }
+}
+
+impl Add<Distance> for Pos {
+ type Output = Self;
+
+ fn add(
+ self,
+ dist: Distance,
+ ) -> Self::Output {
+ Self::Output {
+ x: self.x + dist.dx,
+ y: self.y + dist.dy,
+ }
+ }
+}
+
+impl AddAssign<Distance> for Pos {
+ fn add_assign(
+ &mut self,
+ dist: Distance,
+ ) {
+ *self = Self {
+ x: self.x + dist.dx,
+ y: self.y + dist.dy,
+ };
+ }
+}
+
+impl Sub<Distance> for Pos {
+ type Output = Self;
+
+ fn sub(
+ self,
+ dist: Distance,
+ ) -> Self::Output {
+ Self::Output {
+ x: self.x - dist.dx,
+ y: self.y - dist.dy,
+ }
+ }
+}
+
+impl SubAssign<Distance> for Pos {
+ fn sub_assign(
+ &mut self,
+ dist: Distance,
+ ) {
+ *self = Self {
+ x: self.x - dist.dx,
+ y: self.y - dist.dy,
+ };
+ }
+}
+
+impl Add<Distance> for Dim {
+ type Output = Self;
+
+ fn add(
+ self,
+ dist: Distance,
+ ) -> Self::Output {
+ Self::Output {
+ w: (self.w + dist.dx).abs(),
+ h: (self.h + dist.dy).abs(),
+ }
+ }
+}
+
+impl AddAssign<Distance> for Dim {
+ fn add_assign(
+ &mut self,
+ dist: Distance,
+ ) {
+ *self = Self {
+ w: (self.w + dist.dx).abs(),
+ h: (self.h + dist.dy).abs(),
+ };
+ }
+}
+
+impl Sub<Distance> for Dim {
+ type Output = Self;
+
+ fn sub(
+ self,
+ dist: Distance,
+ ) -> Self::Output {
+ Self::Output {
+ w: (self.w - dist.dx).abs(),
+ h: (self.h - dist.dy).abs(),
+ }
+ }
+}
+
+impl SubAssign<Distance> for Dim {
+ fn sub_assign(
+ &mut self,
+ dist: Distance,
+ ) {
+ *self = Self {
+ w: (self.w - dist.dx).abs(),
+ h: (self.h - dist.dy).abs(),
+ };
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Ratio {
+ pub numerator: i32,
+ pub denominator: i32,
+}
+
+impl Ratio {
+ pub fn new(
+ numerator: i32,
+ denominator: i32,
+ ) -> Self {
+ Self {
+ numerator,
+ denominator,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Strut {
+ pub window: Window,
+ pub width: u32,
+}
+
+impl Strut {
+ pub fn new(
+ window: Window,
+ width: u32,
+ ) -> Self {
+ Self {
+ window,
+ width,
+ }
+ }
+}
+
+impl PartialOrd for Strut {
+ fn partial_cmp(
+ &self,
+ other: &Self,
+ ) -> Option<std::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Strut {
+ fn cmp(
+ &self,
+ other: &Self,
+ ) -> std::cmp::Ordering {
+ other.width.cmp(&self.width)
+ }
+}
diff --git a/src/winsys/hints.rs b/src/winsys/hints.rs
@@ -0,0 +1,201 @@
+use crate::geometry::Dim;
+use crate::geometry::Pos;
+use crate::geometry::Ratio;
+use crate::window::IcccmWindowState;
+use crate::window::Window;
+
+#[derive(Debug, Copy, Clone, PartialOrd)]
+pub struct SizeHints {
+ pub by_user: bool,
+ pub pos: Option<Pos>,
+ pub min_width: Option<i32>,
+ pub min_height: Option<i32>,
+ pub max_width: Option<i32>,
+ pub max_height: Option<i32>,
+ pub base_width: Option<i32>,
+ pub base_height: Option<i32>,
+ pub inc_width: Option<i32>,
+ pub inc_height: Option<i32>,
+ pub min_ratio: Option<f64>,
+ pub max_ratio: Option<f64>,
+ pub min_ratio_vulgar: Option<Ratio>,
+ pub max_ratio_vulgar: Option<Ratio>,
+}
+
+impl SizeHints {
+ fn new(
+ by_user: bool,
+ pos: Option<Pos>,
+ min_width: Option<i32>,
+ min_height: Option<i32>,
+ max_width: Option<i32>,
+ max_height: Option<i32>,
+ base_width: Option<i32>,
+ base_height: Option<i32>,
+ inc_width: Option<i32>,
+ inc_height: Option<i32>,
+ min_ratio: Option<f64>,
+ max_ratio: Option<f64>,
+ min_ratio_vulgar: Option<Ratio>,
+ max_ratio_vulgar: Option<Ratio>,
+ ) -> Self {
+ Self {
+ by_user,
+ pos,
+ min_width,
+ min_height,
+ max_width,
+ max_height,
+ base_width,
+ base_height,
+ inc_width,
+ inc_height,
+ min_ratio,
+ max_ratio,
+ min_ratio_vulgar,
+ max_ratio_vulgar,
+ }
+ }
+
+ pub fn apply(
+ &self,
+ dim: &mut Dim,
+ ) {
+ let mut dest_width = dim.w;
+ let mut dest_height = dim.h;
+
+ if let Some(min_width) = self.min_width {
+ dest_width = std::cmp::max(dest_width, min_width);
+ }
+
+ if let Some(min_height) = self.min_height {
+ dest_height = std::cmp::max(dest_height, min_height);
+ }
+
+ if let Some(max_width) = self.max_width {
+ dest_width = std::cmp::min(dest_width, max_width);
+ }
+
+ if let Some(max_height) = self.max_height {
+ dest_height = std::cmp::min(dest_height, max_height);
+ }
+
+ let base_width = if let Some(base_width) = self.base_width {
+ base_width
+ } else {
+ 0
+ };
+
+ let base_height = if let Some(base_height) = self.base_height {
+ base_height
+ } else {
+ 0
+ };
+
+ let mut width = if base_width < dest_width {
+ dest_width - base_width
+ } else {
+ dest_width
+ };
+
+ let mut height = if base_height < dest_height {
+ dest_height - base_height
+ } else {
+ dest_height
+ };
+
+ if self.min_ratio.is_some() || self.max_ratio.is_some() {
+ if height == 0 {
+ height = 1;
+ }
+
+ let current_ratio = width as f64 / height as f64;
+ let mut new_ratio = None;
+
+ if let Some(min_ratio) = self.min_ratio {
+ if current_ratio < min_ratio {
+ new_ratio = Some(min_ratio);
+ }
+ }
+
+ if new_ratio.is_none() {
+ if let Some(max_ratio) = self.max_ratio {
+ if current_ratio > max_ratio {
+ new_ratio = Some(max_ratio);
+ }
+ }
+ }
+
+ if let Some(new_ratio) = new_ratio {
+ height = (width as f64 / new_ratio).round() as i32;
+ width = (height as f64 * new_ratio).round() as i32;
+
+ dest_width = width + base_width;
+ dest_height = height + base_height;
+ }
+ }
+
+ if let Some(inc_height) = self.inc_height {
+ if dest_height >= base_height {
+ dest_height -= base_height;
+ dest_height -= dest_height % inc_height;
+ dest_height += base_height;
+ }
+ }
+
+ if let Some(inc_width) = self.inc_width {
+ if dest_width >= base_width {
+ dest_width -= base_width;
+ dest_width -= dest_width % inc_width;
+ dest_width += base_width;
+ }
+ }
+
+ dim.w = std::cmp::max(dest_width, 0i32);
+ dim.h = std::cmp::max(dest_height, 0i32);
+ }
+}
+
+impl PartialEq for SizeHints {
+ fn eq(
+ &self,
+ other: &Self,
+ ) -> bool {
+ self.min_width == other.min_width
+ && self.min_height == other.min_height
+ && self.max_width == other.max_width
+ && self.max_height == other.max_height
+ && self.base_width == other.base_width
+ && self.base_height == other.base_height
+ && self.inc_width == other.inc_width
+ && self.inc_height == other.inc_height
+ && self.min_ratio_vulgar == other.min_ratio_vulgar
+ && self.max_ratio_vulgar == other.max_ratio_vulgar
+ }
+}
+
+impl Eq for SizeHints {}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub struct Hints {
+ pub urgent: bool,
+ pub input: Option<bool>,
+ pub initial_state: Option<IcccmWindowState>,
+ pub group: Option<Window>,
+}
+
+impl Hints {
+ fn new(
+ urgent: bool,
+ input: Option<bool>,
+ initial_state: Option<IcccmWindowState>,
+ group: Option<Window>,
+ ) -> Self {
+ Self {
+ urgent,
+ input,
+ initial_state,
+ group,
+ }
+ }
+}
diff --git a/src/winsys/input.rs b/src/winsys/input.rs
@@ -1,7 +1,9 @@
pub use crate::Result;
-use crate::common::Pos;
-use crate::common::Window;
+use crate::geometry::Corner;
+use crate::geometry::Edge;
+use crate::geometry::Pos;
+use crate::window::Window;
use std::collections::HashMap;
use std::convert::TryFrom;
@@ -10,6 +12,26 @@ use std::vec::Vec;
use strum::EnumIter;
use strum::IntoEnumIterator;
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub enum Grip {
+ Edge(Edge),
+ Corner(Corner),
+}
+
+impl Grip {
+ pub fn is_top_grip(&self) -> bool {
+ *self == Grip::Edge(Edge::Top)
+ || *self == Grip::Corner(Corner::TopLeft)
+ || *self == Grip::Corner(Corner::TopRight)
+ }
+
+ pub fn is_left_grip(&self) -> bool {
+ *self == Grip::Edge(Edge::Left)
+ || *self == Grip::Corner(Corner::TopLeft)
+ || *self == Grip::Corner(Corner::BottomLeft)
+ }
+}
+
pub type CodeMap = HashMap<String, u8>;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
diff --git a/src/winsys/macros.rs b/src/winsys/macros.rs
@@ -0,0 +1,12 @@
+#[macro_export]
+macro_rules! map(
+ { $($key:expr => $val:expr,)+ } => {
+ {
+ let mut map = ::std::collections::HashMap::new();
+ $(
+ map.insert($key, $val);
+ )+
+ map
+ }
+ };
+);
diff --git a/src/winsys/mod.rs b/src/winsys/mod.rs
@@ -2,11 +2,16 @@
#![allow(unused_imports)]
#![allow(unused_variables)]
+#[macro_use]
+mod macros;
+
pub type Result<T> = anyhow::Result<T>;
-pub mod common;
pub mod connection;
pub mod event;
+pub mod geometry;
+pub mod hints;
pub mod input;
pub mod screen;
+pub mod window;
pub mod xdata;
diff --git a/src/winsys/screen.rs b/src/winsys/screen.rs
@@ -1,9 +1,9 @@
-use crate::common::Dim;
-use crate::common::Edge;
-use crate::common::Pos;
-use crate::common::Region;
-use crate::common::Strut;
-use crate::common::Window;
+use crate::geometry::Dim;
+use crate::geometry::Edge;
+use crate::geometry::Pos;
+use crate::geometry::Region;
+use crate::geometry::Strut;
+use crate::window::Window;
use std::{
collections::HashMap,
@@ -104,20 +104,20 @@ impl Screen {
if self.showing_struts {
if let Some(strut) = self.struts.get(&Edge::Left).unwrap().last() {
region.pos.x += strut.width as i32;
- region.dim.w -= strut.width;
+ region.dim.w -= strut.width as i32;
}
if let Some(strut) = self.struts.get(&Edge::Right).unwrap().last() {
- region.dim.w -= strut.width;
+ region.dim.w -= strut.width as i32;
}
if let Some(strut) = self.struts.get(&Edge::Top).unwrap().last() {
region.pos.y += strut.width as i32;
- region.dim.h -= strut.width;
+ region.dim.h -= strut.width as i32;
}
if let Some(strut) = self.struts.get(&Edge::Bottom).unwrap().last() {
- region.dim.h -= strut.width;
+ region.dim.h -= strut.width as i32;
}
}
diff --git a/src/winsys/window.rs b/src/winsys/window.rs
@@ -0,0 +1,42 @@
+pub type Window = u32;
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub enum IcccmWindowState {
+ Withdrawn,
+ Normal,
+ Iconic,
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub enum WindowState {
+ Modal,
+ Sticky,
+ MaximizedVert,
+ MaximizedHorz,
+ Shaded,
+ SkipTaskbar,
+ SkipPager,
+ Hidden,
+ Fullscreen,
+ Above,
+ Below,
+ DemandsAttention,
+}
+
+#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub enum WindowType {
+ Desktop,
+ Dock,
+ Toolbar,
+ Menu,
+ Utility,
+ Splash,
+ Dialog,
+ DropdownMenu,
+ PopupMenu,
+ Tooltip,
+ Notification,
+ Combo,
+ Dnd,
+ Normal,
+}
diff --git a/src/winsys/xdata/event.rs b/src/winsys/xdata/event.rs
@@ -1,12 +1,12 @@
use super::super::event::Result;
pub use super::super::event::*;
-use crate::common::Pos;
-use crate::common::Region;
-use crate::common::Window;
-use crate::common::WindowState;
-use crate::common::WindowType;
+use crate::geometry::Pos;
+use crate::geometry::Region;
use crate::input::KeyCode;
use crate::screen::Screen;
+use crate::window::Window;
+use crate::window::WindowState;
+use crate::window::WindowType;
use x11rb::protocol::xproto;
diff --git a/src/winsys/xdata/input.rs b/src/winsys/xdata/input.rs
@@ -1,18 +1,17 @@
use super::super::input::Result;
pub use super::super::input::*;
-use crate::common::Pos;
-use crate::common::Window;
+use crate::geometry::Pos;
+use crate::window::Window;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::vec::Vec;
+use anyhow::anyhow;
use strum::EnumIter;
use strum::IntoEnumIterator;
-use anyhow::anyhow;
-
use x11rb::protocol::xproto::ButtonPressEvent;
use x11rb::protocol::xproto::ButtonReleaseEvent;
use x11rb::protocol::xproto::KeyPressEvent;
diff --git a/src/winsys/xdata/xconnection.rs b/src/winsys/xdata/xconnection.rs
@@ -1,40 +1,36 @@
-use crate::common::Atom;
-use crate::common::Corner;
-use crate::common::Dim;
-use crate::common::Edge;
-use crate::common::Extents;
-use crate::common::Grip;
-use crate::common::Hints;
-use crate::common::IcccmWindowState;
-use crate::common::Pid;
-use crate::common::Pos;
-use crate::common::Ratio;
-use crate::common::Region;
-use crate::common::SizeHints;
-use crate::common::Strut;
-use crate::common::Window;
-use crate::common::WindowState;
-use crate::common::WindowType;
use crate::connection::Connection;
+use crate::connection::Pid;
use crate::event::Event;
use crate::event::PropertyKind;
use crate::event::StackMode;
use crate::event::ToggleAction;
+use crate::geometry::Corner;
+use crate::geometry::Dim;
+use crate::geometry::Edge;
+use crate::geometry::Extents;
+use crate::geometry::Pos;
+use crate::geometry::Ratio;
+use crate::geometry::Region;
+use crate::geometry::Strut;
+use crate::hints::Hints;
+use crate::hints::SizeHints;
use crate::input::Button;
+use crate::input::Grip;
use crate::input::KeyCode;
use crate::input::MouseEvent;
use crate::input::MouseEventKey;
use crate::input::MouseShortcut;
use crate::screen::Screen;
+use crate::window::IcccmWindowState;
+use crate::window::Window;
+use crate::window::WindowState;
+use crate::window::WindowType;
use crate::Result;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::str::FromStr;
-use anyhow::anyhow;
-use strum::*;
-
use x11rb::connection;
use x11rb::cursor::Handle as CursorHandle;
use x11rb::errors::ReplyError;
@@ -51,6 +47,11 @@ use x11rb::protocol::Event as XEvent;
use x11rb::resource_manager::Database;
use x11rb::wrapper::ConnectionExt as _;
+use anyhow::anyhow;
+use strum::*;
+
+type Atom = u32;
+
x11rb::atom_manager! {
pub Atoms: AtomsCookie {
Any,
@@ -165,8 +166,8 @@ x11rb::atom_manager! {
}
}
-pub struct XConnection<'a, C: connection::Connection> {
- conn: &'a C,
+pub struct XConnection<'conn, Conn: connection::Connection> {
+ conn: &'conn Conn,
atoms: Atoms,
type_map: HashMap<Atom, WindowType>,
state_map: HashMap<Atom, WindowState>,
@@ -183,9 +184,9 @@ pub struct XConnection<'a, C: connection::Connection> {
regrab_event_mask: EventMask,
}
-impl<'a, C: connection::Connection> XConnection<'a, C> {
+impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
pub fn new(
- conn: &'a C,
+ conn: &'conn Conn,
screen_num: usize,
) -> Result<Self> {
let screen = conn.setup().roots[screen_num].clone();
@@ -195,7 +196,6 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
.event_mask(EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY);
let res = conn.change_window_attributes(screen.root, &aux)?.check();
-
if let Err(ReplyError::X11Error(err)) = res {
if err.error_kind == ErrorKind::Access {
return Err(anyhow!("another window manager is already running"));
@@ -207,56 +207,37 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
let atoms = Atoms::new(conn)?.reply()?;
let check_window = conn.generate_id()?;
- let type_map: HashMap<Atom, WindowType> = {
- let mut types = HashMap::with_capacity(10);
- types.insert(atoms._NET_WM_WINDOW_TYPE_DESKTOP, WindowType::Desktop);
- types.insert(atoms._NET_WM_WINDOW_TYPE_DOCK, WindowType::Dock);
- types.insert(atoms._NET_WM_WINDOW_TYPE_TOOLBAR, WindowType::Toolbar);
- types.insert(atoms._NET_WM_WINDOW_TYPE_MENU, WindowType::Menu);
- types.insert(atoms._NET_WM_WINDOW_TYPE_UTILITY, WindowType::Utility);
- types.insert(atoms._NET_WM_WINDOW_TYPE_SPLASH, WindowType::Splash);
- types.insert(atoms._NET_WM_WINDOW_TYPE_DIALOG, WindowType::Dialog);
- types.insert(
- atoms._NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
- WindowType::DropdownMenu,
- );
- types.insert(atoms._NET_WM_WINDOW_TYPE_POPUP_MENU, WindowType::PopupMenu);
- types.insert(atoms._NET_WM_WINDOW_TYPE_TOOLTIP, WindowType::Tooltip);
- types.insert(
- atoms._NET_WM_WINDOW_TYPE_NOTIFICATION,
- WindowType::Notification,
- );
- types.insert(atoms._NET_WM_WINDOW_TYPE_COMBO, WindowType::Combo);
- types.insert(atoms._NET_WM_WINDOW_TYPE_DND, WindowType::Dnd);
- types.insert(atoms._NET_WM_WINDOW_TYPE_NORMAL, WindowType::Normal);
- types
- };
+ let type_map: HashMap<Atom, WindowType> = map!(
+ atoms._NET_WM_WINDOW_TYPE_DESKTOP => WindowType::Desktop,
+ atoms._NET_WM_WINDOW_TYPE_DOCK => WindowType::Dock,
+ atoms._NET_WM_WINDOW_TYPE_TOOLBAR => WindowType::Toolbar,
+ atoms._NET_WM_WINDOW_TYPE_MENU => WindowType::Menu,
+ atoms._NET_WM_WINDOW_TYPE_UTILITY => WindowType::Utility,
+ atoms._NET_WM_WINDOW_TYPE_SPLASH => WindowType::Splash,
+ atoms._NET_WM_WINDOW_TYPE_DIALOG => WindowType::Dialog,
+ atoms._NET_WM_WINDOW_TYPE_DROPDOWN_MENU => WindowType::DropdownMenu,
+ atoms._NET_WM_WINDOW_TYPE_POPUP_MENU => WindowType::PopupMenu,
+ atoms._NET_WM_WINDOW_TYPE_TOOLTIP => WindowType::Tooltip,
+ atoms._NET_WM_WINDOW_TYPE_NOTIFICATION => WindowType::Notification,
+ atoms._NET_WM_WINDOW_TYPE_COMBO => WindowType::Combo,
+ atoms._NET_WM_WINDOW_TYPE_DND => WindowType::Dnd,
+ atoms._NET_WM_WINDOW_TYPE_NORMAL => WindowType::Normal,
+ );
- let state_map: HashMap<Atom, WindowState> = {
- let mut states = HashMap::with_capacity(10);
- states.insert(atoms._NET_WM_STATE_MODAL, WindowState::Modal);
- states.insert(atoms._NET_WM_STATE_STICKY, WindowState::Sticky);
- states.insert(
- atoms._NET_WM_STATE_MAXIMIZED_VERT,
- WindowState::MaximizedVert,
- );
- states.insert(
- atoms._NET_WM_STATE_MAXIMIZED_HORZ,
- WindowState::MaximizedHorz,
- );
- states.insert(atoms._NET_WM_STATE_SHADED, WindowState::Shaded);
- states.insert(atoms._NET_WM_STATE_SKIP_TASKBAR, WindowState::SkipTaskbar);
- states.insert(atoms._NET_WM_STATE_SKIP_PAGER, WindowState::SkipPager);
- states.insert(atoms._NET_WM_STATE_HIDDEN, WindowState::Hidden);
- states.insert(atoms._NET_WM_STATE_FULLSCREEN, WindowState::Fullscreen);
- states.insert(atoms._NET_WM_STATE_ABOVE, WindowState::Above);
- states.insert(atoms._NET_WM_STATE_BELOW, WindowState::Below);
- states.insert(
- atoms._NET_WM_STATE_DEMANDS_ATTENTION,
- WindowState::DemandsAttention,
- );
- states
- };
+ let state_map: HashMap<Atom, WindowState> = map!(
+ atoms._NET_WM_STATE_MODAL => WindowState::Modal,
+ atoms._NET_WM_STATE_STICKY => WindowState::Sticky,
+ atoms._NET_WM_STATE_MAXIMIZED_VERT => WindowState::MaximizedVert,
+ atoms._NET_WM_STATE_MAXIMIZED_HORZ => WindowState::MaximizedHorz,
+ atoms._NET_WM_STATE_SHADED => WindowState::Shaded,
+ atoms._NET_WM_STATE_SKIP_TASKBAR => WindowState::SkipTaskbar,
+ atoms._NET_WM_STATE_SKIP_PAGER => WindowState::SkipPager,
+ atoms._NET_WM_STATE_HIDDEN => WindowState::Hidden,
+ atoms._NET_WM_STATE_FULLSCREEN => WindowState::Fullscreen,
+ atoms._NET_WM_STATE_ABOVE => WindowState::Above,
+ atoms._NET_WM_STATE_BELOW => WindowState::Below,
+ atoms._NET_WM_STATE_DEMANDS_ATTENTION => WindowState::DemandsAttention,
+ );
conn.create_window(
x11rb::COPY_DEPTH_FROM_PARENT,
@@ -272,11 +253,11 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
&xproto::CreateWindowAux::default().override_redirect(1),
)?;
- drop(conn.map_window(check_window));
-
- let aux = xproto::ConfigureWindowAux::default().stack_mode(xproto::StackMode::BELOW);
-
- drop(conn.configure_window(check_window, &aux));
+ conn.map_window(check_window)?;
+ conn.configure_window(
+ check_window,
+ &xproto::ConfigureWindowAux::default().stack_mode(xproto::StackMode::BELOW),
+ )?;
randr::select_input(
conn,
@@ -290,7 +271,6 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
conn.create_gc(background_gc, screen.root, &xproto::CreateGCAux::default())?;
let database = Database::new_from_default(conn).ok();
-
if let Some(ref database) = database {
drop(
CursorHandle::new(conn, screen_num, &database).map(|cookie| {
@@ -373,7 +353,7 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
})
}
- pub fn window_is_any_of_state(
+ pub fn window_is_any_of_states(
&self,
window: Window,
states: &[Atom],
@@ -457,7 +437,7 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
&self,
atom: Atom,
) -> Option<WindowState> {
- self.state_map.get(&atom).map(|&state| state)
+ self.state_map.get(&atom).copied()
}
#[inline]
@@ -486,7 +466,7 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
&self,
atom: Atom,
) -> Option<WindowType> {
- self.type_map.get(&atom).map(|&type_| type_)
+ self.type_map.get(&atom).copied()
}
#[inline]
@@ -519,7 +499,7 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
on: bool,
) {
if on {
- if self.window_is_any_of_state(window, &[state_atom]) {
+ if self.window_is_any_of_states(window, &[state_atom]) {
return;
}
@@ -541,13 +521,13 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
0,
std::u32::MAX,
)
- .map_or(Vec::new(), |cookie| {
- cookie.reply().map_or(Vec::new(), |reply| {
- reply.value32().map_or(Vec::new(), |window_states| {
- let mut states = Vec::with_capacity(reply.value_len as usize);
- window_states.for_each(|state| states.push(state));
- states
- })
+ .map_or(Vec::with_capacity(0), |cookie| {
+ cookie.reply().map_or(Vec::with_capacity(0), |reply| {
+ reply
+ .value32()
+ .map_or(Vec::with_capacity(0), |window_states| {
+ window_states.collect()
+ })
})
});
@@ -688,13 +668,13 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
) -> Option<Event> {
self.conn
.get_window_attributes(event.window)
+ .ok()
.map(|cookie| Event::Unmap {
window: event.window,
ignore: cookie
.reply()
.map_or(false, |reply| reply.override_redirect),
})
- .ok()
}
#[inline]
@@ -718,11 +698,11 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
}
if event.value_mask & u16::from(xproto::ConfigWindow::WIDTH) != 0 {
- w = Some(event.width as u32);
+ w = Some(event.width as i32);
}
if event.value_mask & u16::from(xproto::ConfigWindow::HEIGHT) != 0 {
- h = Some(event.height as u32);
+ h = Some(event.height as i32);
}
let pos = match (x, y) {
@@ -805,8 +785,8 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
region: Region::new(
event.x as i32,
event.y as i32,
- event.width as u32,
- event.height as u32,
+ event.width as i32,
+ event.height as i32,
),
on_root: event.window == self.screen.root,
})
@@ -864,7 +844,7 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
8 => event.data.as_data8().iter().map(|&i| i as usize).collect(),
16 => event.data.as_data16().iter().map(|&i| i as usize).collect(),
32 => event.data.as_data32().iter().map(|&i| i as usize).collect(),
- _ => Vec::new(),
+ _ => Vec::with_capacity(0),
};
if event.type_ == self.atoms._NET_WM_STATE {
@@ -897,19 +877,10 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
}
} else if event.type_ == self.atoms._NET_MOVERESIZE_WINDOW {
// TODO: handle gravity
- let x = data.get(1);
- let y = data.get(2);
- let width = data.get(3);
- let height = data.get(4);
-
- if x.is_none() || y.is_none() || width.is_none() || height.is_none() {
- return None;
- }
-
- let x = *x.unwrap();
- let y = *y.unwrap();
- let width = *width.unwrap();
- let height = *height.unwrap();
+ let x = data.get(1)?.clone();
+ let y = data.get(2)?.clone();
+ let width = data.get(3)?.clone();
+ let height = data.get(4)?.clone();
return Some(Event::PlacementRequest {
window: event.window,
@@ -918,23 +889,15 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
y: y as i32,
}),
dim: Some(Dim {
- w: width as u32,
- h: height as u32,
+ w: width as i32,
+ h: height as i32,
}),
on_root: event.window == self.screen.root,
});
} else if event.type_ == self.atoms._NET_WM_MOVERESIZE {
- let x_root = data.get(0);
- let y_root = data.get(1);
- let direction = data.get(2);
-
- if x_root.is_none() || y_root.is_none() || direction.is_none() {
- return None;
- }
-
- let x_root = *x_root.unwrap();
- let y_root = *y_root.unwrap();
- let direction = *direction.unwrap();
+ let x_root = data.get(0)?.clone();
+ let y_root = data.get(1)?.clone();
+ let direction = data.get(2)?.clone();
return Some(Event::GripRequest {
window: event.window,
@@ -962,13 +925,11 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
on_root: event.window == self.screen.root,
});
} else if event.type_ == self.atoms._NET_CURRENT_DESKTOP {
- if let Some(&index) = data.get(0) {
- return Some(Event::WorkspaceRequest {
- window: None,
- index,
- on_root: event.window == self.screen.root,
- });
- }
+ return Some(Event::WorkspaceRequest {
+ window: None,
+ index: data.get(0)?.clone(),
+ on_root: event.window == self.screen.root,
+ });
} else if event.type_ == self.atoms._NET_CLOSE_WINDOW {
return Some(Event::CloseRequest {
window: event.window,
@@ -1007,7 +968,7 @@ impl<'a, C: connection::Connection> XConnection<'a, C> {
}
}
-impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
+impl<'conn, Conn: connection::Connection> Connection for XConnection<'conn, Conn> {
#[inline]
fn flush(&self) -> bool {
self.conn.flush().is_ok()
@@ -1046,28 +1007,30 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
if let Ok(reply) = resources.reply() {
return reply
.crtcs
- .iter()
+ .into_iter()
.flat_map(|crtc| {
- randr::get_crtc_info(self.conn, *crtc, 0)
- .map(|cookie| cookie.reply().map(|reply| reply))
+ randr::get_crtc_info(self.conn, crtc, 0).map(|cookie| cookie.reply())
})
.enumerate()
- .map(|(i, r)| {
- let r = r.unwrap();
+ .map(|(i, reply)| {
+ let reply = reply.unwrap();
let region = Region {
pos: Pos {
- x: r.x as i32,
- y: r.y as i32,
+ x: reply.x as i32,
+ y: reply.y as i32,
},
dim: Dim {
- w: r.width as u32,
- h: r.height as u32,
+ w: reply.width as i32,
+ h: reply.height as i32,
},
};
Screen::new(region, i)
})
- .filter(|screen| screen.full_region().dim.w > 0)
+ .filter(|screen| {
+ let region = screen.full_region();
+ region.dim.w > 0 && region.dim.h > 0
+ })
.collect();
}
}
@@ -1078,13 +1041,12 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
fn top_level_windows(&self) -> Vec<Window> {
self.conn
.query_tree(self.screen.root)
- .map_or(Vec::new(), |cookie| {
- cookie.reply().map_or(Vec::new(), |reply| {
+ .map_or(Vec::with_capacity(0), |cookie| {
+ cookie.reply().map_or(Vec::with_capacity(0), |reply| {
reply
.children
- .iter()
- .filter(|&w| self.must_manage_window(*w))
- .cloned()
+ .into_iter()
+ .filter(|&w| self.must_manage_window(w))
.collect()
})
})
@@ -1108,26 +1070,23 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Option<Window>,
screen: &Screen,
) {
- let (pos, window) = match window {
- Some(window) => {
- let geometry = self.get_window_geometry(window);
-
- if geometry.is_err() {
- return;
- }
-
- (Pos::from_center_of_dim(geometry.unwrap().dim), window)
- },
- None => (
- Pos::from_center_of_dim(screen.placeable_region().dim),
- self.screen.root,
- ),
- };
-
- drop(
- self.conn
- .warp_pointer(x11rb::NONE, window, 0, 0, 0, 0, pos.x as i16, pos.y as i16),
+ let pos = Pos::from_center_of_dim(
+ window
+ .and_then(|window| self.get_window_geometry(window).ok())
+ .unwrap_or(screen.placeable_region())
+ .dim,
);
+
+ drop(self.conn.warp_pointer(
+ x11rb::NONE,
+ window.unwrap_or(self.screen.root),
+ 0,
+ 0,
+ 0,
+ 0,
+ pos.x as i16,
+ pos.y as i16,
+ ));
}
#[inline]
@@ -1164,16 +1123,20 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
) {
if self.confined_to.is_none() {
- if let Ok(_) = self.conn.grab_pointer(
- false,
- self.screen.root,
- u32::from(EventMask::POINTER_MOTION | EventMask::BUTTON_RELEASE) as u16,
- xproto::GrabMode::ASYNC,
- xproto::GrabMode::ASYNC,
- self.screen.root,
- x11rb::NONE,
- x11rb::CURRENT_TIME,
- ) {
+ if self
+ .conn
+ .grab_pointer(
+ false,
+ self.screen.root,
+ u32::from(EventMask::POINTER_MOTION | EventMask::BUTTON_RELEASE) as u16,
+ xproto::GrabMode::ASYNC,
+ xproto::GrabMode::ASYNC,
+ self.screen.root,
+ x11rb::NONE,
+ x11rb::CURRENT_TIME,
+ )
+ .is_ok()
+ {
drop(self.conn.grab_keyboard(
false,
self.screen.root,
@@ -1264,23 +1227,21 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
.backing_store(Some(xproto::BackingStore::ALWAYS))
.event_mask(EventMask::EXPOSURE | EventMask::KEY_PRESS);
- drop(
- self.conn
- .create_window(
- x11rb::COPY_DEPTH_FROM_PARENT,
- frame,
- self.screen.root,
- region.pos.x as i16,
- region.pos.y as i16,
- region.dim.w as u16,
- region.dim.h as u16,
- 0,
- xproto::WindowClass::INPUT_OUTPUT,
- 0,
- &aux,
- )
- .expect(ERR),
- );
+ self.conn
+ .create_window(
+ x11rb::COPY_DEPTH_FROM_PARENT,
+ frame,
+ self.screen.root,
+ region.pos.x as i16,
+ region.pos.y as i16,
+ region.dim.w as u16,
+ region.dim.h as u16,
+ 0,
+ xproto::WindowClass::INPUT_OUTPUT,
+ 0,
+ &aux,
+ )
+ .expect(ERR);
self.flush();
@@ -1294,23 +1255,21 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
let handle = self.conn.generate_id().expect(ERR);
let aux = xproto::CreateWindowAux::new().override_redirect(1);
- drop(
- self.conn
- .create_window(
- x11rb::COPY_DEPTH_FROM_PARENT,
- handle,
- self.screen.root,
- -2,
- -2,
- 1,
- 1,
- 0,
- xproto::WindowClass::INPUT_ONLY,
- 0,
- &aux,
- )
- .expect(ERR),
- );
+ self.conn
+ .create_window(
+ x11rb::COPY_DEPTH_FROM_PARENT,
+ handle,
+ self.screen.root,
+ -2,
+ -2,
+ 1,
+ 1,
+ 0,
+ xproto::WindowClass::INPUT_ONLY,
+ 0,
+ &aux,
+ )
+ .expect(ERR);
self.flush();
@@ -1323,9 +1282,10 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
focus_follows_mouse: bool,
) {
- let aux = xproto::ChangeWindowAttributesAux::default().event_mask(self.window_event_mask);
-
- drop(self.conn.change_window_attributes(window, &aux));
+ drop(self.conn.change_window_attributes(
+ window,
+ &xproto::ChangeWindowAttributesAux::default().event_mask(self.window_event_mask),
+ ));
}
#[inline]
@@ -1334,16 +1294,17 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
focus_follows_mouse: bool,
) {
- let aux = xproto::ChangeWindowAttributesAux::default().event_mask(
- self.frame_event_mask
- | if focus_follows_mouse {
- EventMask::ENTER_WINDOW
- } else {
- EventMask::NO_EVENT
- },
- );
-
- drop(self.conn.change_window_attributes(window, &aux));
+ drop(self.conn.change_window_attributes(
+ window,
+ &xproto::ChangeWindowAttributesAux::default().event_mask(
+ self.frame_event_mask
+ | if focus_follows_mouse {
+ EventMask::ENTER_WINDOW
+ } else {
+ EventMask::NO_EVENT
+ },
+ ),
+ ));
}
#[inline]
@@ -1351,10 +1312,10 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) {
- let aux =
- xproto::ChangeWindowAttributesAux::default().event_mask(EventMask::STRUCTURE_NOTIFY);
-
- drop(self.conn.change_window_attributes(window, &aux));
+ drop(self.conn.change_window_attributes(
+ window,
+ &xproto::ChangeWindowAttributesAux::default().event_mask(EventMask::STRUCTURE_NOTIFY),
+ ));
}
#[inline]
@@ -1423,10 +1384,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> bool {
- match self.send_protocol_client_message(window, self.atoms.WM_DELETE_WINDOW) {
- Ok(_) => self.flush(),
- Err(_) => false,
- }
+ self.send_protocol_client_message(window, self.atoms.WM_DELETE_WINDOW)
+ .map_or(false, |_| self.flush())
}
#[inline]
@@ -1439,11 +1398,9 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
if self.window_has_any_of_protocols(window, protocols) {
self.close_window(window)
} else {
- if self.conn.kill_client(window).is_ok() {
- self.flush()
- } else {
- false
- }
+ self.conn
+ .kill_client(window)
+ .map_or(false, |_| self.flush())
}
}
@@ -1453,13 +1410,16 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
region: &Region,
) {
- let aux = xproto::ConfigureWindowAux::default()
- .x(region.pos.x as i32)
- .y(region.pos.y as i32)
- .width(region.dim.w as u32)
- .height(region.dim.h as u32);
-
- drop(self.conn.configure_window(window, &aux));
+ drop(
+ self.conn.configure_window(
+ window,
+ &xproto::ConfigureWindowAux::default()
+ .x(region.pos.x as i32)
+ .y(region.pos.y as i32)
+ .width(region.dim.w as u32)
+ .height(region.dim.h as u32),
+ ),
+ );
}
#[inline]
@@ -1468,11 +1428,14 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
pos: Pos,
) {
- let aux = xproto::ConfigureWindowAux::default()
- .x(pos.x as i32)
- .y(pos.y as i32);
-
- drop(self.conn.configure_window(window, &aux));
+ drop(
+ self.conn.configure_window(
+ window,
+ &xproto::ConfigureWindowAux::default()
+ .x(pos.x as i32)
+ .y(pos.y as i32),
+ ),
+ );
}
#[inline]
@@ -1481,11 +1444,14 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
dim: Dim,
) {
- let aux = xproto::ConfigureWindowAux::default()
- .width(dim.w as u32)
- .height(dim.h as u32);
-
- drop(self.conn.configure_window(window, &aux));
+ drop(
+ self.conn.configure_window(
+ window,
+ &xproto::ConfigureWindowAux::default()
+ .width(dim.w as u32)
+ .height(dim.h as u32),
+ ),
+ );
}
#[inline]
@@ -1550,12 +1516,12 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
key_codes: &[KeyCode],
mouse_bindings: &[&(MouseEventKey, MouseShortcut)],
) {
- for m in &[0, u16::from(ModMask::M2)] {
+ for &m in &[0, u16::from(ModMask::M2)] {
for k in key_codes {
drop(self.conn.grab_key(
false,
self.screen.root,
- if *m != 0 { k.mask | *m } else { k.mask },
+ if m != 0 { k.mask | m } else { k.mask },
k.code,
xproto::GrabMode::ASYNC,
xproto::GrabMode::ASYNC,
@@ -1572,14 +1538,15 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
x11rb::NONE,
x11rb::NONE,
xproto::ButtonIndex::try_from(state.button()).unwrap(),
- state.mask() | *m,
+ state.mask() | m,
));
}
}
- let aux = xproto::ChangeWindowAttributesAux::default().event_mask(self.root_event_mask);
-
- drop(self.conn.change_window_attributes(self.screen.root, &aux));
+ drop(self.conn.change_window_attributes(
+ self.screen.root,
+ &xproto::ChangeWindowAttributesAux::default().event_mask(self.root_event_mask),
+ ));
self.flush();
}
@@ -1633,9 +1600,10 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
width: u32,
) {
- let aux = xproto::ConfigureWindowAux::default().border_width(width);
-
- drop(self.conn.configure_window(window, &aux));
+ drop(self.conn.configure_window(
+ window,
+ &xproto::ConfigureWindowAux::default().border_width(width),
+ ));
}
#[inline]
@@ -1644,9 +1612,10 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
window: Window,
color: u32,
) {
- let aux = xproto::ChangeWindowAttributesAux::default().border_pixel(color);
-
- drop(self.conn.change_window_attributes(window, &aux));
+ drop(self.conn.change_window_attributes(
+ window,
+ &xproto::ChangeWindowAttributesAux::default().border_pixel(color),
+ ));
}
#[inline]
@@ -1717,14 +1686,14 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> Result<Region> {
- let geometry = self.conn.get_geometry(window)?.reply()?;
-
- Ok(Region::new(
- geometry.x as i32,
- geometry.y as i32,
- geometry.width as u32,
- geometry.height as u32,
- ))
+ Ok(self.conn.get_geometry(window)?.reply().map(|reply| {
+ Region::new(
+ reply.x as i32,
+ reply.y as i32,
+ reply.width as i32,
+ reply.height as i32,
+ )
+ })?)
}
#[inline]
@@ -1787,45 +1756,28 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> bool {
- let has_float_type = self.window_is_any_of_types(window, &[
- self.atoms._NET_WM_WINDOW_TYPE_DIALOG,
- self.atoms._NET_WM_WINDOW_TYPE_UTILITY,
- self.atoms._NET_WM_WINDOW_TYPE_TOOLBAR,
- self.atoms._NET_WM_WINDOW_TYPE_SPLASH,
- ]);
-
- if has_float_type {
- return true;
- }
-
- let has_float_state =
- self.window_is_any_of_state(window, &[self.atoms._NET_WM_STATE_MODAL]);
-
- if has_float_state {
+ if self.get_window_desktop(window) == Some(0xFFFFFFFF)
+ || self.window_is_any_of_states(window, &[self.atoms._NET_WM_STATE_MODAL])
+ || self.window_is_any_of_types(window, &[
+ self.atoms._NET_WM_WINDOW_TYPE_DIALOG,
+ self.atoms._NET_WM_WINDOW_TYPE_UTILITY,
+ self.atoms._NET_WM_WINDOW_TYPE_TOOLBAR,
+ self.atoms._NET_WM_WINDOW_TYPE_SPLASH,
+ ])
+ {
return true;
}
- if let Some(desktop) = self.get_window_desktop(window) {
- if desktop == 0xFFFFFFFF {
- return true;
- }
- }
-
self.get_window_geometry(window).map_or(false, |geometry| {
- let (_, size_hints) = self.get_icccm_window_size_hints(window, None, &None);
- size_hints.map_or(false, |size_hints| {
- size_hints.min_width.map_or(false, |min_width| {
- size_hints.min_height.map_or(false, |min_height| {
- size_hints.max_width.map_or(false, |max_width| {
- size_hints.max_height.map_or(false, |max_height| {
- max_width > 0
- && max_height > 0
- && max_width == min_width
- && max_height == min_height
- })
- })
- })
- })
+ let (_, sh) = self.get_icccm_window_size_hints(window, None, &None);
+
+ sh.map_or(false, |sh| {
+ match (sh.min_width, sh.min_height, sh.max_width, sh.max_height) {
+ (Some(miw), Some(mih), Some(maw), Some(mah)) => {
+ maw > 0 && mah > 0 && maw == miw && mah == mih
+ },
+ _ => false,
+ }
})
})
}
@@ -1843,13 +1795,13 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
default_state,
|cookie| {
cookie.reply().map_or(default_state, |reply| {
- reply.initial_state.map_or(default_state, |i| i)
+ reply.initial_state.unwrap_or(default_state)
})
},
);
reply.class != xproto::WindowClass::INPUT_ONLY
- && !self.window_is_any_of_state(window, &[self.atoms._NET_WM_STATE_HIDDEN])
+ && !self.window_is_any_of_states(window, &[self.atoms._NET_WM_STATE_HIDDEN])
&& match initial_state {
properties::WmHintsState::Normal => true,
_ => false,
@@ -1909,7 +1861,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> String {
- const NO_NAME: &str = "n/a";
+ static NO_NAME: &str = "n/a";
self.conn
.get_property(
@@ -1920,14 +1872,14 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
0,
std::u32::MAX,
)
- .map_or(String::from(NO_NAME), |cookie| {
- cookie.reply().map_or(String::from(NO_NAME), |reply| {
+ .map_or(NO_NAME.to_owned(), |cookie| {
+ cookie.reply().map_or(NO_NAME.to_owned(), |reply| {
std::str::from_utf8(
&reply
.value8()
- .map_or(Vec::new(), |value| value.collect::<Vec<u8>>()),
+ .map_or(Vec::with_capacity(0), |value| value.collect::<Vec<u8>>()),
)
- .map_or(String::from(NO_NAME), |name| name.to_string())
+ .map_or(NO_NAME.to_owned(), |name| name.to_owned())
})
})
}
@@ -1937,12 +1889,12 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> String {
- const NO_CLASS: &str = "n/a";
+ static NO_CLASS: &str = "n/a";
- properties::WmClass::get(self.conn, window).map_or(String::from(NO_CLASS), |cookie| {
- cookie.reply().map_or(String::from(NO_CLASS), |reply| {
+ properties::WmClass::get(self.conn, window).map_or(NO_CLASS.to_owned(), |cookie| {
+ cookie.reply().map_or(NO_CLASS.to_owned(), |reply| {
std::str::from_utf8(reply.class())
- .map_or(String::from(NO_CLASS), |class| String::from(class))
+ .map_or(NO_CLASS.to_owned(), |class| class.to_owned())
})
})
}
@@ -1952,12 +1904,12 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> String {
- const NO_INSTANCE: &str = "n/a";
+ static NO_INSTANCE: &str = "n/a";
- properties::WmClass::get(self.conn, window).map_or(String::from(NO_INSTANCE), |cookie| {
- cookie.reply().map_or(String::from(NO_INSTANCE), |reply| {
+ properties::WmClass::get(self.conn, window).map_or(NO_INSTANCE.to_owned(), |cookie| {
+ cookie.reply().map_or(NO_INSTANCE.to_owned(), |reply| {
std::str::from_utf8(reply.instance())
- .map_or(String::from(NO_INSTANCE), |instance| String::from(instance))
+ .map_or(NO_INSTANCE.to_owned(), |instance| instance.to_owned())
})
})
}
@@ -1978,7 +1930,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
)
.ok()?
.reply()
- .map_or(None, |transient_for| {
+ .ok()
+ .and_then(|transient_for| {
let transient_for: Vec<u32> = transient_for.value32()?.collect();
if transient_for.is_empty() {
@@ -2005,7 +1958,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
)
.ok()?
.reply()
- .map_or(None, |client_leader| {
+ .ok()
+ .and_then(|client_leader| {
let client_leader: Vec<u32> = client_leader.value32()?.collect();
if client_leader.is_empty() {
@@ -2029,6 +1983,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
let urgent = hints.urgent;
let input = hints.input;
let group = hints.window_group;
+
let initial_state = hints.initial_state.map(|state| match state {
properties::WmHintsState::Normal => IcccmWindowState::Normal,
properties::WmHintsState::Iconic => IcccmWindowState::Iconic,
@@ -2051,10 +2006,10 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
) -> (bool, Option<SizeHints>) {
let size_hints = properties::WmSizeHints::get_normal_hints(self.conn, window)
.ok()
- .map_or(None, |cookie| cookie.reply().ok());
+ .and_then(|cookie| cookie.reply().ok());
if size_hints.is_none() {
- return (current_size_hints.is_none(), None);
+ return (!current_size_hints.is_none(), None);
}
let size_hints = size_hints.unwrap();
@@ -2079,9 +2034,9 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
let (sh_min_width, sh_min_height) =
size_hints.min_size.map_or((None, None), |(width, height)| {
(
- if width > 0 { Some(width as u32) } else { None },
+ if width > 0 { Some(width) } else { None },
if height > 0 {
- Some(height as u32)
+ Some(height as i32)
} else {
None
},
@@ -2093,24 +2048,16 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
.base_size
.map_or((None, None), |(width, height)| {
(
- if width > 0 { Some(width as u32) } else { None },
- if height > 0 {
- Some(height as u32)
- } else {
- None
- },
+ if width > 0 { Some(width) } else { None },
+ if height > 0 { Some(height) } else { None },
)
});
let (max_width, max_height) =
size_hints.max_size.map_or((None, None), |(width, height)| {
(
- if width > 0 { Some(width as u32) } else { None },
- if height > 0 {
- Some(height as u32)
- } else {
- None
- },
+ if width > 0 { Some(width) } else { None },
+ if height > 0 { Some(height) } else { None },
)
});
@@ -2174,12 +2121,12 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
.map_or((None, None), |(inc_width, inc_height)| {
(
if inc_width > 0 && inc_width < 0xFFFF {
- Some(inc_width as u32)
+ Some(inc_width)
} else {
None
},
if inc_height > 0 && inc_height < 0xFFFF {
- Some(inc_height as u32)
+ Some(inc_height)
} else {
None
},
@@ -2232,7 +2179,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
max_ratio_vulgar,
});
- (*current_size_hints == size_hints, size_hints)
+ (*current_size_hints != size_hints, size_hints)
}
fn init_wm_properties(
@@ -2404,30 +2351,6 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
}
#[inline]
- fn set_window_above(
- &self,
- window: Window,
- on: bool,
- ) {
- }
-
- #[inline]
- fn set_window_fullscreen(
- &self,
- window: Window,
- on: bool,
- ) {
- }
-
- #[inline]
- fn set_window_below(
- &self,
- window: Window,
- on: bool,
- ) {
- }
-
- #[inline]
fn set_window_state(
&self,
window: Window,
@@ -2462,10 +2385,10 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
) {
let mut frame_extents: Vec<u32> = Vec::with_capacity(4);
- frame_extents.push(extents.left);
- frame_extents.push(extents.right);
- frame_extents.push(extents.top);
- frame_extents.push(extents.bottom);
+ frame_extents.push(extents.left as u32);
+ frame_extents.push(extents.right as u32);
+ frame_extents.push(extents.top as u32);
+ frame_extents.push(extents.bottom as u32);
drop(self.conn.change_property32(
xproto::PropMode::REPLACE,
@@ -2486,8 +2409,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
geometries.iter().for_each(|geometry| {
areas.push(geometry.pos.x as u32);
areas.push(geometry.pos.y as u32);
- areas.push(geometry.dim.w);
- areas.push(geometry.dim.h);
+ areas.push(geometry.dim.w as u32);
+ areas.push(geometry.dim.h as u32);
});
drop(self.conn.change_property32(
@@ -2509,8 +2432,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
viewports.iter().for_each(|viewport| {
areas.push(viewport.pos.x as u32);
areas.push(viewport.pos.y as u32);
- areas.push(viewport.dim.w);
- areas.push(viewport.dim.h);
+ areas.push(viewport.dim.w as u32);
+ areas.push(viewport.dim.h as u32);
});
drop(self.conn.change_property32(
@@ -2532,8 +2455,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
workareas.iter().for_each(|workarea| {
areas.push(workarea.pos.x as u32);
areas.push(workarea.pos.y as u32);
- areas.push(workarea.dim.w);
- areas.push(workarea.dim.h);
+ areas.push(workarea.dim.w as u32);
+ areas.push(workarea.dim.h as u32);
});
drop(self.conn.change_property32(
@@ -2615,7 +2538,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
)
.ok()?
.reply()
- .map_or(None, |strut| {
+ .ok()
+ .and_then(|strut| {
let widths: Vec<u32> = strut.value32()?.collect();
if widths.is_empty() {
@@ -2659,7 +2583,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
)
.ok()?
.reply()
- .map_or(None, |strut_partial| {
+ .ok()
+ .and_then(|strut_partial| {
let widths: Vec<u32> = strut_partial.value32()?.collect();
if widths.is_empty() {
@@ -2703,7 +2628,8 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
)
.ok()?
.reply()
- .map_or(None, |desktop| {
+ .ok()
+ .and_then(|desktop| {
let desktop: Vec<u32> = desktop.value32()?.collect();
if desktop.is_empty() {
@@ -2743,8 +2669,9 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
.ok()
.and_then(|cookie| cookie.reply().ok())
.map(|types| {
- let types: Vec<u32> =
- types.value32().map_or(Vec::new(), |value| value.collect());
+ let types: Vec<u32> = types
+ .value32()
+ .map_or(Vec::with_capacity(0), |value| value.collect());
for type_ in types {
if let Some(type_) = self.get_window_type_from_atom(type_) {
@@ -2762,7 +2689,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> Option<WindowState> {
- self.get_window_states(window).get(0).map(|&state| state)
+ self.get_window_states(window).get(0).copied()
}
fn get_window_states(
@@ -2784,8 +2711,9 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
.ok()
.and_then(|cookie| cookie.reply().ok())
.map(|states| {
- let states: Vec<u32> =
- states.value32().map_or(Vec::new(), |value| value.collect());
+ let states: Vec<u32> = states
+ .value32()
+ .map_or(Vec::with_capacity(0), |value| value.collect());
for state in states {
if let Some(state) = self.get_window_state_from_atom(state) {
@@ -2803,7 +2731,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> bool {
- self.window_is_any_of_state(window, &[self.atoms._NET_WM_STATE_FULLSCREEN])
+ self.window_is_any_of_states(window, &[self.atoms._NET_WM_STATE_FULLSCREEN])
}
#[inline]
@@ -2811,7 +2739,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> bool {
- self.window_is_any_of_state(window, &[self.atoms._NET_WM_STATE_ABOVE])
+ self.window_is_any_of_states(window, &[self.atoms._NET_WM_STATE_ABOVE])
}
#[inline]
@@ -2819,7 +2747,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> bool {
- self.window_is_any_of_state(window, &[self.atoms._NET_WM_STATE_BELOW])
+ self.window_is_any_of_states(window, &[self.atoms._NET_WM_STATE_BELOW])
}
#[inline]
@@ -2827,17 +2755,7 @@ impl<'a, C: connection::Connection> Connection for XConnection<'a, C> {
&self,
window: Window,
) -> bool {
- let has_sticky_state =
- self.window_is_any_of_state(window, &[self.atoms._NET_WM_STATE_STICKY]);
-
- if has_sticky_state {
- return true;
- }
-
- if let Some(desktop) = self.get_window_desktop(window) {
- desktop == 0xFFFFFFFF
- } else {
- false
- }
+ self.window_is_any_of_states(window, &[self.atoms._NET_WM_STATE_STICKY])
+ || self.get_window_desktop(window) == Some(0xFFFFFFFF)
}
}