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}