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}