screencapturekit/shareable_content/
display.rs

1use crate::cg::CGRect;
2use core::fmt;
3use std::ffi::c_void;
4
5/// Opaque wrapper around `SCDisplay` from `ScreenCaptureKit`
6///
7/// Represents a physical or virtual display that can be captured.
8///
9/// # Examples
10///
11/// ```no_run
12/// use screencapturekit::shareable_content::SCShareableContent;
13///
14/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
15/// let content = SCShareableContent::get()?;
16/// for display in content.displays() {
17///     println!("Display {}: {}x{}",
18///         display.display_id(),
19///         display.width(),
20///         display.height()
21///     );
22/// }
23/// # Ok(())
24/// # }
25/// ```
26#[repr(transparent)]
27pub struct SCDisplay(*const c_void);
28
29impl PartialEq for SCDisplay {
30    fn eq(&self, other: &Self) -> bool {
31        self.0 == other.0
32    }
33}
34
35impl Eq for SCDisplay {}
36
37impl std::hash::Hash for SCDisplay {
38    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
39        self.0.hash(state);
40    }
41}
42
43impl SCDisplay {
44    /// Create from raw pointer (used internally by shareable content)
45    pub(crate) unsafe fn from_ptr(ptr: *const c_void) -> Self {
46        Self(ptr)
47    }
48
49    /// Create from FFI-owned pointer (caller transfers ownership)
50    #[allow(dead_code)]
51    pub(crate) fn from_ffi_owned(ptr: *const c_void) -> Self {
52        Self(ptr)
53    }
54
55    /// Get the raw pointer (used internally)
56    pub(crate) fn as_ptr(&self) -> *const c_void {
57        self.0
58    }
59
60    /// Get display ID
61    ///
62    /// # Examples
63    ///
64    /// ```no_run
65    /// # use screencapturekit::shareable_content::SCShareableContent;
66    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
67    /// let content = SCShareableContent::get()?;
68    /// if let Some(display) = content.displays().first() {
69    ///     println!("Display ID: {}", display.display_id());
70    /// }
71    /// # Ok(())
72    /// # }
73    /// ```
74    pub fn display_id(&self) -> u32 {
75        unsafe { crate::ffi::sc_display_get_display_id(self.0) }
76    }
77
78    /// Get display frame (position and size)
79    pub fn frame(&self) -> CGRect {
80        let mut x = 0.0;
81        let mut y = 0.0;
82        let mut width = 0.0;
83        let mut height = 0.0;
84        unsafe {
85            crate::ffi::sc_display_get_frame_packed(
86                self.0,
87                &mut x,
88                &mut y,
89                &mut width,
90                &mut height,
91            );
92        }
93        CGRect::new(x, y, width, height)
94    }
95
96    /// Get display height in pixels
97    ///
98    /// # Examples
99    ///
100    /// ```no_run
101    /// # use screencapturekit::shareable_content::SCShareableContent;
102    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
103    /// let content = SCShareableContent::get()?;
104    /// if let Some(display) = content.displays().first() {
105    ///     println!("Display resolution: {}x{}", display.width(), display.height());
106    /// }
107    /// # Ok(())
108    /// # }
109    /// ```
110    pub fn height(&self) -> u32 {
111        // FFI returns isize but display dimensions are always positive and fit in u32
112        #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
113        unsafe {
114            crate::ffi::sc_display_get_height(self.0) as u32
115        }
116    }
117
118    /// Get display width in pixels
119    pub fn width(&self) -> u32 {
120        // FFI returns isize but display dimensions are always positive and fit in u32
121        #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
122        unsafe {
123            crate::ffi::sc_display_get_width(self.0) as u32
124        }
125    }
126}
127
128impl Drop for SCDisplay {
129    fn drop(&mut self) {
130        if !self.0.is_null() {
131            unsafe {
132                crate::ffi::sc_display_release(self.0);
133            }
134        }
135    }
136}
137
138impl Clone for SCDisplay {
139    fn clone(&self) -> Self {
140        unsafe { Self(crate::ffi::sc_display_retain(self.0)) }
141    }
142}
143
144unsafe impl Send for SCDisplay {}
145unsafe impl Sync for SCDisplay {}
146
147impl fmt::Debug for SCDisplay {
148    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149        f.debug_struct("SCDisplay")
150            .field("display_id", &self.display_id())
151            .field("width", &self.width())
152            .field("height", &self.height())
153            .finish()
154    }
155}
156
157impl fmt::Display for SCDisplay {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        write!(
160            f,
161            "Display {} ({}x{})",
162            self.display_id(),
163            self.width(),
164            self.height()
165        )
166    }
167}