1#![deny(missing_docs)]
2#![doc(html_root_url = "https://docs.rs/ddc-winapi/0.2.2/")]
3
4extern crate winapi;
23extern crate ddc;
24extern crate widestring;
25
26use std::{io, ptr, mem, fmt};
27use std::borrow::Cow;
28use winapi::um::physicalmonitorenumerationapi::*;
29use winapi::um::lowlevelmonitorconfigurationapi::*;
30use winapi::shared::windef::{HMONITOR, HDC, LPRECT};
31use winapi::shared::minwindef::{LPARAM, BYTE, DWORD, BOOL, TRUE};
32use winapi::um::winnt::HANDLE;
33use widestring::{WideCStr, WideStr};
34use ddc::{Ddc, DdcHost, FeatureCode, VcpValue, TimingMessage};
35
36pub struct Monitor {
40 monitor: PHYSICAL_MONITOR,
41}
42
43impl Monitor {
44 pub unsafe fn new(monitor: PHYSICAL_MONITOR) -> Self {
46 Monitor {
47 monitor: monitor,
48 }
49 }
50
51 pub fn enumerate() -> io::Result<Vec<Self>> {
53 enumerate_monitors().and_then(|mon|
54 mon.into_iter().map(|mon|
55 get_physical_monitors_from_hmonitor(mon).map(|mon|
56 mon.into_iter().map(|mon| unsafe { Monitor::new(mon) })
57 )
58 ).collect::<io::Result<Vec<_>>>()
59 ).map(|v| v.into_iter().flat_map(|mon| mon).collect())
60 }
61
62 pub fn description(&self) -> String {
64 let str_ptr = ptr::addr_of!(self.monitor.szPhysicalMonitorDescription);
65 let desc = match (str_ptr as usize) & (mem::align_of::<u16>() - 1) {
66 0 => Cow::Borrowed(unsafe { &*str_ptr }),
67 _ => Cow::Owned(self.monitor.szPhysicalMonitorDescription),
68 };
69 match WideCStr::from_slice_truncate(&desc[..]) {
70 Ok(cstr) => cstr.to_string_lossy(),
71 Err(_) => WideStr::from_slice(&desc[..]).to_string_lossy(),
72 }
73 }
74
75 pub fn handle(&self) -> HANDLE {
77 self.monitor.hPhysicalMonitor
78 }
79
80 pub fn winapi_get_timing_report(&self) -> io::Result<MC_TIMING_REPORT> {
82 unsafe {
83 let mut report = mem::zeroed();
84 if GetTimingReport(self.handle(), &mut report) != TRUE {
85 Err(io::Error::last_os_error())
86 } else {
87 Ok(report)
88 }
89 }
90 }
91
92 pub fn winapi_set_vcp_feature(&self, code: BYTE, value: DWORD) -> io::Result<()> {
94 unsafe {
95 if SetVCPFeature(self.handle(), code, value) != TRUE {
96 Err(io::Error::last_os_error())
97 } else {
98 Ok(())
99 }
100 }
101 }
102
103 pub fn winapi_save_current_settings(&self) -> io::Result<()> {
105 unsafe {
106 if SaveCurrentSettings(self.handle()) != TRUE {
107 Err(io::Error::last_os_error())
108 } else {
109 Ok(())
110 }
111 }
112 }
113
114 pub fn winapi_get_vcp_feature_and_vcp_feature_reply(&self, code: BYTE) -> io::Result<(MC_VCP_CODE_TYPE, DWORD, DWORD)> {
119 unsafe {
120 let mut ty = 0;
121 let mut current = 0;
122 let mut max = 0;
123 if GetVCPFeatureAndVCPFeatureReply(self.handle(), code, &mut ty, &mut current, &mut max) != TRUE {
124 Err(io::Error::last_os_error())
125 } else {
126 Ok((ty, current, max))
127 }
128 }
129 }
130
131 pub fn winapi_get_capabilities_string_length(&self) -> io::Result<DWORD> {
134 unsafe {
135 let mut len = 0;
136 if GetCapabilitiesStringLength(self.handle(), &mut len) != TRUE {
137 Err(io::Error::last_os_error())
138 } else {
139 Ok(len)
140 }
141 }
142 }
143
144 pub fn winapi_capabilities_request_and_capabilities_reply(&self, string: &mut [u8]) -> io::Result<()> {
148 unsafe {
149 if CapabilitiesRequestAndCapabilitiesReply(self.handle(), string.as_mut_ptr() as *mut _, string.len() as _) != TRUE {
150 Err(io::Error::last_os_error())
151 } else {
152 Ok(())
153 }
154 }
155 }
156}
157
158impl DdcHost for Monitor {
159 type Error = io::Error;
160}
161
162impl Ddc for Monitor {
163 fn capabilities_string(&mut self) -> Result<Vec<u8>, Self::Error> {
164 let mut str = vec![0u8; self.winapi_get_capabilities_string_length()? as usize];
165 self.winapi_capabilities_request_and_capabilities_reply(&mut str)
166 .map(|_| {
167 let len = str.len();
168 if len > 0 {
169 str.truncate(len - 1); }
171 str
172 })
173 }
174
175 fn get_vcp_feature(&mut self, code: FeatureCode) -> Result<VcpValue, Self::Error> {
176 self.winapi_get_vcp_feature_and_vcp_feature_reply(code)
177 .map(|(ty, cur, max)| VcpValue {
178 ty: match ty {
179 MC_SET_PARAMETER => 0,
180 MC_MOMENTARY => 1,
181 _ => 0, },
183 mh: (max >> 8) as _,
184 ml: max as _,
185 sh: (cur >> 8) as _,
186 sl: cur as _,
187 })
188 }
189
190 fn set_vcp_feature(&mut self, code: FeatureCode, value: u16) -> Result<(), Self::Error> {
191 self.winapi_set_vcp_feature(code, value as _)
192 }
193
194 fn save_current_settings(&mut self) -> Result<(), Self::Error> {
195 self.winapi_save_current_settings()
196 }
197
198 fn get_timing_report(&mut self) -> Result<TimingMessage, Self::Error> {
199 self.winapi_get_timing_report()
200 .map(|timing| TimingMessage {
201 timing_status: timing.bTimingStatusByte,
202 horizontal_frequency: timing.dwHorizontalFrequencyInHZ as _,
203 vertical_frequency: timing.dwVerticalFrequencyInHZ as _,
204 })
205 }
206}
207
208impl Drop for Monitor {
209 fn drop(&mut self) {
210 unsafe {
211 DestroyPhysicalMonitor(self.handle());
212 }
213 }
214}
215
216impl fmt::Debug for Monitor {
217 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218 f.debug_struct("Monitor")
219 .field("handle", &self.handle())
220 .field("description", &self.description())
221 .finish()
222 }
223}
224
225pub fn get_physical_monitors_from_hmonitor(monitor: HMONITOR) -> io::Result<Vec<PHYSICAL_MONITOR>> {
227 unsafe {
228 let mut len = 0;
229 if GetNumberOfPhysicalMonitorsFromHMONITOR(monitor, &mut len) != TRUE {
230 return Err(io::Error::last_os_error())
231 }
232
233 let mut monitors = vec![mem::zeroed::<PHYSICAL_MONITOR>(); len as usize];
234 if GetPhysicalMonitorsFromHMONITOR(monitor, len, monitors.as_mut_ptr()) != TRUE {
235 Err(io::Error::last_os_error())
236 } else {
237 Ok(monitors)
238 }
239 }
240}
241
242pub fn enumerate_monitors() -> io::Result<Vec<HMONITOR>> {
244 unsafe extern "system" fn callback(monitor: HMONITOR, _hdc_monitor: HDC, _lprc: LPRECT, userdata: LPARAM) -> BOOL {
245 let monitors: &mut Vec<HMONITOR> = &mut *(userdata as *mut Vec<HMONITOR>);
246 monitors.push(monitor);
247 TRUE
248 }
249
250 let mut monitors = Vec::<HMONITOR>::new();
251 if unsafe {
252 let userdata = ptr::addr_of_mut!(monitors);
253 winapi::um::winuser::EnumDisplayMonitors(ptr::null_mut(), ptr::null(), Some(callback), userdata as _)
254 } != TRUE {
255 Err(io::Error::last_os_error())
256 } else {
257 Ok(monitors)
258 }
259}