Split shell, settings, and compositor into focused modules

This commit is contained in:
Samuel Onoja committed 2026-10-01 12:47:26 +01:00
1 parent 2b9f30fa5d
commit cbf048566a
38 files changed
+9998 -9817

No files matched your search

+120
View File
@@ -0,0 +1,120 @@
use super::*;
pub(crate) fn capture_resize_snapshot(
renderer: &mut GlesRenderer,
window: &smithay::desktop::Window,
geometry: Rectangle<i32, Logical>,
scale: f64,
remaining: usize,
) -> Result<Option<ResizeSnapshot>, GlesError> {
let Some(toplevel) = window.toplevel() else {
return Ok(None);
};
let size: Size<i32, Physical> = geometry.size.to_physical_precise_round(scale);
let bytes = (size.w.max(0) as usize)
.saturating_mul(size.h.max(0) as usize)
.saturating_mul(4);
if bytes == 0 || bytes > remaining {
return Ok(None);
}
// Called before on_commit_buffer_handler: renderer surface state still
// owns the previous buffer. Copy only during an actual resize handoff.
let content = render_elements_from_surface_tree::<GlesRenderer, WaylandSurfaceRenderElement<GlesRenderer>>(
renderer,
toplevel.wl_surface(),
Point::<i32, Logical>::from((-geometry.loc.x, -geometry.loc.y)).to_physical_precise_round(scale),
scale,
1.0,
RenderElementKind::Unspecified,
);
if content.is_empty() {
return Ok(None);
}
let mut texture = Offscreen::<GlesTexture>::create_buffer(renderer, Fourcc::Abgr8888, (size.w, size.h).into())?;
{
let mut target = renderer.bind(&mut texture)?;
let mut frame = renderer.render(&mut target, size, Transform::Normal)?;
let damage = Rectangle::from_size(size);
frame.clear(Color32F::new(0.0, 0.0, 0.0, 0.0), &[damage])?;
draw_render_elements(&mut frame, scale, &content, &[damage])?;
let _ = frame.finish()?;
}
Ok(Some(ResizeSnapshot {
texture,
context: renderer.context_id().erased(),
id: Id::new(),
commit: CommitCounter::default(),
elapsed: Duration::ZERO,
last_tick: None,
scale,
}))
}
pub(crate) fn capture_window_buffer(
renderer: &mut GlesRenderer,
window: &smithay::desktop::Window,
geometry: Rectangle<i32, Logical>,
scale: f64,
) -> Result<crate::handlers::screenshot::CaptureBuffer, String> {
capture_window_frame(renderer, window, geometry, scale, None)
}
pub(crate) fn capture_window_frame(
renderer: &mut GlesRenderer,
window: &smithay::desktop::Window,
geometry: Rectangle<i32, Logical>,
scale: f64,
cursor: Option<(&Ferese, Rectangle<i32, Logical>)>,
) -> Result<crate::handlers::screenshot::CaptureBuffer, String> {
let mut snapshot = capture_resize_snapshot(renderer, window, geometry, scale, 128 * 1024 * 1024)
.map_err(|error| error.to_string())?
.ok_or("Window has no capturable content")?;
let size = snapshot.texture.size();
if let Some((state, cursor_geometry)) = cursor {
let elements = cursor_elements(state, renderer, cursor_geometry, scale);
let mut target = renderer.bind(&mut snapshot.texture).map_err(|e| e.to_string())?;
let mut frame = renderer
.render(&mut target, (size.w, size.h).into(), Transform::Normal)
.map_err(|e| e.to_string())?;
draw_render_elements(
&mut frame,
scale,
&elements,
&[Rectangle::from_size((size.w, size.h).into())],
)
.map_err(|e| e.to_string())?;
let _ = frame.finish().map_err(|e| e.to_string())?;
}
let mapping = renderer
.copy_texture(&snapshot.texture, Rectangle::from_size(size), Fourcc::Abgr8888)
.map_err(|error| error.to_string())?;
if mapping.format() != Some(Fourcc::Abgr8888) {
return Err("Unsupported window readback format".into());
}
let bytes = (size.w as usize)
.checked_mul(size.h as usize)
.and_then(|pixels| pixels.checked_mul(4))
.ok_or("Window is too large")?;
let source = renderer.map_texture(&mapping).map_err(|error| error.to_string())?;
if source.len() < bytes {
return Err("Incomplete window readback".into());
}
let mut pixels = source[..bytes].to_vec();
for pixel in pixels.as_chunks_mut::<4>().0 {
pixel.swap(0, 2);
let alpha = pixel[3] as u16;
for channel in &mut pixel[..3] {
*channel = if alpha == 0 {
0
} else {
((*channel as u16 * 255 + alpha / 2) / alpha).min(255) as u8
};
}
}
Ok(crate::handlers::screenshot::CaptureBuffer {
width: size.w,
height: size.h,
stride: size.w as usize * 4,
pixels,
})
}