core_graphics2/
window.rs

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}