core_graphics2/
display.rs1use std::ptr::null;
2
3use core_foundation::{array::CFArray, base::TCFType, string::CFString};
4use libc::c_double;
5
6#[cfg(feature = "window")]
7use crate::window::CGWindowID;
8use crate::{
9 color_space::CGColorSpace,
10 context::CGContext,
11 error::CGError,
12 geometry::{CGPoint, CGRect, CGSize},
13 image::CGImage,
14};
15pub use crate::{direct_display::*, display_configuration::*, display_fade::*, remote_operation::*};
16
17pub const IO1BitIndexedPixels: &str = "P";
19pub const IO2BitIndexedPixels: &str = "PP";
20pub const IO4BitIndexedPixels: &str = "PPPP";
21pub const IO8BitIndexedPixels: &str = "PPPPPPPP";
22pub const IO16BitDirectPixels: &str = "-RRRRRGGGGGBBBBB";
23pub const IO32BitDirectPixels: &str = "--------RRRRRRRRGGGGGGGGBBBBBBBB";
24pub const kIO30BitDirectPixels: &str = "--RRRRRRRRRRGGGGGGGGGGBBBBBBBBBB";
25pub const kIO64BitDirectPixels: &str = "-16R16G16B16";
26pub const kIO16BitFloatPixels: &str = "-16FR16FG16FB16";
27pub const kIO32BitFloatPixels: &str = "-32FR32FG32FB32";
28pub const IOYUV422Pixels: &str = "Y4U2V2";
29pub const IO8BitOverlayPixels: &str = "O8";
30
31pub struct CGDisplayMode(CGDisplayModeRef);
32
33impl Drop for CGDisplayMode {
34 fn drop(&mut self) {
35 unsafe { CGDisplayModeRelease(self.0) }
36 }
37}
38
39impl_TCFType!(CGDisplayMode, CGDisplayModeRef, CGDisplayModeGetTypeID);
40impl_CFTypeDescription!(CGDisplayMode);
41
42impl CGDisplayMode {
43 pub fn width(&self) -> usize {
44 unsafe { CGDisplayModeGetWidth(self.as_concrete_TypeRef()) as usize }
45 }
46
47 pub fn height(&self) -> usize {
48 unsafe { CGDisplayModeGetHeight(self.as_concrete_TypeRef()) as usize }
49 }
50
51 pub fn pixel_width(&self) -> usize {
52 unsafe { CGDisplayModeGetPixelWidth(self.as_concrete_TypeRef()) as usize }
53 }
54
55 pub fn pixel_height(&self) -> usize {
56 unsafe { CGDisplayModeGetPixelHeight(self.as_concrete_TypeRef()) as usize }
57 }
58
59 pub fn copy_pixel_encoding(&self) -> Option<CFString> {
60 unsafe {
61 let encoding = CGDisplayModeCopyPixelEncoding(self.as_concrete_TypeRef());
62 if encoding.is_null() {
63 None
64 } else {
65 Some(TCFType::wrap_under_create_rule(encoding))
66 }
67 }
68 }
69
70 pub fn bit_depth(&self) -> usize {
71 match self.copy_pixel_encoding() {
72 None => 0,
73 Some(encoding) => match encoding.to_string().as_str() {
74 kIO32BitFloatPixels => 96,
75 kIO64BitDirectPixels => 64,
76 kIO16BitFloatPixels => 48,
77 kIO30BitDirectPixels => 30,
78 IO32BitDirectPixels => 32,
79 IO16BitDirectPixels => 16,
80 IOYUV422Pixels => 16,
81 IO8BitOverlayPixels => 8,
82 IO8BitIndexedPixels => 8,
83 IO4BitIndexedPixels => 4,
84 IO2BitIndexedPixels => 2,
85 IO1BitIndexedPixels => 1,
86 _ => 0,
87 },
88 }
89 }
90
91 pub fn refresh_rate(&self) -> f64 {
92 unsafe { CGDisplayModeGetRefreshRate(self.as_concrete_TypeRef()) }
93 }
94
95 pub fn io_flags(&self) -> u32 {
96 unsafe { CGDisplayModeGetIOFlags(self.as_concrete_TypeRef()) }
97 }
98
99 pub fn io_display_mode_id(&self) -> i32 {
100 unsafe { CGDisplayModeGetIODisplayModeID(self.as_concrete_TypeRef()) }
101 }
102
103 pub fn is_usable_for_desktop_gui(&self) -> bool {
104 unsafe { CGDisplayModeIsUsableForDesktopGUI(self.as_concrete_TypeRef()) }
105 }
106}
107
108#[derive(Clone, Copy, Debug, Eq, PartialEq)]
109pub struct CGDisplay {
110 pub id: CGDirectDisplayID,
111}
112
113impl CGDisplay {
114 pub fn new(id: CGDirectDisplayID) -> Self {
115 CGDisplay {
116 id,
117 }
118 }
119
120 pub fn main() -> Self {
121 unsafe { CGDisplay::new(CGMainDisplayID()) }
122 }
123
124 pub fn copy_display_modes(&self) -> Option<CFArray<CGDisplayMode>> {
125 unsafe {
126 let modes = CGDisplayCopyAllDisplayModes(self.id, null());
127 if modes.is_null() {
128 None
129 } else {
130 Some(TCFType::wrap_under_create_rule(modes))
131 }
132 }
133 }
134
135 pub fn copy_display_mode(&self) -> Option<CGDisplayMode> {
136 unsafe {
137 let mode = CGDisplayCopyDisplayMode(self.id);
138 if mode.is_null() {
139 None
140 } else {
141 Some(TCFType::wrap_under_create_rule(mode))
142 }
143 }
144 }
145
146 pub fn bounds(&self) -> CGRect {
147 unsafe { CGDisplayBounds(self.id) }
148 }
149
150 pub fn pixels_wide(&self) -> usize {
151 unsafe { CGDisplayPixelsWide(self.id) as usize }
152 }
153
154 pub fn pixels_high(&self) -> usize {
155 unsafe { CGDisplayPixelsHigh(self.id) as usize }
156 }
157
158 pub fn set_display_mode(&self, mode: &CGDisplayMode) -> Result<(), CGError> {
159 let result = unsafe { CGDisplaySetDisplayMode(self.id, mode.as_concrete_TypeRef(), null()) };
160 if result == CGError::Success {
161 Ok(())
162 } else {
163 Err(result)
164 }
165 }
166
167 pub fn capture(&self) -> Result<(), CGError> {
168 let result = unsafe { CGDisplayCapture(self.id) };
169 if result == CGError::Success {
170 Ok(())
171 } else {
172 Err(result)
173 }
174 }
175
176 pub fn capture_with_options(&self, options: CGCaptureOptions) -> Result<(), CGError> {
177 let result = unsafe { CGDisplayCaptureWithOptions(self.id, options) };
178 if result == CGError::Success {
179 Ok(())
180 } else {
181 Err(result)
182 }
183 }
184
185 #[cfg(feature = "window")]
186 pub fn shielding_window_id(&self) -> CGWindowID {
187 unsafe { CGShieldingWindowID(self.id) }
188 }
189
190 pub fn new_image(&self) -> Option<CGImage> {
191 unsafe {
192 let image = CGDisplayCreateImage(self.id);
193 if image.is_null() {
194 None
195 } else {
196 Some(TCFType::wrap_under_create_rule(image))
197 }
198 }
199 }
200
201 pub fn new_image_for_rect(&self, rect: CGRect) -> Option<CGImage> {
202 unsafe {
203 let image = CGDisplayCreateImageForRect(self.id, rect);
204 if image.is_null() {
205 None
206 } else {
207 Some(TCFType::wrap_under_create_rule(image))
208 }
209 }
210 }
211
212 pub fn hide_cursor(&self) -> Result<(), CGError> {
213 let result = unsafe { CGDisplayHideCursor(self.id) };
214 if result == CGError::Success {
215 Ok(())
216 } else {
217 Err(result)
218 }
219 }
220
221 pub fn show_cursor(&self) -> Result<(), CGError> {
222 let result = unsafe { CGDisplayShowCursor(self.id) };
223 if result == CGError::Success {
224 Ok(())
225 } else {
226 Err(result)
227 }
228 }
229
230 pub fn move_cursor_to_point(&self, point: CGPoint) -> Result<(), CGError> {
231 let result = unsafe { CGDisplayMoveCursorToPoint(self.id, point) };
232 if result == CGError::Success {
233 Ok(())
234 } else {
235 Err(result)
236 }
237 }
238
239 pub fn warp_mouse_cursor_position(&self, point: CGPoint) -> Result<(), CGError> {
240 let result = unsafe { CGWarpMouseCursorPosition(point) };
241 if result == CGError::Success {
242 Ok(())
243 } else {
244 Err(result)
245 }
246 }
247
248 pub fn get_drawing_context(&self) -> Option<CGContext> {
249 unsafe {
250 let context = CGDisplayGetDrawingContext(self.id);
251 if context.is_null() {
252 None
253 } else {
254 Some(TCFType::wrap_under_create_rule(context))
255 }
256 }
257 }
258
259 pub fn set_stereo_operation(&self, stereo: bool, force_blue_line: bool, option: CGConfigureOption) -> Result<(), CGError> {
262 let result = unsafe { CGDisplaySetStereoOperation(self.id, stereo as _, force_blue_line as _, option) };
263 if result == CGError::Success {
264 Ok(())
265 } else {
266 Err(result)
267 }
268 }
269
270 pub fn is_active(&self) -> bool {
271 unsafe { CGDisplayIsActive(self.id) != 0 }
272 }
273
274 pub fn is_asleep(&self) -> bool {
275 unsafe { CGDisplayIsAsleep(self.id) != 0 }
276 }
277
278 pub fn is_online(&self) -> bool {
279 unsafe { CGDisplayIsOnline(self.id) != 0 }
280 }
281
282 pub fn is_main(&self) -> bool {
283 unsafe { CGDisplayIsMain(self.id) != 0 }
284 }
285
286 pub fn is_built_in(&self) -> bool {
287 unsafe { CGDisplayIsBuiltin(self.id) != 0 }
288 }
289
290 pub fn is_in_mirror_set(&self) -> bool {
291 unsafe { CGDisplayIsInMirrorSet(self.id) != 0 }
292 }
293
294 pub fn is_always_in_mirror_set(&self) -> bool {
295 unsafe { CGDisplayIsInHWMirrorSet(self.id) != 0 }
296 }
297
298 pub fn is_in_hw_mirror_set(&self) -> bool {
299 unsafe { CGDisplayIsInHWMirrorSet(self.id) != 0 }
300 }
301
302 pub fn is_stereo(&self) -> bool {
303 unsafe { CGDisplayIsStereo(self.id) != 0 }
304 }
305
306 pub fn uses_opengl_acceleration(&self) -> bool {
307 unsafe { CGDisplayUsesOpenGLAcceleration(self.id) != 0 }
308 }
309
310 pub fn mirrors_display(&self) -> Self {
311 unsafe { CGDisplay::new(CGDisplayMirrorsDisplay(self.id)) }
312 }
313
314 pub fn primary_display(&self) -> Self {
315 unsafe { CGDisplay::new(CGDisplayPrimaryDisplay(self.id)) }
316 }
317
318 pub fn unit_number(&self) -> u32 {
319 unsafe { CGDisplayUnitNumber(self.id) }
320 }
321
322 pub fn vendor_number(&self) -> u32 {
323 unsafe { CGDisplayVendorNumber(self.id) }
324 }
325
326 pub fn model_number(&self) -> u32 {
327 unsafe { CGDisplayModelNumber(self.id) }
328 }
329
330 pub fn serial_number(&self) -> u32 {
331 unsafe { CGDisplaySerialNumber(self.id) }
332 }
333
334 pub fn screen_size(&self) -> CGSize {
335 unsafe { CGDisplayScreenSize(self.id) }
336 }
337
338 pub fn rotation(&self) -> c_double {
339 unsafe { CGDisplayRotation(self.id) }
340 }
341
342 pub fn copy_color_space(&self) -> Option<CGColorSpace> {
343 unsafe {
344 let space = CGDisplayCopyColorSpace(self.id);
345 if space.is_null() {
346 None
347 } else {
348 Some(TCFType::wrap_under_create_rule(space))
349 }
350 }
351 }
352}
353
354fn get_displays_from_ids(ids: &mut Vec<CGDirectDisplayID>, count: usize) -> Option<Vec<CGDisplay>> {
355 ids.truncate(count as usize);
356 Some(ids.into_iter().map(|id| CGDisplay::new(*id)).collect())
357}
358
359pub fn get_displays_with_point(point: CGPoint, max_displays: usize) -> Option<Vec<CGDisplay>> {
360 unsafe {
361 let mut count = max_displays as u32;
362 let mut ids: Vec<CGDirectDisplayID> = vec![0; max_displays];
363 let result = CGGetDisplaysWithPoint(point, count, ids.as_mut_ptr(), &mut count);
364 if result == CGError::Success {
365 get_displays_from_ids(&mut ids, count as usize)
366 } else {
367 None
368 }
369 }
370}
371
372pub fn get_displays_with_rect(rect: CGRect, max_displays: usize) -> Option<Vec<CGDisplay>> {
373 unsafe {
374 let mut count = max_displays as u32;
375 let mut ids = vec![0; max_displays];
376 let result = CGGetDisplaysWithRect(rect, count, ids.as_mut_ptr(), &mut count);
377 if result == CGError::Success {
378 get_displays_from_ids(&mut ids, count as usize)
379 } else {
380 None
381 }
382 }
383}
384
385pub fn get_displays_with_opengl_display_mask(mask: CGOpenGLDisplayMask, max_displays: usize) -> Option<Vec<CGDisplay>> {
386 unsafe {
387 let mut count = max_displays as u32;
388 let mut ids = vec![0; max_displays];
389 let result = CGGetDisplaysWithOpenGLDisplayMask(mask, count, ids.as_mut_ptr(), &mut count);
390 if result == CGError::Success {
391 get_displays_from_ids(&mut ids, count as usize)
392 } else {
393 None
394 }
395 }
396}
397
398pub fn get_active_display_list(max_displays: usize) -> Option<Vec<CGDisplay>> {
399 unsafe {
400 let mut count = max_displays as u32;
401 let mut ids = vec![0; max_displays];
402 let result = CGGetActiveDisplayList(count, ids.as_mut_ptr(), &mut count);
403 if result == CGError::Success {
404 get_displays_from_ids(&mut ids, count as usize)
405 } else {
406 None
407 }
408 }
409}
410
411pub fn get_online_display_list(max_displays: usize) -> Option<Vec<CGDisplay>> {
412 unsafe {
413 let mut count = max_displays as u32;
414 let mut ids = vec![0; max_displays];
415 let result = CGGetOnlineDisplayList(count, ids.as_mut_ptr(), &mut count);
416 if result == CGError::Success {
417 get_displays_from_ids(&mut ids, count as usize)
418 } else {
419 None
420 }
421 }
422}
423
424pub fn display_id_to_opengl_display_mask(display_id: CGDirectDisplayID) -> CGOpenGLDisplayMask {
425 unsafe { CGDisplayIDToOpenGLDisplayMask(display_id) }
426}
427
428pub fn opengl_display_mask_to_display_id(mask: CGOpenGLDisplayMask) -> CGDirectDisplayID {
429 unsafe { CGOpenGLDisplayMaskToDisplayID(mask) }
430}
431
432pub fn capture_all_displays() -> Result<(), CGError> {
433 let result = unsafe { CGCaptureAllDisplays() };
434 if result == CGError::Success {
435 Ok(())
436 } else {
437 Err(result)
438 }
439}
440
441pub fn capture_all_displays_with_options(options: CGCaptureOptions) -> Result<(), CGError> {
442 let result = unsafe { CGCaptureAllDisplaysWithOptions(options) };
443 if result == CGError::Success {
444 Ok(())
445 } else {
446 Err(result)
447 }
448}
449
450pub fn release_all_displays() -> Result<(), CGError> {
451 let result = unsafe { CGReleaseAllDisplays() };
452 if result == CGError::Success {
453 Ok(())
454 } else {
455 Err(result)
456 }
457}