From fbcde44fa2f726fa61b777348cc6bf376d1ccc78 Mon Sep 17 00:00:00 2001 From: Innes Anderson-Morrison Date: Sun, 2 Jun 2024 10:41:50 +0100 Subject: [PATCH] adding a spacer widget for the status bar --- crates/penrose_ui/src/bar/mod.rs | 16 ++++- crates/penrose_ui/src/bar/widgets/mod.rs | 72 +++++++++++++++++++++++ src/core/mod.rs | 2 +- src/extensions/hooks/window_swallowing.rs | 8 ++- src/pure/stack_set.rs | 2 +- 5 files changed, 93 insertions(+), 7 deletions(-) diff --git a/crates/penrose_ui/src/bar/mod.rs b/crates/penrose_ui/src/bar/mod.rs index 2ccc72eb..42081af3 100644 --- a/crates/penrose_ui/src/bar/mod.rs +++ b/crates/penrose_ui/src/bar/mod.rs @@ -133,10 +133,15 @@ impl StatusBar { let mut extents = Vec::with_capacity(self.widgets.len()); let mut greedy_indices = vec![]; - for (i, w) in self.widgets.iter_mut().enumerate() { + for (j, w) in self + .widgets + .iter_mut() + .filter(|w| w.required_for_screen(i)) + .enumerate() + { extents.push(w.current_extent(&mut ctx, self.h)?); if w.is_greedy() { - greedy_indices.push(i) + greedy_indices.push(j) } } @@ -152,7 +157,12 @@ impl StatusBar { } let mut x = 0; - for (wd, (w, _)) in self.widgets.iter_mut().zip(extents) { + for (wd, (w, _)) in self + .widgets + .iter_mut() + .filter(|w| w.required_for_screen(i)) + .zip(extents) + { wd.draw(&mut ctx, self.active_screen, screen_has_focus, w, self.h)?; x += w; ctx.flush(); diff --git a/crates/penrose_ui/src/bar/widgets/mod.rs b/crates/penrose_ui/src/bar/widgets/mod.rs index ce22729b..8444e8ea 100644 --- a/crates/penrose_ui/src/bar/widgets/mod.rs +++ b/crates/penrose_ui/src/bar/widgets/mod.rs @@ -49,6 +49,16 @@ where /// space will be split evenly between all widgets. fn is_greedy(&self) -> bool; + /// Whether or not this widget should be displayed on the given screen index. + /// + /// By default all widgets are displayed on all screens but this allows widgets to + /// conditionally render on a subset of screens (e.g. a systray widget only displaying + /// on the primary screen). + #[allow(unused_variables)] + fn required_for_screen(&self, idx: usize) -> bool { + true + } + #[allow(unused_variables)] /// A startup hook to be run in order to initialise this Widget fn on_startup(&mut self, state: &mut State, x: &X) -> Result<()> { @@ -380,3 +390,65 @@ impl Widget for IntervalText { Widget::::require_draw(&*inner) } } + +/// A simple percentage based spacer widget that can be conditionally applied to +/// specific screens. +#[derive(Debug)] +pub struct Spacer { + screen_indices: Vec, + perc: f32, + w: u32, +} + +impl Spacer { + /// Construct a new spacer for rendering on the specified screens. + /// + /// It will consume `perc`% of the width of any screen it is rendered on. + /// + /// # Panics + /// This method will panic if `perc` is not in the range `0.0..=1.0`. + pub fn new(screen_indices: Vec, perc: f32) -> Self { + if !(0.0..=1.0).contains(&perc) { + panic!("{perc} is an invalid percentage"); + } + + Self { + screen_indices, + perc, + w: 0, + } + } +} + +impl Widget for Spacer { + fn draw(&mut self, ctx: &mut Context<'_>, _: usize, _: bool, w: u32, h: u32) -> Result<()> { + ctx.fill_bg(Rect::new(0, 0, w, h)) + } + + fn current_extent(&mut self, _: &mut Context<'_>, h: u32) -> Result<(u32, u32)> { + Ok((self.w, h)) + } + + fn is_greedy(&self) -> bool { + false + } + + fn require_draw(&self) -> bool { + false + } + + fn required_for_screen(&self, idx: usize) -> bool { + self.screen_indices.contains(&idx) + } + + fn on_startup(&mut self, state: &mut State, _: &X) -> Result<()> { + self.w = state + .client_set + .screens() + .next() + .map(|s| (s.geometry().w as f32 * self.perc) as u32) + .unwrap(); + + Ok(()) + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs index 5324db42..3520b36e 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -140,7 +140,7 @@ where pub fn extension(&self) -> Result>> { self.extensions .get() - .map(Arc::clone) + .cloned() .ok_or(Error::UnknownStateExtension { type_id: TypeId::of::(), }) diff --git a/src/extensions/hooks/window_swallowing.rs b/src/extensions/hooks/window_swallowing.rs index 56724bfb..cb6e5f49 100644 --- a/src/extensions/hooks/window_swallowing.rs +++ b/src/extensions/hooks/window_swallowing.rs @@ -23,7 +23,8 @@ struct WindowSwallowingState { impl WindowSwallowingState { fn stash_state(&mut self, state: &mut State) -> Result { self.stack_before_close = state.client_set.current_stack().cloned(); - self.floating_before_close = state.client_set.floating.clone(); + self.floating_before_close + .clone_from(&state.client_set.floating); Ok(true) } @@ -65,7 +66,10 @@ impl WindowSwallowingState { info!(%parent, %child, "restoring swallowed parent in place of child"); transfer_floating_state(child, parent, &mut self.floating_before_close); - state.client_set.floating = self.floating_before_close.clone(); + state + .client_set + .floating + .clone_from(&self.floating_before_close); old_stack.focus = parent; state.client_set.modify_occupied(|_| old_stack); x.refresh(state)?; diff --git a/src/pure/stack_set.rs b/src/pure/stack_set.rs index 585f8e5f..b3d16c01 100644 --- a/src/pure/stack_set.rs +++ b/src/pure/stack_set.rs @@ -1193,7 +1193,7 @@ pub mod tests { // This state is technically invalid for us to get in to but the point is // to check that we definitely leave the previous tag alone during this // operation and don't end up with it anywhere it shouldn't be. - s.previous_tag = "PREVIOUS".to_owned(); + "PREVIOUS".clone_into(&mut s.previous_tag); assert_eq!(s.screens.focus.workspace.tag, "3"); assert_eq!(s.previous_tag, "PREVIOUS");