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(e: xcap::XCapError) -> Error {
Error::Capture(e.to_string())
}
pub struct XCapCapture {
monitor: xcap::Monitor,
}
impl XCapCapture {
pub fn primary() -> Result<Self> {
let monitors = xcap::Monitor::all().map_err(xcap_err)?;
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".into()))?;
Ok(XCapCapture { monitor })
}
pub fn from_point(x: i32, y: i32) -> Result<Self> {
Ok(XCapCapture {
monitor: xcap::Monitor::from_point(x, y).map_err(xcap_err)?,
})
}
pub fn monitor_count() -> Result<usize> {
Ok(xcap::Monitor::all().map_err(xcap_err)?.len())
}
}
impl Capture for XCapCapture {
fn grab(&mut self) -> Result<Frame> {
let img = self.monitor.capture_image().map_err(xcap_err)?;
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(xcap_err)? != 0 || self.monitor.y().map_err(xcap_err)? != 0 {
return Ok(None);
}
let (mw, mh) = (
self.monitor.width().map_err(xcap_err)? as u64,
self.monitor.height().map_err(xcap_err)? 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(xcap_err)?;
Ok(Some(Frame::rgba8(
img.width() as usize,
img.height() as usize,
img.into_raw(),
)))
}
fn backend(&self) -> &'static str {
"xcap"
}
}