wzrd

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in Rust
git clone git://git.deurzen.net/wzrd
Log | Files | Refs | LICENSE

commit 2ff313b6dbe6a91375ce0c8879bd04bd81f680f0
parent 3dadec096115d65484b82aa8cab329c4da17f108
Author: deurzen <m.deurzen@tum.de>
Date:   Sat, 13 Mar 2021 15:30:27 +0100

implements client decoration handling

Diffstat:
Msrc/core/client.rs | 49++++++++++++++++++++++++-------------------------
Msrc/core/common.rs | 8--------
Msrc/core/model.rs | 186++++++++++++++++++++++++++++++-------------------------------------------------
Msrc/core/zone.rs | 131++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
4 files changed, 208 insertions(+), 166 deletions(-)

diff --git a/src/core/client.rs b/src/core/client.rs @@ -1,6 +1,8 @@ use crate::common::Ident; use crate::common::Identify; use crate::common::NO_EXTENTS; +use crate::zone::Decoration; +use crate::zone::Frame; use winsys::common::Extents; use winsys::common::Hex32; use winsys::common::Pid; @@ -26,7 +28,7 @@ pub struct Client { inner_region: Region, free_region: Region, tile_region: Region, - frame_extents: Option<Extents>, + decoration: Decoration, size_hints: Option<SizeHints>, warp_pos: Option<Pos>, parent: Option<Window>, @@ -80,12 +82,12 @@ impl Client { context: 0, workspace: 0, window_type, - active_region: Region::default(), - previous_region: Region::default(), - inner_region: Region::default(), - free_region: Region::default(), - tile_region: Region::default(), - frame_extents: None, + active_region: Default::default(), + previous_region: Default::default(), + inner_region: Default::default(), + free_region: Default::default(), + tile_region: Default::default(), + decoration: Default::default(), size_hints: None, warp_pos: None, parent: None, @@ -229,16 +231,17 @@ impl Client { &mut self, active_region: &Region, ) { - self.inner_region = if let Some(frame_extents) = self.frame_extents { - let mut inner_region = *active_region - frame_extents; + self.inner_region = if let Some(frame) = self.decoration.frame { + let extents = frame.extents; + let mut inner_region = *active_region - extents; - inner_region.pos.x = frame_extents.left as i32; - inner_region.pos.y = frame_extents.top as i32; + inner_region.pos.x = extents.left as i32; + inner_region.pos.y = extents.top as i32; inner_region.dim.w = - active_region.dim.w - frame_extents.left - frame_extents.right; + active_region.dim.w - extents.left - extents.right; inner_region.dim.h = - active_region.dim.h - frame_extents.top - frame_extents.bottom; + active_region.dim.h - extents.top - extents.bottom; inner_region } else { @@ -292,25 +295,21 @@ impl Client { } #[inline] - pub fn frame_extents_unchecked(&self) -> Extents { - if let Some(frame_extents) = self.frame_extents { - frame_extents - } else { - NO_EXTENTS - } + pub fn decoration(&self) -> &Decoration { + &self.decoration } #[inline] - pub fn frame_extents(&self) -> &Option<Extents> { - &self.frame_extents + pub fn frame_extents(&self) -> Extents { + NO_EXTENTS + self.decoration } #[inline] - pub fn set_frame_extents( + pub fn set_decoration( &mut self, - frame_extents: Option<Extents>, + decoration: Decoration, ) { - self.frame_extents = frame_extents; + self.decoration = decoration; } #[inline] @@ -684,7 +683,7 @@ impl std::fmt::Debug for Client { .field("inner_region", &self.inner_region) .field("free_region", &self.free_region) .field("tile_region", &self.tile_region) - .field("frame_extents", &self.frame_extents) + .field("decoration", &self.decoration) .field("size_hints", &self.size_hints) .field("warp_pos", &self.warp_pos) .field("parent", &self.parent.map(|parent| Hex32(parent))) diff --git a/src/core/common.rs b/src/core/common.rs @@ -11,14 +11,6 @@ macro_rules! WM_NAME ( () => { "wzrd" }; ); -pub const FOCUSED_FRAME_COLOR: Color = 0xD7005F; -pub const URGENT_FRAME_COLOR: Color = 0xD08928; -pub const REGULAR_DISOWNED_FRAME_COLOR: Color = 0x707070; -pub const FOCUSED_DISOWNED_FRAME_COLOR: Color = 0x00AA80; -pub const REGULAR_STICKY_FRAME_COLOR: Color = 0x6C9EF8; -pub const FOCUSED_STICKY_FRAME_COLOR: Color = 0xB77FDB; -pub const REGULAR_FRAME_COLOR: Color = 0x191A2A; - pub const MIN_WINDOW_DIM: Dim = Dim { w: 75, h: 50, diff --git a/src/core/model.rs b/src/core/model.rs @@ -4,13 +4,8 @@ use crate::client::Client; use crate::common::Change; use crate::common::Direction; use crate::common::Index; -use crate::common::FOCUSED_FRAME_COLOR; -use crate::common::FOCUSED_STICKY_FRAME_COLOR; use crate::common::FREE_EXTENTS; use crate::common::MIN_WINDOW_DIM; -use crate::common::REGULAR_FRAME_COLOR; -use crate::common::REGULAR_STICKY_FRAME_COLOR; -use crate::common::URGENT_FRAME_COLOR; use crate::consume::get_spawner_pid; use crate::cycle::Cycle; use crate::cycle::InsertPos; @@ -1066,27 +1061,53 @@ impl<'a> Model<'a> { self.sync_focus(); } - fn refresh_client( + fn redraw_client( &self, window: Window, ) { if let Some(client) = self.client(window) { - self.conn.set_window_background_color( - client.frame(), - if client.is_focused() { - if client.is_sticky() { - FOCUSED_STICKY_FRAME_COLOR + let decoration = client.decoration(); + + if let Some(border) = decoration.border { + self.conn + .set_window_border_width(client.frame(), border.width); + + self.conn.set_window_border_color( + client.frame(), + if client.is_focused() { + if client.is_sticky() { + border.colors.fsticky + } else { + border.colors.focused + } + } else if client.is_urgent() { + border.colors.urgent + } else if client.is_sticky() { + border.colors.rsticky } else { - FOCUSED_FRAME_COLOR - } - } else if client.is_urgent() { - URGENT_FRAME_COLOR - } else if client.is_sticky() { - REGULAR_STICKY_FRAME_COLOR - } else { - REGULAR_FRAME_COLOR - }, - ); + border.colors.regular + }, + ); + } + + if let Some(frame) = decoration.frame { + self.conn.set_window_background_color( + client.frame(), + if client.is_focused() { + if client.is_sticky() { + frame.colors.fsticky + } else { + frame.colors.focused + } + } else if client.is_urgent() { + frame.colors.urgent + } else if client.is_sticky() { + frame.colors.rsticky + } else { + frame.colors.regular + }, + ); + } } } @@ -1099,9 +1120,7 @@ impl<'a> Model<'a> { let client = self.client_mut(window).unwrap(); let region = &placement.region.unwrap(); - client.set_frame_extents( - placement.decoration.frame.map(|f| f.extents), - ); + client.set_decoration(placement.decoration); match placement.method { PlacementMethod::Free => client.set_free_region(region), @@ -1130,7 +1149,7 @@ impl<'a> Model<'a> { PlacementMethod::Tile => &client.tile_region(), }); - self.refresh_client(window); + self.redraw_client(window); self.conn.update_window_offset(window, frame); } @@ -1145,7 +1164,7 @@ impl<'a> Model<'a> { info!("mapping client with window {:#0x}", window); self.conn.map_window(window); self.conn.map_window(frame); - self.refresh_client(window); + self.redraw_client(window); let client = self.client_mut(window).unwrap(); client.set_mapped(true); @@ -1855,7 +1874,7 @@ impl<'a> Model<'a> { } self.focus = Some(window); - self.refresh_client(window); + self.redraw_client(window); self.apply_stack(client_workspace_index); } } @@ -1869,16 +1888,14 @@ impl<'a> Model<'a> { let (window, frame) = client.windows(); let current_pos = self.conn.get_pointer_position(); - self.conn - .set_window_background_color(frame, REGULAR_FRAME_COLOR); - self.conn.regrab_buttons(frame); - info!("unfocusing client with window {:#0x}", window); + self.conn.regrab_buttons(frame); + let client = self.client_mut(window).unwrap(); client.set_warp_pos(current_pos); client.set_focused(false); - self.refresh_client(window); + self.redraw_client(window); } } @@ -2144,7 +2161,7 @@ impl<'a> Model<'a> { } } - self.refresh_client(window); + self.redraw_client(window); } fn unstick( @@ -2180,7 +2197,7 @@ impl<'a> Model<'a> { } } - self.refresh_client(window); + self.redraw_client(window); } pub fn iconify_focus(&mut self) { @@ -2316,28 +2333,15 @@ impl<'a> Model<'a> { }, } - let id = self.zone_manager.client_zone(window); - let extents = *client.frame_extents(); - let decoration = Decoration { - border: None, - frame: extents.map(|e| Frame { - extents: e, - colors: Default::default(), - }), - }; - let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: id, + zone: self.zone_manager.client_zone(window), region: Some(region), - // TODO: zone change: should be proper frame - decoration, + decoration: *client.decoration(), }; - // TODO: zone change self.update_client_placement(&placement); - // TODO: zone change self.place_client(window, placement.method); } } @@ -2376,22 +2380,12 @@ impl<'a> Model<'a> { Edge::Bottom => region.pos.y += step, } - let id = self.zone_manager.client_zone(window); - let extents = *client.frame_extents(); - let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: id, + zone: self.zone_manager.client_zone(window), region: Some(region), - // TODO: zone change: should be proper frame - decoration: Decoration { - border: None, - frame: extents.map(|e| Frame { - extents: e, - colors: Default::default(), - }), - }, + decoration: *client.decoration(), }; self.update_client_placement(&placement); @@ -2407,7 +2401,7 @@ impl<'a> Model<'a> { ) { if let Some(client) = self.client(window) { if self.is_free(client) { - let frame_extents = client.frame_extents_unchecked(); + let frame_extents = client.frame_extents(); let original_region = *client.free_region(); let region = original_region; let window = client.window(); @@ -2453,22 +2447,12 @@ impl<'a> Model<'a> { region.pos.x -= width_shift; region.pos.y -= height_shift; - let id = self.zone_manager.client_zone(window); - let extents = *client.frame_extents(); - let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: id, + zone: self.zone_manager.client_zone(window), region: Some(region), - // TODO: zone change: should be proper frame - decoration: Decoration { - border: None, - frame: extents.map(|e| Frame { - extents: e, - colors: Default::default(), - }), - }, + decoration: *client.decoration(), }; self.update_client_placement(&placement); @@ -2495,7 +2479,7 @@ impl<'a> Model<'a> { ) { if let Some(client) = self.client(window) { if self.is_free(client) { - let frame_extents = client.frame_extents_unchecked(); + let frame_extents = client.frame_extents(); let window = client.window(); let mut region = (*client.free_region()).without_extents(&frame_extents); @@ -2563,23 +2547,14 @@ impl<'a> Model<'a> { } let window = client.window(); - let id = self.zone_manager.client_zone(window); let region = region.with_extents(&frame_extents); - let extents = *client.frame_extents(); let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: id, + zone: self.zone_manager.client_zone(window), region: Some(region), - // TODO: zone change: should be proper frame - decoration: Decoration { - border: None, - frame: extents.map(|e| Frame { - extents: e, - colors: Default::default(), - }), - }, + decoration: *client.decoration(), }; self.update_client_placement(&placement); @@ -2628,8 +2603,6 @@ impl<'a> Model<'a> { self.move_buffer.window_region() { let window = client.window(); - let id = self.zone_manager.client_zone(window); - let extents = *client.frame_extents(); let region = Region { pos: window_region.pos + grip_pos.dist(*pos), dim: client.free_region().dim, @@ -2638,16 +2611,9 @@ impl<'a> Model<'a> { let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: id, + zone: self.zone_manager.client_zone(window), region: Some(region), - // TODO: zone change: should be proper frame - decoration: Decoration { - border: None, - frame: extents.map(|e| Frame { - extents: e, - colors: Default::default(), - }), - }, + decoration: *client.decoration(), }; self.update_client_placement(&placement); @@ -2702,7 +2668,7 @@ impl<'a> Model<'a> { let current_pos = *pos; let previous_region = *client.previous_region(); - let frame_extents = client.frame_extents_unchecked(); + let frame_extents = client.frame_extents(); let (pos, mut dim) = client .free_region() .without_extents(&frame_extents) @@ -3164,7 +3130,7 @@ impl<'a> Model<'a> { if let Some(client) = self.client_any_mut(window) { client.set_urgent(true); - self.refresh_client(window); + self.redraw_client(window); } }, _ => {}, @@ -3184,7 +3150,7 @@ impl<'a> Model<'a> { if let Some(client) = self.client_any_mut(window) { client.set_urgent(false); - self.refresh_client(window); + self.redraw_client(window); } }, _ => {}, @@ -3261,7 +3227,7 @@ impl<'a> Model<'a> { if let Some(client) = self.client(window) { if self.is_free(client) { let window = client.window(); - let frame_extents = client.frame_extents_unchecked(); + let frame_extents = client.frame_extents(); let region = if event_window == window { Some(Region { @@ -3315,22 +3281,12 @@ impl<'a> Model<'a> { }); if let Some(region) = region { - let id = self.zone_manager.client_zone(window); - let extents = *client.frame_extents(); - let placement = Placement { method: PlacementMethod::Free, kind: PlacementKind::Client(window), - zone: id, + zone: self.zone_manager.client_zone(window), region: Some(region), - // TODO: zone change: should be proper frame - decoration: Decoration { - border: None, - frame: extents.map(|e| Frame { - extents: e, - colors: Default::default(), - }), - }, + decoration: *client.decoration(), }; self.update_client_placement(&placement); @@ -3446,7 +3402,7 @@ impl<'a> Model<'a> { return; } - let frame_extents = client.frame_extents_unchecked(); + let frame_extents = client.frame_extents(); let mut geometry = geometry.unwrap(); let (_, size_hints) = self.conn.get_icccm_window_size_hints( @@ -3501,7 +3457,7 @@ impl<'a> Model<'a> { self.conn.set_window_frame_extents( window, if let Some(client) = self.client_any(window) { - client.frame_extents_unchecked() + client.frame_extents() } else { if self.conn.must_manage_window(window) { FREE_EXTENTS diff --git a/src/core/zone.rs b/src/core/zone.rs @@ -16,6 +16,7 @@ use strum_macros::EnumIter; use strum_macros::ToString; use std::collections::HashMap; +use std::ops::Add; use std::string::ToString; use std::sync::atomic; use std::vec::Vec; @@ -68,12 +69,44 @@ pub struct Border { pub colors: ColorScheme, } +impl Add<Border> for Padding { + type Output = Self; + + fn add( + self, + border: 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>, @@ -89,6 +122,25 @@ impl Default for Decoration { } } +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 + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum Disposition { Unchanged, @@ -179,6 +231,8 @@ pub enum LayoutKind { Paper = b'/', SStack = b'+', Stack = b'S', + Horz = b'H', + Vert = b'V', } #[inline] @@ -308,6 +362,46 @@ impl LayoutKind { 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, + gap: true, + 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, + gap: true, + persistent: false, + single: false, + wraps: true, + }, #[allow(unreachable_patterns)] _ => unimplemented!( @@ -319,20 +413,27 @@ impl LayoutKind { fn default_data(&self) -> LayoutData { match *self { - // TODO - LayoutKind::Float => LayoutData::default(), - LayoutKind::SingleFloat => LayoutData::default(), + LayoutKind::Float => Default::default(), + LayoutKind::SingleFloat => Default::default(), LayoutKind::Center => LayoutData { - margin: None, - gap_size: 0, - main_count: 5u32, main_factor: 0.40f32, + ..Default::default() + }, + LayoutKind::Monocle => Default::default(), + LayoutKind::Paper => Default::default(), + LayoutKind::SStack => LayoutData { + main_count: 1u32, + main_factor: 0.50f32, + ..Default::default() }, - LayoutKind::Monocle => LayoutData::default(), - LayoutKind::Paper => LayoutData::default(), - LayoutKind::SStack => LayoutData::default(), - LayoutKind::Stack => LayoutData::default(), + LayoutKind::Stack => LayoutData { + main_count: 1u32, + main_factor: 0.50f32, + ..Default::default() + }, + LayoutKind::Horz => Default::default(), + LayoutKind::Vert => Default::default(), #[allow(unreachable_patterns)] _ => unimplemented!( @@ -487,7 +588,6 @@ impl LayoutKind { )]; } - let cw = (dim.w as f32 * if data.main_factor > min_w_ratio { data.main_factor @@ -526,12 +626,7 @@ impl LayoutKind { ( Disposition::Changed( - Region::new( - x, - pos.y, - w as u32, - dim.h, - ), + Region::new(x, pos.y, w as u32, dim.h), config.decoration, ), true, @@ -920,7 +1015,7 @@ impl ZoneManager { let mut zone_changes: Vec<(ZoneId, ZoneChange)> = Vec::new(); - let mut placements = match &content { + let placements = match &content { ZoneContent::Client(window) => { return vec![Placement { method,