Skip to content

Commit

Permalink
Make region, sizing, and positioning data structs reusable
Browse files Browse the repository at this point in the history
We use different structs/fields to store the same three types of data everywhere:
- Position (x,y)
- Size (width,height)
- Region(position, size)

This makes it so they all reuse the same information.
  • Loading branch information
AndreasBackx committed Feb 2, 2024
1 parent 7d6e20b commit 044910d
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 150 deletions.
22 changes: 10 additions & 12 deletions libwayshot/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use wayland_protocols_wlr::screencopy::v1::client::{
};

use crate::{
output::{OutputInfo, OutputPositioning, WlOutputMode},
output::OutputInfo,
region::{Position, Region, Size},
screencopy::FrameFormat,
};

Expand Down Expand Up @@ -64,8 +65,7 @@ impl Dispatch<WlRegistry, ()> for OutputCaptureState {
description: String::new(),
transform: wl_output::Transform::Normal,
scale: 1,
dimensions: OutputPositioning::default(),
mode: WlOutputMode::default(),
region: Region::default(),
});
} else {
tracing::error!("Ignoring a wl_output with version < 4.");
Expand Down Expand Up @@ -100,9 +100,7 @@ impl Dispatch<WlOutput, ()> for OutputCaptureState {
wl_output::Event::Description { description } => {
output.description = description;
}
wl_output::Event::Mode { width, height, .. } => {
output.mode = WlOutputMode { width, height };
}
wl_output::Event::Mode { .. } => {}
wl_output::Event::Geometry {
transform: WEnum::Value(transform),
..
Expand Down Expand Up @@ -141,12 +139,13 @@ impl Dispatch<ZxdgOutputV1, usize> for OutputCaptureState {

match event {
zxdg_output_v1::Event::LogicalPosition { x, y } => {
output_info.dimensions.x = x;
output_info.dimensions.y = y;
output_info.region.position = Position { x, y };
}
zxdg_output_v1::Event::LogicalSize { width, height } => {
output_info.dimensions.width = width;
output_info.dimensions.height = height;
output_info.region.size = Size {
width: width as u32,
height: height as u32,
};
}
zxdg_output_v1::Event::Done => {}
zxdg_output_v1::Event::Name { .. } => {}
Expand Down Expand Up @@ -191,8 +190,7 @@ impl Dispatch<ZwlrScreencopyFrameV1, ()> for CaptureFrameState {
if let Value(f) = format {
frame.formats.push(FrameFormat {
format: f,
width,
height,
size: Size { width, height },
stride,
})
} else {
Expand Down
92 changes: 52 additions & 40 deletions libwayshot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use wayland_client::{
globals::{registry_queue_init, GlobalList},
protocol::{
wl_compositor::WlCompositor,
wl_output::WlOutput,
wl_output::{Transform, WlOutput},
wl_shm::{self, WlShm},
},
Connection, EventQueue,
Expand All @@ -52,7 +52,7 @@ use crate::{
convert::create_converter,
dispatch::{CaptureFrameState, FrameState, OutputCaptureState, WayshotState},
output::OutputInfo,
region::LogicalRegion,
region::{LogicalRegion, Region, Size},
screencopy::{create_shm_fd, FrameCopy, FrameFormat},
};

Expand Down Expand Up @@ -214,10 +214,10 @@ impl WayshotConnection {
screencopy_manager.capture_output_region(
cursor_overlay,
output,
embedded_region.inner.x,
embedded_region.inner.y,
embedded_region.inner.width,
embedded_region.inner.height,
embedded_region.inner.position.x,
embedded_region.inner.position.y,
embedded_region.inner.size.width as i32,
embedded_region.inner.size.height as i32,
&qh,
(),
)
Expand Down Expand Up @@ -275,16 +275,21 @@ impl WayshotConnection {
// Connecting to wayland environment.
let qh = event_queue.handle();

// Bytes of data in the frame = stride * height.
let frame_bytes = frame_format.stride * frame_format.height;

// Instantiate shm global.
let shm = self.globals.bind::<WlShm, _, _>(&qh, 1..=1, ())?;
let shm_pool = shm.create_pool(fd.as_fd(), frame_bytes as i32, &qh, ());
let shm_pool = shm.create_pool(
fd.as_fd(),
frame_format
.byte_size()
.try_into()
.map_err(|_| Error::BufferTooSmall)?,
&qh,
(),
);
let buffer = shm_pool.create_buffer(
0,
frame_format.width as i32,
frame_format.height as i32,
frame_format.size.width as i32,
frame_format.size.height as i32,
frame_format.stride as i32,
frame_format.format,
&qh,
Expand Down Expand Up @@ -322,9 +327,7 @@ impl WayshotConnection {
let (state, event_queue, frame, frame_format) =
self.capture_output_frame_get_state(cursor_overlay as i32, output, capture_region)?;

// Bytes of data in the frame = stride * height.
let frame_bytes = frame_format.stride * frame_format.height;
file.set_len(frame_bytes as u64)?;
file.set_len(frame_format.byte_size())?;

let frame_guard =
self.capture_output_frame_inner(state, event_queue, frame, frame_format, file)?;
Expand All @@ -333,7 +336,7 @@ impl WayshotConnection {
}

/// Get a FrameCopy instance with screenshot pixel data for any wl_output object.
#[tracing::instrument(skip_all, fields(output = output_info.name, region = capture_region.map(|r| format!("{:}", r))))]
#[tracing::instrument(skip_all, fields(output = format!("{output_info}"), region = capture_region.map(|r| format!("{:}", r))))]
fn capture_frame_copy(
&self,
cursor_overlay: bool,
Expand Down Expand Up @@ -361,22 +364,30 @@ impl WayshotConnection {
tracing::error!("You can send a feature request for the above format to the mailing list for wayshot over at https://sr.ht/~shinyzenith/wayshot.");
return Err(Error::NoSupportedBufferFormat);
};
let rotated_size = match output_info.transform {
Transform::_90 | Transform::_270 | Transform::Flipped90 | Transform::Flipped270 => {
Size {
width: frame_format.size.height,
height: frame_format.size.width,
}
}
_ => frame_format.size,
};
let frame_copy = FrameCopy {
frame_format,
frame_color_type,
frame_mmap,
transform: output_info.transform,
position: capture_region
.map(|capture_region| {
let logical_region = capture_region.logical();
(logical_region.inner.x as i64, logical_region.inner.y as i64)
})
.unwrap_or_else(|| {
(
output_info.dimensions.x as i64,
output_info.dimensions.y as i64,
)
}),
region: LogicalRegion {
inner: Region {
position: capture_region
.map(|capture_region: EmbeddedRegion| {
capture_region.logical().inner.position
})
.unwrap_or_else(|| output_info.region.position),
size: rotated_size,
},
},
};
tracing::debug!("Created frame copy: {:#?}", frame_copy);
Ok((frame_copy, frame_guard))
Expand Down Expand Up @@ -451,7 +462,7 @@ impl WayshotConnection {
tracing::span!(
tracing::Level::DEBUG,
"overlay_frames::surface",
output = output_info.name.as_str()
output = format!("{output_info}")
)
.in_scope(|| -> Result<()> {
let surface = compositor.create_surface(&qh, ());
Expand All @@ -468,8 +479,8 @@ impl WayshotConnection {
layer_surface.set_exclusive_zone(-1);
layer_surface.set_anchor(Anchor::Top | Anchor::Left);
layer_surface.set_size(
frame_copy.frame_format.width,
frame_copy.frame_format.height,
frame_copy.frame_format.size.width,
frame_copy.frame_format.size.height,
);

debug!("Committing surface creation changes.");
Expand Down Expand Up @@ -515,8 +526,8 @@ impl WayshotConnection {
tracing::Level::DEBUG,
"filter_map",
output = format!(
"{name} at {region}",
name = output_info.name,
"{output_info} at {region}",
output_info = format!("{output_info}"),
region = LogicalRegion::from(output_info),
),
capture_region = format!("{}", capture_region),
Expand Down Expand Up @@ -561,8 +572,8 @@ impl WayshotConnection {
image_util::rotate_image_buffer(
image,
frame_copy.transform,
frame_copy.frame_format.width,
frame_copy.frame_format.height,
frame_copy.frame_format.size.width,
frame_copy.frame_format.size.height,
),
frame_copy,
))
Expand All @@ -580,23 +591,24 @@ impl WayshotConnection {
// Default to a transparent image.
let composite_image = composite_image.unwrap_or_else(|| {
Ok(DynamicImage::new_rgba8(
capture_region.inner.width as u32,
capture_region.inner.height as u32,
capture_region.inner.size.width,
capture_region.inner.size.height,
))
});

Some(|| -> Result<_> {
let mut composite_image = composite_image?;
let (image, frame_copy) = image?;
let frame_copy_region = LogicalRegion::from(&frame_copy);
let (x, y) = (
frame_copy_region.inner.x as i64 - capture_region.inner.x as i64,
frame_copy_region.inner.y as i64 - capture_region.inner.y as i64,
frame_copy.region.inner.position.x as i64
- capture_region.inner.position.x as i64,
frame_copy.region.inner.position.y as i64
- capture_region.inner.position.y as i64,
);
tracing::span!(
tracing::Level::DEBUG,
"replace",
frame_copy_region = format!("{}", frame_copy_region),
frame_copy_region = format!("{}", frame_copy.region),
capture_region = format!("{}", capture_region),
x = x,
y = y,
Expand Down
28 changes: 14 additions & 14 deletions libwayshot/src/output.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use std::fmt::Display;

use wayland_client::protocol::{wl_output, wl_output::WlOutput};

use crate::region::Region;

/// Represents an accessible wayland output.
///
/// Do not instantiate, instead use [`crate::WayshotConnection::get_all_outputs`].
Expand All @@ -10,20 +14,16 @@ pub struct OutputInfo {
pub description: String,
pub transform: wl_output::Transform,
pub scale: i32,
pub dimensions: OutputPositioning,
pub mode: WlOutputMode,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
pub struct WlOutputMode {
pub width: i32,
pub height: i32,
pub region: Region,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
pub struct OutputPositioning {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
impl Display for OutputInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{name} ({description})",
name = self.name,
description = self.description
)
}
}
Loading

0 comments on commit 044910d

Please sign in to comment.