use crate::frame::{Frame, Rect};
use crate::{Error, Result};
pub trait Capture {
fn grab(&mut self) -> Result<Frame>;
fn grab_into(&mut self, dst: &mut Frame) -> Result<bool> {
*dst = self.grab()?;
Ok(true)
}
fn grab_region(&mut self, rect: Rect) -> Result<Option<Frame>> {
let _ = rect;
Ok(None)
}
fn backend(&self) -> &'static str {
"unknown"
}
}
fn xcap_err(step: impl Into<String>, e: xcap::XCapError) -> Error {
Error::capture_from(format!("xcap {}", step.into()), e)
}
pub struct XCapCapture {
monitor: xcap::Monitor,
}
impl XCapCapture {
pub fn primary() -> Result<Self> {
let monitors = xcap::Monitor::all().map_err(|e| xcap_err("Monitor::all()", e))?;
let monitor = monitors
.iter()
.find(|m| m.is_primary().unwrap_or(false))
.or_else(|| monitors.first())
.cloned()
.ok_or_else(|| Error::capture("no display found"))?;
Ok(XCapCapture { monitor })
}
pub fn from_point(x: i32, y: i32) -> Result<Self> {
Ok(XCapCapture {
monitor: xcap::Monitor::from_point(x, y)
.map_err(|e| xcap_err(format!("Monitor::from_point({x}, {y})"), e))?,
})
}
pub fn monitor_count() -> Result<usize> {
Ok(xcap::Monitor::all()
.map_err(|e| xcap_err("Monitor::all()", e))?
.len())
}
}
impl Capture for XCapCapture {
fn grab(&mut self) -> Result<Frame> {
let img = self
.monitor
.capture_image()
.map_err(|e| xcap_err("Monitor::capture_image()", e))?;
Ok(Frame::rgba8(
img.width() as usize,
img.height() as usize,
img.into_raw(),
))
}
fn grab_region(&mut self, rect: Rect) -> Result<Option<Frame>> {
if self.monitor.x().map_err(|e| xcap_err("Monitor::x()", e))? != 0
|| self.monitor.y().map_err(|e| xcap_err("Monitor::y()", e))? != 0
{
return Ok(None);
}
let (mw, mh) = (
self.monitor
.width()
.map_err(|e| xcap_err("Monitor::width()", e))? as u64,
self.monitor
.height()
.map_err(|e| xcap_err("Monitor::height()", e))? as u64,
);
let (x, y, w, h) = (
rect.x as u64,
rect.y as u64,
rect.width as u64,
rect.height as u64,
);
if w == 0 || h == 0 || x + w > mw || y + h > mh {
return Ok(None);
}
let img = self
.monitor
.capture_region(x as u32, y as u32, w as u32, h as u32)
.map_err(|e| xcap_err(format!("Monitor::capture_region({x}, {y}, {w}, {h})"), e))?;
Ok(Some(Frame::rgba8(
img.width() as usize,
img.height() as usize,
img.into_raw(),
)))
}
fn backend(&self) -> &'static str {
"xcap"
}
}