element: Refactor element acquisition to be push based

This commit is contained in:
Victoria Brekenfeld 2026-03-04 18:57:37 +01:00 committed by Victoria Brekenfeld
parent 178c6593dc
commit e4c0716951
18 changed files with 1096 additions and 1137 deletions

View file

@ -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<DrmNode>,
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
where
push: &mut dyn FnMut(WorkspaceRenderElement<R>),
) where
R: AsGlowRenderer,
R::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
@ -1631,80 +1632,83 @@ impl Workspace {
CosmicStackRenderElement<R>: RenderElement<R>,
WorkspaceRenderElement<R>: RenderElement<R>,
{
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<WorkspaceRenderElement<R>> {
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<R>; 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::<WorkspaceRenderElement<_>>::into(elem)
}
};
RescaleRenderElement::from_element(elem, render_loc, scale).into()
} else {
Into::<WorkspaceRenderElement<_>>::into(elem)
}
};
fullscreen
.surface
.render_elements::<R, CosmicWindowRenderElement<R>>(
let mut fullscreen_push = |elem: SurfaceRenderElement<R>| {
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::<Vec<_>>()
};
[0, 0, 0, 0],
&mut fullscreen_push,
None,
);
};
let top_fullscreen = self.get_fullscreen(last_active_seat);
let mut fullscreen_elements: Vec<WorkspaceRenderElement<R>> = 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::<R>(
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::<R>(
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::<CosmicMappedRenderElement<R>>::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<Data>>)>),
theme: &CosmicTheme,
scanout_node: Option<DrmNode>,
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
where
push: &mut dyn FnMut(WorkspaceRenderElement<R>),
) where
R: AsGlowRenderer,
R::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
@ -1861,8 +1845,6 @@ impl Workspace {
CosmicStackRenderElement<R>: RenderElement<R>,
WorkspaceRenderElement<R>: RenderElement<R>,
{
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::<R, CosmicWindowRenderElement<R>>(
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::<R>(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::<R>(
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<R>),
OverrideRedirect(SurfaceRenderElement<R>),
Fullscreen(RescaleRenderElement<CosmicWindowRenderElement<R>>),
FullscreenPopup(CosmicWindowRenderElement<R>),
Window(CosmicMappedRenderElement<R>),
@ -2244,13 +2211,13 @@ where
}
}
impl<R> From<WaylandSurfaceRenderElement<R>> for WorkspaceRenderElement<R>
impl<R> From<SurfaceRenderElement<R>> for WorkspaceRenderElement<R>
where
R: AsGlowRenderer,
R::TextureId: 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
fn from(elem: WaylandSurfaceRenderElement<R>) -> Self {
fn from(elem: SurfaceRenderElement<R>) -> Self {
WorkspaceRenderElement::OverrideRedirect(elem)
}
}