Skip to main content

core_graphics2/
window.rs

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}