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, renderer: &mut R,
output: &Output, output: &Output,
include_pointer: bool, include_pointer: bool,
mut target: RenderTarget, target: RenderTarget,
) -> Vec<OutputRenderElements<R>> { ) -> 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"); let _span = tracy_client::span!("Niri::render");
if target == RenderTarget::Output { if target == RenderTarget::Output {
@@ -4299,26 +4320,25 @@ impl Niri {
let output_scale = Scale::from(output.current_scale().fractional_scale()); let output_scale = Scale::from(output.current_scale().fractional_scale());
// The pointer goes on the top. // The pointer goes on the top.
let mut elements = vec![];
if include_pointer && self.pointer_visibility.is_visible() { 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. // Next, the screen transition texture.
{ {
let state = self.output_state.get(output).unwrap(); let state = self.output_state.get(output).unwrap();
if let Some(transition) = &state.screen_transition { if let Some(transition) = &state.screen_transition {
elements.push(transition.render(target).into()); push(transition.render(target).into());
} }
} }
// Next, the exit confirm dialog. // Next, the exit confirm dialog.
self.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. // Next, the config error notification too.
if let Some(element) = self.config_error_notification.render(renderer, output) { 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. // If the session is locked, draw the lock surface.
@@ -4332,12 +4352,12 @@ impl Niri {
output_scale, output_scale,
1., 1.,
Kind::ScanoutCandidate, Kind::ScanoutCandidate,
&mut |elem| elements.push(elem.into()), &mut |elem| push(elem.into()),
); );
} }
// Draw the solid color background. // Draw the solid color background.
elements.push( push(
SolidColorRenderElement::from_buffer( SolidColorRenderElement::from_buffer(
&state.lock_color_buffer, &state.lock_color_buffer,
(0., 0.), (0., 0.),
@@ -4347,10 +4367,7 @@ impl Niri {
.into(), .into(),
); );
if self.debug_draw_opaque_regions { return;
draw_opaque_regions(&mut elements, output_scale);
}
return elements;
} }
// Prepare the background elements. // Prepare the background elements.
@@ -4366,26 +4383,23 @@ impl Niri {
// If the screenshot UI is open, draw it. // If the screenshot UI is open, draw it.
if self.screenshot_ui.is_open() { if self.screenshot_ui.is_open() {
self.screenshot_ui 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. // 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 { return;
draw_opaque_regions(&mut elements, output_scale);
}
return elements;
} }
// Draw the hotkey overlay on top. // Draw the hotkey overlay on top.
if let Some(element) = self.hotkey_overlay.render(renderer, output) { if let Some(element) = self.hotkey_overlay.render(renderer, output) {
elements.push(element.into()); push(element.into());
} }
// Then, the Alt-Tab switcher. // Then, the Alt-Tab switcher.
self.window_mru_ui self.window_mru_ui
.render_output(self, output, renderer, target, &mut |elem| { .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 // Don't draw the focus ring on the workspaces while interactively moving above those
@@ -4399,20 +4413,20 @@ impl Niri {
// Get layer-shell elements. // Get layer-shell elements.
let layer_map = layer_map_for_output(output); 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). // into different functions).
macro_rules! push_popups_from_layer { macro_rules! push_popups_from_layer {
($layer:expr, $backdrop:expr, $push:expr) => {{ ($layer:expr, $backdrop:expr, $push:expr) => {{
self.render_layer_popups(renderer, target, &layer_map, $layer, $backdrop, $push); self.render_layer_popups(renderer, target, &layer_map, $layer, $backdrop, $push);
}}; }};
($layer:expr, true) => {{ ($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) => {{ ($layer:expr, $push:expr) => {{
push_popups_from_layer!($layer, false, $push); push_popups_from_layer!($layer, false, $push);
}}; }};
($layer:expr) => {{ ($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 { macro_rules! push_normal_from_layer {
@@ -4420,13 +4434,13 @@ impl Niri {
self.render_layer_normal(renderer, target, &layer_map, $layer, $backdrop, $push); self.render_layer_normal(renderer, target, &layer_map, $layer, $backdrop, $push);
}}; }};
($layer:expr, true) => {{ ($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) => {{ ($layer:expr, $push:expr) => {{
push_normal_from_layer!($layer, false, $push); push_normal_from_layer!($layer, false, $push);
}}; }};
($layer:expr) => {{ ($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() { if mon.render_above_top_layer() {
self.layout self.layout
.render_interactive_move_for_output(renderer, output, target, &mut |elem| { .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| { mon.render_insert_hint_between_workspaces(renderer, &mut |elem| push(elem.into()));
elements.push(elem.into())
});
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| { mon.render_workspaces(renderer, target, focus_ring, &mut |elem| push(elem.into()));
elements.push(elem.into())
});
push_popups_from_layer!(Layer::Top); push_popups_from_layer!(Layer::Top);
push_normal_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(). // We don't expect more than one workspace when render_above_top_layer().
if let Some((ws, _geo)) = mon.workspaces_with_render_geo().next() { if let Some((ws, _geo)) = mon.workspaces_with_render_geo().next() {
elements.push(ws.render_background().into()); push(ws.render_background().into());
} }
} else { } else {
push_popups_from_layer!(Layer::Top); push_popups_from_layer!(Layer::Top);
@@ -4468,19 +4478,17 @@ impl Niri {
self.layout self.layout
.render_interactive_move_for_output(renderer, output, target, &mut |elem| { .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| { mon.render_insert_hint_between_workspaces(renderer, &mut |elem| push(elem.into()));
elements.push(elem.into())
});
// Macro instead of closure to avoid borrowing elements. // Macro instead of closure to avoid borrowing push().
macro_rules! process { macro_rules! process {
($geo:expr) => {{ ($geo:expr) => {{
&mut |elem| { &mut |elem| {
if let Some(elem) = scale_relocate_crop(elem, output_scale, zoom, $geo) { 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)); push_popups_from_layer!(Layer::Background, process!(geo));
} }
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| { mon.render_workspaces(renderer, target, focus_ring, &mut |elem| push(elem.into()));
elements.push(elem.into())
});
for (ws, geo) in mon.workspaces_with_render_geo() { for (ws, geo) in mon.workspaces_with_render_geo() {
push_normal_from_layer!(Layer::Bottom, process!(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. // Then the backdrop.
push_popups_from_layer!(Layer::Background, true); push_popups_from_layer!(Layer::Background, true);
push_normal_from_layer!(Layer::Background, true); push_normal_from_layer!(Layer::Background, true);
elements.push(backdrop); push(backdrop);
if self.debug_draw_opaque_regions {
draw_opaque_regions(&mut elements, output_scale);
}
elements
} }
fn layers_in_render_order<'a>( fn layers_in_render_order<'a>(