diff options
| -rw-r--r-- | niri-config/src/lib.rs | 2 | ||||
| -rw-r--r-- | niri-visual-tests/src/cases/window.rs | 2 | ||||
| -rw-r--r-- | niri-visual-tests/src/test_window.rs | 5 | ||||
| -rw-r--r-- | resources/default-config.kdl | 10 | ||||
| -rw-r--r-- | src/layout/mod.rs | 2 | ||||
| -rw-r--r-- | src/layout/tile.rs | 8 | ||||
| -rw-r--r-- | src/window/mapped.rs | 3 | ||||
| -rw-r--r-- | src/window/mod.rs | 7 |
8 files changed, 34 insertions, 5 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 6e8bab2e..9bf62e13 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -697,6 +697,8 @@ pub struct WindowRule { #[knuffel(child, unwrap(argument))] pub draw_border_with_background: Option<bool>, + #[knuffel(child, unwrap(argument))] + pub opacity: Option<f32>, } // Remember to update the PartialEq impl when adding fields! diff --git a/niri-visual-tests/src/cases/window.rs b/niri-visual-tests/src/cases/window.rs index f8f7a1af..a8855f46 100644 --- a/niri-visual-tests/src/cases/window.rs +++ b/niri-visual-tests/src/cases/window.rs @@ -49,7 +49,7 @@ impl TestCase for Window { let location = Point::from(((size.w - win_size.w) / 2, (size.h - win_size.h) / 2)); self.window - .render(renderer, location, Scale::from(1.)) + .render(renderer, location, Scale::from(1.), 1.) .into_iter() .map(|elem| Box::new(elem) as _) .collect() diff --git a/niri-visual-tests/src/test_window.rs b/niri-visual-tests/src/test_window.rs index 4f89d15e..341f4fbf 100644 --- a/niri-visual-tests/src/test_window.rs +++ b/niri-visual-tests/src/test_window.rs @@ -146,6 +146,7 @@ impl LayoutElement for TestWindow { _renderer: &mut R, location: Point<i32, Logical>, scale: Scale<f64>, + alpha: f32, ) -> Vec<LayoutElementRenderElement<R>> { let inner = self.inner.borrow(); @@ -154,7 +155,7 @@ impl LayoutElement for TestWindow { &inner.buffer, location.to_physical_precise_round(scale), scale, - 1., + alpha, Kind::Unspecified, ) .into(), @@ -163,7 +164,7 @@ impl LayoutElement for TestWindow { (location - Point::from((inner.csd_shadow_width, inner.csd_shadow_width))) .to_physical_precise_round(scale), scale, - 1., + alpha, Kind::Unspecified, ) .into(), diff --git a/resources/default-config.kdl b/resources/default-config.kdl index 485ab649..0878f213 100644 --- a/resources/default-config.kdl +++ b/resources/default-config.kdl @@ -414,6 +414,16 @@ animations { // Set this to `false` to draw them as borders around the window even for // windows which use client-side decorations. draw-border-with-background false + + // Set the opacity of the window. + // This is applied on top of the window's own opacity, so semitransparent + // windows will become even more transparent. + // Opacity is applied to every surface of the window individually, so + // subsurfaces and pop-up menus will show window content behind them. + // Also, focus ring and border with background will show through + // semitransparent windows (see prefer-no-csd and + // the draw-border-with-background property above). + opacity 0.5 } // Here's a useful example. Work around WezTerm's initial configure bug diff --git a/src/layout/mod.rs b/src/layout/mod.rs index bc5c8dcf..bbca41c9 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -95,6 +95,7 @@ pub trait LayoutElement { renderer: &mut R, location: Point<i32, Logical>, scale: Scale<f64>, + alpha: f32, ) -> Vec<LayoutElementRenderElement<R>>; fn request_size(&self, size: Size<i32, Logical>); @@ -1856,6 +1857,7 @@ mod tests { _renderer: &mut R, _location: Point<i32, Logical>, _scale: Scale<f64>, + _alpha: f32, ) -> Vec<LayoutElementRenderElement<R>> { vec![] } diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 0609583e..faa17840 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -325,9 +325,15 @@ impl<W: LayoutElement> Tile<W> { view_size: Size<i32, Logical>, focus_ring: bool, ) -> impl Iterator<Item = TileRenderElement<R>> { + let alpha = if self.is_fullscreen { + 1. + } else { + self.window.rules().opacity.unwrap_or(1.).clamp(0., 1.) + }; + let rv = self .window - .render(renderer, location + self.window_loc(), scale) + .render(renderer, location + self.window_loc(), scale, alpha) .into_iter() .map(Into::into); diff --git a/src/window/mapped.rs b/src/window/mapped.rs index a48ca636..52b9ac92 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -108,13 +108,14 @@ impl LayoutElement for Mapped { renderer: &mut R, location: Point<i32, Logical>, scale: Scale<f64>, + alpha: f32, ) -> Vec<LayoutElementRenderElement<R>> { let buf_pos = location - self.window.geometry().loc; self.window.render_elements( renderer, buf_pos.to_physical_precise_round(scale), scale, - 1., + alpha, ) } diff --git a/src/window/mod.rs b/src/window/mod.rs index 63cdbe3f..ddf712b0 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -52,6 +52,9 @@ pub struct ResolvedWindowRules { /// /// `None` means using the SSD heuristic. pub draw_border_with_background: Option<bool>, + + /// Extra opacity to draw this window with. + pub opacity: Option<f32>, } impl<'a> WindowRef<'a> { @@ -82,6 +85,7 @@ impl ResolvedWindowRules { max_width: None, max_height: None, draw_border_with_background: None, + opacity: None, } } @@ -153,6 +157,9 @@ impl ResolvedWindowRules { if let Some(x) = rule.draw_border_with_background { resolved.draw_border_with_background = Some(x); } + if let Some(x) = rule.opacity { + resolved.opacity = Some(x); + } } resolved.open_on_output = open_on_output.map(|x| x.to_owned()); |
