use crate::{arc, cf, cg, define_cf_type};
#[cfg(all(feature = "io_surface", any(feature = "blocks", feature = "dispatch")))]
use crate::io;
#[cfg(all(feature = "blocks", feature = "io_surface"))]
use crate::blocks;
#[cfg(all(feature = "dispatch", feature = "io_surface"))]
use crate::dispatch;
define_cf_type!(
#[doc(alias = "CGDisplayStream")]
#[doc(alias = "CGDisplayStreamRef")]
DisplayStream(cf::Type)
);
define_cf_type!(
#[doc(alias = "CGDisplayStreamUpdate")]
#[doc(alias = "CGDisplayStreamUpdateRef")]
Update(cf::Type)
);
#[doc(alias = "CGDisplayStreamUpdateRectType")]
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[repr(i32)]
pub enum UpdateRectType {
RefreshedRects,
MovedRects,
DirtyRects,
ReducedDirtyRects,
}
#[doc(alias = "CGDisplayStreamFrameStatus")]
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[repr(i32)]
pub enum FrameStatus {
FrameComplete,
FrameIdle,
FrameBlank,
StatusStopped,
}
#[doc(alias = "CGDisplayStreamFrameAvailableHandler")]
#[cfg(all(feature = "blocks", feature = "io_surface"))]
pub type FrameAvailableHandler<Attr> =
blocks::Block<fn(FrameStatus, u64, Option<&io::Surf>, Option<&Update>), Attr>;
impl Update {
#[inline]
pub fn type_id() -> cf::TypeId {
unsafe { CGDisplayStreamUpdateGetTypeID() }
}
#[inline]
pub fn merged(first: Option<&Self>, second: Option<&Self>) -> Option<arc::R<Self>> {
unsafe { CGDisplayStreamUpdateCreateMergedUpdate(first, second) }
}
pub unsafe fn get_rects(
&self,
rect_type: UpdateRectType,
rect_count: *mut usize,
) -> *const cg::Rect {
unsafe { CGDisplayStreamUpdateGetRects(self, rect_type, rect_count) }
}
pub unsafe fn moved_rect_delta(&self, x: *mut cg::Float, y: *mut cg::Float) {
unsafe { CGDisplayStreamUpdateGetMovedRectsDelta(self, x, y) }
}
#[inline]
pub fn drop_count(&self) -> usize {
unsafe { CGDisplayStreamUpdateGetDropCount(self) }
}
}
define_cf_type!(PropKey(cf::String));
impl PropKey {
pub fn source_rect() -> &'static Self {
unsafe { kCGDisplayStreamSourceRect }
}
pub fn destination_rect() -> &'static Self {
unsafe { kCGDisplayStreamDestinationRect }
}
pub fn preserve_aspect_ratio() -> &'static Self {
unsafe { kCGDisplayStreamPreserveAspectRatio }
}
pub fn color_space() -> &'static Self {
unsafe { kCGDisplayStreamColorSpace }
}
pub fn minimum_frame_rate() -> &'static Self {
unsafe { kCGDisplayStreamMinimumFrameTime }
}
pub fn show_cursor() -> &'static Self {
unsafe { kCGDisplayStreamShowCursor }
}
pub fn queue_depth() -> &'static Self {
unsafe { kCGDisplayStreamQueueDepth }
}
pub fn ycbcr_matric() -> &'static Self {
unsafe { kCGDisplayStreamYCbCrMatrix }
}
}
define_cf_type!(YCbCrMatrix(cf::String));
impl YCbCrMatrix {
pub fn itu_r_709_2() -> &'static Self {
unsafe { kCGDisplayStreamYCbCrMatrix_ITU_R_709_2 }
}
pub fn itu_r_601_4() -> &'static Self {
unsafe { kCGDisplayStreamYCbCrMatrix_ITU_R_601_4 }
}
pub fn smpte_240m_1995() -> &'static Self {
unsafe { kCGDisplayStreamYCbCrMatrix_SMPTE_240M_1995 }
}
}
impl DisplayStream {
#[inline]
pub fn type_id() -> cf::TypeId {
unsafe { CGDisplayStreamGetTypeID() }
}
#[cfg(all(feature = "blocks", feature = "io_surface"))]
pub fn with_runloop(
display: cg::DirectDisplayId,
output_width: usize,
output_height: usize,
pixel_format: i32,
properties: Option<&cf::DictionaryOf<PropKey, cf::Plist>>,
handler: Option<&mut FrameAvailableHandler<blocks::Esc>>,
) -> Option<arc::R<DisplayStream>> {
unsafe {
CGDisplayStreamCreate(
display,
output_width,
output_height,
pixel_format,
properties,
handler,
)
}
}
#[cfg(all(feature = "blocks", feature = "dispatch", feature = "io_surface"))]
pub fn with_dispatch_queue(
display: cg::DirectDisplayId,
output_width: usize,
output_height: usize,
pixel_format: i32,
properties: Option<&cf::DictionaryOf<PropKey, cf::Plist>>,
queue: &dispatch::Queue,
handler: Option<&mut FrameAvailableHandler<blocks::Esc>>,
) -> Option<arc::R<DisplayStream>> {
unsafe {
CGDisplayStreamCreateWithDispatchQueue(
display,
output_width,
output_height,
pixel_format,
properties,
queue,
handler,
)
}
}
#[inline]
pub unsafe fn stream_start(&self) -> cg::Status {
unsafe { CGDisplayStreamStart(self) }
}
pub fn start(&self) -> Result<(), cg::Error> {
unsafe { self.stream_start().result() }
}
#[inline]
pub unsafe fn stream_stop(&self) -> cg::Status {
unsafe { CGDisplayStreamStop(self) }
}
pub fn stop(&self) -> Result<(), cg::Error> {
unsafe { self.stream_stop().result() }
}
#[inline]
pub fn run_loop_source(&self) -> Option<&cf::RunLoop> {
unsafe { CGDisplayStreamGetRunLoopSource(self) }
}
}
unsafe extern "C-unwind" {
fn CGDisplayStreamUpdateGetTypeID() -> cf::TypeId;
fn CGDisplayStreamUpdateGetRects(
update_ref: &Update,
rect_type: UpdateRectType,
rect_count: *mut usize,
) -> *const cg::Rect;
fn CGDisplayStreamUpdateCreateMergedUpdate(
first: Option<&Update>,
second: Option<&Update>,
) -> Option<arc::R<Update>>;
fn CGDisplayStreamUpdateGetMovedRectsDelta(
update_ref: &Update,
x: *mut cg::Float,
y: *mut cg::Float,
);
fn CGDisplayStreamUpdateGetDropCount(update_ref: &Update) -> usize;
static kCGDisplayStreamSourceRect: &'static PropKey;
static kCGDisplayStreamDestinationRect: &'static PropKey;
static kCGDisplayStreamPreserveAspectRatio: &'static PropKey;
static kCGDisplayStreamColorSpace: &'static PropKey;
static kCGDisplayStreamMinimumFrameTime: &'static PropKey;
static kCGDisplayStreamShowCursor: &'static PropKey;
static kCGDisplayStreamQueueDepth: &'static PropKey;
static kCGDisplayStreamYCbCrMatrix: &'static PropKey;
static kCGDisplayStreamYCbCrMatrix_ITU_R_709_2: &'static YCbCrMatrix;
static kCGDisplayStreamYCbCrMatrix_ITU_R_601_4: &'static YCbCrMatrix;
static kCGDisplayStreamYCbCrMatrix_SMPTE_240M_1995: &'static YCbCrMatrix;
fn CGDisplayStreamGetTypeID() -> cf::TypeId;
#[cfg(all(feature = "blocks", feature = "io_surface"))]
fn CGDisplayStreamCreate(
display: cg::DirectDisplayId,
output_width: usize,
output_height: usize,
pixel_format: i32,
properties: Option<&cf::DictionaryOf<PropKey, cf::Plist>>,
handler: Option<&mut FrameAvailableHandler<blocks::Esc>>,
) -> Option<arc::R<DisplayStream>>;
#[cfg(all(feature = "dispatch", feature = "blocks", feature = "io_surface"))]
fn CGDisplayStreamCreateWithDispatchQueue(
display: cg::DirectDisplayId,
output_width: usize,
output_height: usize,
pixel_format: i32,
properties: Option<&cf::DictionaryOf<PropKey, cf::Plist>>,
queue: &dispatch::Queue,
handler: Option<&mut FrameAvailableHandler<blocks::Esc>>,
) -> Option<arc::R<DisplayStream>>;
fn CGDisplayStreamStart(stream: &DisplayStream) -> cg::Status;
fn CGDisplayStreamStop(stream: &DisplayStream) -> cg::Status;
fn CGDisplayStreamGetRunLoopSource(stream: &DisplayStream) -> Option<&cf::RunLoop>;
}
#[cfg(test)]
mod tests {
use std::{thread::sleep, time::Duration};
#[test]
#[cfg(all(feature = "blocks", feature = "io_surface", feature = "dispatch"))]
fn basics() {
use crate::{blocks, cg, dispatch};
let mut block = cg::DisplayStreamFrameAvailableHandler::<blocks::Esc>::new4(
|_frame_status, _timestamp, _surf, _update| {
eprint!(".");
},
);
let queue = dispatch::Queue::global(0).unwrap();
let stream = cg::DisplayStream::with_dispatch_queue(
cg::DirectDisplayId::main(),
640,
480,
i32::from_be_bytes(*b"420f"),
None,
queue,
Some(&mut block),
)
.unwrap();
stream.start().unwrap();
sleep(Duration::from_secs(1));
stream.stop().unwrap();
}
}