1#![cfg_attr(all(doc, not(doctest)), feature(doc_cfg))]
2#![warn(missing_docs)]
3#![doc = include_str!("../README.md")]
4
5use std::mem;
6
7pub use crate::device_id::DeviceId;
8pub use crate::error::{Error, Win32Error};
9use crate::windows::{
10 DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME,
11 DISPLAYCONFIG_DEVICE_INFO_HEADER, DISPLAYCONFIG_DEVICE_INFO_TYPE, DISPLAYCONFIG_MODE_INFO,
12 DISPLAYCONFIG_PATH_INFO, DISPLAYCONFIG_SOURCE_DEVICE_NAME, DISPLAYCONFIG_TARGET_DEVICE_NAME,
13 DisplayConfigGetDeviceInfo, ERROR_INSUFFICIENT_BUFFER, GetDisplayConfigBufferSizes,
14 QUERY_DISPLAY_CONFIG_FLAGS, QueryDisplayConfig, SET_DISPLAY_CONFIG_FLAGS, SetDisplayConfig,
15};
16
17mod device_id;
18#[cfg(feature = "dump")]
19mod dump;
20mod error;
21pub mod util;
22pub mod windows;
23
24pub type Result<T, E = error::Error> = std::result::Result<T, E>;
26
27pub fn query_display_config(
39 flags: QUERY_DISPLAY_CONFIG_FLAGS,
40) -> Result<(Vec<DISPLAYCONFIG_PATH_INFO>, Vec<DISPLAYCONFIG_MODE_INFO>)> {
41 loop {
42 let mut path_count = 0;
43 let mut mode_count = 0;
44
45 let result =
46 unsafe { GetDisplayConfigBufferSizes(flags, &raw mut path_count, &raw mut mode_count) };
47 Error::new(result, "GetDisplayConfigBufferSizes").to_result(())?;
48
49 let mut paths = vec![DISPLAYCONFIG_PATH_INFO::default(); path_count as usize];
50 let mut modes = vec![DISPLAYCONFIG_MODE_INFO::default(); mode_count as usize];
51
52 let result = unsafe {
53 QueryDisplayConfig(
54 flags,
55 &raw mut path_count,
56 paths.as_mut_ptr(),
57 &raw mut mode_count,
58 modes.as_mut_ptr(),
59 None,
60 )
61 };
62
63 if result != ERROR_INSUFFICIENT_BUFFER {
64 let error = Error::new(result, "QueryDisplayConfig");
65
66 #[cfg(feature = "dump")]
67 crate::dump::dump_query_display_config(
68 error, flags, &paths, path_count, &modes, mode_count, None,
69 );
70
71 return error.to_result_with(|| {
72 paths.truncate(path_count as usize);
73 modes.truncate(mode_count as usize);
74 (paths, modes)
75 });
76 }
77
78 }
80}
81
82pub fn set_display_config(
89 paths: Option<&[DISPLAYCONFIG_PATH_INFO]>,
90 modes: Option<&[DISPLAYCONFIG_MODE_INFO]>,
91 flags: SET_DISPLAY_CONFIG_FLAGS,
92) -> Result<()> {
93 let result = unsafe { SetDisplayConfig(paths, modes, flags) };
94 let error = Error::new(result, "SetDisplayConfig");
95
96 #[cfg(feature = "dump")]
97 crate::dump::dump_set_display_config(error, paths, modes, flags);
98
99 error.to_result(())
100}
101
102mod private {
103 cfg_select! {
104 feature = "dump" => {
105 pub trait GetDeviceInfoBase: Default + crate::dump::ToJsonValue {}
106 impl<T: Default + crate::dump::ToJsonValue> GetDeviceInfoBase for T {}
107 }
108 _ => {
109 pub trait GetDeviceInfoBase: Default {}
110 impl<T: Default> GetDeviceInfoBase for T {}
111 }
112 }
113}
114
115pub trait GetDeviceInfo: private::GetDeviceInfoBase {
117 const TYPE: DISPLAYCONFIG_DEVICE_INFO_TYPE;
119
120 #[cfg(feature = "dump")]
122 fn header(&self) -> &DISPLAYCONFIG_DEVICE_INFO_HEADER;
123
124 fn header_mut(&mut self) -> &mut DISPLAYCONFIG_DEVICE_INFO_HEADER;
126}
127
128impl GetDeviceInfo for DISPLAYCONFIG_SOURCE_DEVICE_NAME {
129 const TYPE: DISPLAYCONFIG_DEVICE_INFO_TYPE = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
130
131 #[cfg(feature = "dump")]
132 fn header(&self) -> &DISPLAYCONFIG_DEVICE_INFO_HEADER {
133 &self.header
134 }
135
136 fn header_mut(&mut self) -> &mut DISPLAYCONFIG_DEVICE_INFO_HEADER {
137 &mut self.header
138 }
139}
140
141impl GetDeviceInfo for DISPLAYCONFIG_TARGET_DEVICE_NAME {
142 const TYPE: DISPLAYCONFIG_DEVICE_INFO_TYPE = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
143
144 #[cfg(feature = "dump")]
145 fn header(&self) -> &DISPLAYCONFIG_DEVICE_INFO_HEADER {
146 &self.header
147 }
148
149 fn header_mut(&mut self) -> &mut DISPLAYCONFIG_DEVICE_INFO_HEADER {
150 &mut self.header
151 }
152}
153
154pub fn display_config_get_device_info<T: GetDeviceInfo>(
179 device_id: impl Into<DeviceId>,
180) -> Result<T> {
181 let device_id = device_id.into();
182
183 let mut device_info = T::default();
184 *device_info.header_mut() = DISPLAYCONFIG_DEVICE_INFO_HEADER {
185 r#type: T::TYPE,
186 #[expect(clippy::cast_possible_truncation)]
187 size: mem::size_of::<T>() as u32,
188 adapterId: device_id.adapter_id,
189 id: device_id.id,
190 };
191
192 let result = unsafe { DisplayConfigGetDeviceInfo(device_info.header_mut()) };
193 let error = Error::new(result, "DisplayConfigGetDeviceInfo");
194
195 #[cfg(feature = "dump")]
196 crate::dump::dump_display_config_get_device_info(error, &device_info);
197
198 error.to_result(device_info)
199}