libdisplay_info/
info.rs

1//! High-level API.
2use crate::{edid::Edid, ffi, string_from_owned_ffi_ptr};
3
4#[cfg(any(feature = "v0_2", feature = "v0_3"))]
5use libdisplay_info_derive::FFIFrom;
6
7/// Display HDR static metadata
8#[derive(Debug, Copy, Clone, FFIFrom)]
9#[ffi(ffi::info::di_hdr_static_metadata)]
10#[cfg(any(feature = "v0_2", feature = "v0_3"))]
11pub struct HdrStaticMetadata {
12    pub desired_content_max_luminance: f32,
13    pub desired_content_max_frame_avg_luminance: f32,
14    pub desired_content_min_luminance: f32,
15    pub type1: bool,
16    pub traditional_sdr: bool,
17    pub traditional_hdr: bool,
18    pub pq: bool,
19    pub hlg: bool,
20}
21
22/// CIE 1931 2-degree observer chromaticity coordinates
23#[derive(Debug, Copy, Clone, FFIFrom)]
24#[ffi(ffi::info::di_chromaticity_cie1931)]
25#[cfg(any(feature = "v0_2", feature = "v0_3"))]
26pub struct ChromaticityCie1931 {
27    pub x: f32,
28    pub y: f32,
29}
30
31/// Display color primaries and default white point
32#[derive(Debug, Copy, Clone, FFIFrom)]
33#[ffi(ffi::info::di_color_primaries)]
34#[cfg(any(feature = "v0_2", feature = "v0_3"))]
35pub struct ColorPrimaries {
36    pub has_primaries: bool,
37    pub has_default_white_point: bool,
38    pub primary: [ChromaticityCie1931; 3usize],
39    pub default_white: ChromaticityCie1931,
40}
41
42/// Additional signal colorimetry encodings supported by the display
43#[derive(Debug, Copy, Clone, FFIFrom)]
44#[ffi(ffi::info::di_supported_signal_colorimetry)]
45#[cfg(any(feature = "v0_2", feature = "v0_3"))]
46pub struct SupportedSignalColorimetry {
47    pub bt2020_cycc: bool,
48    pub bt2020_ycc: bool,
49    pub bt2020_rgb: bool,
50    pub st2113_rgb: bool,
51    pub ictcp: bool,
52}
53
54/// Information about a display device.
55///
56/// This includes at least one EDID or DisplayID blob.
57///
58/// Use [`Info::parse_edid`](Info::parse_edid) to create a [`Info`] from an EDID blob.
59/// DisplayID blobs are not yet supported.
60#[derive(Debug)]
61pub struct Info(*mut ffi::info::di_info);
62
63/// Parsing the EDID blob failed
64#[derive(Debug, thiserror::Error)]
65#[error("Parsing the EDID blob failed")]
66pub struct ParseFailed;
67
68impl Info {
69    /// Parse an EDID blob.
70    pub fn parse_edid(data: &[u8]) -> Result<Self, ParseFailed> {
71        let info = unsafe {
72            ffi::info::di_info_parse_edid(data.as_ptr() as *const std::ffi::c_void, data.len())
73        };
74
75        if info.is_null() {
76            return Err(ParseFailed);
77        }
78
79        Ok(Self(info))
80    }
81
82    /// Get the failure messages for this blob.
83    ///
84    /// `None` is returned if the blob conforms to the relevant specifications.
85    pub fn failure_msg(&self) -> Option<&std::ffi::CStr> {
86        let failure_msg = unsafe { ffi::info::di_info_get_failure_msg(self.0) };
87
88        if failure_msg.is_null() {
89            None
90        } else {
91            Some(unsafe { std::ffi::CStr::from_ptr(failure_msg) })
92        }
93    }
94
95    /// Returns the EDID the display device information was constructed with.
96    ///
97    /// The returned [`Edid`] can be used to query low-level EDID information,
98    /// see [`edid`](crate::edid) module level docs. Users should prefer the high-level API if
99    /// possible.
100    ///
101    /// `None` is returned if the [`Info`] doesn't contain an EDID.
102    pub fn edid(&self) -> Option<Edid<'_>> {
103        Edid::from_ptr(unsafe { ffi::info::di_info_get_edid(self.0) as *const ffi::edid::di_edid })
104    }
105
106    /// Get the make of the display device.
107    ///
108    /// This is the manufacturer name, either company name or PNP ID.
109    /// This string is informational and not meant to be used in programmatic
110    /// decisions, configuration keys, etc.
111    ///
112    /// The string is in UTF-8 and may contain any characters except ASCII control
113    /// codes.
114    ///
115    /// `None` is returned if the information is not available.
116    pub fn make(&self) -> Option<String> {
117        string_from_owned_ffi_ptr(unsafe { ffi::info::di_info_get_make(self.0) })
118    }
119
120    /// Get the model of the display device.
121    ///
122    /// This is the product name/model string or product number.
123    /// This string is informational and not meant to be used in programmatic
124    /// decisions, configuration keys, etc.
125    ///
126    /// The string is in UTF-8 and may contain any characters except ASCII control
127    /// codes.
128    ///
129    /// `None` is returned if the information is not available.
130    pub fn model(&self) -> Option<String> {
131        string_from_owned_ffi_ptr(unsafe { ffi::info::di_info_get_model(self.0) })
132    }
133
134    /// Get the serial of the display device.
135    ///
136    /// This is the product serial string or the serial number.
137    /// This string is informational and not meant to be used in programmatic
138    /// decisions, configuration keys, etc.
139    ///
140    /// The string is in UTF-8 and may contain any characters except ASCII control
141    /// codes.
142    ///
143    /// `None` is returned if the information is not available.
144    pub fn serial(&self) -> Option<String> {
145        string_from_owned_ffi_ptr(unsafe { ffi::info::di_info_get_serial(self.0) })
146    }
147
148    /// Get HDR static metadata support information as defined in ANSI/CTA-861-H
149    /// as HDR Static Metadata Data Block.
150    ///  
151    /// When HDR static metadata does not exist,
152    /// all luminance fields are zero and only traditional_sdr is flagged as
153    /// supported.
154    #[cfg(any(feature = "v0_2", feature = "v0_3"))]
155    pub fn hdr_static_metadata(&self) -> HdrStaticMetadata {
156        // SAFETY: The returned pointer is owned by the struct di_info passed in. It remains
157        // valid only as long as the di_info exists, and must not be freed by the
158        // caller.
159        //
160        // This function does not return NULL.
161        HdrStaticMetadata::from(unsafe { *ffi::info::di_info_get_hdr_static_metadata(self.0) })
162    }
163
164    /// Get display color primaries and default white point
165    ///
166    /// Get the parameters of the default RGB colorimetry mode which is always
167    /// supported. Primaries for monochrome displays might be all zeroes.
168    ///
169    /// These primaries might not be display's physical primaries, but only the
170    /// primaries of the default RGB colorimetry signal when using IT Video Format
171    /// (ANSI/CTA-861-H, Section 5).
172    #[cfg(any(feature = "v0_2", feature = "v0_3"))]
173    pub fn default_color_primaries(&self) -> ColorPrimaries {
174        // SAFETY: The returned pointer is owned by the struct di_info passed in. It remains
175        // valid only as long as the di_info exists, and must not be freed by the
176        // caller.
177        //
178        // This function does not return NULL.
179        ColorPrimaries::from(unsafe { *ffi::info::di_info_get_default_color_primaries(self.0) })
180    }
181
182    /// Get signal colorimetry encodings supported by the display
183    ///
184    /// These signal colorimetry encodings are supported in addition to the
185    /// display's default RGB colorimetry. When you wish to use one of the additional
186    /// encodings, they need to be explicitly enabled in the video signal. How to
187    /// do that is specific to the signalling used, e.g. HDMI.
188    ///
189    /// Signal colorimetry encoding provides the color space that the signal is
190    /// encoded for. This includes primary and white point chromaticities, and the
191    /// YCbCr-RGB conversion if necessary. Also the transfer function is implied
192    /// unless explicitly set otherwise, e.g. with HDR static metadata.
193    /// See ANSI/CTA-861-H for details.
194    ///
195    /// The signal color volume can be considerably larger than the physically
196    /// displayable color volume.
197    #[cfg(any(feature = "v0_2", feature = "v0_3"))]
198    pub fn supported_signal_colorimetry(&self) -> SupportedSignalColorimetry {
199        // SAFETY: The returned pointer is owned by the struct di_info passed in. It remains
200        // valid only as long as the di_info exists, and must not be freed by the
201        // caller.
202        //
203        // This function does not return NULL.
204        SupportedSignalColorimetry::from(unsafe {
205            *ffi::info::di_info_get_supported_signal_colorimetry(self.0)
206        })
207    }
208
209    /// Get display default transfer characteristic exponent (gamma)
210    ///
211    /// This should be the display gamma value when the display has been reset to
212    /// its factory defaults, and it is driven with the default RGB colorimetry.
213    ///
214    /// Returns `None` when unknown.
215    #[cfg(any(feature = "v0_2", feature = "v0_3"))]
216    pub fn default_gamma(&self) -> Option<f32> {
217        // SAFETY: The value is zero when unknown.
218        let default_gamma = unsafe { ffi::info::di_info_get_default_gamma(self.0) };
219        if default_gamma == 0f32 {
220            None
221        } else {
222            Some(default_gamma)
223        }
224    }
225}
226
227impl Drop for Info {
228    fn drop(&mut self) {
229        unsafe {
230            ffi::info::di_info_destroy(self.0);
231        }
232    }
233}