diff options
Diffstat (limited to 'src/niri.rs')
| -rw-r--r-- | src/niri.rs | 156 |
1 files changed, 128 insertions, 28 deletions
diff --git a/src/niri.rs b/src/niri.rs index 2543ddb3..de88da71 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -15,7 +15,7 @@ use anyhow::{bail, ensure, Context}; use calloop::futures::Scheduler; use niri_config::{ Config, FloatOrInt, Key, Modifiers, OutputName, PreviewRender, TrackLayout, - WarpMouseToFocusMode, WorkspaceReference, DEFAULT_BACKGROUND_COLOR, + WarpMouseToFocusMode, WorkspaceReference, DEFAULT_BACKDROP_COLOR, DEFAULT_BACKGROUND_COLOR, }; use smithay::backend::allocator::Fourcc; use smithay::backend::input::Keycode; @@ -26,10 +26,12 @@ use smithay::backend::renderer::element::surface::{ render_elements_from_surface_tree, WaylandSurfaceRenderElement, }; use smithay::backend::renderer::element::utils::{ - select_dmabuf_feedback, Relocate, RelocateRenderElement, + select_dmabuf_feedback, CropRenderElement, Relocate, RelocateRenderElement, + RescaleRenderElement, }; use smithay::backend::renderer::element::{ - default_primary_scanout_output_compare, Id, Kind, PrimaryScanoutOutput, RenderElementStates, + default_primary_scanout_output_compare, Element, Id, Kind, PrimaryScanoutOutput, + RenderElementStates, }; use smithay::backend::renderer::gles::GlesRenderer; use smithay::backend::renderer::sync::SyncPoint; @@ -428,6 +430,7 @@ pub struct OutputState { /// Solid color buffer for the background 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<LockSurface>, pub lock_color_buffer: SolidColorBuffer, @@ -1465,11 +1468,22 @@ impl State { background_color[3] = 1.; let background_color = Color32F::from(background_color); + let mut backdrop_color = config + .map(|c| c.backdrop_color) + .unwrap_or(DEFAULT_BACKDROP_COLOR) + .to_array_unpremul(); + backdrop_color[3] = 1.; + 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()); + } } } @@ -2640,6 +2654,12 @@ impl Niri { .to_array_unpremul(); background_color[3] = 1.; + let mut backdrop_color = c + .map(|c| c.backdrop_color) + .unwrap_or(DEFAULT_BACKDROP_COLOR) + .to_array_unpremul(); + backdrop_color[3] = 1.; + // FIXME: fix winit damage on other transforms. if name.connector == "winit" { transform = Transform::Flipped180; @@ -2673,6 +2693,7 @@ impl Niri { 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, lock_color_buffer: SolidColorBuffer::new(size, CLEAR_COLOR_LOCKED), @@ -2777,6 +2798,7 @@ impl Niri { 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); if let Some(lock_surface) = &state.lock_surface { @@ -2894,11 +2916,18 @@ impl Niri { layers .layers_on(layer) .rev() - .find_map(|layer| { - let layer_pos_within_output = - layers.layer_geometry(layer).unwrap().loc.to_f64(); + .find_map(|layer_surface| { + let mut layer_pos_within_output = + layers.layer_geometry(layer_surface).unwrap().loc.to_f64(); + + // Background and bottom layers move together with the workspaces. + let mon = self.layout.monitor_for_output(output)?; + let (_, geo) = mon.workspace_under(pos_within_output)?; + layer_pos_within_output += geo.loc; + let surface_type = WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE; - layer.surface_under(pos_within_output - layer_pos_within_output, surface_type) + layer_surface + .surface_under(pos_within_output - layer_pos_within_output, surface_type) }) .is_some() }; @@ -3001,20 +3030,29 @@ impl Niri { layers .layers_on(layer) .rev() - .find_map(|layer| { - let layer_pos_within_output = - layers.layer_geometry(layer).unwrap().loc.to_f64(); + .find_map(|layer_surface| { + let mut layer_pos_within_output = + layers.layer_geometry(layer_surface).unwrap().loc.to_f64(); + + // Background and bottom layers move together with the workspaces. + if matches!(layer, Layer::Background | Layer::Bottom) { + let mon = self.layout.monitor_for_output(output)?; + let (_, geo) = mon.workspace_under(pos_within_output)?; + layer_pos_within_output += geo.loc; + } + let surface_type = if popup { WindowSurfaceType::POPUP } else { WindowSurfaceType::TOPLEVEL } | WindowSurfaceType::SUBSURFACE; - layer + + layer_surface .surface_under(pos_within_output - layer_pos_within_output, surface_type) .map(|(surface, pos_within_layer)| { ( (surface, pos_within_layer.to_f64() + layer_pos_within_output), - layer, + layer_surface, ) }) }) @@ -3791,10 +3829,18 @@ impl Niri { return elements; } - // Prepare the background element. + // Prepare the background elements. let state = self.output_state.get(output).unwrap(); + let background_buffer = state.background_buffer.clone(); let background = SolidColorRenderElement::from_buffer( - &state.background_buffer, + &background_buffer, + (0, 0), + output_scale, + 1., + Kind::Unspecified, + ); + let backdrop = SolidColorRenderElement::from_buffer( + &state.backdrop_buffer, (0, 0), output_scale, 1., @@ -3811,8 +3857,8 @@ impl Niri { .map(OutputRenderElements::from), ); - // Add the background for outputs that were connected while the screenshot UI was open. - elements.push(background); + // Add the backdrop for outputs that were connected while the screenshot UI was open. + elements.push(backdrop); if self.debug_draw_opaque_regions { draw_opaque_regions(&mut elements, output_scale); @@ -3831,7 +3877,11 @@ impl Niri { // Get monitor elements. let mon = self.layout.monitor_for_output(output).unwrap(); - let monitor_elements: Vec<_> = mon.render_elements(renderer, target, focus_ring).collect(); + let zoom = 1.; + let monitor_elements = Vec::from_iter( + mon.render_elements(renderer, target, focus_ring) + .map(|(geo, iter)| (geo, Vec::from_iter(iter))), + ); let int_move_elements: Vec<_> = self .layout .render_interactive_move_for_output(renderer, output, target) @@ -3854,24 +3904,31 @@ impl Niri { extend_from_layer(&mut layer_elems, Layer::Top); let top_layer = layer_elems; - // Collect all other layer-shell elements. - let mut layer_elems = SplitElements::default(); - extend_from_layer(&mut layer_elems, Layer::Bottom); - extend_from_layer(&mut layer_elems, Layer::Background); - // When rendering above the top layer, we put the regular monitor elements first. // Otherwise, we will render all layer-shell pop-ups and the top layer on top. if mon.render_above_top_layer() { + // Collect all other layer-shell elements. + let mut layer_elems = SplitElements::default(); + extend_from_layer(&mut layer_elems, Layer::Bottom); + extend_from_layer(&mut layer_elems, Layer::Background); + elements.extend( int_move_elements .into_iter() .map(OutputRenderElements::from), ); - elements.extend(monitor_elements.into_iter().map(OutputRenderElements::from)); + elements.extend( + monitor_elements + .into_iter() + .flat_map(|(_ws_geo, iter)| iter) + .map(OutputRenderElements::from), + ); elements.extend(top_layer.into_iter().map(OutputRenderElements::from)); elements.extend(layer_elems.popups.drain(..).map(OutputRenderElements::from)); elements.extend(layer_elems.normal.drain(..).map(OutputRenderElements::from)); + + elements.push(OutputRenderElements::from(background)); } else { elements.extend(top_layer.into_iter().map(OutputRenderElements::from)); @@ -3881,15 +3938,40 @@ impl Niri { .map(OutputRenderElements::from), ); - elements.extend(layer_elems.popups.drain(..).map(OutputRenderElements::from)); + for (ws_geo, 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); + extend_from_layer(&mut layer_elems, Layer::Background); + + elements.extend( + layer_elems + .popups + .into_iter() + .filter_map(|elem| scale_relocate_crop(elem, output_scale, zoom, ws_geo)) + .map(OutputRenderElements::from), + ); - elements.extend(monitor_elements.into_iter().map(OutputRenderElements::from)); + elements.extend(ws_elements.into_iter().map(OutputRenderElements::from)); - elements.extend(layer_elems.normal.drain(..).map(OutputRenderElements::from)); + elements.extend( + layer_elems + .normal + .into_iter() + .filter_map(|elem| scale_relocate_crop(elem, output_scale, zoom, ws_geo)) + .map(OutputRenderElements::from), + ); + + if let Some(elem) = + scale_relocate_crop(background.clone(), output_scale, zoom, ws_geo) + { + elements.push(OutputRenderElements::from(elem)); + } + } } - // Then the background. - elements.push(background); + // Then the backdrop. + elements.push(backdrop); if self.debug_draw_opaque_regions { draw_opaque_regions(&mut elements, output_scale); @@ -5712,14 +5794,32 @@ impl ClientData for ClientState { fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {} } +fn scale_relocate_crop<E: Element>( + elem: E, + output_scale: Scale<f64>, + zoom: f64, + ws_geo: Rectangle<f64, Logical>, +) -> Option<CropRenderElement<RelocateRenderElement<RescaleRenderElement<E>>>> { + let ws_geo = ws_geo.to_physical_precise_round(output_scale); + let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom); + let elem = RelocateRenderElement::from_element(elem, ws_geo.loc, Relocate::Relative); + CropRenderElement::from_element(elem, output_scale, ws_geo) +} + niri_render_elements! { OutputRenderElements<R> => { Monitor = MonitorRenderElement<R>, Tile = TileRenderElement<R>, LayerSurface = LayerSurfaceRenderElement<R>, + RelocatedLayerSurface = CropRenderElement<RelocateRenderElement<RescaleRenderElement< + LayerSurfaceRenderElement<R> + >>>, Wayland = WaylandSurfaceRenderElement<R>, NamedPointer = MemoryRenderBufferRenderElement<R>, SolidColor = SolidColorRenderElement, + RelocatedSolidColor = CropRenderElement<RelocateRenderElement<RescaleRenderElement< + SolidColorRenderElement + >>>, ScreenshotUi = ScreenshotUiRenderElement, Texture = PrimaryGpuTextureRenderElement, // Used for the CPU-rendered panels. |
