1use std::ffi::c_void;
2
3use crate::cf::{CFType, CFUUID};
4
5use super::{CGDisplayID, CGRect};
6
7#[link(name = "CoreGraphics", kind = "framework")]
8extern "C" {
9 fn CGGetActiveDisplayList(
10 max_displays: u32,
11 active_displays: *mut CGDisplayID,
12 display_count: *mut u32,
13 ) -> i32;
14 fn CGMainDisplayID() -> CGDisplayID;
15 fn CGDisplayBounds(display_id: CGDisplayID) -> CGRect;
16 fn CGDisplayCopyDisplayMode(display_id: CGDisplayID) -> *mut c_void;
17 fn CGDisplayModeGetWidth(mode: *mut c_void) -> usize;
18 fn CGDisplayModeGetHeight(mode: *mut c_void) -> usize;
19 fn CGDisplayModeGetPixelWidth(mode: *mut c_void) -> usize;
20 fn CGDisplayModeGetPixelHeight(mode: *mut c_void) -> usize;
21 fn CGDisplayModeGetRefreshRate(mode: *mut c_void) -> f64;
22}
23
24#[link(name = "ApplicationServices", kind = "framework")]
25extern "C" {
26 fn CGDisplayCreateUUIDFromDisplayID(display_id: CGDisplayID) -> *mut c_void;
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub struct Display(CGDisplayID);
31
32impl Display {
33 #[must_use]
34 pub const fn new(id: CGDisplayID) -> Self {
35 Self(id)
36 }
37
38 #[must_use]
39 pub const fn id(self) -> CGDisplayID {
40 self.0
41 }
42
43 #[must_use]
44 pub fn active() -> Vec<Self> {
45 let mut count = 0;
46 if unsafe { CGGetActiveDisplayList(0, std::ptr::null_mut(), &raw mut count) } != 0 {
47 return Vec::new();
48 }
49 if count == 0 {
50 return Vec::new();
51 }
52
53 let mut displays = vec![0; count as usize];
54 if unsafe { CGGetActiveDisplayList(count, displays.as_mut_ptr(), &raw mut count) } != 0 {
55 return Vec::new();
56 }
57 displays.truncate(count as usize);
58 displays.into_iter().map(Self).collect()
59 }
60
61 #[must_use]
62 pub fn main() -> Self {
63 Self(unsafe { CGMainDisplayID() })
64 }
65
66 #[must_use]
67 pub fn bounds(self) -> CGRect {
68 unsafe { CGDisplayBounds(self.0) }
69 }
70
71 #[must_use]
72 pub fn uuid(self) -> Option<CFUUID> {
73 let ptr = unsafe { CGDisplayCreateUUIDFromDisplayID(self.0) };
74 unsafe { CFUUID::from_raw(ptr) }
75 }
76
77 #[must_use]
78 pub fn mode(self) -> Option<DisplayMode> {
79 let ptr = unsafe { CGDisplayCopyDisplayMode(self.0) };
80 unsafe { CFType::from_raw(ptr) }.map(DisplayMode)
81 }
82}
83
84#[derive(Debug, Clone)]
85pub struct DisplayMode(CFType);
86
87impl DisplayMode {
88 #[must_use]
89 pub fn width(&self) -> usize {
90 unsafe { CGDisplayModeGetWidth(self.0.as_ptr()) }
91 }
92
93 #[must_use]
94 pub fn height(&self) -> usize {
95 unsafe { CGDisplayModeGetHeight(self.0.as_ptr()) }
96 }
97
98 #[must_use]
99 pub fn pixel_width(&self) -> usize {
100 unsafe { CGDisplayModeGetPixelWidth(self.0.as_ptr()) }
101 }
102
103 #[must_use]
104 pub fn pixel_height(&self) -> usize {
105 unsafe { CGDisplayModeGetPixelHeight(self.0.as_ptr()) }
106 }
107
108 #[must_use]
109 pub fn refresh_rate(&self) -> f64 {
110 unsafe { CGDisplayModeGetRefreshRate(self.0.as_ptr()) }
111 }
112}