Skip to main content

apple_cf/cg/
display.rs

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}