1use core_foundation::{
2 array::{CFArray, CFArrayRef},
3 base::{CFType, TCFType},
4 dictionary::CFDictionary,
5 string::{CFString, CFStringRef},
6};
7
8use crate::{
9 geometry::CGRect,
10 image::{CGImage, CGImageRef},
11};
12
13pub type CGWindowID = u32;
14
15#[repr(u32)]
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub enum CGWindowSharingType {
18 #[doc(alias = "kCGWindowSharingNone")]
19 None = 0,
20 #[doc(alias = "kCGWindowSharingReadOnly")]
21 ReadOnly = 1,
22 #[doc(alias = "kCGWindowSharingReadWrite")]
23 ReadWrite = 2,
24}
25
26#[repr(u32)]
27#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub enum CGWindowBackingType {
29 #[doc(alias = "kCGWindowBackingStoreRetained")]
30 Retained = 0,
31 #[doc(alias = "kCGWindowBackingStoreNonretained")]
32 Nonretained = 1,
33 #[doc(alias = "kCGWindowBackingStoreBuffered")]
34 Buffered = 2,
35}
36
37bitflags! {
38 #[repr(C)]
39 #[derive(Clone, Copy, Debug, Default, PartialEq)]
40 pub struct CGWindowListOption: u32 {
41 #[doc(alias = "kCGWindowListOptionAll")]
42 const All = 0;
43 #[doc(alias = "kCGWindowListOptionOnScreenOnly")]
44 const OnScreenOnly = 1 << 0;
45 #[doc(alias = "kCGWindowListOptionOnScreenAboveWindow")]
46 const OnScreenAboveWindow = 1 << 1;
47 #[doc(alias = "kCGWindowListOptionOnScreenBelowWindow")]
48 const OnScreenBelowWindow = 1 << 2;
49 #[doc(alias = "kCGWindowListOptionIncludingWindow")]
50 const IncludingWindow = 1 << 3;
51 #[doc(alias = "kCGWindowListExcludeDesktopElements")]
52 const ExcludeDesktopElements = 1 << 4;
53 }
54}
55
56bitflags! {
57 #[repr(C)]
58 #[derive(Clone, Copy, Debug, Default, PartialEq)]
59 pub struct CGWindowImageOption: u32 {
60 #[doc(alias = "kCGWindowImageDefault")]
61 const Default = 0;
62 #[doc(alias = "kCGWindowImageBoundsIgnoreFraming")]
63 const BoundsIgnoreFraming = 1 << 0;
64 #[doc(alias = "kCGWindowImageShouldBeOpaque")]
65 const ShouldBeOpaque = 1 << 1;
66 #[doc(alias = "kCGWindowImageOnlyShadows")]
67 const OnlyShadows = 1 << 2;
68 #[doc(alias = "kCGWindowImageBestResolution")]
69 const BestResolution = 1 << 3;
70 #[doc(alias = "kCGWindowImageNominalResolution")]
71 const NominalResolution = 1 << 4;
72 }
73}
74
75pub const kCGNullWindowID: CGWindowID = 0;
76
77extern "C" {
78 pub static kCGWindowNumber: CFStringRef;
79 pub static kCGWindowStoreType: CFStringRef;
80 pub static kCGWindowLayer: CFStringRef;
81 pub static kCGWindowBounds: CFStringRef;
82 pub static kCGWindowSharingState: CFStringRef;
83 pub static kCGWindowAlpha: CFStringRef;
84 pub static kCGWindowOwnerPID: CFStringRef;
85 pub static kCGWindowMemoryUsage: CFStringRef;
86 pub static kCGWindowWorkspace: CFStringRef;
87 pub static kCGWindowOwnerName: CFStringRef;
88 pub static kCGWindowName: CFStringRef;
89 pub static kCGWindowIsOnscreen: CFStringRef;
90 pub static kCGWindowBackingLocationVideoMemory: CFStringRef;
91
92 pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID) -> CFArrayRef;
93 pub fn CGWindowListCreate(option: CGWindowListOption, relativeToWindow: CGWindowID) -> CFArrayRef;
94 pub fn CGWindowListCreateDescriptionFromArray(windowArray: CFArrayRef) -> CFArrayRef;
95 pub fn CGWindowListCreateImage(
96 screenBounds: CGRect,
97 listOption: CGWindowListOption,
98 windowID: CGWindowID,
99 imageOption: CGWindowImageOption,
100 ) -> CGImageRef;
101 pub fn CGWindowListCreateImageFromArray(screenBounds: CGRect, windowArray: CFArrayRef, imageOption: CGWindowImageOption) -> CGImageRef;
102}
103
104extern "C" {
105 pub fn CGRequestScreenCaptureAccess() -> bool;
106 pub fn CGPreflightScreenCaptureAccess() -> bool;
107}
108
109pub fn copy_window_info(option: CGWindowListOption, relative_to_window: CGWindowID) -> Option<CFArray> {
110 unsafe {
111 let array = CGWindowListCopyWindowInfo(option, relative_to_window);
112 if array.is_null() {
113 None
114 } else {
115 Some(TCFType::wrap_under_create_rule(array))
116 }
117 }
118}
119
120pub fn new_window_list(option: CGWindowListOption, relative_to_window: CGWindowID) -> Option<CFArray<CGWindowID>> {
121 unsafe {
122 let array = CGWindowListCreate(option, relative_to_window);
123 if array.is_null() {
124 None
125 } else {
126 Some(TCFType::wrap_under_create_rule(array))
127 }
128 }
129}
130
131pub fn new_description_from_array(window_array: CFArray<CGWindowID>) -> Option<CFArray<CFDictionary<CFString, CFType>>> {
132 unsafe {
133 let array = CGWindowListCreateDescriptionFromArray(window_array.as_concrete_TypeRef());
134 if array.is_null() {
135 None
136 } else {
137 Some(TCFType::wrap_under_create_rule(array))
138 }
139 }
140}
141
142pub fn new_image(
143 screen_bounds: CGRect,
144 list_option: CGWindowListOption,
145 window_id: CGWindowID,
146 image_option: CGWindowImageOption,
147) -> Option<CGImage> {
148 unsafe {
149 let image = CGWindowListCreateImage(screen_bounds, list_option, window_id, image_option);
150 if image.is_null() {
151 None
152 } else {
153 Some(TCFType::wrap_under_create_rule(image))
154 }
155 }
156}
157
158pub fn new_image_from_array(screen_bounds: CGRect, window_array: CFArray<CGWindowID>, image_option: CGWindowImageOption) -> Option<CGImage> {
159 unsafe {
160 let image = CGWindowListCreateImageFromArray(screen_bounds, window_array.as_concrete_TypeRef(), image_option);
161 if image.is_null() {
162 None
163 } else {
164 Some(TCFType::wrap_under_create_rule(image))
165 }
166 }
167}
168
169pub fn request_screen_capture_access() -> bool {
170 unsafe { CGRequestScreenCaptureAccess() }
171}
172
173pub fn preflight_screen_capture_access() -> bool {
174 unsafe { CGPreflightScreenCaptureAccess() }
175}
176
177pub enum WindowKeys {
178 Number,
179 StoreType,
180 Layer,
181 Bounds,
182 SharingState,
183 Alpha,
184 OwnerPID,
185 MemoryUsage,
186 Workspace,
187 OwnerName,
188 Name,
189 IsOnscreen,
190 BackingLocationVideoMemory,
191}
192
193impl From<WindowKeys> for CFStringRef {
194 fn from(key: WindowKeys) -> Self {
195 unsafe {
196 match key {
197 WindowKeys::Number => kCGWindowNumber,
198 WindowKeys::StoreType => kCGWindowStoreType,
199 WindowKeys::Layer => kCGWindowLayer,
200 WindowKeys::Bounds => kCGWindowBounds,
201 WindowKeys::SharingState => kCGWindowSharingState,
202 WindowKeys::Alpha => kCGWindowAlpha,
203 WindowKeys::OwnerPID => kCGWindowOwnerPID,
204 WindowKeys::MemoryUsage => kCGWindowMemoryUsage,
205 WindowKeys::Workspace => kCGWindowWorkspace,
206 WindowKeys::OwnerName => kCGWindowOwnerName,
207 WindowKeys::Name => kCGWindowName,
208 WindowKeys::IsOnscreen => kCGWindowIsOnscreen,
209 WindowKeys::BackingLocationVideoMemory => kCGWindowBackingLocationVideoMemory,
210 }
211 }
212 }
213}
214
215impl From<WindowKeys> for CFString {
216 fn from(key: WindowKeys) -> Self {
217 unsafe { CFString::wrap_under_get_rule(CFStringRef::from(key)) }
218 }
219}