From 1c9c5c018a24ebd5593c15b184d36945793aff5e Mon Sep 17 00:00:00 2001 From: Ryan Stewart Date: Tue, 24 Mar 2015 13:29:17 -0700 Subject: enumerate monitors in addition to adapters; this allows the MonitorID implementation to return a more useful monitor name, and the correct native monitor ID --- src/win32/init.rs | 2 +- src/win32/monitor.rs | 102 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/win32/init.rs b/src/win32/init.rs index 8ec8cb1..8d2eb1e 100644 --- a/src/win32/init.rs +++ b/src/win32/init.rs @@ -301,7 +301,7 @@ unsafe fn switch_to_fullscreen(rect: &mut winapi::RECT, monitor: &MonitorID) screen_settings.dmBitsPerPel = 32; // TODO: ? 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(), winapi::CDS_FULLSCREEN, ptr::null_mut()); diff --git a/src/win32/monitor.rs b/src/win32/monitor.rs index 819aa7f..b5ffe2d 100644 --- a/src/win32/monitor.rs +++ b/src/win32/monitor.rs @@ -7,8 +7,11 @@ use native_monitor::NativeMonitorId; /// Win32 implementation of the main `MonitorID` object. pub struct MonitorID { + /// The system name of the adapter. + adapter_name: [winapi::WCHAR; 32], + /// The system name of the monitor. - name: [winapi::WCHAR; 32], + monitor_name: String, /// Name to give to the user. readable_name: String, @@ -26,27 +29,43 @@ pub struct MonitorID { dimensions: (u32, u32), } -/// Win32 implementation of the main `get_available_monitors` function. -pub fn get_available_monitors() -> VecDeque { - use std::{iter, mem, ptr}; +struct DeviceEnumerator { + parent_device: *const winapi::WCHAR, + current_index: u32, +} - // return value - let mut result = VecDeque::new(); +impl DeviceEnumerator { + 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. - // until the query function returns null - for id in iter::count(0u32, 1) { - // getting the DISPLAY_DEVICEW object of the current device - let output = { + 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 { + use std::mem; + loop { let mut output: winapi::DISPLAY_DEVICEW = unsafe { mem::zeroed() }; output.cb = mem::size_of::() as winapi::DWORD; - if unsafe { user32::EnumDisplayDevicesW(ptr::null(), - id as winapi::DWORD, &mut output, 0) } == 0 + if unsafe { user32::EnumDisplayDevicesW(self.parent_device, + self.current_index as winapi::DWORD, &mut output, 0) } == 0 { // the device doesn't exist, which means we have finished enumerating break; } + self.current_index += 1; if (output.StateFlags & winapi::DISPLAY_DEVICE_ACTIVE) == 0 || (output.StateFlags & winapi::DISPLAY_DEVICE_MIRRORING_DRIVER) != 0 @@ -56,19 +75,34 @@ pub fn get_available_monitors() -> VecDeque { continue; } - output - }; + return Some(output); + } + None + } +} - // computing the human-friendly name - let readable_name = String::from_utf16_lossy(output.DeviceString.as_slice()); - let readable_name = readable_name.as_slice().trim_right_matches(0 as char).to_string(); +fn wchar_as_string(wchar: &[winapi::WCHAR]) -> String { + String::from_utf16_lossy(wchar) + .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 { + use std::{iter, mem, ptr}; + + // return value + let mut result = VecDeque::new(); + + for adapter in DeviceEnumerator::adapters() { // getting the position let (position, dimensions) = unsafe { let mut dev: winapi::DEVMODEW = mem::zeroed(); dev.dmSize = mem::size_of::() 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 { continue; @@ -82,16 +116,18 @@ pub fn get_available_monitors() -> VecDeque { (position, dimensions) }; - // adding to the resulting list - result.push_back(MonitorID { - name: output.DeviceName, - readable_name: readable_name, - flags: output.StateFlags, - position: position, - dimensions: dimensions, - }); + for monitor in DeviceEnumerator::monitors(adapter.DeviceName.as_ptr()) { + // adding to the resulting list + result.push_back(MonitorID { + adapter_name: adapter.DeviceName, + monitor_name: wchar_as_string(monitor.DeviceName.as_slice()), + readable_name: wchar_as_string(monitor.DeviceString.as_slice()), + flags: monitor.StateFlags, + position: position, + dimensions: dimensions, + }); + } } - result } @@ -117,7 +153,7 @@ impl MonitorID { /// See the docs of the crate root file. 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. @@ -126,10 +162,10 @@ impl MonitorID { self.dimensions } - /// This is a Win32-only function for `MonitorID` that returns the system name of the device. - pub fn get_system_name(&self) -> &[winapi::WCHAR] { - // TODO: retreive the position every time this is called - self.name.as_slice() + /// This is a Win32-only function for `MonitorID` that returns the system name of the adapter + /// device. + pub fn get_adapter_name(&self) -> &[winapi::WCHAR] { + self.adapter_name.as_slice() } /// This is a Win32-only function for `MonitorID` that returns the position of the -- cgit v1.2.3