Skip to content

Commit

Permalink
Merge pull request #2 from waycrate/freeze-feat-andreas
Browse files Browse the repository at this point in the history
  • Loading branch information
Gigas002 authored Mar 27, 2024
2 parents b1aa92f + 7381159 commit 2ca3cc3
Show file tree
Hide file tree
Showing 8 changed files with 548 additions and 351 deletions.
706 changes: 419 additions & 287 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docs/wayshot.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ Wayshot - Screenshot tool for compositors implementing zwlr_screencopy_v1 such a
*-c*, *--cursor*
Enable cursor visibility in screenshots.

*--clipboard*
Copy image contents to clipboard.

*-e*, *--extension*
Set the image encoder.
Valid arguments:
Expand All @@ -30,6 +33,7 @@ Wayshot - Screenshot tool for compositors implementing zwlr_screencopy_v1 such a
- png (Default encoder)
- ppm
- qoi
- webp

*-f*, *--file*
Set a custom file path. The default path is `./{current_unix_timestamp}-wayshot.{encoder}`
Expand Down
49 changes: 21 additions & 28 deletions libwayshot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ impl WayshotConnection {
}

/// Fetch all accessible wayland outputs.
pub fn get_all_outputs(&self) -> &Vec<OutputInfo> {
&self.output_infos
pub fn get_all_outputs(&self) -> &[OutputInfo] {
self.output_infos.as_slice()
}

/// refresh the outputs, to get new outputs
Expand Down Expand Up @@ -129,7 +129,6 @@ impl WayshotConnection {
// Fetch all outputs; when their names arrive, add them to the list
let _ = self.conn.display().get_registry(&qh, ());
event_queue.roundtrip(&mut state)?;
event_queue.roundtrip(&mut state)?;

// We loop over each output and request its position data.
let xdg_outputs: Vec<ZxdgOutputV1> = state
Expand Down Expand Up @@ -389,37 +388,32 @@ impl WayshotConnection {

pub fn capture_frame_copies(
&self,
output_capture_regions: &Vec<(OutputInfo, Option<EmbeddedRegion>)>,
output_capture_regions: &[(OutputInfo, Option<EmbeddedRegion>)],
cursor_overlay: bool,
) -> Result<Vec<(FrameCopy, FrameGuard, OutputInfo)>> {
let frame_copies = thread::scope(|scope| -> Result<_> {
let join_handles = output_capture_regions
.into_iter()
.iter()
.map(|(output_info, capture_region)| {
scope.spawn(move || {
self.capture_frame_copy(
cursor_overlay,
&output_info,
capture_region.clone(),
)
.map(|(frame_copy, frame_guard)| {
(frame_copy, frame_guard, output_info.clone())
})
self.capture_frame_copy(cursor_overlay, output_info, *capture_region)
.map(|(frame_copy, frame_guard)| {
(frame_copy, frame_guard, output_info.clone())
})
})
})
.collect::<Vec<_>>();

join_handles
.into_iter()
.map(|join_handle| join_handle.join())
.flatten()
.flat_map(|join_handle| join_handle.join())
.collect::<Result<_>>()
})?;

Ok(frame_copies)
}

fn overlay_frames(&self, frames: &Vec<(FrameCopy, FrameGuard, OutputInfo)>) -> Result<()> {
fn overlay_frames(&self, frames: &[(FrameCopy, FrameGuard, OutputInfo)]) -> Result<()> {
let mut state = LayerShellState {
configured_outputs: HashSet::new(),
};
Expand Down Expand Up @@ -507,15 +501,15 @@ impl WayshotConnection {
region_capturer: RegionCapturer,
cursor_overlay: bool,
) -> Result<DynamicImage> {
let outputs_capture_regions: &Vec<(OutputInfo, Option<EmbeddedRegion>)> =
&match region_capturer {
let outputs_capture_regions: Vec<(OutputInfo, Option<EmbeddedRegion>)> =
match region_capturer {
RegionCapturer::Outputs(ref outputs) => outputs
.into_iter()
.iter()
.map(|output_info| (output_info.clone(), None))
.collect(),
RegionCapturer::Region(capture_region) => self
.get_all_outputs()
.into_iter()
.iter()
.filter_map(|output_info| {
tracing::span!(
tracing::Level::DEBUG,
Expand All @@ -542,15 +536,15 @@ impl WayshotConnection {
.collect(),
RegionCapturer::Freeze(_) => self
.get_all_outputs()
.into_iter()
.iter()
.map(|output_info| (output_info.clone(), None))
.collect(),
};

let frames = self.capture_frame_copies(outputs_capture_regions, cursor_overlay)?;
let frames = self.capture_frame_copies(&outputs_capture_regions, cursor_overlay)?;

let capture_region: LogicalRegion = match region_capturer {
RegionCapturer::Outputs(ref outputs) => outputs.try_into()?,
RegionCapturer::Outputs(outputs) => outputs.as_slice().try_into()?,
RegionCapturer::Region(region) => region,
RegionCapturer::Freeze(callback) => {
self.overlay_frames(&frames).and_then(|_| callback())?
Expand All @@ -566,7 +560,7 @@ impl WayshotConnection {
.map(|(output_info, _)| output_info.scale())
.fold(1.0, f64::max);

tracing::Span::current().record("max_scale", &max_scale);
tracing::Span::current().record("max_scale", max_scale);

let rotate_join_handles = frames
.into_iter()
Expand All @@ -588,8 +582,7 @@ impl WayshotConnection {

rotate_join_handles
.into_iter()
.map(|join_handle| join_handle.join())
.flatten()
.flat_map(|join_handle| join_handle.join())
.fold(
None,
|composite_image: Option<Result<_>>, image: Result<_>| {
Expand Down Expand Up @@ -667,14 +660,14 @@ impl WayshotConnection {
/// Take a screenshot from all of the specified outputs.
pub fn screenshot_outputs(
&self,
outputs: &Vec<OutputInfo>,
outputs: &[OutputInfo],
cursor_overlay: bool,
) -> Result<DynamicImage> {
if outputs.is_empty() {
return Err(Error::NoOutputs);
}

self.screenshot_region_capturer(RegionCapturer::Outputs(outputs.clone()), cursor_overlay)
self.screenshot_region_capturer(RegionCapturer::Outputs(outputs.to_owned()), cursor_overlay)
}

/// Take a screenshot from all accessible outputs.
Expand Down
6 changes: 3 additions & 3 deletions libwayshot/src/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl EmbeddedRegion {
};

Some(Self {
relative_to: relative_to,
relative_to,
inner: Region {
position: Position { x: x1, y: y1 },
size: Size { width, height },
Expand Down Expand Up @@ -195,10 +195,10 @@ impl From<&OutputInfo> for LogicalRegion {
}
}

impl TryFrom<&Vec<OutputInfo>> for LogicalRegion {
impl TryFrom<&[OutputInfo]> for LogicalRegion {
type Error = Error;

fn try_from(output_info: &Vec<OutputInfo>) -> std::result::Result<Self, Self::Error> {
fn try_from(output_info: &[OutputInfo]) -> std::result::Result<Self, Self::Error> {
let x1 = output_info
.iter()
.map(|output| output.logical_region.inner.position.x)
Expand Down
5 changes: 5 additions & 0 deletions wayshot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@ image = { version = "0.24", default-features = false, features = [
"png",
"pnm",
"qoi",
"webp-encoder",
] }

dialoguer = { version = "0.11.0", features = ["fuzzy-select"] }
eyre = "0.6.8"
chrono = "0.4.35"

wl-clipboard-rs = "0.8.0"
nix = { version = "0.28.0", features = ["process"] }

[[bin]]
name = "wayshot"
Expand Down
14 changes: 11 additions & 3 deletions wayshot/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ use clap::builder::TypedValueParser;
#[derive(Parser)]
#[command(version, about)]
pub struct Cli {
/// Where to save the screenshot, "-" for stdout. Defaults to "$UNIX_TIMESTAMP-wayshot.$EXTENSION".
#[arg(value_name = "OUTPUT")]
/// Custom output path can be of the following types:
/// 1. Directory (Default naming scheme is used for the image output).
/// 2. Path (Encoding is automatically inferred from the extension).
/// 3. `-` (Indicates writing to terminal [stdout]).
#[arg(value_name = "OUTPUT", verbatim_doc_comment)]
pub file: Option<PathBuf>,

/// Copy image to clipboard. Can be used simultaneously with [OUTPUT] or stdout.
/// Wayshot persists in the background offering the image till the clipboard is overwritten.
#[arg(long, verbatim_doc_comment)]
pub clipboard: bool,

/// Log level to be used for printing to stderr
#[arg(long, default_value = "info", value_parser = clap::builder::PossibleValuesParser::new(["trace", "debug", "info", "warn", "error"]).map(|s| -> tracing::Level{ s.parse().wrap_err_with(|| format!("Failed to parse log level: {}", s)).unwrap()}))]
pub log_level: tracing::Level,
Expand All @@ -29,7 +37,7 @@ pub struct Cli {

/// Set image encoder, by default uses the file extension from the OUTPUT
/// positional argument. Otherwise defaults to png.
#[arg(long, visible_aliases = ["extension", "format", "output-format"], value_name = "FILE_EXTENSION")]
#[arg(long, verbatim_doc_comment, visible_aliases = ["extension", "format", "output-format"], value_name = "FILE_EXTENSION")]
pub encoding: Option<EncodingFormat>,

/// List all valid outputs
Expand Down
20 changes: 9 additions & 11 deletions wayshot/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
use clap::ValueEnum;
use eyre::{bail, ContextCompat, Error, Result};

use std::{
fmt::Display,
path::PathBuf,
str::FromStr,
time::{SystemTime, UNIX_EPOCH},
};
use std::{fmt::Display, path::PathBuf, str::FromStr};

use chrono::{DateTime, Local};
use libwayshot::region::{LogicalRegion, Position, Region, Size};

pub fn parse_geometry(g: &str) -> Result<LogicalRegion> {
Expand Down Expand Up @@ -62,6 +58,8 @@ pub enum EncodingFormat {
Ppm,
/// Qut encoder.
Qoi,
/// WebP encoder,
Webp,
}

impl Default for EncodingFormat {
Expand All @@ -77,6 +75,7 @@ impl From<EncodingFormat> for image::ImageOutputFormat {
EncodingFormat::Png => image::ImageFormat::Png.into(),
EncodingFormat::Ppm => image::ImageFormat::Pnm.into(),
EncodingFormat::Qoi => image::ImageFormat::Qoi.into(),
EncodingFormat::Webp => image::ImageFormat::WebP.into(),
}
}
}
Expand Down Expand Up @@ -115,6 +114,7 @@ impl From<EncodingFormat> for &str {
EncodingFormat::Png => "png",
EncodingFormat::Ppm => "ppm",
EncodingFormat::Qoi => "qoi",
EncodingFormat::Webp => "webp",
}
}
}
Expand All @@ -134,10 +134,8 @@ impl FromStr for EncodingFormat {
}

pub fn get_default_file_name(extension: EncodingFormat) -> PathBuf {
let time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|time| time.as_secs().to_string())
.unwrap_or("unknown".into());
let current_datetime: DateTime<Local> = Local::now();
let formated_time = format!("{}", current_datetime.format("%Y_%m_%d-%H_%M_%S"));

format!("{time}-wayshot.{extension}").into()
format!("wayshot-{formated_time}.{extension}").into()
}
Loading

0 comments on commit 2ca3cc3

Please sign in to comment.