fix: honor screencopy cursor overlay requests

This commit is contained in:
Samuel Onoja committed 2026-09-25 02:31:18 +01:00
1 parent 4a1eab5b4a
commit f0862348c9
4 files changed
+130 -13

No files matched your search

+25 -2
View File
@@ -38,7 +38,10 @@ use smithay::{
wayland::presentation::Refresh,
};
use crate::{Ferese, winit::animated_window_elements};
use crate::{
Ferese,
winit::{animated_window_elements, cursorless_window_elements, redraw_output},
};
pub struct DirectBackendState {
pub session: LibSeatSession,
@@ -349,7 +352,27 @@ fn render_output(state: &mut Ferese, node: DrmNode, crtc: crtc::Handle) {
&elements,
[0.035, 0.04, 0.055, 1.0],
)?;
if state.process_screencopies(&mut device.renderer, &framebuffer, &output.output) {
let cursorless_capture = state.has_pending_screencopy(&output.output, false);
let captured_with_cursor =
state.process_screencopies(&mut device.renderer, &framebuffer, &output.output, true);
if cursorless_capture {
let cursorless_elements =
cursorless_window_elements(state, &mut device.renderer, &output.output);
redraw_output(
&mut device.renderer,
&mut framebuffer,
&output.output,
&cursorless_elements,
)?;
state.process_screencopies(&mut device.renderer, &framebuffer, &output.output, false);
redraw_output(
&mut device.renderer,
&mut framebuffer,
&output.output,
&elements,
)?;
} else if captured_with_cursor {
let _ = device
.renderer
.render(
+34 -4
View File
@@ -28,6 +28,7 @@ const BYTES_PER_PIXEL: usize = 4;
pub(crate) struct FrameData {
output: Option<Output>,
region: Rectangle<i32, Buffer>,
overlay_cursor: bool,
used: Mutex<bool>,
}
@@ -37,6 +38,7 @@ pub(crate) struct PendingScreencopy {
buffer: WlBuffer,
pub(crate) output: Output,
region: Rectangle<i32, Buffer>,
overlay_cursor: bool,
with_damage: bool,
}
@@ -75,14 +77,14 @@ impl Dispatch<ZwlrScreencopyManagerV1, ()> for Ferese {
match request {
zwlr_screencopy_manager_v1::Request::CaptureOutput {
frame,
overlay_cursor: _,
overlay_cursor,
output,
} => {
create_frame(data_init, frame, output, None);
create_frame(data_init, frame, output, None, overlay_cursor != 0);
}
zwlr_screencopy_manager_v1::Request::CaptureOutputRegion {
frame,
overlay_cursor: _,
overlay_cursor,
output,
x,
y,
@@ -94,6 +96,7 @@ impl Dispatch<ZwlrScreencopyManagerV1, ()> for Ferese {
frame,
output,
Some(Rectangle::new((x, y).into(), (width, height).into())),
overlay_cursor != 0,
);
}
zwlr_screencopy_manager_v1::Request::Destroy => {}
@@ -161,6 +164,7 @@ impl Ferese {
buffer,
output,
region: data.region,
overlay_cursor: data.overlay_cursor,
with_damage,
});
crate::backends::direct::render_all(self);
@@ -171,6 +175,7 @@ impl Ferese {
renderer: &mut R,
framebuffer: &R::Framebuffer<'_>,
output: &Output,
overlay_cursor: bool,
) -> bool
where
R: ExportMem,
@@ -180,7 +185,9 @@ impl Ferese {
let captures = std::mem::take(&mut self.pending_screencopies);
for capture in captures {
if &capture.output != output {
if &capture.output != output
|| !cursor_overlay_matches(capture.overlay_cursor, overlay_cursor)
{
remaining.push(capture);
continue;
}
@@ -198,6 +205,17 @@ impl Ferese {
self.pending_screencopies = remaining;
framebuffer_binding_changed
}
pub(crate) fn has_pending_screencopy(&self, output: &Output, overlay_cursor: bool) -> bool {
self.pending_screencopies.iter().any(|capture| {
capture.output == *output
&& cursor_overlay_matches(capture.overlay_cursor, overlay_cursor)
})
}
}
fn cursor_overlay_matches(requested: bool, rendered: bool) -> bool {
requested == rendered
}
fn create_frame(
@@ -205,6 +223,7 @@ fn create_frame(
frame: New<ZwlrScreencopyFrameV1>,
wl_output: smithay::reexports::wayland_server::protocol::wl_output::WlOutput,
requested: Option<Rectangle<i32, Logical>>,
overlay_cursor: bool,
) {
let Some(output) = Output::from_resource(&wl_output) else {
let frame = data_init.init(
@@ -212,6 +231,7 @@ fn create_frame(
Arc::new(FrameData {
output: None,
region: Rectangle::from_size((1, 1).into()),
overlay_cursor,
used: Mutex::new(true),
}),
);
@@ -224,6 +244,7 @@ fn create_frame(
Arc::new(FrameData {
output: Some(output),
region: Rectangle::from_size((1, 1).into()),
overlay_cursor,
used: Mutex::new(true),
}),
);
@@ -235,6 +256,7 @@ fn create_frame(
let data = Arc::new(FrameData {
output: Some(output),
region,
overlay_cursor,
used: Mutex::new(false),
});
let frame = data_init.init(frame, data);
@@ -392,4 +414,12 @@ mod tests {
capture_region_for_geometry(mode, 2.0, Transform::Normal, Some(requested),).is_none()
);
}
#[test]
fn cursor_overlay_requests_use_only_the_matching_render_pass() {
assert!(cursor_overlay_matches(false, false));
assert!(cursor_overlay_matches(true, true));
assert!(!cursor_overlay_matches(false, true));
assert!(!cursor_overlay_matches(true, false));
}
}
+69 -4
View File
@@ -6,10 +6,10 @@ use std::{
use smithay::{
backend::{
renderer::{
Frame, ImportDma, Renderer,
Color32F, Frame, ImportDma, Renderer,
damage::OutputDamageTracker,
element::{
AsRenderElements, Kind as RenderElementKind,
AsRenderElements, Kind as RenderElementKind, RenderElement,
memory::MemoryRenderBufferRenderElement,
render_elements,
surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree},
@@ -19,6 +19,7 @@ use smithay::{
},
},
gles::GlesRenderer,
utils::draw_render_elements,
},
winit::{self, WinitEvent},
},
@@ -143,7 +144,22 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
&elements,
[0.035, 0.04, 0.055, 1.0],
)?;
if state.process_screencopies(renderer, &framebuffer, &output) {
let cursorless_capture = state.has_pending_screencopy(&output, false);
let captured_with_cursor =
state.process_screencopies(renderer, &framebuffer, &output, true);
if cursorless_capture {
let cursorless_elements =
output_elements(state, renderer, &output, false);
redraw_output(
renderer,
&mut framebuffer,
&output,
&cursorless_elements,
)?;
state.process_screencopies(renderer, &framebuffer, &output, false);
redraw_output(renderer, &mut framebuffer, &output, &elements)?;
} else if captured_with_cursor {
let _ = renderer
.render(
&mut framebuffer,
@@ -203,13 +219,34 @@ pub(crate) fn animated_window_elements(
state: &Ferese,
renderer: &mut GlesRenderer,
output: &Output,
) -> Vec<AnimatedWindowRenderElement> {
output_elements(state, renderer, output, true)
}
pub(crate) fn cursorless_window_elements(
state: &Ferese,
renderer: &mut GlesRenderer,
output: &Output,
) -> Vec<AnimatedWindowRenderElement> {
output_elements(state, renderer, output, false)
}
fn output_elements(
state: &Ferese,
renderer: &mut GlesRenderer,
output: &Output,
include_cursor: bool,
) -> Vec<AnimatedWindowRenderElement> {
let Some(output_geometry) = state.space.output_geometry(output) else {
return Vec::new();
};
let scale = output.current_scale().fractional_scale();
let mut elements = cursor_elements(state, renderer, output_geometry, scale);
let mut elements = if include_cursor {
cursor_elements(state, renderer, output_geometry, scale)
} else {
Vec::new()
};
elements.extend(layer_elements(
renderer,
output,
@@ -264,6 +301,34 @@ pub(crate) fn animated_window_elements(
elements
}
pub(crate) fn redraw_output<R, E>(
renderer: &mut R,
framebuffer: &mut R::Framebuffer<'_>,
output: &Output,
elements: &[E],
) -> Result<(), R::Error>
where
R: Renderer,
R::TextureId: 'static,
E: RenderElement<R>,
{
let mode = output.current_mode().expect("output has a mode");
let transform = output.current_transform().invert();
let damage = Rectangle::from_size(transform.transform_size(mode.size));
let mut frame = renderer.render(framebuffer, mode.size, transform)?;
frame.clear(Color32F::new(0.035, 0.04, 0.055, 1.0), &[damage])?;
draw_render_elements(
&mut frame,
output.current_scale().fractional_scale(),
elements,
&[damage],
)?;
let _ = frame.finish()?;
Ok(())
}
fn layer_surfaces(output: &Output) -> Vec<LayerSurface> {
layer_map_for_output(output).layers().cloned().collect()
}