use winapi;
use user32;
use std::collections::VecDeque;
use std::mem;
use native_monitor::NativeMonitorId;
#[derive(Clone)]
pub struct MonitorId {
adapter_name: [winapi::WCHAR; 32],
monitor_name: String,
readable_name: String,
flags: winapi::DWORD,
primary: bool,
position: (u32, u32),
dimensions: (u32, u32),
}
struct DeviceEnumerator {
parent_device: *const winapi::WCHAR,
current_index: u32,
}
impl DeviceEnumerator {
fn adapters() -> DeviceEnumerator {
use std::ptr;
DeviceEnumerator {
parent_device: ptr::null(),
current_index: 0
}
}
fn monitors(adapter_name: *const winapi::WCHAR) -> DeviceEnumerator {
DeviceEnumerator {
parent_device: adapter_name,
current_index: 0
}
}
}
impl Iterator for DeviceEnumerator {
type Item = winapi::DISPLAY_DEVICEW;
fn next(&mut self) -> Option<winapi::DISPLAY_DEVICEW> {
use std::mem;
loop {
let mut output: winapi::DISPLAY_DEVICEW = unsafe { mem::zeroed() };
output.cb = mem::size_of::<winapi::DISPLAY_DEVICEW>() as winapi::DWORD;
if unsafe { user32::EnumDisplayDevicesW(self.parent_device,
self.current_index as winapi::DWORD, &mut output, 0) } == 0
{
break;
}
self.current_index += 1;
if (output.StateFlags & winapi::DISPLAY_DEVICE_ACTIVE) == 0 ||
(output.StateFlags & winapi::DISPLAY_DEVICE_MIRRORING_DRIVER) != 0
{
continue;
}
return Some(output);
}
None
}
}
fn wchar_as_string(wchar: &[winapi::WCHAR]) -> String {
String::from_utf16_lossy(wchar)
.trim_right_matches(0 as char)
.to_string()
}
pub fn get_available_monitors() -> VecDeque<MonitorId> {
let mut result = VecDeque::new();
for adapter in DeviceEnumerator::adapters() {
let (position, dimensions) = unsafe {
let mut dev: winapi::DEVMODEW = mem::zeroed();
dev.dmSize = mem::size_of::<winapi::DEVMODEW>() as winapi::WORD;
if user32::EnumDisplaySettingsExW(adapter.DeviceName.as_ptr(),
winapi::ENUM_CURRENT_SETTINGS,
&mut dev, 0) == 0
{
continue;
}
let point: &winapi::POINTL = mem::transmute(&dev.union1);
let position = (point.x as u32, point.y as u32);
let dimensions = (dev.dmPelsWidth as u32, dev.dmPelsHeight as u32);
(position, dimensions)
};
for (num, monitor) in DeviceEnumerator::monitors(adapter.DeviceName.as_ptr()).enumerate() {
result.push_back(MonitorId {
adapter_name: adapter.DeviceName,
monitor_name: wchar_as_string(&monitor.DeviceName),
readable_name: wchar_as_string(&monitor.DeviceString),
flags: monitor.StateFlags,
primary: (adapter.StateFlags & winapi::DISPLAY_DEVICE_PRIMARY_DEVICE) != 0 &&
num == 0,
position: position,
dimensions: dimensions,
});
}
}
result
}
pub fn get_primary_monitor() -> MonitorId {
for monitor in get_available_monitors().into_iter() {
if monitor.primary {
return monitor;
}
}
panic!("Failed to find the primary monitor")
}
impl MonitorId {
#[inline]
pub fn get_name(&self) -> Option<String> {
Some(self.readable_name.clone())
}
#[inline]
pub fn get_native_identifier(&self) -> NativeMonitorId {
NativeMonitorId::Name(self.monitor_name.clone())
}
#[inline]
pub fn get_dimensions(&self) -> (u32, u32) {
self.dimensions
}
#[inline]
pub fn get_adapter_name(&self) -> &[winapi::WCHAR] {
&self.adapter_name
}
#[inline]
pub fn get_position(&self) -> (u32, u32) {
self.position
}
}