Add a push version of render()

Will be useful for screencasting.
This commit is contained in:
Ivan Molodetskikh
2026-01-09 18:25:10 +03:00
parent 19b1074a8b
commit 39d3cd2415
+50 -50
View File
@@ -4283,8 +4283,29 @@ impl Niri {
renderer: &mut R,
output: &Output,
include_pointer: bool,
mut target: RenderTarget,
target: RenderTarget,
) -> Vec<OutputRenderElements<R>> {
let mut elements = Vec::new();
self.render_inner(renderer, output, include_pointer, target, &mut |elem| {
elements.push(elem)
});
if self.debug_draw_opaque_regions {
let output_scale = Scale::from(output.current_scale().fractional_scale());
draw_opaque_regions(&mut elements, output_scale);
}
elements
}
pub fn render_inner<R: NiriRenderer>(
&self,
renderer: &mut R,
output: &Output,
include_pointer: bool,
mut target: RenderTarget,
push: &mut dyn FnMut(OutputRenderElements<R>),
) {
let _span = tracy_client::span!("Niri::render");
if target == RenderTarget::Output {
@@ -4299,26 +4320,25 @@ impl Niri {
let output_scale = Scale::from(output.current_scale().fractional_scale());
// The pointer goes on the top.
let mut elements = vec![];
if include_pointer && self.pointer_visibility.is_visible() {
self.render_pointer(renderer, output, &mut |elem| elements.push(elem.into()));
self.render_pointer(renderer, output, &mut |elem| push(elem.into()));
}
// Next, the screen transition texture.
{
let state = self.output_state.get(output).unwrap();
if let Some(transition) = &state.screen_transition {
elements.push(transition.render(target).into());
push(transition.render(target).into());
}
}
// Next, the exit confirm dialog.
self.exit_confirm_dialog
.render(renderer, output, &mut |elem| elements.push(elem.into()));
.render(renderer, output, &mut |elem| push(elem.into()));
// Next, the config error notification too.
if let Some(element) = self.config_error_notification.render(renderer, output) {
elements.push(element.into());
push(element.into());
}
// If the session is locked, draw the lock surface.
@@ -4332,12 +4352,12 @@ impl Niri {
output_scale,
1.,
Kind::ScanoutCandidate,
&mut |elem| elements.push(elem.into()),
&mut |elem| push(elem.into()),
);
}
// Draw the solid color background.
elements.push(
push(
SolidColorRenderElement::from_buffer(
&state.lock_color_buffer,
(0., 0.),
@@ -4347,10 +4367,7 @@ impl Niri {
.into(),
);
if self.debug_draw_opaque_regions {
draw_opaque_regions(&mut elements, output_scale);
}
return elements;
return;
}
// Prepare the background elements.
@@ -4366,26 +4383,23 @@ impl Niri {
// If the screenshot UI is open, draw it.
if self.screenshot_ui.is_open() {
self.screenshot_ui
.render_output(output, target, &mut |elem| elements.push(elem.into()));
.render_output(output, target, &mut |elem| push(elem.into()));
// Add the backdrop for outputs that were connected while the screenshot UI was open.
elements.push(backdrop);
push(backdrop);
if self.debug_draw_opaque_regions {
draw_opaque_regions(&mut elements, output_scale);
}
return elements;
return;
}
// Draw the hotkey overlay on top.
if let Some(element) = self.hotkey_overlay.render(renderer, output) {
elements.push(element.into());
push(element.into());
}
// Then, the Alt-Tab switcher.
self.window_mru_ui
.render_output(self, output, renderer, target, &mut |elem| {
elements.push(elem.into())
push(elem.into())
});
// Don't draw the focus ring on the workspaces while interactively moving above those
@@ -4399,20 +4413,20 @@ impl Niri {
// Get layer-shell elements.
let layer_map = layer_map_for_output(output);
// We use macros instead of closures to avoid borrowing issues (renderer and elements go
// We use macros instead of closures to avoid borrowing issues (renderer and push() go
// into different functions).
macro_rules! push_popups_from_layer {
($layer:expr, $backdrop:expr, $push:expr) => {{
self.render_layer_popups(renderer, target, &layer_map, $layer, $backdrop, $push);
}};
($layer:expr, true) => {{
push_popups_from_layer!($layer, true, &mut |elem| elements.push(elem.into()));
push_popups_from_layer!($layer, true, &mut |elem| push(elem.into()));
}};
($layer:expr, $push:expr) => {{
push_popups_from_layer!($layer, false, $push);
}};
($layer:expr) => {{
push_popups_from_layer!($layer, false, &mut |elem| elements.push(elem.into()));
push_popups_from_layer!($layer, false, &mut |elem| push(elem.into()));
}};
}
macro_rules! push_normal_from_layer {
@@ -4420,13 +4434,13 @@ impl Niri {
self.render_layer_normal(renderer, target, &layer_map, $layer, $backdrop, $push);
}};
($layer:expr, true) => {{
push_normal_from_layer!($layer, true, &mut |elem| elements.push(elem.into()));
push_normal_from_layer!($layer, true, &mut |elem| push(elem.into()));
}};
($layer:expr, $push:expr) => {{
push_normal_from_layer!($layer, false, $push);
}};
($layer:expr) => {{
push_normal_from_layer!($layer, false, &mut |elem| elements.push(elem.into()));
push_normal_from_layer!($layer, false, &mut |elem| push(elem.into()));
}};
}
@@ -4439,16 +4453,12 @@ impl Niri {
if mon.render_above_top_layer() {
self.layout
.render_interactive_move_for_output(renderer, output, target, &mut |elem| {
elements.push(elem.into())
push(elem.into())
});
mon.render_insert_hint_between_workspaces(renderer, &mut |elem| {
elements.push(elem.into())
});
mon.render_insert_hint_between_workspaces(renderer, &mut |elem| push(elem.into()));
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| {
elements.push(elem.into())
});
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| push(elem.into()));
push_popups_from_layer!(Layer::Top);
push_normal_from_layer!(Layer::Top);
@@ -4460,7 +4470,7 @@ impl Niri {
// We don't expect more than one workspace when render_above_top_layer().
if let Some((ws, _geo)) = mon.workspaces_with_render_geo().next() {
elements.push(ws.render_background().into());
push(ws.render_background().into());
}
} else {
push_popups_from_layer!(Layer::Top);
@@ -4468,19 +4478,17 @@ impl Niri {
self.layout
.render_interactive_move_for_output(renderer, output, target, &mut |elem| {
elements.push(elem.into())
push(elem.into())
});
mon.render_insert_hint_between_workspaces(renderer, &mut |elem| {
elements.push(elem.into())
});
mon.render_insert_hint_between_workspaces(renderer, &mut |elem| push(elem.into()));
// Macro instead of closure to avoid borrowing elements.
// Macro instead of closure to avoid borrowing push().
macro_rules! process {
($geo:expr) => {{
&mut |elem| {
if let Some(elem) = scale_relocate_crop(elem, output_scale, zoom, $geo) {
elements.push(elem.into());
push(elem.into());
}
}
}};
@@ -4491,9 +4499,7 @@ impl Niri {
push_popups_from_layer!(Layer::Background, process!(geo));
}
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| {
elements.push(elem.into())
});
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| push(elem.into()));
for (ws, geo) in mon.workspaces_with_render_geo() {
push_normal_from_layer!(Layer::Bottom, process!(geo));
@@ -4503,19 +4509,13 @@ impl Niri {
}
}
mon.render_workspace_shadows(renderer, &mut |elem| elements.push(elem.into()));
mon.render_workspace_shadows(renderer, &mut |elem| push(elem.into()));
// Then the backdrop.
push_popups_from_layer!(Layer::Background, true);
push_normal_from_layer!(Layer::Background, true);
elements.push(backdrop);
if self.debug_draw_opaque_regions {
draw_opaque_regions(&mut elements, output_scale);
}
elements
push(backdrop);
}
fn layers_in_render_order<'a>(