diff --git a/niri-visual-tests/src/cases/layout.rs b/niri-visual-tests/src/cases/layout.rs index d6175efe..b7f31dfb 100644 --- a/niri-visual-tests/src/cases/layout.rs +++ b/niri-visual-tests/src/cases/layout.rs @@ -272,7 +272,7 @@ impl TestCase for Layout { .monitor_for_output(&self.output) .unwrap() .render_elements(renderer, RenderTarget::Output, true) - .flat_map(|(_, iter)| iter) + .flat_map(|(_, _, iter)| iter) .map(|elem| Box::new(elem) as _) .collect() } diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index ec513857..54bcf9af 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -23,6 +23,7 @@ use crate::input::swipe_tracker::SwipeTracker; use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::shadow::ShadowRenderElement; +use crate::render_helpers::solid_color::SolidColorRenderElement; use crate::render_helpers::RenderTarget; use crate::rubber_band::RubberBand; use crate::utils::transaction::Transaction; @@ -175,6 +176,7 @@ niri_render_elements! { InsertHint = CropRenderElement, UncroppedInsertHint = InsertHintRenderElement, Shadow = ShadowRenderElement, + SolidColor = SolidColorRenderElement, } } @@ -1619,6 +1621,7 @@ impl Monitor { ) -> impl Iterator< Item = ( Rectangle, + MonitorRenderElement, impl Iterator> + 'a, ), > { @@ -1692,7 +1695,7 @@ impl Monitor { let iter = floating.chain(hint).chain(scrolling); - let iter = iter.map(move |elem| { + let scale_relocate = move |elem| { let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom); RelocateRenderElement::from_element( elem, @@ -1702,9 +1705,14 @@ impl Monitor { geo.loc.to_physical_precise_round(scale), Relocate::Relative, ) - }); + }; - (geo, iter) + let iter = iter.map(scale_relocate); + + let background = ws.render_background(); + let background = scale_relocate(MonitorInnerRenderElement::SolidColor(background)); + + (geo, background, iter) }) } diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index 06d3009d..3831ffe3 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -6,6 +6,7 @@ use niri_config::{ CenterFocusedColumn, CornerRadius, OutputName, PresetSize, Workspace as WorkspaceConfig, }; use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout}; +use smithay::backend::renderer::element::Kind; use smithay::backend::renderer::gles::GlesRenderer; use smithay::desktop::{layer_map_for_output, Window}; use smithay::output::Output; @@ -29,6 +30,7 @@ use crate::animation::Clock; use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::shadow::ShadowRenderElement; +use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement}; use crate::render_helpers::RenderTarget; use crate::utils::id::IdCounter; use crate::utils::transaction::{Transaction, TransactionBlocker}; @@ -87,6 +89,9 @@ pub struct Workspace { /// This workspace's shadow in the overview. shadow: Shadow, + /// This workspace's background. + background_buffer: SolidColorBuffer, + /// Clock for driving animations. pub(super) clock: Clock, @@ -246,6 +251,8 @@ impl Workspace { let shadow_config = compute_workspace_shadow_config(options.overview.workspace_shadow, view_size); + let background_color = options.layout.background_color.to_array_unpremul(); + Self { scrolling, floating, @@ -256,6 +263,7 @@ impl Workspace { view_size, working_area, shadow: Shadow::new(shadow_config), + background_buffer: SolidColorBuffer::new(view_size, background_color), output: Some(output), clock, base_options, @@ -309,6 +317,8 @@ impl Workspace { let shadow_config = compute_workspace_shadow_config(options.overview.workspace_shadow, view_size); + let background_color = options.layout.background_color.to_array_unpremul(); + Self { scrolling, floating, @@ -320,6 +330,7 @@ impl Workspace { view_size, working_area, shadow: Shadow::new(shadow_config), + background_buffer: SolidColorBuffer::new(view_size, background_color), clock, base_options, options, @@ -409,6 +420,9 @@ impl Workspace { compute_workspace_shadow_config(options.overview.workspace_shadow, self.view_size); self.shadow.update_config(shadow_config); + let background_color = options.layout.background_color.to_array_unpremul(); + self.background_buffer.set_color(background_color); + self.base_options = base_options; self.options = options; } @@ -563,6 +577,8 @@ impl Workspace { self.shadow.update_config(shadow_config); } + self.background_buffer.resize(size); + if scale_transform_changed { for window in self.windows() { window.set_preferred_scale_transform(self.scale, self.transform); @@ -1513,6 +1529,15 @@ impl Workspace { self.shadow.render(renderer, Point::from((0., 0.))) } + pub fn render_background(&self) -> SolidColorRenderElement { + SolidColorRenderElement::from_buffer( + &self.background_buffer, + Point::new(0., 0.), + 1., + Kind::Unspecified, + ) + } + pub fn render_above_top_layer(&self) -> bool { self.scrolling.render_above_top_layer() } @@ -1831,6 +1856,12 @@ impl Workspace { assert!(self.view_size.w > 0.); assert!(self.view_size.h > 0.); + assert_eq!(self.background_buffer.size(), self.view_size); + assert_eq!( + self.background_buffer.color().components(), + options.layout.background_color.to_array_unpremul(), + ); + assert_eq!(self.view_size, self.scrolling.view_size()); assert_eq!(self.working_area, self.scrolling.parent_area()); assert_eq!(&self.clock, self.scrolling.clock()); diff --git a/src/niri.rs b/src/niri.rs index 8835cfb8..9351fb8e 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -474,9 +474,8 @@ pub struct OutputState { /// would occur, based on the last presentation time and output refresh interval. Sequence /// is incremented in that timer, before attempting a redraw or sending frame callbacks. pub frame_callback_sequence: u32, - /// Solid color buffer for the background that we use instead of clearing to avoid damage + /// Solid color buffer for the backdrop that we use instead of clearing to avoid damage /// tracking issues and make screenshots easier. - pub background_buffer: SolidColorBuffer, pub backdrop_buffer: SolidColorBuffer, pub lock_render_state: LockRenderState, pub lock_surface: Option, @@ -1655,12 +1654,6 @@ impl State { resized_outputs.push(output.clone()); } - let background_color = config - .and_then(|c| c.background_color) - .unwrap_or_else(|| full_config.resolve_layout().background_color) - .to_array_unpremul(); - let background_color = Color32F::from(background_color); - let mut backdrop_color = config .and_then(|c| c.backdrop_color) .unwrap_or(full_config.overview.backdrop_color) @@ -1669,10 +1662,6 @@ impl State { let backdrop_color = Color32F::from(backdrop_color); if let Some(state) = self.niri.output_state.get_mut(output) { - if state.background_buffer.color() != background_color { - state.background_buffer.set_color(background_color); - recolored_outputs.push(output.clone()); - } if state.backdrop_buffer.color() != backdrop_color { state.backdrop_buffer.set_color(backdrop_color); recolored_outputs.push(output.clone()); @@ -2904,11 +2893,6 @@ impl Niri { .map(|c| ipc_transform_to_smithay(c.transform)) .unwrap_or(Transform::Normal); - let background_color = c - .and_then(|c| c.background_color) - .unwrap_or_else(|| config.resolve_layout().background_color) - .to_array_unpremul(); - let mut backdrop_color = c .and_then(|c| c.backdrop_color) .unwrap_or(config.overview.backdrop_color) @@ -2947,7 +2931,6 @@ impl Niri { frame_clock: FrameClock::new(refresh_interval, vrr), last_drm_sequence: None, frame_callback_sequence: 0, - background_buffer: SolidColorBuffer::new(size, background_color), backdrop_buffer: SolidColorBuffer::new(size, backdrop_color), lock_render_state, lock_surface: None, @@ -3056,7 +3039,6 @@ impl Niri { self.layout.update_output_size(output); if let Some(state) = self.output_state.get_mut(output) { - state.background_buffer.resize(output_size); state.backdrop_buffer.resize(output_size); state.lock_color_buffer.resize(output_size); @@ -4239,13 +4221,6 @@ impl Niri { // Prepare the background elements. let state = self.output_state.get(output).unwrap(); - let background_buffer = state.background_buffer.clone(); - let background = SolidColorRenderElement::from_buffer( - &background_buffer, - (0., 0.), - 1., - Kind::Unspecified, - ); let backdrop = SolidColorRenderElement::from_buffer( &state.backdrop_buffer, (0., 0.), @@ -4286,7 +4261,7 @@ impl Niri { let zoom = mon.overview_zoom(); let monitor_elements = Vec::from_iter( mon.render_elements(renderer, target, focus_ring) - .map(|(geo, iter)| (geo, Vec::from_iter(iter))), + .map(|(geo, bg, iter)| (geo, bg, Vec::from_iter(iter))), ); let workspace_shadow_elements = Vec::from_iter(mon.render_workspace_shadows(renderer)); let insert_hint_elements = mon.render_insert_hint_between_workspaces(renderer); @@ -4330,17 +4305,24 @@ impl Niri { .into_iter() .map(OutputRenderElements::from), ); + + let mut ws_background = None; elements.extend( monitor_elements .into_iter() - .flat_map(|(_ws_geo, iter)| iter) + .flat_map(|(_ws_geo, ws_bg, iter)| { + ws_background = Some(ws_bg); + iter + }) .map(OutputRenderElements::from), ); elements.extend(top_layer.into_iter().map(OutputRenderElements::from)); elements.extend(layer_elems.into_iter().map(OutputRenderElements::from)); - elements.push(OutputRenderElements::from(background)); + if let Some(ws_background) = ws_background { + elements.push(OutputRenderElements::from(ws_background)); + } elements.extend( workspace_shadow_elements @@ -4362,7 +4344,7 @@ impl Niri { .map(OutputRenderElements::from), ); - for (ws_geo, ws_elements) in monitor_elements { + for (ws_geo, ws_background, ws_elements) in monitor_elements { // Collect all other layer-shell elements. let mut layer_elems = SplitElements::default(); extend_from_layer(&mut layer_elems, Layer::Bottom, false); @@ -4386,11 +4368,7 @@ impl Niri { .map(OutputRenderElements::from), ); - if let Some(elem) = - scale_relocate_crop(background.clone(), output_scale, zoom, ws_geo) - { - elements.push(OutputRenderElements::from(elem)); - } + elements.push(OutputRenderElements::from(ws_background)); } elements.extend( @@ -6351,9 +6329,6 @@ niri_render_elements! { Wayland = WaylandSurfaceRenderElement, NamedPointer = MemoryRenderBufferRenderElement, SolidColor = SolidColorRenderElement, - RelocatedSolidColor = CropRenderElement>>, ScreenshotUi = ScreenshotUiRenderElement, ExitConfirmDialog = ExitConfirmDialogRenderElement, Texture = PrimaryGpuTextureRenderElement,