cidre/sc/
shareable_content.rs1use crate::{arc, cg, define_cls, define_obj_type, ns, objc, sc, sys};
2
3#[cfg(feature = "blocks")]
4use crate::blocks;
5
6#[doc(alias = "SCShareableContentStyle")]
7#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8#[repr(isize)]
9pub enum Style {
10 None,
12 Window,
14 Display,
16 Application,
18}
19
20define_obj_type!(
21 #[doc(alias = "SCRunningApplication")]
23 pub RunningApp(ns::Id)
24);
25
26impl RunningApp {
27 #[objc::msg_send(bundleIdentifier)]
29 pub fn bundle_id(&self) -> arc::R<ns::String>;
30
31 #[objc::msg_send(applicationName)]
33 pub fn app_name(&self) -> arc::R<ns::String>;
34
35 #[objc::msg_send(processID)]
37 pub fn process_id(&self) -> sys::Pid;
38}
39
40define_obj_type!(
41 #[doc(alias = "SCDisplay")]
43 pub Display(ns::Id)
44);
45
46impl Display {
47 #[objc::msg_send(displayID)]
49 pub fn display_id(&self) -> cg::DirectDisplayId;
50
51 #[objc::msg_send(width)]
53 pub fn width(&self) -> isize;
54
55 #[objc::msg_send(height)]
57 pub fn height(&self) -> isize;
58
59 #[objc::msg_send(frame)]
61 pub fn frame(&self) -> cg::Rect;
62}
63
64define_obj_type!(
65 #[doc(alias = "SCWindow")]
67 pub Window(ns::Id)
68);
69
70impl Window {
71 #[objc::msg_send(windowID)]
73 pub fn id(&self) -> cg::WindowId;
74
75 #[objc::msg_send(frame)]
77 pub fn frame(&self) -> cg::Rect;
78
79 #[objc::msg_send(title)]
81 pub fn title(&self) -> Option<arc::R<ns::String>>;
82
83 #[objc::msg_send(windowLayer)]
85 pub fn window_layer(&self) -> ns::Integer;
86
87 #[objc::msg_send(owningApplication)]
89 pub fn owning_app(&self) -> Option<arc::R<RunningApp>>;
90
91 #[objc::msg_send(isOnScreen)]
93 pub fn is_on_screen(&self) -> bool;
94
95 #[objc::msg_send(isActive)]
97 #[objc::available(macos = 13.1)]
98 pub fn is_active(&self) -> bool;
99}
100
101impl std::fmt::Display for Window {
102 #[cfg(not(all(target_os = "macos", feature = "macos_13_1")))]
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 f.debug_struct("Window")
105 .field("id", &self.id())
106 .field("frame", &self.frame())
107 .field("title", &self.title())
108 .field("is_on_screen", &self.is_on_screen())
109 .finish()
110 }
111 #[cfg(all(target_os = "macos", feature = "macos_13_1"))]
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 f.debug_struct("Window")
114 .field("id", &self.id())
115 .field("frame", &self.frame())
116 .field("title", &self.title())
117 .field("is_on_screen", &self.is_on_screen())
118 .field("is_active", &self.is_active())
119 .finish()
120 }
121}
122
123unsafe extern "C" {
124 static SC_SHAREABLE_CONTENT: &'static objc::Class<ShareableContent>;
125}
126
127define_obj_type!(
128 #[doc(alias = "SCShareableContent")]
130 pub ShareableContent(ns::Id)
131);
132
133unsafe impl Send for ShareableContent {}
134
135impl ShareableContent {
136 define_cls!(SC_SHAREABLE_CONTENT);
137
138 #[objc::msg_send(windows)]
140 pub fn windows(&self) -> arc::R<ns::Array<Window>>;
141
142 #[objc::msg_send(displays)]
144 pub fn displays(&self) -> arc::R<ns::Array<Display>>;
145
146 #[objc::msg_send(applications)]
148 pub fn apps(&self) -> arc::R<ns::Array<RunningApp>>;
149
150 #[cfg(feature = "blocks")]
151 #[objc::msg_send(getShareableContentWithCompletionHandler:)]
153 pub fn current_with_ch_block(block: &mut blocks::ResultCh<Self>);
154
155 #[cfg(feature = "blocks")]
156 pub fn current_with_ch(f: impl FnMut(Option<&Self>, Option<&ns::Error>) + 'static) {
158 let mut block = blocks::ResultCh::new2(f);
159 Self::current_with_ch_block(&mut block);
160 }
161
162 #[cfg(all(feature = "blocks", feature = "async"))]
163 pub async fn current() -> Result<arc::R<Self>, arc::R<ns::Error>> {
165 let (future, mut block) = blocks::result();
166 Self::current_with_ch_block(&mut block);
167 future.await
168 }
169
170 #[cfg(feature = "blocks")]
171 #[objc::msg_send(getCurrentProcessShareableContentWithCompletionHandler:)]
173 pub fn current_process_with_ch(block: &mut blocks::ResultCh<Self>);
174
175 #[cfg(all(feature = "blocks", feature = "async"))]
176 pub async fn current_process() -> Result<arc::R<Self>, arc::R<ns::Error>> {
178 let (future, mut block) = blocks::result();
179 Self::current_process_with_ch(&mut block);
180 future.await
181 }
182
183 #[objc::msg_send(infoForFilter:)]
185 pub fn info_for_filter(filter: &sc::ContentFilter) -> arc::R<Info>;
186}
187
188define_obj_type!(
189 #[doc(alias = "SCShareableContentInfo")]
191 pub Info(ns::Id)
192);
193
194impl Info {
195 #[objc::msg_send(style)]
197 pub fn style(&self) -> Style;
198
199 #[objc::msg_send(pointPixelScale)]
201 pub fn point_pixel_scale(&self) -> f32;
202
203 #[objc::msg_send(contentRect)]
205 pub fn content_rect(&self) -> cg::Rect;
206}
207
208#[cfg(test)]
209mod tests {
210
211 use crate::{
212 blocks, define_obj_type, dispatch, objc,
213 sc::{
214 self,
215 stream::{Delegate, DelegateImpl, Output, OutputImpl},
216 },
217 };
218
219 use super::ShareableContent;
220
221 define_obj_type!(OutputObj + OutputImpl, usize, OUTPUT_CLS);
222
223 impl Output for OutputObj {}
224
225 #[objc::add_methods]
226 impl OutputImpl for OutputObj {}
227
228 define_obj_type!(DelegateObj + DelegateImpl, usize, OUTPUT_CLS);
229
230 impl Delegate for DelegateObj {}
231
232 #[objc::add_methods]
233 impl DelegateImpl for DelegateObj {}
234
235 #[tokio::test]
236 pub async fn current() {
237 let f = sc::ShareableContent::current().await.expect("result");
238 assert!(!f.windows().is_empty());
239 println!(
240 "current retain count {:?} {:?}",
241 f.as_type_ref().retain_count(),
242 f.windows().len()
243 );
244 }
245
246 #[tokio::test]
247 pub async fn current2() {
248 let f = sc::ShareableContent::current().await.expect("result");
249 assert!(!f.windows().is_empty());
250 println!(
251 "current retain count {:?} {:?}",
252 f.as_type_ref().retain_count(),
253 f.windows().len()
254 );
255 }
256
257 #[test]
258 pub fn current_ch() {
259 let sema = dispatch::Semaphore::new(0);
260
261 let signal_guard = sema.guard();
262 let mut bl = blocks::ResultCh::new2(move |content, error| {
263 _ = &signal_guard;
264 println!("nice {:?} {:?}", content, error);
265 });
266
267 dispatch::Queue::global(0).unwrap().async_mut(move || {
268 ShareableContent::current_with_ch_block(&mut bl);
269 });
270
271 sema.wait_forever();
272 }
273}