Merge pull request #324 from binsoftware/win32-monitor

Win32 monitor handling
This commit is contained in:
tomaka 2015-03-25 06:17:35 +01:00
commit 8c78cabcf2
2 changed files with 77 additions and 36 deletions

View file

@ -164,6 +164,12 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
(None, None) (None, None)
}; };
let (x, y) = if builder.monitor.is_some() {
(Some(rect.left), Some(rect.top))
} else {
(None, None)
};
let style = if !builder.visible || builder.headless { let style = if !builder.visible || builder.headless {
style style
} else { } else {
@ -173,8 +179,7 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
let handle = user32::CreateWindowExW(ex_style, class_name.as_ptr(), let handle = user32::CreateWindowExW(ex_style, class_name.as_ptr(),
title.as_ptr() as winapi::LPCWSTR, title.as_ptr() as winapi::LPCWSTR,
style | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN, style | winapi::WS_CLIPSIBLINGS | winapi::WS_CLIPCHILDREN,
if builder.monitor.is_some() { 0 } else { winapi::CW_USEDEFAULT }, x.unwrap_or(winapi::CW_USEDEFAULT), y.unwrap_or(winapi::CW_USEDEFAULT),
if builder.monitor.is_some() { 0 } else { winapi::CW_USEDEFAULT },
width.unwrap_or(winapi::CW_USEDEFAULT), height.unwrap_or(winapi::CW_USEDEFAULT), width.unwrap_or(winapi::CW_USEDEFAULT), height.unwrap_or(winapi::CW_USEDEFAULT),
ptr::null_mut(), ptr::null_mut(), kernel32::GetModuleHandleW(ptr::null()), ptr::null_mut(), ptr::null_mut(), kernel32::GetModuleHandleW(ptr::null()),
ptr::null_mut()); ptr::null_mut());
@ -296,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)
}; };
// adding to the resulting list for monitor in DeviceEnumerator::monitors(adapter.DeviceName.as_ptr()) {
result.push_back(MonitorID { // adding to the resulting list
name: output.DeviceName, result.push_back(MonitorID {
readable_name: readable_name, adapter_name: adapter.DeviceName,
flags: output.StateFlags, monitor_name: wchar_as_string(monitor.DeviceName.as_slice()),
position: position, readable_name: wchar_as_string(monitor.DeviceString.as_slice()),
dimensions: dimensions, flags: monitor.StateFlags,
}); position: position,
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