From e4c0716951fd69984c582720c4c4572c327b2493 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 4 Mar 2026 18:57:37 +0100 Subject: [PATCH] element: Refactor element acquisition to be push based --- Cargo.lock | 5 +- Cargo.toml | 1 + src/backend/render/cursor.rs | 41 +- src/backend/render/mod.rs | 356 ++++++------ src/backend/render/wayland/mod.rs | 24 +- src/shell/element/mod.rs | 91 ++- src/shell/element/stack.rs | 86 ++- src/shell/element/surface.rs | 67 +-- src/shell/element/window.rs | 69 ++- src/shell/grabs/menu/mod.rs | 42 +- src/shell/grabs/moving.rs | 231 ++++---- src/shell/layout/floating/mod.rs | 274 +++++---- src/shell/layout/tiling/mod.rs | 521 +++++++++--------- src/shell/workspace.rs | 283 +++++----- src/shell/zoom.rs | 30 +- src/utils/iced/mod.rs | 22 +- src/utils/screenshot.rs | 7 +- .../handlers/image_copy_capture/render.rs | 83 +-- 18 files changed, 1096 insertions(+), 1137 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f664669..9030c5e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -841,6 +841,7 @@ dependencies = [ "sanitize-filename", "serde", "serde_json", + "smallvec", "smithay", "smithay-egui", "thiserror 2.0.18", @@ -4790,9 +4791,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smithay" diff --git a/Cargo.toml b/Cargo.toml index f1a04f02..a8c2dc2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,7 @@ logind-zbus = { version = "5.3.2", optional = true } futures-executor = { version = "0.3.32" } futures-util = "0.3.32" cgmath = "0.18.0" +smallvec = "1.15.2" [dependencies.id_tree] branch = "feature/copy_clone" diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 8373e714..e43d99e5 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -3,7 +3,7 @@ use crate::{ backend::render::{ element::AsGlowRenderer, - wayland::{SurfaceRenderElement, render_elements_from_surface_tree}, + wayland::{SurfaceRenderElement, push_render_elements_from_surface_tree}, }, utils::prelude::*, wayland::handlers::compositor::FRAME_TIME_FILTER, @@ -185,8 +185,8 @@ pub fn draw_surface_cursor( surface: &wl_surface::WlSurface, location: Point, scale: impl Into>, -) -> Vec<(CursorRenderElement, Point)> -where + push: &mut dyn FnMut(CursorRenderElement, Point), +) where R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, { @@ -202,7 +202,7 @@ where .to_physical_precise_round(scale) }); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface, location.to_physical(scale).to_i32_round(), @@ -212,10 +212,9 @@ where false, [0; 4], Kind::Cursor, - ) - .into_iter() - .map(|elem| (elem, h)) - .collect() + &mut |elem| push(elem.into(), h), + None, + ); } #[profiling::function] @@ -224,8 +223,8 @@ pub fn draw_dnd_icon( surface: &wl_surface::WlSurface, location: Point, scale: impl Into>, -) -> Vec> -where + push: &mut dyn FnMut(SurfaceRenderElement), +) where R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, { @@ -236,7 +235,7 @@ where ); } let scale = scale.into(); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface, location.to_physical(scale).to_i32_round(), @@ -246,7 +245,9 @@ where false, [0; 4], FRAME_TIME_FILTER, - ) + push, + None, + ); } pub type CursorState = Mutex; @@ -330,8 +331,8 @@ pub fn draw_cursor( buffer_scale: f64, time: Time, draw_default: bool, -) -> Vec<(CursorRenderElement, Point)> -where + push: &mut dyn FnMut(CursorRenderElement, Point), +) where R: Renderer + ImportMem + ImportAll + AsGlowRenderer, R::TextureId: Send + Clone + 'static, { @@ -343,7 +344,7 @@ where let state = &mut *state_ref; if state.hidden { - return Vec::new(); + return; } let named_cursor = state.current_cursor.or(match cursor_status { @@ -352,7 +353,7 @@ where }); if let Some(current_cursor) = named_cursor { if !draw_default && current_cursor == CursorIcon::Default { - return Vec::new(); + return; } let integer_scale = (scale.x.max(scale.y) * buffer_scale).ceil() as u32; @@ -389,7 +390,7 @@ where ); state.current_image = Some(frame); - return vec![( + push( CursorRenderElement::Static( MemoryRenderBufferRenderElement::from_buffer( renderer, @@ -403,11 +404,9 @@ where .expect("Failed to import cursor bitmap"), ), hotspot.to_physical_precise_round(scale), - )]; + ); } else if let CursorImageStatus::Surface(ref wl_surface) = cursor_status { - return draw_surface_cursor(renderer, wl_surface, location, scale); - } else { - Vec::new() + draw_surface_cursor(renderer, wl_surface, location, scale, push); } } diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 458000a5..717fe54e 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -17,7 +17,11 @@ use crate::{ render::{ element::DamageElement, shadow::{SHADOW_SHADER, ShadowShader}, - wayland::clipped_surface::{CLIPPING_SHADER, ClippingShader}, + wayland::{ + SurfaceRenderElement, + clipped_surface::{CLIPPING_SHADER, ClippingShader}, + push_render_elements_from_surface_tree, + }, }, }, config::ScreenFilter, @@ -47,11 +51,10 @@ use smithay::{ allocator::Fourcc, drm::{DrmDeviceFd, DrmNode}, renderer::{ - Color32F, ImportAll, Offscreen, Renderer, Texture, TextureFilter, + Color32F, Offscreen, Texture, TextureFilter, damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult}, element::{ Element, Id, Kind, RenderElement, WeakId, - surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree}, texture::{TextureRenderBuffer, TextureRenderElement}, utils::{ ConstrainAlign, ConstrainScaleBehavior, CropRenderElement, Relocate, @@ -68,6 +71,7 @@ use smithay::{ sync::SyncPoint, }, }, + desktop::utils::bbox_from_surface_tree, input::Seat, output::{Output, OutputModeSource, OutputNoMode}, utils::{ @@ -475,8 +479,8 @@ pub fn cursor_elements<'a, 'frame, R>( mode: CursorMode, exclude_dnd_icon: bool, scanout_node: Option, -) -> Vec> -where + push: &mut dyn FnMut(CosmicElement), +) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -490,7 +494,6 @@ where ) }) .unwrap_or_else(|| ((0., 0.).into(), 1.)); - let mut elements = Vec::new(); for seat in seats { let pointer = match seat.get_pointer() { @@ -500,19 +503,16 @@ where let location = pointer.current_location() - output.current_location().to_f64(); if mode != CursorMode::None { - elements.extend( - cursor::draw_cursor( - renderer, - seat, - location, - scale.into(), - zoom_scale, - now, - mode != CursorMode::NotDefault, - ) - .into_iter() - .map(|(elem, hotspot)| { - CosmicElement::Cursor(RescaleRenderElement::from_element( + cursor::draw_cursor( + renderer, + seat, + location, + scale.into(), + zoom_scale, + now, + mode != CursorMode::NotDefault, + &mut |elem, hotspot| { + push(CosmicElement::Cursor(RescaleRenderElement::from_element( RelocateRenderElement::from_element( elem, Point::from((-hotspot.x, -hotspot.y)), @@ -523,70 +523,54 @@ where .to_physical(output.current_scale().fractional_scale()) .to_i32_round(), zoom_scale, - )) - }), + ))) + }, ); } if !exclude_dnd_icon && let Some(dnd_icon) = get_dnd_icon(seat) { - elements.extend( - cursor::draw_dnd_icon( - renderer, - &dnd_icon.surface, - (location + dnd_icon.offset.to_f64()).to_i32_round(), - scale, - ) - .into_iter() - .map(CosmicElement::Dnd), + cursor::draw_dnd_icon( + renderer, + &dnd_icon.surface, + (location + dnd_icon.offset.to_f64()).to_i32_round(), + scale, + &mut |elem| push(CosmicElement::Dnd(elem)), ); } let theme = theme.cosmic(); - if let Some(grab_elements) = seat + if let Some(grab_state) = seat .user_data() .get::() .unwrap() .lock() .unwrap() .as_ref() - .map(|state| { - state.render::, R>( - renderer, - output, - theme, - scanout_node, - ) - }) { - elements.extend(grab_elements.into_iter().map(|elem| { - CosmicElement::MoveGrab(RescaleRenderElement::from_element( + grab_state.render(renderer, output, theme, scanout_node, &mut |elem| { + push(CosmicElement::MoveGrab(RescaleRenderElement::from_element( elem, focal_point .as_logical() .to_physical(output.current_scale().fractional_scale()) .to_i32_round(), zoom_scale, - )) - })); + ))); + }) } - if let Some((grab_elements, should_scale)) = seat + if let Some(grab_state) = seat .user_data() .get::() .unwrap() .lock() .unwrap() .as_ref() - .map(|state| { - ( - state.render::, R>(renderer, output), - !state.is_in_screen_space(), - ) - }) { - elements.extend(grab_elements.into_iter().map(|elem| { - CosmicElement::MoveGrab(RescaleRenderElement::from_element( - elem, + let should_scale = !grab_state.is_in_screen_space(); + grab_state.render(renderer, output, &mut |elem| { + push(CosmicElement::MoveGrab(RescaleRenderElement::from_element( + elem.into(), if should_scale { focal_point .as_logical() @@ -596,12 +580,10 @@ where Point::from((0, 0)) }, if should_scale { zoom_scale } else { 1.0 }, - )) - })); + ))); + }) } } - - elements } #[cfg(not(feature = "debug"))] @@ -729,7 +711,7 @@ where CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = Vec::new(); + let mut elements = Vec::>::new(); let shell_ref = shell.read(); let seats = shell_ref.seats.iter().cloned().collect::>(); @@ -742,7 +724,7 @@ where // that is prone to deadlock with the main-thread on some grabs. std::mem::drop(shell_ref); - elements.extend(cursor_elements( + cursor_elements( renderer, seats.iter(), zoom_level, @@ -752,7 +734,8 @@ where cursor_mode, element_filter == ElementFilter::ExcludeWorkspaceOverview, scanout_node, - )); + &mut |elem| elements.push(elem), + ); let shell = shell.read(); let overview = shell.overview_mode(); @@ -828,72 +811,81 @@ where render_input_order::<()>(&shell, output, previous, current, element_filter, |stage| { match stage { Stage::ZoomUI => { - elements.extend(ZoomState::render(renderer, output)); + ZoomState::render(renderer, output, &mut |elem| { + elements.push(CosmicElement::Zoom(elem)) + }); } Stage::SessionLock(lock_surface) => { - elements.extend( - session_lock_elements(renderer, output, lock_surface) - .into_iter() - .map(Into::into) - .flat_map(crop_to_output) - .map(Into::into), - ); + session_lock_elements(renderer, output, lock_surface, &mut |elem| { + elements.extend(crop_to_output(elem.into()).map(Into::into)) + }) } Stage::LayerPopup { popup, location, .. } => { - elements.extend( - render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( - renderer, - popup.wl_surface(), - location - .to_local(output) - .as_logical() - .to_physical_precise_round(scale), - Scale::from(scale), - 1.0, - FRAME_TIME_FILTER, - ) - .into_iter() - .flat_map(crop_to_output) - .map(Into::into), - ); + let mut geometry = popup.geometry().as_global(); + geometry.loc += location; + + push_render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + location + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + geometry.to_local(output).as_logical().to_f64(), + Scale::from(scale), + 1.0, + false, + [0; 4], + FRAME_TIME_FILTER, + &mut |elem| elements.extend(crop_to_output(elem.into()).map(Into::into)), + None, + ) } Stage::LayerSurface { layer, location } => { - elements.extend( - render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( - renderer, - layer.wl_surface(), - location - .to_local(output) - .as_logical() - .to_physical_precise_round(scale), - Scale::from(scale), - 1.0, - FRAME_TIME_FILTER, - ) - .into_iter() - .flat_map(crop_to_output) - .map(Into::into), + let mut geometry = layer.geometry().as_global(); + geometry.loc += location; + + push_render_elements_from_surface_tree( + renderer, + layer.wl_surface(), + location + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + geometry.to_local(output).as_logical().to_f64(), + Scale::from(scale), + 1.0, + false, + [0; 4], + FRAME_TIME_FILTER, + &mut |elem| elements.extend(crop_to_output(elem.into()).map(Into::into)), + None, ); } Stage::OverrideRedirect { surface, location } => { - elements.extend(surface.wl_surface().into_iter().flat_map(|surface| { - render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( + if let Some(wl_surface) = surface.wl_surface() { + let mut geometry = surface.geometry().as_global(); + geometry.loc += location; + + push_render_elements_from_surface_tree( renderer, - &surface, + &wl_surface, location .to_local(output) .as_logical() .to_physical_precise_round(scale), + geometry.to_local(output).as_logical().to_f64(), Scale::from(scale), 1.0, + false, + [0; 4], FRAME_TIME_FILTER, - ) - .into_iter() - .flat_map(crop_to_output) - .map(Into::into) - })); + &mut |elem| elements.extend(crop_to_output(elem.into()).map(Into::into)), + None, + ); + } } Stage::StickyPopups(layout) => { let alpha = match &overview.0 { @@ -914,14 +906,11 @@ where OverviewMode::None => 1.0, }; - elements.extend( - layout - .render_popups(renderer, alpha, scanout_node) - .into_iter() - .map(Into::into) - .flat_map(crop_to_output) - .map(Into::into), - ); + layout.render_popups(renderer, alpha, scanout_node, &mut |elem| { + if let Some(elem) = crop_to_output(elem.into()) { + elements.push(elem.into()) + } + }); } Stage::Sticky(layout) => { let alpha = match &overview.0 { @@ -946,82 +935,66 @@ where .then_some(last_active_seat) .map(|seat| workspace.focus_stack.get(seat)); - elements.extend( - layout - .render( - renderer, - current_focus.as_ref().and_then(|stack| { - stack.last().and_then(|t| match t { - FocusTarget::Window(w) => Some(w), - _ => None, - }) - }), - resize_indicator.clone(), - active_hint, - alpha, - theme.cosmic(), - scanout_node, - ) - .into_iter() - .map(Into::into) - .flat_map(crop_to_output) - .map(Into::into), - ) + layout.render( + renderer, + current_focus.as_ref().and_then(|stack| { + stack.last().and_then(|t| match t { + FocusTarget::Window(w) => Some(w), + _ => None, + }) + }), + resize_indicator.clone(), + active_hint, + alpha, + theme.cosmic(), + scanout_node, + &mut |elem| { + if let Some(elem) = crop_to_output(elem.into()) { + elements.push(elem.into()) + } + }, + ); } Stage::WorkspacePopups { workspace, offset } => { - elements.extend( - match workspace.render_popups( - renderer, - last_active_seat, - !move_active && is_active_space, - overview.clone(), - theme.cosmic(), - scanout_node, - ) { - Ok(elements) => { - elements - .into_iter() - .flat_map(crop_to_output) - .map(|element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - element, - offset.to_physical_precise_round(scale), - Relocate::Relative, - )) - }) - } - Err(_) => { - return ControlFlow::Break(Err(OutputNoMode)); + workspace.render_popups( + renderer, + last_active_seat, + !move_active && is_active_space, + overview.clone(), + theme.cosmic(), + scanout_node, + &mut |elem| { + if let Some(elem) = crop_to_output(elem) { + elements.push(CosmicElement::Workspace( + RelocateRenderElement::from_element( + elem, + offset.to_physical_precise_round(scale), + Relocate::Relative, + ), + )); } }, ); } Stage::Workspace { workspace, offset } => { - elements.extend( - match workspace.render( - renderer, - last_active_seat, - !move_active && is_active_space, - overview.clone(), - resize_indicator.clone(), - active_hint, - theme.cosmic(), - scanout_node, - ) { - Ok(elements) => { - elements - .into_iter() - .flat_map(crop_to_output) - .map(|element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - element, - offset.to_physical_precise_round(scale), - Relocate::Relative, - )) - }) - } - Err(_) => { - return ControlFlow::Break(Err(OutputNoMode)); + workspace.render( + renderer, + last_active_seat, + !move_active && is_active_space, + overview.clone(), + resize_indicator.clone(), + active_hint, + theme.cosmic(), + scanout_node, + &mut |elem| { + if let Some(elem) = crop_to_output(elem) { + elements.push(CosmicElement::Workspace( + RelocateRenderElement::from_element( + elem, + offset.to_physical_precise_round(scale), + Relocate::Relative, + ), + )); } }, ); @@ -1038,23 +1011,26 @@ fn session_lock_elements( renderer: &mut R, output: &Output, lock_surface: Option<&LockSurface>, -) -> Vec> -where - R: Renderer + ImportAll, + push: &mut dyn FnMut(SurfaceRenderElement), +) where + R: AsGlowRenderer, R::TextureId: Clone + 'static, { if let Some(surface) = lock_surface { let scale = Scale::from(output.current_scale().fractional_scale()); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface.wl_surface(), (0, 0), + bbox_from_surface_tree(surface.wl_surface(), (0, 0)).to_f64(), scale, 1.0, + false, + [0; 4], FRAME_TIME_FILTER, + push, + None, ) - } else { - Vec::new() } } diff --git a/src/backend/render/wayland/mod.rs b/src/backend/render/wayland/mod.rs index 64c5945f..d766552a 100644 --- a/src/backend/render/wayland/mod.rs +++ b/src/backend/render/wayland/mod.rs @@ -23,7 +23,7 @@ render_elements! { Wayland=WaylandSurfaceRenderElement, } -pub fn render_elements_from_surface_tree( +pub fn push_render_elements_from_surface_tree( renderer: &mut R, main_surface: &wl_surface::WlSurface, location: impl Into>, @@ -33,17 +33,17 @@ pub fn render_elements_from_surface_tree( should_clip: bool, radii: [u8; 4], kind: impl Into, -) -> Vec -where + push_above: &mut dyn FnMut(SurfaceRenderElement), + mut push_below: Option<&mut dyn FnMut(SurfaceRenderElement)>, +) where R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, - E: From>, { let location = location.into().to_f64(); let geometry = geometry.into().to_f64(); let scale = scale.into(); let kind = kind.into(); - let mut surfaces: Vec = Vec::new(); + let mut passed_main = false; compositor::with_surface_tree_downward( main_surface, @@ -94,7 +94,13 @@ where } else { surface.into() }; - surfaces.push(elem.into()); + if let Some(push_below) = push_below.as_mut() + && passed_main + { + push_below(elem); + } else { + push_above(elem); + } } Ok(None) => {} // surface is not mapped Err(err) => { @@ -103,9 +109,11 @@ where }; } } + + if surface == main_surface { + passed_main = true; + } }, |_, _, _| true, ); - - surfaces } diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 69a8391f..11861591 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -598,42 +598,38 @@ impl CosmicMapped { } } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, scanout_node: Option, - ) -> Vec - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, - C: From>, { match &self.element { - CosmicMappedInternal::Stack(s) => s - .popup_render_elements::>( - renderer, - location, - scale, - alpha, - scanout_node, - ), - CosmicMappedInternal::Window(w) => w - .popup_render_elements::>( - renderer, - location, - scale, - alpha, - scanout_node, - ), + CosmicMappedInternal::Stack(s) => s.push_popup_render_elements( + renderer, + location, + scale, + alpha, + scanout_node, + &mut |elem| push(elem.into()), + ), + CosmicMappedInternal::Window(w) => w.push_popup_render_elements( + renderer, + location, + scale, + alpha, + scanout_node, + &mut |elem| push(elem.into()), + ), _ => unreachable!(), } - .into_iter() - .map(C::from) - .collect() } pub fn shadow_render_element( @@ -680,7 +676,7 @@ impl CosmicMapped { } } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: smithay::utils::Point, @@ -689,15 +685,15 @@ impl CosmicMapped { alpha: f32, scanout_override: Option, scanout_node: Option, - ) -> Vec - where + push_above: &mut dyn FnMut(CosmicMappedRenderElement), + push_below: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, - C: From>, { #[cfg(feature = "debug")] - let mut elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { + if let Some(debug) = self.debug.lock().unwrap().as_mut() { let window = self.active_window(); let window_geo = window.geometry(); let (min_size, max_size, size) = ( @@ -858,21 +854,15 @@ impl CosmicMapped { scale.x, 0.8, ) { - Ok(element) => vec![CosmicMappedRenderElement::from(element)], + Ok(element) => push_above(element.into()), Err(err) => { debug!(?err, "Error rendering debug overlay."); - Vec::new() } } - } else { - Vec::new() }; - #[cfg(not(feature = "debug"))] - let mut elements = Vec::new(); - #[cfg_attr(not(feature = "debug"), allow(unused_mut))] - elements.extend(match &self.element { - CosmicMappedInternal::Stack(s) => s.render_elements::>( + match &self.element { + CosmicMappedInternal::Stack(s) => s.push_render_elements( renderer, location, max_size, @@ -880,21 +870,22 @@ impl CosmicMapped { alpha, scanout_override, scanout_node, + &mut |elem| push_above(elem.into()), + &mut |elem| push_below(elem.into()), + ), + CosmicMappedInternal::Window(w) => w.push_render_elements( + renderer, + location, + max_size, + scale, + alpha, + scanout_override, + scanout_node, + &mut |elem| push_above(elem.into()), + &mut |elem| push_below(elem.into()), ), - CosmicMappedInternal::Window(w) => w - .render_elements::>( - renderer, - location, - max_size, - scale, - alpha, - scanout_override, - scanout_node, - ), _ => unreachable!(), - }); - - elements.into_iter().map(C::from).collect() + } } pub(crate) fn update_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index fe25a4e6..58e28753 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -39,8 +39,8 @@ use smithay::{ renderer::{ ImportAll, ImportMem, Renderer, element::{ - AsRenderElements, Element, Id as RendererId, Kind, RenderElement, - UnderlyingStorage, memory::MemoryRenderBufferRenderElement, + Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage, + memory::MemoryRenderBufferRenderElement, }, gles::element::PixelShaderElement, glow::GlowRenderer, @@ -645,35 +645,31 @@ impl CosmicStack { self.0.loop_handle() } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, scanout_node: Option, - ) -> Vec - where + push: &mut dyn FnMut(CosmicStackRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, - C: From>, { let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); self.0.with_program(|p| { let windows = p.windows.lock().unwrap(); let active = p.active.load(Ordering::SeqCst); - windows[active] - .popup_render_elements::>( - renderer, - window_loc, - scale, - alpha, - scanout_node, - ) - .into_iter() - .map(C::from) - .collect() + windows[active].push_popup_render_elements( + renderer, + window_loc, + scale, + alpha, + scanout_node, + &mut |elem| push(elem.into()), + ) }) } @@ -744,7 +740,7 @@ impl CosmicStack { }) } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: Point, @@ -753,17 +749,17 @@ impl CosmicStack { alpha: f32, scanout_override: Option, scanout_node: Option, - ) -> Vec - where + push_above: &mut dyn FnMut(CosmicStackRenderElement), + push_below: &mut dyn FnMut(CosmicStackRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, - C: From>, { if !self .0 .with_program(|p| p.override_alive.load(Ordering::Acquire)) { - return Vec::new(); + return; } let geometry = self @@ -773,11 +769,12 @@ impl CosmicStack { let stack_loc = location + geometry.loc; let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); - let mut elements = AsRenderElements::::render_elements::>( - &self.0, renderer, stack_loc, scale, alpha, - ); + self.0 + .push_render_elements(renderer, stack_loc, scale, alpha, &mut |elem| { + push_above(elem.into()) + }); - elements.extend(self.0.with_program(|p| { + self.0.with_program(|p| { let windows = p.windows.lock().unwrap(); let active = p.active.load(Ordering::SeqCst); let theme = p.theme.lock().unwrap(); @@ -804,9 +801,9 @@ impl CosmicStack { let window_key = CosmicMappedKey(CosmicMappedKeyInner::Stack(Arc::downgrade(&self.0.0))); - let border = (!maximized).then(|| { + if !maximized { let (r, g, b, a) = theme.cosmic().bg_divider().into_components(); - CosmicStackRenderElement::Border(IndicatorShader::element( + push_above(CosmicStackRenderElement::Border(IndicatorShader::element( renderer, Key::Window(Usage::Border, window_key.clone()), geo.to_i32_round().as_local(), @@ -815,24 +812,23 @@ impl CosmicStack { a * alpha, scale.x, [r, g, b], - )) - }); + ))); + }; - border.into_iter().chain( - windows[active].render_elements::>( - renderer, - window_loc, - scale, - alpha, - scanout_override, - scanout_node, - radii.is_some(), - radii.unwrap_or([0; 4]), - ), - ) - })); - - elements.into_iter().map(C::from).collect() + let radii = radii.map(|[a, _, c, _]| [a, 0, c, 0]); + windows[active].push_render_elements( + renderer, + window_loc, + scale, + alpha, + scanout_override, + scanout_node, + radii.is_some(), + radii.unwrap_or([0; 4]), + &mut |elem| push_above(elem.into()), + Some(&mut |elem| push_below(elem.into())), + ); + }); } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 374b8ea4..53c3d4bd 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -1,7 +1,7 @@ use crate::{ backend::render::{ element::AsGlowRenderer, - wayland::{SurfaceRenderElement, render_elements_from_surface_tree}, + wayland::{SurfaceRenderElement, push_render_elements_from_surface_tree}, }, shell::focus::target::PointerFocusTarget, wayland::{ @@ -859,48 +859,47 @@ impl CosmicSurface { self.0.user_data() } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, scanout_node: Option, - ) -> Vec - where + push: &mut dyn FnMut(SurfaceRenderElement), + ) where R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, - C: From>, { match self.0.underlying_surface() { WindowSurface::Wayland(toplevel) => { let surface = toplevel.wl_surface(); - PopupManager::popups_for_surface(surface) - .flat_map(move |(popup, popup_offset)| { - let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc) - .to_physical_precise_round(scale); - let mut geometry = popup.geometry().to_f64(); - geometry.loc += location.to_f64().to_logical(scale) + popup_offset.to_f64(); + for (popup, popup_offset) in PopupManager::popups_for_surface(surface) { + let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc) + .to_physical_precise_round(scale); + let mut geometry = popup.geometry().to_f64(); + geometry.loc += location.to_f64().to_logical(scale) + popup_offset.to_f64(); - render_elements_from_surface_tree( - renderer, - popup.wl_surface(), - location + offset, - geometry, - scale, - alpha, - false, - [0; 4], - scanout_kind_eval(None, scanout_node), - ) - }) - .collect() + push_render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + location + offset, + geometry, + scale, + alpha, + false, + [0; 4], + scanout_kind_eval(None, scanout_node), + push, + None, + ) + } } - WindowSurface::X11(_) => Vec::new(), + WindowSurface::X11(_) => {} } } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: Point, @@ -910,11 +909,11 @@ impl CosmicSurface { scanout_node: Option, should_clip: bool, radii: [u8; 4], - ) -> Vec - where + push_above: &mut dyn FnMut(SurfaceRenderElement), + push_below: Option<&mut dyn FnMut(SurfaceRenderElement)>, + ) where R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, - C: From>, { let mut geometry = self.0.geometry().to_f64(); geometry.loc += location.to_f64().to_logical(scale); @@ -923,7 +922,7 @@ impl CosmicSurface { WindowSurface::Wayland(toplevel) => { let surface = toplevel.wl_surface(); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface, location, @@ -933,14 +932,16 @@ impl CosmicSurface { should_clip, radii, scanout_kind_eval(scanout_override, scanout_node), + push_above, + push_below, ) } WindowSurface::X11(surface) => { let Some(surface) = surface.wl_surface() else { - return Vec::new(); + return; }; - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, &surface, location, @@ -950,6 +951,8 @@ impl CosmicSurface { should_clip, radii, scanout_kind_eval(scanout_override, scanout_node), + push_above, + push_below, ) } } diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index cc12e0f9..48949127 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -25,8 +25,8 @@ use smithay::{ renderer::{ ImportAll, ImportMem, Renderer, element::{ - AsRenderElements, Element, Id as RendererId, Kind, RenderElement, - UnderlyingStorage, memory::MemoryRenderBufferRenderElement, + Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage, + memory::MemoryRenderBufferRenderElement, }, gles::element::PixelShaderElement, glow::GlowRenderer, @@ -348,18 +348,17 @@ impl CosmicWindow { self.0.loop_handle() } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, scanout_node: Option, - ) -> Vec - where - R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + push: &mut dyn FnMut(CosmicWindowRenderElement), + ) where + R: Renderer + AsGlowRenderer + ImportAll + ImportMem, R::TextureId: Send + Clone + 'static, - C: From>, { let has_ssd = self.0.with_program(|p| p.has_ssd(false)); @@ -370,17 +369,14 @@ impl CosmicWindow { }; self.0.with_program(|p| { - p.window - .popup_render_elements::>( - renderer, - window_loc, - scale, - alpha, - scanout_node, - ) - .into_iter() - .map(C::from) - .collect() + p.window.push_popup_render_elements( + renderer, + window_loc, + scale, + alpha, + scanout_node, + &mut |elem| push(elem.into()), + ) }) } @@ -464,7 +460,7 @@ impl CosmicWindow { }) } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: Point, @@ -473,11 +469,11 @@ impl CosmicWindow { alpha: f32, scanout_override: Option, scanout_node: Option, - ) -> Vec - where + push_above: &mut dyn FnMut(CosmicWindowRenderElement), + push_below: &mut dyn FnMut(CosmicWindowRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, - C: From>, { let (has_ssd, is_tiled, is_maximized, mut radii, appearance) = self.0.with_program(|p| { ( @@ -514,8 +510,6 @@ impl CosmicWindow { location }; - let mut elements = Vec::new(); - let (mut geo, bg_divider) = self.0.with_program(|p| { ( SpaceElement::geometry(&p.window).to_f64(), @@ -545,15 +539,15 @@ impl CosmicWindow { scale.x, [r, g, b], )); - elements.push(elem); + push_above(elem); } - if has_ssd { - radii[1] = 0; - radii[3] = 0; - } - elements.extend(self.0.with_program(|p| { - p.window.render_elements::>( + self.0.with_program(|p| { + if has_ssd { + radii[1] = 0; + radii[3] = 0; + } + p.window.push_render_elements( renderer, window_loc, scale, @@ -562,8 +556,10 @@ impl CosmicWindow { scanout_node, clip, radii, + &mut |elem| push_above(elem.into()), + Some(&mut |elem| push_below(elem.into())), ) - })); + }); if has_ssd { let ssd_loc = location @@ -571,12 +567,11 @@ impl CosmicWindow { .0 .with_program(|p| p.window.geometry().loc) .to_physical_precise_round(scale); - elements.extend(AsRenderElements::::render_elements::< - CosmicWindowRenderElement, - >(&self.0, renderer, ssd_loc, scale, alpha)) + self.0 + .push_render_elements(renderer, ssd_loc, scale, alpha, &mut |elem| { + push_above(elem.into()) + }); } - - elements.into_iter().map(C::from).collect() } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index 14a9f917..e79734e9 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -18,10 +18,7 @@ use cosmic::{ use smithay::{ backend::{ input::{ButtonState, TouchSlot}, - renderer::{ - ImportMem, Renderer, - element::{AsRenderElements, memory::MemoryRenderBufferRenderElement}, - }, + renderer::{ImportMem, Renderer, element::memory::MemoryRenderBufferRenderElement}, }, desktop::space::SpaceElement, input::{ @@ -65,29 +62,28 @@ pub struct MenuGrabState { pub type SeatMenuGrabState = Mutex>; impl MenuGrabState { - pub fn render(&self, renderer: &mut R, output: &Output) -> Vec - where + pub fn render( + &self, + renderer: &mut R, + output: &Output, + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where R: Renderer + ImportMem, R::TextureId: Send + Clone + 'static, - I: From>, { let scale = output.current_scale().fractional_scale(); - self.elements - .lock() - .unwrap() - .iter() - .flat_map(|elem| { - elem.iced.render_elements( - renderer, - elem.position - .to_local(output) - .as_logical() - .to_physical_precise_round(scale), - scale.into(), - 1.0, - ) - }) - .collect() + for elem in self.elements.lock().unwrap().iter() { + elem.iced.push_render_elements( + renderer, + elem.position + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + scale.into(), + 1.0, + push, + ) + } } pub fn is_in_screen_space(&self) -> bool { diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 1fd8a9b6..48ebd4ba 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -19,13 +19,14 @@ use crate::{ use calloop::LoopHandle; use cosmic::theme::CosmicTheme; +use smallvec::SmallVec; use smithay::{ backend::{ drm::DrmNode, input::ButtonState, renderer::{ ImportAll, ImportMem, Renderer, - element::{AsRenderElements, RenderElement, utils::RescaleRenderElement}, + element::{RenderElement, utils::RescaleRenderElement}, }, }, desktop::{WindowSurfaceType, layer_map_for_output, space::SpaceElement}, @@ -69,18 +70,17 @@ pub struct MoveGrabState { impl MoveGrabState { #[profiling::function] - pub fn render( + pub fn render( &self, renderer: &mut R, output: &Output, theme: &CosmicTheme, scanout_node: Option, - ) -> Vec - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, - I: From>, { let scale = if self.previous == ManagedLayer::Tiling { 0.6 + ((1.0 @@ -105,7 +105,7 @@ impl MoveGrabState { .intersection(window_geo) .is_none() { - return Vec::new(); + return; } let output_scale: Scale = output.current_scale().fractional_scale().into(); @@ -115,13 +115,32 @@ impl MoveGrabState { + self.window_offset - scaling_offset; + for (indicator, location) in self.stacking_indicator.iter() { + indicator.push_render_elements( + renderer, + location.to_physical_precise_round(output_scale), + output_scale, + 1.0, + &mut |elem| push(elem.into()), + ); + } + + self.window.push_popup_render_elements::( + renderer, + (render_location - self.window.geometry().loc).to_physical_precise_round(output_scale), + output_scale, + alpha, + scanout_node, + push, + ); + let active_window_hint = crate::theme::active_window_hint(theme); let radius = self .element() .corner_radius(window_geo.size, self.indicator_thickness); - let focus_element = if self.indicator_thickness > 0 { - Some(CosmicMappedRenderElement::from( + if self.indicator_thickness > 0 { + push( IndicatorShader::focus_element( renderer, Key::Window(Usage::MoveGrabIndicator, self.window.key()), @@ -144,12 +163,57 @@ impl MoveGrabState { active_window_hint.green, active_window_hint.blue, ], - ), - )) - } else { - None + ) + .into(), + ) + } + + let map_window_element = |elem| match elem { + CosmicMappedRenderElement::Stack(stack) => { + CosmicMappedRenderElement::GrabbedStack(RescaleRenderElement::from_element( + stack, + render_location + .to_physical_precise_round(output.current_scale().fractional_scale()), + scale, + )) + } + CosmicMappedRenderElement::Window(window) => { + CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element( + window, + render_location + .to_physical_precise_round(output.current_scale().fractional_scale()), + scale, + )) + } + x => x, }; + let mut lower_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + self.window.push_render_elements( + renderer, + (render_location - self.window.geometry().loc).to_physical_precise_round(output_scale), + None, + output_scale, + alpha, + Some(false), + scanout_node, + &mut |elem| push(map_window_element(elem)), + &mut |elem| lower_elements.push(map_window_element(elem)), + ); + if let Some(shadow_element) = self.window.shadow_render_element( + renderer, + (render_location - self.window.geometry().loc).to_physical_precise_round(output_scale), + None, + output_scale, + scale, + alpha, + ) { + push(shadow_element); + } + for elem in lower_elements.into_iter() { + push(elem); + } + let non_exclusive_geometry = { let layers = layer_map_for_output(output); layers.non_exclusive_zone() @@ -158,119 +222,46 @@ impl MoveGrabState { let gaps = (theme.gaps.0 as i32, theme.gaps.1 as i32); let thickness = self.indicator_thickness.max(1); - let snapping_indicator = match &self.snapping_zone { - Some(t) if &self.cursor_output == output => { - let base_color = theme.palette.neutral_9; - let overlay_geometry = t.overlay_geometry(non_exclusive_geometry, gaps); - vec![ - CosmicMappedRenderElement::from(IndicatorShader::element( - renderer, - Key::Window(Usage::SnappingIndicator, self.window.key()), - overlay_geometry, - thickness, - [ - theme.radius_s()[0] as u8, - theme.radius_s()[1] as u8, - theme.radius_s()[2] as u8, - theme.radius_s()[3] as u8, - ], - 1.0, - output_scale.x, - [ - active_window_hint.red, - active_window_hint.green, - active_window_hint.blue, - ], - )), - CosmicMappedRenderElement::from(BackdropShader::element( - renderer, - Key::Window(Usage::SnappingIndicator, self.window.key()), - t.overlay_geometry(non_exclusive_geometry, gaps), - theme.radius_s()[0], // TODO: Fix once shaders support 4 corner radii customization - 0.4, - [base_color.red, base_color.green, base_color.blue], - )), - ] - } - _ => vec![], - }; + if let Some(t) = &self.snapping_zone + && &self.cursor_output == output + { + let base_color = theme.palette.neutral_9; + let overlay_geometry = t.overlay_geometry(non_exclusive_geometry, gaps); - let w_elements = self - .window - .render_elements::>( - renderer, - (render_location - self.window.geometry().loc) - .to_physical_precise_round(output_scale), - None, - output_scale, - alpha, - Some(false), - scanout_node, - ); - let p_elements = self - .window - .popup_render_elements::>( - renderer, - (render_location - self.window.geometry().loc) - .to_physical_precise_round(output_scale), - output_scale, - alpha, - scanout_node, - ); - let shadow_element = self.window.shadow_render_element( - renderer, - (render_location - self.window.geometry().loc).to_physical_precise_round(output_scale), - None, - output_scale, - scale, - alpha, - ); - - self.stacking_indicator - .iter() - .flat_map(|(indicator, location)| { - indicator.render_elements( + push( + IndicatorShader::element( renderer, - location.to_physical_precise_round(output_scale), - output_scale, + Key::Window(Usage::SnappingIndicator, self.window.key()), + overlay_geometry, + thickness, + [ + theme.radius_s()[0] as u8, + theme.radius_s()[1] as u8, + theme.radius_s()[2] as u8, + theme.radius_s()[3] as u8, + ], 1.0, + output_scale.x, + [ + active_window_hint.red, + active_window_hint.green, + active_window_hint.blue, + ], ) - }) - .chain(p_elements) - .chain(focus_element) - .chain( - w_elements - .into_iter() - .chain(shadow_element) - .map(|elem| match elem { - CosmicMappedRenderElement::Stack(stack) => { - CosmicMappedRenderElement::GrabbedStack( - RescaleRenderElement::from_element( - stack, - render_location.to_physical_precise_round( - output.current_scale().fractional_scale(), - ), - scale, - ), - ) - } - CosmicMappedRenderElement::Window(window) => { - CosmicMappedRenderElement::GrabbedWindow( - RescaleRenderElement::from_element( - window, - render_location.to_physical_precise_round( - output.current_scale().fractional_scale(), - ), - scale, - ), - ) - } - x => x, - }), + .into(), + ); + push( + BackdropShader::element( + renderer, + Key::Window(Usage::SnappingIndicator, self.window.key()), + t.overlay_geometry(non_exclusive_geometry, gaps), + theme.radius_s()[0], // TODO: Fix once shaders support 4 corner radii customization + 0.4, + [base_color.red, base_color.green, base_color.blue], + ) + .into(), ) - .chain(snapping_indicator) - .map(I::from) - .collect() + } } pub fn element(&self) -> CosmicMapped { diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 84677188..aad738f8 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -9,11 +9,12 @@ use std::{ use cosmic_comp_config::AppearanceConfig; use cosmic_settings_config::shortcuts::action::ResizeDirection; use keyframe::{ease, functions::EaseInOutCubic}; +use smallvec::SmallVec; use smithay::{ backend::{ drm::DrmNode, renderer::element::{ - AsRenderElements, RenderElement, + RenderElement, utils::{Relocate, RelocateRenderElement, RescaleRenderElement}, }, }, @@ -1443,8 +1444,8 @@ impl FloatingLayout { renderer: &mut R, alpha: f32, scanout_node: Option, - ) -> Vec> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1454,8 +1455,6 @@ impl FloatingLayout { let output = self.space.outputs().next().unwrap(); let output_scale = output.current_scale().fractional_scale(); - let mut elements = Vec::default(); - for elem in self .animations .iter() @@ -1470,20 +1469,17 @@ impl FloatingLayout { .unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha)); let render_location = geometry.loc - elem.geometry().loc.as_local(); - elements.extend( - elem.popup_render_elements( - renderer, - render_location - .as_logical() - .to_physical_precise_round(output_scale), - output_scale.into(), - alpha, - scanout_node, - ), + elem.push_popup_render_elements( + renderer, + render_location + .as_logical() + .to_physical_precise_round(output_scale), + output_scale.into(), + alpha, + scanout_node, + push, ); } - - elements } #[profiling::function] @@ -1496,8 +1492,8 @@ impl FloatingLayout { alpha: f32, theme: &cosmic::theme::CosmicTheme, scanout_node: Option, - ) -> Vec> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1510,8 +1506,7 @@ impl FloatingLayout { layers.non_exclusive_zone() }; let output_scale = output.current_scale().fractional_scale(); - - let mut elements = Vec::default(); + let mut lower_elements = SmallVec::<[_; 4]>::new_const(); for elem in self .animations @@ -1525,122 +1520,9 @@ impl FloatingLayout { .get(elem) .map(|anim| (*anim.previous_geometry(), alpha * anim.alpha())) .unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha)); - let render_location = geometry.loc - elem.geometry().loc.as_local(); - let mut window_elements = elem.render_elements( - renderer, - render_location - .as_logical() - .to_physical_precise_round(output_scale), - None, - output_scale.into(), - alpha, - None, - scanout_node, - ); - window_elements.extend( - elem.shadow_render_element( - renderer, - render_location - .as_logical() - .to_physical_precise_round(output_scale), - None, - output_scale.into(), - 1., - alpha, - ), - ); - - if let Some(anim) = self.animations.get(elem) { - let original_geo = anim.previous_geometry(); - geometry = anim.geometry( - output_geometry, - self.space - .element_geometry(elem) - .map(RectExt::as_local) - .unwrap_or(geometry), - elem.floating_tiled.lock().unwrap().as_ref(), - self.gaps(), - ); - - let buffer_size = elem.geometry().size; - let scale = Scale { - x: geometry.size.w as f64 / buffer_size.w as f64, - y: geometry.size.h as f64 / buffer_size.h as f64, - }; - - window_elements = window_elements - .into_iter() - .map(|element| match element { - CosmicMappedRenderElement::Stack(elem) => { - CosmicMappedRenderElement::MovingStack({ - let rescaled = RescaleRenderElement::from_element( - elem, - original_geo - .loc - .as_logical() - .to_physical_precise_round(output_scale), - scale, - ); - - RelocateRenderElement::from_element( - rescaled, - (geometry.loc - original_geo.loc) - .as_logical() - .to_physical_precise_round(output_scale), - Relocate::Relative, - ) - }) - } - CosmicMappedRenderElement::Window(elem) => { - CosmicMappedRenderElement::MovingWindow({ - let rescaled = RescaleRenderElement::from_element( - elem, - original_geo - .loc - .as_logical() - .to_physical_precise_round(output_scale), - scale, - ); - - RelocateRenderElement::from_element( - rescaled, - (geometry.loc - original_geo.loc) - .as_logical() - .to_physical_precise_round(output_scale), - Relocate::Relative, - ) - }) - } - x => x, - }) - .collect(); - } if focused == Some(elem) && !elem.is_maximized(false) { - if let Some((mode, resize)) = resize_indicator.as_mut() { - let mut resize_geometry = geometry; - resize_geometry.loc -= (18, 18).into(); - resize_geometry.size += (36, 36).into(); - - resize.resize(resize_geometry.size.as_logical()); - resize.output_enter(output, Rectangle::default() /* unused */); - window_elements = resize - .render_elements::>( - renderer, - resize_geometry - .loc - .as_logical() - .to_physical_precise_round(output_scale), - output_scale.into(), - alpha * mode.alpha().unwrap_or(1.0), - ) - .into_iter() - .map(CosmicMappedRenderElement::Window) - .chain(window_elements.into_iter()) - .collect(); - } - let active_window_hint = crate::theme::active_window_hint(theme); let radius = elem.corner_radius(geometry.size.as_logical(), indicator_thickness); if indicator_thickness > 0 { @@ -1658,14 +1540,130 @@ impl FloatingLayout { active_window_hint.blue, ], ); - window_elements.insert(0, element.into()); + push(element.into()); + } + + if let Some((mode, resize)) = resize_indicator.as_mut() { + let mut resize_geometry = geometry; + resize_geometry.loc -= (18, 18).into(); + resize_geometry.size += (36, 36).into(); + + resize.resize(resize_geometry.size.as_logical()); + resize.output_enter(output, Rectangle::default() /* unused */); + resize.push_render_elements( + renderer, + resize_geometry + .loc + .as_logical() + .to_physical_precise_round(output_scale), + output_scale.into(), + alpha * mode.alpha().unwrap_or(1.0), + &mut |elem| push(CosmicMappedRenderElement::Window(elem.into())), + ); } } - elements.extend(window_elements); - } + let maybe_map = if let Some(anim) = self.animations.get(elem) { + let original_geo = anim.previous_geometry(); + geometry = anim.geometry( + output_geometry, + self.space + .element_geometry(elem) + .map(RectExt::as_local) + .unwrap_or(geometry), + elem.floating_tiled.lock().unwrap().as_ref(), + self.gaps(), + ); - elements + let buffer_size = elem.geometry().size; + let scale = Scale { + x: geometry.size.w as f64 / buffer_size.w as f64, + y: geometry.size.h as f64 / buffer_size.h as f64, + }; + + Some(move |element| match element { + CosmicMappedRenderElement::Stack(elem) => { + CosmicMappedRenderElement::MovingStack({ + let rescaled = RescaleRenderElement::from_element( + elem, + original_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale), + scale, + ); + + RelocateRenderElement::from_element( + rescaled, + (geometry.loc - original_geo.loc) + .as_logical() + .to_physical_precise_round(output_scale), + Relocate::Relative, + ) + }) + } + CosmicMappedRenderElement::Window(elem) => { + CosmicMappedRenderElement::MovingWindow({ + let rescaled = RescaleRenderElement::from_element( + elem, + original_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale), + scale, + ); + + RelocateRenderElement::from_element( + rescaled, + (geometry.loc - original_geo.loc) + .as_logical() + .to_physical_precise_round(output_scale), + Relocate::Relative, + ) + }) + } + x => x, + }) + } else { + None + }; + let map_anim = |elem| { + if let Some(map) = maybe_map { + map(elem) + } else { + elem + } + }; + + elem.push_render_elements( + renderer, + render_location + .as_logical() + .to_physical_precise_round(output_scale), + None, + output_scale.into(), + alpha, + None, + scanout_node, + &mut |elem| push(map_anim(elem)), + &mut |elem| lower_elements.push(map_anim(elem)), + ); + if let Some(shadow_element) = elem.shadow_render_element( + renderer, + render_location + .as_logical() + .to_physical_precise_round(output_scale), + None, + output_scale.into(), + 1., + alpha, + ) { + push(map_anim(shadow_element)); + } + for elem in lower_elements.drain(..) { + push(elem); + } + } } pub fn snap_to_corner(&self, mapped: &CosmicMapped, corners: &TiledCorners) { diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 14a65ea7..fbcec105 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -6,8 +6,7 @@ use crate::{ element::AsGlowRenderer, }, shell::{ - CosmicSurface, Direction, FocusResult, MoveResult, OutputNotMapped, OverviewMode, - ResizeMode, Trigger, + CosmicSurface, Direction, FocusResult, MoveResult, OverviewMode, ResizeMode, Trigger, element::{ CosmicMapped, CosmicMappedRenderElement, CosmicStack, CosmicWindow, resize_indicator::ResizeIndicator, @@ -45,12 +44,13 @@ use keyframe::{ ease, functions::{EaseInOutCubic, Linear}, }; +use smallvec::SmallVec; use smithay::{ backend::{ drm::DrmNode, renderer::{ element::{ - AsRenderElements, Id, RenderElement, + Id, RenderElement, utils::{ ConstrainAlign, ConstrainScaleBehavior, RescaleRenderElement, constrain_render_elements, @@ -3424,8 +3424,8 @@ impl TilingLayout { None, None, self.theme.cosmic(), - ) - .0; + &mut |_| {}, + ); let mut result = None; let mut lookup = Some(root.clone()); @@ -4011,8 +4011,8 @@ impl TilingLayout { indicator_thickness: u8, theme: &cosmic::theme::CosmicTheme, scanout_node: Option, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -4052,8 +4052,6 @@ impl TilingLayout { }; let draw_groups = overview.0.alpha(); - let mut elements = Vec::default(); - let is_overview = !matches!(overview.0, OverviewMode::None); let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); @@ -4065,7 +4063,7 @@ impl TilingLayout { // all gone windows and fade them out let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() { - let (geometries, _) = if let Some(transition) = draw_groups { + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( reference_tree, &mut *renderer, @@ -4080,14 +4078,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |_elem| {}, )) } else { None - } - .unzip(); + }; // all old windows we want to fade out - elements.extend(render_old_tree_windows( + render_old_tree_windows( reference_tree, target_tree, renderer, @@ -4098,14 +4096,16 @@ impl TilingLayout { swap_desc.is_some(), theme, scanout_node, - )); + push, + ); geometries } else { None }; - let (geometries, group_elements) = if let Some(transition) = draw_groups { + let mut group_elements = SmallVec::<[_; 4]>::new_const(); + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( target_tree, &mut *renderer, @@ -4119,14 +4119,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |elem| group_elements.push(elem), )) } else { None - } - .unzip(); + }; // all alive windows - elements.extend(render_new_tree_windows( + render_new_tree_windows( target_tree, reference_tree, renderer, @@ -4155,14 +4155,13 @@ impl TilingLayout { &self.backdrop_id, theme, scanout_node, - )); + push, + ); // tiling hints - if let Some(group_elements) = group_elements { - elements.extend(group_elements); + for elem in group_elements.into_iter() { + push(elem); } - - Ok(elements) } #[profiling::function] @@ -4174,8 +4173,8 @@ impl TilingLayout { overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), theme: &cosmic::theme::CosmicTheme, scanout_node: Option, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -4207,8 +4206,6 @@ impl TilingLayout { }; let draw_groups = overview.0.alpha(); - let mut elements = Vec::default(); - let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() { @@ -4219,7 +4216,7 @@ impl TilingLayout { // all gone windows and fade them out let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() { - let (geometries, _) = if let Some(transition) = draw_groups { + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( reference_tree, &mut *renderer, @@ -4234,14 +4231,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |_| {}, )) } else { None - } - .unzip(); + }; // all old windows we want to fade out - elements.extend(render_old_tree_popups( + render_old_tree_popups( reference_tree, target_tree, renderer, @@ -4250,14 +4247,15 @@ impl TilingLayout { percentage, swap_desc.is_some(), scanout_node, - )); + push, + ); geometries } else { None }; - let (geometries, _) = if let Some(transition) = draw_groups { + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( target_tree, &mut *renderer, @@ -4271,14 +4269,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |_| {}, )) } else { None - } - .unzip(); + }; // all alive windows - elements.extend(render_new_tree_popups( + render_new_tree_popups( target_tree, reference_tree, renderer, @@ -4290,9 +4288,8 @@ impl TilingLayout { overview, swap_desc.clone(), scanout_node, - )); - - Ok(elements) + push, + ); } fn gaps(&self) -> (i32, i32) { @@ -4347,10 +4344,8 @@ fn geometries_for_groupview<'a, R>( swap_desc: Option, swap_tree: Option<&Tree>, _theme: &cosmic::theme::CosmicTheme, -) -> ( - HashMap>, - Vec>, -) + push: &mut dyn FnMut(CosmicMappedRenderElement), +) -> HashMap> where R: AsGlowRenderer + 'a, R::TextureId: 'static, @@ -4373,11 +4368,18 @@ where // push bogos value, that will get ignored anyway stack.push((Rectangle::from_size((320, 240).into()), 0)); } - if root.is_some() { + + let has_root = root.is_some(); + if has_root { stack.push((non_exclusive_zone, 0)); } - let mut elements = Vec::new(); + let mut push = |elem| { + if has_root { + push(elem) + } + }; + let mut geometries: HashMap> = HashMap::new(); let alpha = alpha * transition; @@ -4532,7 +4534,7 @@ where if let Some(renderer) = renderer.as_mut() { if (render_potential_group || render_active_child) && Some(&node_id) != root { - elements.push( + push( IndicatorShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4550,7 +4552,7 @@ where && pill_indicator.is_some() && Some(&node_id) != root { - elements.push( + push( IndicatorShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4614,7 +4616,7 @@ where }; if draw_outline { - elements.push( + push( IndicatorShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4675,7 +4677,7 @@ where }; if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, backdrop_id.clone(), @@ -4693,7 +4695,7 @@ where if matches!(swap_desc, Some(ref desc) if desc.node == node_id) { if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4778,7 +4780,7 @@ where .unwrap_or(false) { if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, backdrop_id.clone(), @@ -4820,7 +4822,7 @@ where .unwrap_or(false) { if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, backdrop_id.clone(), @@ -4851,7 +4853,7 @@ where if let Some(renderer) = renderer.as_mut() { if render_potential_group { - elements.push( + push( IndicatorShader::element( *renderer, Key::Window(Usage::PotentialGroupIndicator, mapped.key()), @@ -4891,7 +4893,7 @@ where geo.loc += (WINDOW_BACKDROP_BORDER, WINDOW_BACKDROP_BORDER).into(); geo.size -= (WINDOW_BACKDROP_BORDER * 2, WINDOW_BACKDROP_BORDER * 2).into(); - elements.push( + push( BackdropShader::element( *renderer, Key::Window(Usage::OverviewBackdrop, mapped.key()), @@ -4948,7 +4950,7 @@ where if let Some(renderer) = renderer.as_mut() { geo.loc += (WINDOW_BACKDROP_BORDER, WINDOW_BACKDROP_BORDER).into(); geo.size -= (WINDOW_BACKDROP_BORDER * 2, WINDOW_BACKDROP_BORDER * 2).into(); - elements.push( + push( BackdropShader::element( *renderer, id.clone(), @@ -4967,11 +4969,7 @@ where } } - if root.is_none() { - elements.clear(); - } - - (geometries, elements) + geometries } fn render_old_tree_popups( @@ -4983,16 +4981,14 @@ fn render_old_tree_popups( percentage: f32, is_swap_mode: bool, scanout_node: Option, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, CosmicWindowRenderElement: RenderElement, CosmicStackRenderElement: RenderElement, { - let mut elements = Vec::default(); - render_old_tree( reference_tree, target_tree, @@ -5001,20 +4997,16 @@ where percentage, is_swap_mode, |mapped, elem_geometry, geo, alpha, _| { - elements.extend( - mapped.popup_render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - Scale::from(output_scale), - alpha, - scanout_node, - ), - ); + mapped.push_popup_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + Scale::from(output_scale), + alpha, + scanout_node, + push, + ) }, - ); - - elements + ) } fn render_old_tree_windows( @@ -5028,8 +5020,8 @@ fn render_old_tree_windows( is_swap_mode: bool, theme: &cosmic::theme::CosmicTheme, scanout_node: Option, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -5037,8 +5029,35 @@ where CosmicStackRenderElement: RenderElement, { let window_hint = crate::theme::active_window_hint(theme); - let mut elements = Vec::default(); - let mut shadow_elements = Vec::default(); + let mut lower_elements = Vec::default(); + let mut shadow_elements = SmallVec::<[_; 4]>::new_const(); + + let window_map = + |elem, geo: Rectangle, elem_geometry: Rectangle| match elem { + CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( + std::iter::once(elem), + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + geo.as_logical().to_physical_precise_round(output_scale), + elem_geometry, + ConstrainScaleBehavior::Stretch, + ConstrainAlign::CENTER, + output_scale, + ) + .next() + .map(CosmicMappedRenderElement::TiledStack), + CosmicMappedRenderElement::Window(elem) => constrain_render_elements( + std::iter::once(elem), + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + geo.as_logical().to_physical_precise_round(output_scale), + elem_geometry, + ConstrainScaleBehavior::Stretch, + ConstrainAlign::CENTER, + output_scale, + ) + .next() + .map(CosmicMappedRenderElement::TiledWindow), + x => Some(x), + }; render_old_tree( reference_tree, @@ -5048,57 +5067,9 @@ where percentage, is_swap_mode, |mapped, elem_geometry, geo, alpha, is_minimizing| { - shadow_elements.extend(mapped.shadow_render_element( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, - Some(geo.size.as_logical()), - Scale::from(output_scale), - 1., - alpha, - )); - - let window_elements = mapped.render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, - Some(geo.size.as_logical()), - Scale::from(output_scale), - alpha, - None, - scanout_node, - ); - - elements.extend(window_elements.into_iter().flat_map(|element| { - match element { - CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( - std::iter::once(elem), - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - geo.as_logical().to_physical_precise_round(output_scale), - elem_geometry, - ConstrainScaleBehavior::Stretch, - ConstrainAlign::CENTER, - output_scale, - ) - .next() - .map(CosmicMappedRenderElement::TiledStack), - CosmicMappedRenderElement::Window(elem) => constrain_render_elements( - std::iter::once(elem), - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - geo.as_logical().to_physical_precise_round(output_scale), - elem_geometry, - ConstrainScaleBehavior::Stretch, - ConstrainAlign::CENTER, - output_scale, - ) - .next() - .map(CosmicMappedRenderElement::TiledWindow), - x => Some(x), - } - })); let radius = mapped.corner_radius(geo.size.as_logical(), indicator_thickness); if is_minimizing && indicator_thickness > 0 { - elements.push(CosmicMappedRenderElement::FocusIndicator( + push(CosmicMappedRenderElement::FocusIndicator( IndicatorShader::focus_element( renderer, Key::Window(Usage::FocusIndicator, mapped.clone().key()), @@ -5111,10 +5082,44 @@ where ), )); } + + mapped.push_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + Some(geo.size.as_logical()), + Scale::from(output_scale), + alpha, + None, + scanout_node, + &mut |elem| { + if let Some(elem) = window_map(elem, geo, elem_geometry) { + push(elem); + } + }, + &mut |elem| { + if let Some(elem) = window_map(elem, geo, elem_geometry) { + lower_elements.push(elem); + } + }, + ); + + shadow_elements.extend(mapped.shadow_render_element( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + Some(geo.size.as_logical()), + Scale::from(output_scale), + 1., + alpha, + )); }, ); - shadow_elements.into_iter().chain(elements).collect() + for elem in shadow_elements { + push(elem); + } + for elem in lower_elements { + push(elem); + } } fn render_old_tree( @@ -5210,15 +5215,14 @@ fn render_new_tree_popups( overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), swap_desc: Option, scanout_node: Option, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, CosmicWindowRenderElement: RenderElement, CosmicStackRenderElement: RenderElement, { - let mut popup_elements = Vec::new(); let output_scale = output.current_scale().fractional_scale(); let is_active_output = seat @@ -5241,21 +5245,18 @@ where if let Data::Mapped { mapped, .. } = data { let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); - popup_elements.extend( - mapped.popup_render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - Scale::from(output_scale), - alpha, - scanout_node, - ), + mapped.push_popup_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + Scale::from(output_scale), + alpha, + scanout_node, + push, ); } }, ); - - popup_elements } fn render_new_tree_windows( @@ -5278,8 +5279,8 @@ fn render_new_tree_windows( backdrop_id: &Id, theme: &cosmic::theme::CosmicTheme, scanout_node: Option, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -5319,14 +5320,18 @@ where .map(|seat| &seat.active_output() == output) .unwrap_or(false); - let mut animating_window_elements = Vec::new(); - let mut window_elements = Vec::new(); + let mut animating_window_upper_elements = Vec::new(); + let mut animating_window_lower_elements = Vec::new(); + let mut animating_shadow_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + + let mut window_upper_elements = Vec::new(); + let mut window_lower_elements = Vec::new(); + let mut shadow_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); let mut group_backdrop = None; - let mut indicators = Vec::new(); - let mut resize_elements = None; - let mut swap_elements = Vec::new(); - let mut shadow_elements = Vec::new(); + let mut indicators = SmallVec::<[CosmicMappedRenderElement; 2]>::new_const(); + let mut resize_element = None; + let mut swap_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); let output_geo = output.geometry(); let output_scale = output.current_scale().fractional_scale(); @@ -5339,7 +5344,7 @@ where // render placeholder, if we are swapping to an empty workspace if target_tree.root_node_id().is_none() && swap_desc.is_some() { - window_elements.push( + window_upper_elements.push( BackdropShader::element( renderer, backdrop_id.clone(), @@ -5394,22 +5399,19 @@ where let render_loc = (swap_geo.loc.as_logical() - window_geo.loc).to_physical_precise_round(output_scale); - swap_elements.extend( - window - .render_elements( - renderer, - render_loc, - output_scale.into(), - 1.0, - None, - scanout_node, - false, - [0; 4], - ) - .into_iter() - .map(|window| { - CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element( - window, + window.push_render_elements( + renderer, + render_loc, + output_scale.into(), + 1.0, + None, + scanout_node, + false, + [0, 0, 0, 0], + &mut |elem| { + swap_elements.push(CosmicMappedRenderElement::GrabbedWindow( + RescaleRenderElement::from_element( + elem.into(), swap_geo .loc .as_logical() @@ -5420,9 +5422,11 @@ where swap_factor(window_geo.size), transition.unwrap_or(1.0), ), - )) - }), - ) + ), + )); + }, + None, + ); } // render actual tree nodes @@ -5538,15 +5542,12 @@ where { swap.resize(geo.size.as_logical()); swap.output_enter(output, output_geo.as_logical()); - swap_elements.extend( - swap.render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale), - output_scale.into(), - alpha * overview.0.alpha().unwrap_or(1.0), - ) - .into_iter() - .map(CosmicMappedRenderElement::from), + swap.push_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale), + output_scale.into(), + alpha * overview.0.alpha().unwrap_or(1.0), + &mut |elem| swap_elements.push(elem.into()), ); } } @@ -5572,17 +5573,14 @@ where }) { resize.force_update(); } - resize_elements = Some( - resize - .render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale), - output_scale.into(), - alpha * mode.alpha().unwrap_or(1.0), - ) - .into_iter() - .map(CosmicMappedRenderElement::from) - .collect::>(), + resize.push_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale), + output_scale.into(), + alpha * mode.alpha().unwrap_or(1.0), + &mut |elem| { + resize_element = Some(elem.into()); + }, ); } } @@ -5608,52 +5606,6 @@ where scale.x.min(scale.y), alpha, ); - let mut elements = mapped.render_elements::>( - renderer, - //original_location, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - max_size, - Scale::from(output_scale), - alpha, - None, - scanout_node, - ); - - if swap_desc - .as_ref() - .filter(|swap_desc| swap_desc.node == node_id) - .and_then(|swap_desc| swap_desc.stack_window.as_ref()) - .zip(focused.as_ref()) - .map(|(stack_window, focused_id)| { - target_tree - .get(focused_id) - .ok() - .map(|focused| match focused.data() { - Data::Mapped { mapped, .. } => mapped - .stack_ref() - .map(|stack| &stack.active() == stack_window) - .unwrap_or(false), - _ => false, - }) - .unwrap_or(false) - }) - .unwrap_or(false) - { - let mut active_geo = mapped.active_window_geometry().as_local(); - active_geo.loc += geo.loc - mapped.geometry().loc.as_local(); - elements.insert( - 0, - CosmicMappedRenderElement::Overlay(BackdropShader::element( - renderer, - Key::Window(Usage::Overlay, mapped.key()), - active_geo, - 0.0, - 0.3, - group_color, - )), - ) - } let (behavior, align) = if is_overview { (ConstrainScaleBehavior::Fit, ConstrainAlign::CENTER) @@ -5663,7 +5615,7 @@ where (ConstrainScaleBehavior::CutOff, ConstrainAlign::TOP_LEFT) }; - let elements = elements.into_iter().flat_map(|element| match element { + let map_elem = |element| match element { CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( std::iter::once(elem), geo.loc.as_logical().to_physical_precise_round(output_scale) @@ -5701,7 +5653,66 @@ where .next() .map(CosmicMappedRenderElement::TiledOverlay), x => Some(x), - }); + }; + + let mut upper_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + let mut lower_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + mapped.push_render_elements( + renderer, + //original_location, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + max_size, + Scale::from(output_scale), + alpha, + None, + scanout_node, + &mut |elem| { + if let Some(elem) = map_elem(elem) { + upper_elements.push(elem) + } + }, + &mut |elem| { + if let Some(elem) = map_elem(elem) { + lower_elements.push(elem) + } + }, + ); + + if swap_desc + .as_ref() + .filter(|swap_desc| swap_desc.node == node_id) + .and_then(|swap_desc| swap_desc.stack_window.as_ref()) + .zip(focused.as_ref()) + .map(|(stack_window, focused_id)| { + target_tree + .get(focused_id) + .ok() + .map(|focused| match focused.data() { + Data::Mapped { mapped, .. } => mapped + .stack_ref() + .map(|stack| &stack.active() == stack_window) + .unwrap_or(false), + _ => false, + }) + .unwrap_or(false) + }) + .unwrap_or(false) + { + let mut active_geo = mapped.active_window_geometry().as_local(); + active_geo.loc += geo.loc - mapped.geometry().loc.as_local(); + upper_elements.insert( + 0, + CosmicMappedRenderElement::Overlay(BackdropShader::element( + renderer, + Key::Window(Usage::Overlay, mapped.key()), + active_geo, + 0.0, + 0.3, + group_color, + )), + ) + } if swap_desc .as_ref() @@ -5714,30 +5725,36 @@ where }) .unwrap_or(false) { + swap_elements.extend(upper_elements); swap_elements.extend(shadow_element); - swap_elements.extend(elements); + swap_elements.extend(lower_elements); + } else if animating { + animating_window_upper_elements.extend(upper_elements); + animating_shadow_elements.extend(shadow_element); + animating_window_lower_elements.extend(lower_elements); } else { + window_upper_elements.extend(upper_elements); shadow_elements.extend(shadow_element); - if animating { - animating_window_elements.extend(elements); - } else { - window_elements.extend(elements); - } + window_lower_elements.extend(lower_elements); } } }, ); - resize_elements + for elem in resize_element .into_iter() - .flatten() .chain(swap_elements) .chain(indicators) - .chain(window_elements) - .chain(animating_window_elements) + .chain(window_upper_elements) .chain(shadow_elements) + .chain(window_lower_elements) + .chain(animating_window_upper_elements) + .chain(animating_shadow_elements) + .chain(animating_window_lower_elements) .chain(group_backdrop.into_iter().map(Into::into)) - .collect() + { + push(elem); + } } fn render_new_tree( diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index c5f5cb90..6407935d 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -1,3 +1,4 @@ +use crate::backend::render::wayland::SurfaceRenderElement; use crate::shell::focus::FocusTarget; use crate::shell::layout::tiling::RestoreTilingState; use crate::wayland::handlers::xdg_activation::ActivationContext; @@ -28,6 +29,7 @@ use cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::Tiling use id_tree::Tree; use indexmap::IndexSet; use keyframe::{ease, functions::EaseInOutCubic}; +use smallvec::SmallVec; use smithay::backend::drm::DrmNode; use smithay::backend::renderer::element::Kind; use smithay::output::WeakOutput; @@ -35,8 +37,7 @@ use smithay::utils::user_data::UserDataMap; use smithay::{ backend::renderer::{ element::{ - Element, Id, RenderElement, surface::WaylandSurfaceRenderElement, - texture::TextureRenderElement, utils::RescaleRenderElement, + Element, Id, RenderElement, texture::TextureRenderElement, utils::RescaleRenderElement, }, gles::GlesTexture, glow::GlowRenderer, @@ -1622,8 +1623,8 @@ impl Workspace { indicator_thickness: u8, theme: &CosmicTheme, scanout_node: Option, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(WorkspaceRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1631,80 +1632,83 @@ impl Workspace { CosmicStackRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = Vec::default(); - let output_scale = self.output.current_scale().fractional_scale(); let zone = { let layer_map = layer_map_for_output(&self.output); layer_map.non_exclusive_zone().as_local() }; let focused = self.focus_stack.get(last_active_seat).last().cloned(); + let fullscreen_focused = matches!(focused, Some(FocusTarget::Fullscreen(_))); - let render_fullscreen = |fullscreen: &FullscreenSurface, - renderer: &mut R, - output_scale: f64| - -> Vec> { - let fullscreen_geo = self.fullscreen_geometry_for(fullscreen); - let previous_geo = fullscreen - .previous_geometry - .as_ref() - .unwrap_or(&fullscreen_geo); + let mut fullscreen_elements = SmallVec::<[WorkspaceRenderElement; 2]>::new_const(); + let mut render_fullscreen = + |fullscreen: &FullscreenSurface, renderer: &mut R, output_scale: f64| { + let fullscreen_geo = self.fullscreen_geometry_for(fullscreen); + let previous_geo = fullscreen + .previous_geometry + .as_ref() + .unwrap_or(&fullscreen_geo); - let (target_geo, alpha) = match (fullscreen.start_at, fullscreen.ended_at) { - (Some(started), _) => { - let duration = Instant::now().duration_since(started).as_secs_f64() - / FULLSCREEN_ANIMATION_DURATION.as_secs_f64(); - ( - ease( - EaseInOutCubic, - EaseRectangle(*previous_geo), - EaseRectangle(fullscreen_geo), - duration, + let (target_geo, alpha) = match (fullscreen.start_at, fullscreen.ended_at) { + (Some(started), _) => { + let duration = Instant::now().duration_since(started).as_secs_f64() + / FULLSCREEN_ANIMATION_DURATION.as_secs_f64(); + ( + ease( + EaseInOutCubic, + EaseRectangle(*previous_geo), + EaseRectangle(fullscreen_geo), + duration, + ) + .0, + ease(EaseInOutCubic, 0.0, 1.0, duration), ) - .0, - ease(EaseInOutCubic, 0.0, 1.0, duration), - ) - } - (_, Some(ended)) => { - let duration = Instant::now().duration_since(ended).as_secs_f64() - / FULLSCREEN_ANIMATION_DURATION.as_secs_f64(); - ( - ease( - EaseInOutCubic, - EaseRectangle(fullscreen_geo), - EaseRectangle(*previous_geo), - duration, + } + (_, Some(ended)) => { + let duration = Instant::now().duration_since(ended).as_secs_f64() + / FULLSCREEN_ANIMATION_DURATION.as_secs_f64(); + ( + ease( + EaseInOutCubic, + EaseRectangle(fullscreen_geo), + EaseRectangle(*previous_geo), + duration, + ) + .0, + ease(EaseInOutCubic, 1.0, 0.0, duration), ) - .0, - ease(EaseInOutCubic, 1.0, 0.0, duration), - ) - } - (None, None) => (fullscreen_geo, 1.0), - }; + } + (None, None) => (fullscreen_geo, 1.0), + }; - let render_loc = target_geo - .loc - .as_logical() - .to_physical_precise_round(output_scale); + let render_loc = target_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale); - // Only rescale geometry when animating - let animation_rescale = |elem| { - if fullscreen.is_animating() { - let fullscreen_geo = fullscreen.surface.0.geometry(); - let scale = Scale { - x: target_geo.size.w as f64 / fullscreen_geo.size.w as f64, - y: target_geo.size.h as f64 / fullscreen_geo.size.h as f64, - }; + // Only rescale geometry when animating + let animation_rescale = |elem| { + if fullscreen.is_animating() { + let fullscreen_geo = fullscreen.surface.0.geometry(); + let scale = Scale { + x: target_geo.size.w as f64 / fullscreen_geo.size.w as f64, + y: target_geo.size.h as f64 / fullscreen_geo.size.h as f64, + }; - RescaleRenderElement::from_element(elem, render_loc, scale).into() - } else { - Into::>::into(elem) - } - }; + RescaleRenderElement::from_element(elem, render_loc, scale).into() + } else { + Into::>::into(elem) + } + }; - fullscreen - .surface - .render_elements::>( + let mut fullscreen_push = |elem: SurfaceRenderElement| { + if fullscreen_focused { + push(animation_rescale(elem.into())) + } else { + fullscreen_elements.push(animation_rescale(elem.into())) + } + }; + fullscreen.surface.push_render_elements( renderer, render_loc, output_scale.into(), @@ -1712,30 +1716,24 @@ impl Workspace { Some(true), scanout_node, false, - [0; 4], - ) - .into_iter() - .map(animation_rescale) - .collect::>() - }; + [0, 0, 0, 0], + &mut fullscreen_push, + None, + ); + }; let top_fullscreen = self.get_fullscreen(last_active_seat); - let mut fullscreen_elements: Vec> = Vec::new(); if let Some(fs) = top_fullscreen { - fullscreen_elements.extend(render_fullscreen(fs, renderer, output_scale)); + render_fullscreen(fs, renderer, output_scale) } // Also render any animating (entering/exiting) fullscreens for fs in self.fullscreen_surfaces.iter().filter(|f| f.is_animating()) { if top_fullscreen.is_none_or(|top| top.surface != fs.surface) { - fullscreen_elements.extend(render_fullscreen(fs, renderer, output_scale)); + render_fullscreen(fs, renderer, output_scale); }; } - if matches!(focused, Some(FocusTarget::Fullscreen(_))) { - elements.append(&mut fullscreen_elements); - } - let any_fullscreen_animating = self .fullscreen_surfaces .iter() @@ -1766,29 +1764,21 @@ impl Workspace { OverviewMode::None => 1.0, }; - elements.extend( - self.floating_layer - .render::( - renderer, - render_focus - .then(|| { - focused.as_ref().and_then(|target| { - if let FocusTarget::Window(mapped) = target { - Some(mapped) - } else { - None - } - }) - }) - .flatten(), - resize_indicator.clone(), - indicator_thickness, - alpha, - theme, - scanout_node, - ) - .into_iter() - .map(WorkspaceRenderElement::from), + self.floating_layer.render( + renderer, + focused.as_ref().and_then(|target| { + if let FocusTarget::Window(mapped) = target { + Some(mapped) + } else { + None + } + }), + resize_indicator.clone(), + indicator_thickness, + alpha, + theme, + scanout_node, + &mut |elem| push(elem.into()), ); let alpha = match &overview.0 { @@ -1805,24 +1795,20 @@ impl Workspace { }; //tiling surfaces - elements.extend( - self.tiling_layer - .render::( - renderer, - render_focus.then_some(last_active_seat), - zone, - overview, - resize_indicator, - indicator_thickness, - theme, - scanout_node, - )? - .into_iter() - .map(WorkspaceRenderElement::from), + self.tiling_layer.render( + renderer, + render_focus.then_some(last_active_seat), + zone, + overview, + resize_indicator, + indicator_thickness, + theme, + scanout_node, + &mut |elem| push(elem.into()), ); if let Some(alpha) = alpha { - elements.push( + push( Into::>::into(BackdropShader::element( renderer, self.backdrop_id.clone(), @@ -1836,11 +1822,9 @@ impl Workspace { } } - if !matches!(focused, Some(FocusTarget::Fullscreen(_))) { - elements.extend(fullscreen_elements.into_iter()); + for elem in fullscreen_elements { + push(elem); } - - Ok(elements) } #[profiling::function] @@ -1852,8 +1836,8 @@ impl Workspace { overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), theme: &CosmicTheme, scanout_node: Option, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(WorkspaceRenderElement), + ) where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1861,8 +1845,6 @@ impl Workspace { CosmicStackRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = Vec::default(); - let output_scale = self.output.current_scale().fractional_scale(); let zone = { let layer_map = layer_map_for_output(&self.output); @@ -1917,18 +1899,13 @@ impl Workspace { .as_logical() .to_physical_precise_round(output_scale); - elements.extend( - fullscreen - .surface - .popup_render_elements::>( - renderer, - render_loc, - output_scale.into(), - alpha, - scanout_node, - ) - .into_iter() - .map(Into::into), + fullscreen.surface.push_popup_render_elements( + renderer, + render_loc, + output_scale.into(), + alpha, + scanout_node, + &mut |elem| push(WorkspaceRenderElement::FullscreenPopup(elem.into())), ); } @@ -1962,30 +1939,20 @@ impl Workspace { OverviewMode::None => 1.0, }; - elements.extend( - self.floating_layer - .render_popups::(renderer, alpha, scanout_node) - .into_iter() - .map(WorkspaceRenderElement::from), - ); + self.floating_layer + .render_popups(renderer, alpha, scanout_node, &mut |elem| push(elem.into())); //tiling surfaces - elements.extend( - self.tiling_layer - .render_popups::( - renderer, - render_focus.then_some(last_active_seat), - zone, - overview, - theme, - scanout_node, - )? - .into_iter() - .map(WorkspaceRenderElement::from), + self.tiling_layer.render_popups( + renderer, + render_focus.then_some(last_active_seat), + zone, + overview, + theme, + scanout_node, + &mut |elem| push(elem.into()), ); } - - Ok(elements) } } @@ -2006,7 +1973,7 @@ where R: AsGlowRenderer, R::TextureId: 'static, { - OverrideRedirect(WaylandSurfaceRenderElement), + OverrideRedirect(SurfaceRenderElement), Fullscreen(RescaleRenderElement>), FullscreenPopup(CosmicWindowRenderElement), Window(CosmicMappedRenderElement), @@ -2244,13 +2211,13 @@ where } } -impl From> for WorkspaceRenderElement +impl From> for WorkspaceRenderElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - fn from(elem: WaylandSurfaceRenderElement) -> Self { + fn from(elem: SurfaceRenderElement) -> Self { WorkspaceRenderElement::OverrideRedirect(elem) } } diff --git a/src/shell/zoom.rs b/src/shell/zoom.rs index ffeed63b..02d1be55 100644 --- a/src/shell/zoom.rs +++ b/src/shell/zoom.rs @@ -11,7 +11,7 @@ use cosmic_comp_config::ZoomMovement; use cosmic_config::ConfigSet; use keyframe::{ease, functions::Linear}; use smithay::{ - backend::renderer::{ImportMem, Renderer, element::AsRenderElements}, + backend::renderer::{ImportMem, Renderer, element::memory::MemoryRenderBufferRenderElement}, desktop::space::SpaceElement, input::{ Seat, @@ -192,9 +192,12 @@ impl OutputZoomState { }); } - fn render(&mut self, renderer: &mut R, output: &Output) -> Vec - where - C: From< as AsRenderElements>::RenderElement>, + fn render( + &mut self, + renderer: &mut R, + output: &Output, + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where R: Renderer + ImportMem, R::TextureId: Send + Clone + 'static, { @@ -208,8 +211,13 @@ impl OutputZoomState { .to_physical(scale.fractional_scale()) .to_i32_round(); - self.element - .render_elements(renderer, location, scale.fractional_scale().into(), 1.0) + self.element.push_render_elements( + renderer, + location, + scale.fractional_scale().into(), + 1.0, + push, + ) } } @@ -382,14 +390,16 @@ impl ZoomState { None } - pub fn render(renderer: &mut R, output: &Output) -> Vec - where - C: From< as AsRenderElements>::RenderElement>, + pub fn render( + renderer: &mut R, + output: &Output, + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where R: Renderer + ImportMem, R::TextureId: Send + Clone + 'static, { let output_state = output.user_data().get::>().unwrap(); - output_state.lock().unwrap().render(renderer, output) + output_state.lock().unwrap().render(renderer, output, push) } } diff --git a/src/utils/iced/mod.rs b/src/utils/iced/mod.rs index 44a722db..2ee79733 100644 --- a/src/utils/iced/mod.rs +++ b/src/utils/iced/mod.rs @@ -35,7 +35,7 @@ use smithay::{ renderer::{ ImportMem, Renderer, element::{ - AsRenderElements, Kind, + Kind, memory::{MemoryRenderBuffer, MemoryRenderBufferRenderElement}, }, }, @@ -910,21 +910,18 @@ impl SpaceElement for IcedElement

{ } } -impl AsRenderElements for IcedElement

-where - P: Program + Send + 'static, - R: Renderer + ImportMem, - R::TextureId: Send + Clone + 'static, -{ - type RenderElement = MemoryRenderBufferRenderElement; - - fn render_elements>( +impl IcedElement

{ + pub fn push_render_elements( &self, renderer: &mut R, location: Point, mut scale: Scale, alpha: f32, - ) -> Vec { + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where + R: Renderer + ImportMem, + R::TextureId: Send + Clone + 'static, + { let mut internal = self.0.lock().unwrap(); // makes partial borrows easier let internal_ref = &mut *internal; @@ -1055,11 +1052,10 @@ where Kind::Unspecified, ) { Ok(buffer) => { - return vec![C::from(buffer)]; + push(buffer); } Err(err) => tracing::warn!("What? {:?}", err), } } - Vec::new() } } diff --git a/src/utils/screenshot.rs b/src/utils/screenshot.rs index 541371cf..eb7730c7 100644 --- a/src/utils/screenshot.rs +++ b/src/utils/screenshot.rs @@ -14,7 +14,7 @@ use smithay::{ use tracing::warn; use crate::{ - backend::render::{RendererRef, element::AsGlowRenderer, wayland::SurfaceRenderElement}, + backend::render::{RendererRef, element::AsGlowRenderer}, shell::element::CosmicSurface, state::{State, advertised_node_for_surface}, }; @@ -27,7 +27,8 @@ pub fn screenshot_window(state: &mut State, surface: &CosmicSurface) { R::Error: Send + Sync + 'static, { let bbox = bbox_from_surface_tree(&window.wl_surface().unwrap(), (0, 0)); - let elements = window.render_elements::>( + let mut elements = Vec::new(); + window.push_render_elements( renderer, (-bbox.loc.x, -bbox.loc.y).into(), Scale::from(1.0), @@ -36,6 +37,8 @@ pub fn screenshot_window(state: &mut State, surface: &CosmicSurface) { None, false, [0; 4], + &mut |elem| elements.push(elem), + None, ); // TODO: 10-bit diff --git a/src/wayland/handlers/image_copy_capture/render.rs b/src/wayland/handlers/image_copy_capture/render.rs index c640a6d7..85759165 100644 --- a/src/wayland/handlers/image_copy_capture/render.rs +++ b/src/wayland/handlers/image_copy_capture/render.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use calloop::LoopHandle; +use smallvec::SmallVec; use smithay::{ backend::{ allocator::{Buffer, Fourcc, format::get_transparent}, @@ -39,7 +40,8 @@ use tracing::warn; use crate::{ backend::render::{ - CursorMode, ElementFilter, RendererRef, cursor, + CursorMode, ElementFilter, RendererRef, + cursor::{self, CursorRenderElement}, element::{AsGlowRenderer, CosmicElement, DamageElement}, render_workspace, wayland::SurfaceRenderElement, @@ -591,44 +593,49 @@ pub fn render_window_to_buffer( if let Some(location) = location { if draw_cursor { - elements.extend( - cursor::draw_cursor( - renderer, - &seat, - location, - 1.0.into(), - 1.0, - common.clock.now(), - true, - ) - .into_iter() - .map(|(elem, hotspot)| { - WindowCaptureElement::CursorElement(RelocateRenderElement::from_element( - elem, - Point::from((-hotspot.x, -hotspot.y)), - Relocate::Relative, - )) - }), + cursor::draw_cursor( + renderer, + &seat, + location, + 1.0.into(), + 1.0, + common.clock.now(), + true, + &mut |elem, hotspot| { + elements.push(WindowCaptureElement::CursorElement( + RelocateRenderElement::from_element( + elem, + Point::from((-hotspot.x, -hotspot.y)), + Relocate::Relative, + ), + )); + }, ); } // TODO cosmic-workspaces wants to omit, but metadata cursor capture in portal should // still include dnd surface in window capture buffer? if draw_cursor && let Some(dnd_icon) = get_dnd_icon(&seat) { - elements.extend( - cursor::draw_dnd_icon( - renderer, - &dnd_icon.surface, - (location + dnd_icon.offset.to_f64()).to_i32_round(), - 1.0, - ) - .into_iter() - .map(WindowCaptureElement::from), + cursor::draw_dnd_icon( + renderer, + &dnd_icon.surface, + (location + dnd_icon.offset.to_f64()).to_i32_round(), + 1.0, + &mut |elem| { + elements.push( + RelocateRenderElement::from_element( + CursorRenderElement::Surface(elem), + Point::new(0, 0), + Relocate::Relative, + ) + .into(), + ) + }, ); } } - elements.extend(toplevel.render_elements::>( + toplevel.push_render_elements( renderer, (-geometry.loc.x, -geometry.loc.y).into(), Scale::from(1.0), @@ -637,7 +644,9 @@ pub fn render_window_to_buffer( None, false, [0; 4], - )); + &mut |elem| elements.push(elem.into()), + None, + ); if let Ok(dmabuf) = get_dmabuf(buffer) { let mut dmabuf_clone = dmabuf.clone(); @@ -803,7 +812,8 @@ pub fn render_cursor_to_buffer( .collect(); dt.damage_output(age, &additional_damage_elements)?; - let elements = cursor::draw_cursor( + let mut elements = SmallVec::<[WindowCaptureElement; 4]>::new_const(); + cursor::draw_cursor( renderer, seat, Point::from((0.0, 0.0)), @@ -811,11 +821,12 @@ pub fn render_cursor_to_buffer( 1.0, common.clock.now(), true, - ) - .into_iter() - .map(|(elem, _)| RelocateRenderElement::from_element(elem, (0, 0), Relocate::Relative)) - .map(WindowCaptureElement::from) - .collect::>(); + &mut |elem, _| { + elements.push( + RelocateRenderElement::from_element(elem, (0, 0), Relocate::Relative).into(), + ) + }, + ); if let Ok(dmabuf) = get_dmabuf(buffer) { let mut dmabuf_clone = dmabuf.clone();