use crate::{api, arc, cg, define_obj_type, ns, objc, ut};
#[cfg(feature = "blocks")]
use crate::blocks;
#[cfg(feature = "blocks")]
use crate::sc;
#[cfg(all(feature = "blocks", feature = "cm"))]
use crate::cm;
define_obj_type!(
#[doc(alias = "SCScreenshotConfiguration")]
pub ScreenshotCfg(ns::Id),
SC_SCREENSHOT_CONFIGURATION,
#[api::available(macos = 26.0, maccatalyst = 26.0)]
);
#[doc(alias = "SCScreenshotDisplayIntent")]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(isize)]
pub enum DisplayIntent {
#[doc(alias = "SCScreenshotDisplayIntentCanonical")]
Canonical,
#[doc(alias = "SCScreenshotDisplayIntentLocal")]
Local,
}
#[doc(alias = "SCScreenshotDynamicRange")]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(isize)]
pub enum DynamicRange {
#[doc(alias = "SCScreenshotDynamicRangeSDR")]
Sdr,
#[doc(alias = "SCScreenshotDynamicRangeHDR")]
Hdr,
#[doc(alias = "SCScreenshotDynamicRangeSDRAndHDR")]
SdrAndHdr,
}
impl ScreenshotCfg {
#[objc::msg_send(width)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn width(&self) -> ns::Integer;
#[objc::msg_send(setWidth:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_width(&mut self, val: ns::Integer);
#[objc::msg_send(height)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn height(&self) -> ns::Integer;
#[objc::msg_send(setHeight:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_height(&mut self, val: ns::Integer);
#[objc::msg_send(showsCursor)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn shows_cursor(&self) -> bool;
#[objc::msg_send(setShowsCursor:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_shows_cursor(&mut self, val: bool);
#[objc::msg_send(sourceRect)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn src_rect(&self) -> cg::Rect;
#[objc::msg_send(setSourceRect:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_src_rect(&mut self, val: cg::Rect);
#[objc::msg_send(destinationRect)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn dst_rect(&self) -> cg::Rect;
#[objc::msg_send(setDestinationRect:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_dst_rect(&mut self, val: cg::Rect);
#[objc::msg_send(ignoreShadows)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn ignore_shadows(&self) -> bool;
#[objc::msg_send(setIgnoreShadows:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_ignore_shadows(&mut self, val: bool);
#[objc::msg_send(ignoreClipping)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn ignore_clipping(&self) -> bool;
#[objc::msg_send(setIgnoreClipping:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_ignore_clipping(&mut self, val: bool);
#[objc::msg_send(includeChildWindows)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn include_child_windows(&self) -> bool;
#[objc::msg_send(setIncludeChildWindows:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_include_child_windows(&mut self, val: bool);
#[objc::msg_send(displayIntent)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn display_intent(&self) -> DisplayIntent;
#[objc::msg_send(setDisplayIntent:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_display_intent(&mut self, val: DisplayIntent);
#[objc::msg_send(dynamicRange)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn dynamic_range(&self) -> DynamicRange;
#[objc::msg_send(setDynamicRange:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_dynamic_range(&mut self, val: DynamicRange);
#[objc::msg_send(contentType)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn content_type(&self) -> arc::R<ut::Type>;
#[objc::msg_send(setContentType:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_content_type(&mut self, val: &ut::Type);
#[objc::msg_send(fileURL)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn file_url(&self) -> Option<arc::R<ns::Url>>;
#[objc::msg_send(setFileURL:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_file_url(&mut self, val: Option<&ns::Url>);
#[objc::msg_send(supportedContentTypes)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn supported_content_types() -> arc::R<ns::Array<ut::Type>>;
}
define_obj_type!(
#[doc(alias = "SCScreenshotOutput")]
pub ScreenshotOutput(ns::Id),
SC_SCREENSHOT_OUTPUT,
#[api::available(macos = 26.0, maccatalyst = 26.0)]
);
impl ScreenshotOutput {
#[objc::msg_send(sdrImage)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn sdr_image(&self) -> Option<&cg::Image>;
#[objc::msg_send(setSdrImage:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_sdr_image(&mut self, val: Option<&cg::Image>);
#[objc::msg_send(hdrImage)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn hdr_image(&self) -> Option<&cg::Image>;
#[objc::msg_send(setHdrImage:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn set_hdr_image(&mut self, val: Option<&cg::Image>);
#[objc::msg_send(fileURL)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn file_url(&self) -> Option<arc::R<ns::Url>>;
}
define_obj_type!(
#[doc(alias = "SCScreenshotManager")]
pub ScreenshotManager(ns::Id)
);
impl ScreenshotManager {
#[api::available(macos = 14.0)]
crate::define_cls!(SC_SCREENSHOT_MANAGER);
#[cfg(all(feature = "blocks", feature = "cm"))]
#[objc::msg_send(captureSampleBufferWithFilter:configuration:completionHandler:)]
#[api::available(macos = 14.0)]
pub fn capture_sample_buf_ch(
filter: &sc::ContentFilter,
cfg: &sc::StreamCfg,
handler: Option<&mut blocks::ResultCh<cm::SampleBuf>>,
);
#[cfg(all(feature = "blocks", feature = "async", feature = "cm"))]
#[api::available(macos = 14.0)]
pub async fn capture_sample_buf(
filter: &sc::ContentFilter,
cfg: &sc::StreamCfg,
) -> Result<arc::R<cm::SampleBuf>, arc::R<ns::Error>> {
let (future, mut block) = blocks::result();
Self::capture_sample_buf_ch(filter, cfg, Some(&mut block));
future.await
}
#[cfg(feature = "blocks")]
#[objc::msg_send(captureImageWithFilter:configuration:completionHandler:)]
#[api::available(macos = 14.0)]
pub fn capture_image_ch(
filter: &sc::ContentFilter,
cfg: &sc::StreamCfg,
handler: Option<&mut blocks::ResultCh<cg::Image>>,
);
#[cfg(all(feature = "blocks", feature = "async"))]
#[api::available(macos = 14.0)]
pub async fn capture_image(
filter: &sc::ContentFilter,
cfg: &sc::StreamCfg,
) -> Result<arc::R<cg::Image>, arc::R<ns::Error>> {
let (future, mut block) = blocks::result();
Self::capture_image_ch(filter, cfg, Some(&mut block));
future.await
}
#[cfg(feature = "blocks")]
#[objc::msg_send(captureImageInRect:completionHandler:)]
#[api::available(macos = 15.2)]
pub fn capture_image_in_rect_ch(
rect: cg::Rect,
handler: Option<&mut blocks::ResultCh<cg::Image>>,
);
#[cfg(all(feature = "blocks", feature = "async"))]
#[api::available(macos = 15.2)]
#[allow(unused_unsafe)]
pub async fn capture_image_in_rect(
rect: cg::Rect,
) -> Result<arc::R<cg::Image>, arc::R<ns::Error>> {
let (future, mut block) = blocks::result();
unsafe { Self::capture_image_in_rect_ch(rect, Some(&mut block)) };
future.await
}
#[cfg(feature = "blocks")]
#[objc::msg_send(captureScreenshotWithFilter:configuration:completionHandler:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn capture_screenshot_ch(
filter: &sc::ContentFilter,
cfg: &ScreenshotCfg,
handler: Option<&mut blocks::ResultCh<ScreenshotOutput>>,
);
#[cfg(all(feature = "blocks", feature = "async"))]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub async fn capture_screenshot(
filter: &sc::ContentFilter,
cfg: &ScreenshotCfg,
) -> Result<arc::R<ScreenshotOutput>, arc::R<ns::Error>> {
let (future, mut block) = blocks::result();
#[cfg(any(feature = "macos_26_0", feature = "maccatalyst_26_0"))]
{
Self::capture_screenshot_ch(filter, cfg, Some(&mut block));
}
#[cfg(not(any(feature = "macos_26_0", feature = "maccatalyst_26_0")))]
{
unsafe { Self::capture_screenshot_ch(filter, cfg, Some(&mut block)) };
}
future.await
}
#[cfg(feature = "blocks")]
#[objc::msg_send(captureScreenshotWithRect:configuration:completionHandler:)]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub fn capture_screenshot_in_rect_ch(
rect: cg::Rect,
cfg: &ScreenshotCfg,
handler: Option<&mut blocks::ResultCh<ScreenshotOutput>>,
);
#[cfg(all(feature = "blocks", feature = "async"))]
#[api::available(macos = 26.0, maccatalyst = 26.0)]
pub async fn capture_screenshot_in_rect(
rect: cg::Rect,
cfg: &ScreenshotCfg,
) -> Result<arc::R<ScreenshotOutput>, arc::R<ns::Error>> {
let (future, mut block) = blocks::result();
#[cfg(any(feature = "macos_26_0", feature = "maccatalyst_26_0"))]
{
Self::capture_screenshot_in_rect_ch(rect, cfg, Some(&mut block));
}
#[cfg(not(any(feature = "macos_26_0", feature = "maccatalyst_26_0")))]
{
unsafe { Self::capture_screenshot_in_rect_ch(rect, cfg, Some(&mut block)) };
}
future.await
}
}
unsafe extern "C" {
static SC_SCREENSHOT_MANAGER: &'static objc::Class<ScreenshotManager>;
static SC_SCREENSHOT_CONFIGURATION: &'static objc::Class<ScreenshotCfg>;
static SC_SCREENSHOT_OUTPUT: &'static objc::Class<ScreenshotOutput>;
}
#[cfg(test)]
mod tests {
use crate::{ns, sc};
#[tokio::test]
async fn basics() {
let content = sc::ShareableContent::current_process().await.unwrap();
let displays = content.displays();
let display = displays.first().unwrap();
let filter = sc::ContentFilter::with_display_excluding_windows(&display, &ns::Array::new());
let cfg = sc::StreamCfg::new();
let buf = sc::ScreenshotManager::capture_sample_buf(&filter, &cfg)
.await
.unwrap();
let image_buf = buf.image_buf().unwrap();
assert!(image_buf.width() > 0);
assert!(image_buf.height() > 0);
let image = sc::ScreenshotManager::capture_image(&filter, &cfg)
.await
.unwrap();
assert!(image.width() > 0);
assert!(image.height() > 0);
}
}