use crate::{quartz, Pixfmt}; use std::marker::PhantomData; use std::sync::{Arc, Mutex, TryLockError}; use std::{io, mem}; pub struct Capturer { inner: quartz::Capturer, frame: Arc>>, saved_raw_data: Vec, // for faster compare and copy } impl Capturer { pub fn new(display: Display) -> io::Result { let frame = Arc::new(Mutex::new(None)); let f = frame.clone(); let inner = quartz::Capturer::new( display.0, display.width(), display.height(), quartz::PixelFormat::Argb8888, Default::default(), move |inner| { if let Ok(mut f) = f.lock() { *f = Some(inner); } }, ) .map_err(|_| io::Error::from(io::ErrorKind::Other))?; Ok(Capturer { inner, frame, saved_raw_data: Vec::new(), }) } pub fn width(&self) -> usize { self.inner.width() } pub fn height(&self) -> usize { self.inner.height() } } impl crate::TraitCapturer for Capturer { fn frame<'a>(&'a mut self, _timeout_ms: std::time::Duration) -> io::Result> { match self.frame.try_lock() { Ok(mut handle) => { let mut frame = None; mem::swap(&mut frame, &mut handle); match frame { Some(mut frame) => { crate::would_block_if_equal(&mut self.saved_raw_data, frame.inner())?; frame.surface_to_bgra(self.height()); Ok(Frame { frame, data: PhantomData, width: self.width(), height: self.height(), }) } None => Err(io::ErrorKind::WouldBlock.into()), } } Err(TryLockError::WouldBlock) => Err(io::ErrorKind::WouldBlock.into()), Err(TryLockError::Poisoned(..)) => Err(io::ErrorKind::Other.into()), } } } pub struct Frame<'a> { frame: quartz::Frame, data: PhantomData<&'a [u8]>, width: usize, height: usize, } impl<'a> crate::TraitFrame for Frame<'a> { fn data(&self) -> &[u8] { &*self.frame } fn width(&self) -> usize { self.width } fn height(&self) -> usize { self.height } fn stride(&self) -> Vec { let mut v = Vec::new(); v.push(self.frame.stride()); v } fn pixfmt(&self) -> Pixfmt { Pixfmt::BGRA } } pub struct Display(quartz::Display); impl Display { pub fn primary() -> io::Result { Ok(Display(quartz::Display::primary())) } pub fn all() -> io::Result> { Ok(quartz::Display::online() .map_err(|_| io::Error::from(io::ErrorKind::Other))? .into_iter() .map(Display) .collect()) } pub fn width(&self) -> usize { self.0.width() } pub fn height(&self) -> usize { self.0.height() } pub fn name(&self) -> String { self.0.id().to_string() } pub fn is_online(&self) -> bool { self.0.is_online() } pub fn origin(&self) -> (i32, i32) { let o = self.0.bounds().origin; (o.x as _, o.y as _) } pub fn is_primary(&self) -> bool { self.0.is_primary() } }