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