screencapturekit/shareable_content/
window.rs1use crate::cg::CGRect;
2use crate::utils::ffi_string::ffi_string_owned;
3use core::fmt;
4use std::ffi::c_void;
5
6use super::SCRunningApplication;
7
8#[repr(transparent)]
28pub struct SCWindow(*const c_void);
29
30impl PartialEq for SCWindow {
31 fn eq(&self, other: &Self) -> bool {
32 self.0 == other.0
33 }
34}
35
36impl Eq for SCWindow {}
37
38impl std::hash::Hash for SCWindow {
39 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
40 self.0.hash(state);
41 }
42}
43
44impl SCWindow {
45 pub(crate) unsafe fn from_ptr(ptr: *const c_void) -> Self {
47 Self(ptr)
48 }
49
50 #[allow(dead_code)]
52 pub(crate) fn from_ffi_owned(ptr: *const c_void) -> Self {
53 Self(ptr)
54 }
55
56 pub(crate) fn as_ptr(&self) -> *const c_void {
58 self.0
59 }
60
61 pub fn owning_application(&self) -> Option<SCRunningApplication> {
63 unsafe {
64 let app_ptr = crate::ffi::sc_window_get_owning_application(self.0);
65 if app_ptr.is_null() {
66 None
67 } else {
68 Some(SCRunningApplication::from_ptr(app_ptr))
69 }
70 }
71 }
72
73 pub fn window_id(&self) -> u32 {
75 unsafe { crate::ffi::sc_window_get_window_id(self.0) }
76 }
77
78 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_window_get_frame_packed(self.0, &mut x, &mut y, &mut width, &mut height);
86 }
87 CGRect::new(x, y, width, height)
88 }
89
90 pub fn title(&self) -> Option<String> {
92 unsafe { ffi_string_owned(|| crate::ffi::sc_window_get_title_owned(self.0)) }
93 }
94
95 pub fn window_layer(&self) -> i32 {
97 #[allow(clippy::cast_possible_truncation)]
99 unsafe {
100 crate::ffi::sc_window_get_window_layer(self.0) as i32
101 }
102 }
103
104 pub fn is_on_screen(&self) -> bool {
106 unsafe { crate::ffi::sc_window_is_on_screen(self.0) }
107 }
108
109 #[cfg(feature = "macos_13_0")]
115 pub fn is_active(&self) -> bool {
116 unsafe { crate::ffi::sc_window_is_active(self.0) }
117 }
118}
119
120impl Drop for SCWindow {
121 fn drop(&mut self) {
122 if !self.0.is_null() {
123 unsafe {
124 crate::ffi::sc_window_release(self.0);
125 }
126 }
127 }
128}
129
130impl Clone for SCWindow {
131 fn clone(&self) -> Self {
132 unsafe { Self(crate::ffi::sc_window_retain(self.0)) }
133 }
134}
135
136impl fmt::Debug for SCWindow {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 let mut debug = f.debug_struct("SCWindow");
139 debug
140 .field("window_id", &self.window_id())
141 .field("title", &self.title())
142 .field("frame", &self.frame())
143 .field("window_layer", &self.window_layer())
144 .field("is_on_screen", &self.is_on_screen());
145 #[cfg(feature = "macos_13_0")]
146 debug.field("is_active", &self.is_active());
147 debug.finish()
148 }
149}
150
151impl fmt::Display for SCWindow {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(
154 f,
155 "Window {} \"{}\" ({})",
156 self.window_id(),
157 self.title().unwrap_or_else(|| String::from("<untitled>")),
158 self.frame()
159 )
160 }
161}
162
163unsafe impl Send for SCWindow {}
164unsafe impl Sync for SCWindow {}