enumerate monitors in addition to adapters; this allows the MonitorID implementation to return a more useful monitor name, and the correct native monitor ID

This commit is contained in:
Ryan Stewart 2015-03-24 13:29:17 -07:00
parent 1c20ff87f1
commit 1c9c5c018a
2 changed files with 70 additions and 34 deletions

View file

@ -301,7 +301,7 @@ unsafe fn switch_to_fullscreen(rect: &mut winapi::RECT, monitor: &MonitorID)
screen_settings.dmBitsPerPel = 32; // TODO: ? screen_settings.dmBitsPerPel = 32; // TODO: ?
screen_settings.dmFields = winapi::DM_BITSPERPEL | winapi::DM_PELSWIDTH | winapi::DM_PELSHEIGHT; screen_settings.dmFields = winapi::DM_BITSPERPEL | winapi::DM_PELSWIDTH | winapi::DM_PELSHEIGHT;
let result = user32::ChangeDisplaySettingsExW(monitor.get_system_name().as_ptr(), let result = user32::ChangeDisplaySettingsExW(monitor.get_adapter_name().as_ptr(),
&mut screen_settings, ptr::null_mut(), &mut screen_settings, ptr::null_mut(),
winapi::CDS_FULLSCREEN, ptr::null_mut()); winapi::CDS_FULLSCREEN, ptr::null_mut());

View file

@ -7,8 +7,11 @@ use native_monitor::NativeMonitorId;
/// Win32 implementation of the main `MonitorID` object. /// Win32 implementation of the main `MonitorID` object.
pub struct MonitorID { pub struct MonitorID {
/// The system name of the adapter.
adapter_name: [winapi::WCHAR; 32],
/// The system name of the monitor. /// The system name of the monitor.
name: [winapi::WCHAR; 32], monitor_name: String,
/// Name to give to the user. /// Name to give to the user.
readable_name: String, readable_name: String,
@ -26,27 +29,43 @@ pub struct MonitorID {
dimensions: (u32, u32), dimensions: (u32, u32),
} }
/// Win32 implementation of the main `get_available_monitors` function. struct DeviceEnumerator {
pub fn get_available_monitors() -> VecDeque<MonitorID> { parent_device: *const winapi::WCHAR,
use std::{iter, mem, ptr}; current_index: u32,
}
// return value impl DeviceEnumerator {
let mut result = VecDeque::new(); fn adapters() -> DeviceEnumerator {
use std::ptr;
DeviceEnumerator {
parent_device: ptr::null(),
current_index: 0
}
}
// enumerating the devices is done by querying device 0, then device 1, then device 2, etc. fn monitors(adapter_name: *const winapi::WCHAR) -> DeviceEnumerator {
// until the query function returns null DeviceEnumerator {
for id in iter::count(0u32, 1) { parent_device: adapter_name,
// getting the DISPLAY_DEVICEW object of the current device current_index: 0
let output = { }
}
}
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() }; let mut output: winapi::DISPLAY_DEVICEW = unsafe { mem::zeroed() };
output.cb = mem::size_of::<winapi::DISPLAY_DEVICEW>() as winapi::DWORD; output.cb = mem::size_of::<winapi::DISPLAY_DEVICEW>() as winapi::DWORD;
if unsafe { user32::EnumDisplayDevicesW(ptr::null(), if unsafe { user32::EnumDisplayDevicesW(self.parent_device,
id as winapi::DWORD, &mut output, 0) } == 0 self.current_index as winapi::DWORD, &mut output, 0) } == 0
{ {
// the device doesn't exist, which means we have finished enumerating // the device doesn't exist, which means we have finished enumerating
break; break;
} }
self.current_index += 1;
if (output.StateFlags & winapi::DISPLAY_DEVICE_ACTIVE) == 0 || if (output.StateFlags & winapi::DISPLAY_DEVICE_ACTIVE) == 0 ||
(output.StateFlags & winapi::DISPLAY_DEVICE_MIRRORING_DRIVER) != 0 (output.StateFlags & winapi::DISPLAY_DEVICE_MIRRORING_DRIVER) != 0
@ -56,19 +75,34 @@ pub fn get_available_monitors() -> VecDeque<MonitorID> {
continue; continue;
} }
output return Some(output);
}; }
None
}
}
// computing the human-friendly name fn wchar_as_string(wchar: &[winapi::WCHAR]) -> String {
let readable_name = String::from_utf16_lossy(output.DeviceString.as_slice()); String::from_utf16_lossy(wchar)
let readable_name = readable_name.as_slice().trim_right_matches(0 as char).to_string(); .as_slice()
.trim_right_matches(0 as char)
.to_string()
}
/// Win32 implementation of the main `get_available_monitors` function.
pub fn get_available_monitors() -> VecDeque<MonitorID> {
use std::{iter, mem, ptr};
// return value
let mut result = VecDeque::new();
for adapter in DeviceEnumerator::adapters() {
// getting the position // getting the position
let (position, dimensions) = unsafe { let (position, dimensions) = unsafe {
let mut dev: winapi::DEVMODEW = mem::zeroed(); let mut dev: winapi::DEVMODEW = mem::zeroed();
dev.dmSize = mem::size_of::<winapi::DEVMODEW>() as winapi::WORD; dev.dmSize = mem::size_of::<winapi::DEVMODEW>() as winapi::WORD;
if user32::EnumDisplaySettingsExW(output.DeviceName.as_ptr(), winapi::ENUM_CURRENT_SETTINGS, if user32::EnumDisplaySettingsExW(adapter.DeviceName.as_ptr(),
winapi::ENUM_CURRENT_SETTINGS,
&mut dev, 0) == 0 &mut dev, 0) == 0
{ {
continue; continue;
@ -82,16 +116,18 @@ pub fn get_available_monitors() -> VecDeque<MonitorID> {
(position, dimensions) (position, dimensions)
}; };
for monitor in DeviceEnumerator::monitors(adapter.DeviceName.as_ptr()) {
// adding to the resulting list // adding to the resulting list
result.push_back(MonitorID { result.push_back(MonitorID {
name: output.DeviceName, adapter_name: adapter.DeviceName,
readable_name: readable_name, monitor_name: wchar_as_string(monitor.DeviceName.as_slice()),
flags: output.StateFlags, readable_name: wchar_as_string(monitor.DeviceString.as_slice()),
flags: monitor.StateFlags,
position: position, position: position,
dimensions: dimensions, dimensions: dimensions,
}); });
} }
}
result result
} }
@ -117,7 +153,7 @@ impl MonitorID {
/// See the docs of the crate root file. /// See the docs of the crate root file.
pub fn get_native_identifier(&self) -> NativeMonitorId { pub fn get_native_identifier(&self) -> NativeMonitorId {
NativeMonitorId::Name(self.readable_name.clone()) NativeMonitorId::Name(self.monitor_name.clone())
} }
/// See the docs if the crate root file. /// See the docs if the crate root file.
@ -126,10 +162,10 @@ impl MonitorID {
self.dimensions self.dimensions
} }
/// This is a Win32-only function for `MonitorID` that returns the system name of the device. /// This is a Win32-only function for `MonitorID` that returns the system name of the adapter
pub fn get_system_name(&self) -> &[winapi::WCHAR] { /// device.
// TODO: retreive the position every time this is called pub fn get_adapter_name(&self) -> &[winapi::WCHAR] {
self.name.as_slice() self.adapter_name.as_slice()
} }
/// This is a Win32-only function for `MonitorID` that returns the position of the /// This is a Win32-only function for `MonitorID` that returns the position of the