Skip to content

Commit

Permalink
feat: Merge pull request #78
Browse files Browse the repository at this point in the history
Introduce freeze feature
  • Loading branch information
Shinyzenith authored Feb 12, 2024
2 parents cb6bd68 + 044910d commit f2aa2b6
Show file tree
Hide file tree
Showing 16 changed files with 993 additions and 461 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ target
*.gz
*.out
.direnv
*.jpg
*.jpeg
*.png
*.ppm
*.qoi
48 changes: 42 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions libwayshot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
```rust
use libwayshot::WayshotConnection;

let wayshot_connection = WayshotConnection::new().unwrap();
let image_buffer = wayshot_connection.screenshot_all().unwrap();
let wayshot_connection = WayshotConnection::new()?;
let image_buffer = wayshot_connection.screenshot_all()?;
```
139 changes: 91 additions & 48 deletions libwayshot/src/dispatch.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
use std::{
process::exit,
collections::HashSet,
sync::atomic::{AtomicBool, Ordering},
};
use wayland_client::{
delegate_noop,
globals::GlobalListContents,
protocol::{
wl_buffer::WlBuffer, wl_output, wl_output::WlOutput, wl_registry, wl_registry::WlRegistry,
wl_shm::WlShm, wl_shm_pool::WlShmPool,
wl_buffer::WlBuffer, wl_compositor::WlCompositor, wl_output, wl_output::WlOutput,
wl_registry, wl_registry::WlRegistry, wl_shm::WlShm, wl_shm_pool::WlShmPool,
wl_surface::WlSurface,
},
Connection, Dispatch, QueueHandle, WEnum,
WEnum::Value,
};
use wayland_protocols::xdg::xdg_output::zv1::client::{
zxdg_output_manager_v1::ZxdgOutputManagerV1, zxdg_output_v1, zxdg_output_v1::ZxdgOutputV1,
};
use wayland_protocols_wlr::layer_shell::v1::client::{
zwlr_layer_shell_v1::ZwlrLayerShellV1,
zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1},
};
use wayland_protocols_wlr::screencopy::v1::client::{
zwlr_screencopy_frame_v1, zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1,
};

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

#[derive(Debug)]
pub struct OutputCaptureState {
pub outputs: Vec<OutputInfo>,
}

impl Dispatch<WlRegistry, ()> for OutputCaptureState {
#[tracing::instrument(skip(wl_registry, qh), ret, level = "trace")]
fn event(
state: &mut Self,
wl_registry: &WlRegistry,
Expand All @@ -56,16 +64,8 @@ impl Dispatch<WlRegistry, ()> for OutputCaptureState {
name: "".to_string(),
description: String::new(),
transform: wl_output::Transform::Normal,
dimensions: OutputPositioning {
x: 0,
y: 0,
width: 0,
height: 0,
},
mode: WlOutputMode {
width: 0,
height: 0,
},
scale: 1,
region: Region::default(),
});
} else {
tracing::error!("Ignoring a wl_output with version < 4.");
Expand All @@ -76,6 +76,7 @@ impl Dispatch<WlRegistry, ()> for OutputCaptureState {
}

impl Dispatch<WlOutput, ()> for OutputCaptureState {
#[tracing::instrument(skip(wl_output), ret, level = "trace")]
fn event(
state: &mut Self,
wl_output: &WlOutput,
Expand All @@ -84,11 +85,13 @@ impl Dispatch<WlOutput, ()> for OutputCaptureState {
_: &Connection,
_: &QueueHandle<Self>,
) {
let output: &mut OutputInfo = state
.outputs
.iter_mut()
.find(|x| x.wl_output == *wl_output)
.unwrap();
let output: &mut OutputInfo =
if let Some(output) = state.outputs.iter_mut().find(|x| x.wl_output == *wl_output) {
output
} else {
tracing::error!("Received event for an output that is not registered: {event:#?}");
return;
};

match event {
wl_output::Event::Name { name } => {
Expand All @@ -97,23 +100,26 @@ 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),
..
} => {
output.transform = transform;
}
_ => (),
wl_output::Event::Scale { factor } => {
output.scale = factor;
}
wl_output::Event::Done => {}
_ => {}
}
}
}

delegate_noop!(OutputCaptureState: ignore ZxdgOutputManagerV1);

impl Dispatch<ZxdgOutputV1, usize> for OutputCaptureState {
#[tracing::instrument(ret, level = "trace")]
fn event(
state: &mut Self,
_: &ZxdgOutputV1,
Expand All @@ -122,25 +128,34 @@ impl Dispatch<ZxdgOutputV1, usize> for OutputCaptureState {
_: &Connection,
_: &QueueHandle<Self>,
) {
let output_info = state.outputs.get_mut(*index).unwrap();
let output_info = if let Some(output_info) = state.outputs.get_mut(*index) {
output_info
} else {
tracing::error!(
"Received event for output index {index} that is not registered: {event:#?}"
);
return;
};

match event {
zxdg_output_v1::Event::LogicalPosition { x, y } => {
output_info.dimensions.x = x;
output_info.dimensions.y = y;
tracing::debug!("Logical position event fired!");
output_info.region.position = Position { x, y };
}
zxdg_output_v1::Event::LogicalSize { width, height } => {
output_info.dimensions.width = width;
output_info.dimensions.height = height;
tracing::debug!("Logical size event fired!");
output_info.region.size = Size {
width: width as u32,
height: height as u32,
};
}
zxdg_output_v1::Event::Done => {}
zxdg_output_v1::Event::Name { .. } => {}
zxdg_output_v1::Event::Description { .. } => {}
_ => {}
};
}
}

/// State of the frame after attemting to copy it's data to a wl_buffer.
/// State of the frame after attempting to copy it's data to a wl_buffer.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FrameState {
/// Compositor returned a failed event on calling `frame.copy`.
Expand All @@ -156,6 +171,7 @@ pub struct CaptureFrameState {
}

impl Dispatch<ZwlrScreencopyFrameV1, ()> for CaptureFrameState {
#[tracing::instrument(skip(frame), ret, level = "trace")]
fn event(
frame: &mut Self,
_: &ZwlrScreencopyFrameV1,
Expand All @@ -171,43 +187,30 @@ impl Dispatch<ZwlrScreencopyFrameV1, ()> for CaptureFrameState {
height,
stride,
} => {
tracing::debug!("Received Buffer event");
if let Value(f) = format {
frame.formats.push(FrameFormat {
format: f,
width,
height,
size: Size { width, height },
stride,
})
} else {
tracing::debug!("Received Buffer event with unidentified format");
exit(1);
}
}
zwlr_screencopy_frame_v1::Event::Flags { .. } => {
tracing::debug!("Received Flags event");
}
zwlr_screencopy_frame_v1::Event::Ready { .. } => {
// If the frame is successfully copied, a “flags” and a “ready” events are sent. Otherwise, a “failed” event is sent.
// This is useful when we call .copy on the frame object.
tracing::debug!("Received Ready event");
frame.state.replace(FrameState::Finished);
}
zwlr_screencopy_frame_v1::Event::Failed => {
tracing::debug!("Received Failed event");
frame.state.replace(FrameState::Failed);
}
zwlr_screencopy_frame_v1::Event::Damage { .. } => {
tracing::debug!("Received Damage event");
}
zwlr_screencopy_frame_v1::Event::LinuxDmabuf { .. } => {
tracing::debug!("Received LinuxDmaBuf event");
}
zwlr_screencopy_frame_v1::Event::Damage { .. } => {}
zwlr_screencopy_frame_v1::Event::LinuxDmabuf { .. } => {}
zwlr_screencopy_frame_v1::Event::BufferDone => {
tracing::debug!("Received bufferdone event");
frame.buffer_done.store(true, Ordering::SeqCst);
}
_ => unreachable!(),
_ => {}
};
}
}
Expand All @@ -232,3 +235,43 @@ impl wayland_client::Dispatch<wl_registry::WlRegistry, GlobalListContents> for W
) {
}
}

pub struct LayerShellState {
pub configured_outputs: HashSet<WlOutput>,
}

delegate_noop!(LayerShellState: ignore WlCompositor);
delegate_noop!(LayerShellState: ignore WlShm);
delegate_noop!(LayerShellState: ignore WlShmPool);
delegate_noop!(LayerShellState: ignore WlBuffer);
delegate_noop!(LayerShellState: ignore ZwlrLayerShellV1);
delegate_noop!(LayerShellState: ignore WlSurface);

impl wayland_client::Dispatch<ZwlrLayerSurfaceV1, WlOutput> for LayerShellState {
// No need to instrument here, span from lib.rs is automatically used.
fn event(
state: &mut Self,
proxy: &ZwlrLayerSurfaceV1,
event: <ZwlrLayerSurfaceV1 as wayland_client::Proxy>::Event,
data: &WlOutput,
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
match event {
zwlr_layer_surface_v1::Event::Configure {
serial,
width: _,
height: _,
} => {
tracing::debug!("Acking configure");
state.configured_outputs.insert(data.clone());
proxy.ack_configure(serial);
tracing::trace!("Acked configure");
}
zwlr_layer_surface_v1::Event::Closed => {
tracing::debug!("Closed")
}
_ => {}
}
}
}
Loading

0 comments on commit f2aa2b6

Please sign in to comment.