Split shell, settings, and compositor into focused modules
This commit is contained in:
1 parent
2b9f30fa5d
commit
cbf048566a
38 files changed
+9998
-9817
No files matched your search
@@ -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,
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user