2014-12-02 04:24:15 +11:00
|
|
|
use winapi;
|
2015-01-26 13:52:17 +11:00
|
|
|
use user32;
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2015-02-22 00:40:23 +11:00
|
|
|
use std::collections::VecDeque;
|
2015-03-26 05:57:38 +11:00
|
|
|
use std::mem;
|
2015-01-02 18:09:16 +11:00
|
|
|
|
2015-03-19 08:16:35 +11:00
|
|
|
use native_monitor::NativeMonitorId;
|
2015-03-17 07:52:58 +11:00
|
|
|
|
2014-08-02 07:02:26 +10:00
|
|
|
/// Win32 implementation of the main `MonitorID` object.
|
2015-07-19 21:53:40 +10:00
|
|
|
#[derive(Clone)]
|
2014-07-31 18:52:05 +10:00
|
|
|
pub struct MonitorID {
|
2015-03-25 07:29:17 +11:00
|
|
|
/// The system name of the adapter.
|
|
|
|
adapter_name: [winapi::WCHAR; 32],
|
|
|
|
|
2014-08-02 07:02:26 +10:00
|
|
|
/// The system name of the monitor.
|
2015-03-25 07:29:17 +11:00
|
|
|
monitor_name: String,
|
2014-08-02 07:02:26 +10:00
|
|
|
|
|
|
|
/// Name to give to the user.
|
2014-07-31 18:52:05 +10:00
|
|
|
readable_name: String,
|
2014-08-02 07:02:26 +10:00
|
|
|
|
|
|
|
/// See the `StateFlags` element here:
|
|
|
|
/// http://msdn.microsoft.com/en-us/library/dd183569(v=vs.85).aspx
|
2014-12-02 04:24:15 +11:00
|
|
|
flags: winapi::DWORD,
|
2014-08-02 07:02:26 +10:00
|
|
|
|
2015-04-12 17:32:25 +10:00
|
|
|
/// True if this is the primary monitor.
|
|
|
|
primary: bool,
|
|
|
|
|
2014-08-02 07:02:26 +10:00
|
|
|
/// The position of the monitor in pixels on the desktop.
|
|
|
|
///
|
|
|
|
/// A window that is positionned at these coordinates will overlap the monitor.
|
2015-01-13 23:21:36 +11:00
|
|
|
position: (u32, u32),
|
2014-08-02 19:17:49 +10:00
|
|
|
|
|
|
|
/// The current resolution in pixels on the monitor.
|
2015-01-13 23:21:36 +11:00
|
|
|
dimensions: (u32, u32),
|
2014-07-31 18:52:05 +10:00
|
|
|
}
|
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
struct DeviceEnumerator {
|
|
|
|
parent_device: *const winapi::WCHAR,
|
|
|
|
current_index: u32,
|
|
|
|
}
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
impl DeviceEnumerator {
|
|
|
|
fn adapters() -> DeviceEnumerator {
|
|
|
|
use std::ptr;
|
|
|
|
DeviceEnumerator {
|
|
|
|
parent_device: ptr::null(),
|
|
|
|
current_index: 0
|
|
|
|
}
|
|
|
|
}
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
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 {
|
2014-12-02 04:24:15 +11:00
|
|
|
let mut output: winapi::DISPLAY_DEVICEW = unsafe { mem::zeroed() };
|
|
|
|
output.cb = mem::size_of::<winapi::DISPLAY_DEVICEW>() as winapi::DWORD;
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
if unsafe { user32::EnumDisplayDevicesW(self.parent_device,
|
|
|
|
self.current_index as winapi::DWORD, &mut output, 0) } == 0
|
2014-08-02 07:02:26 +10:00
|
|
|
{
|
|
|
|
// the device doesn't exist, which means we have finished enumerating
|
|
|
|
break;
|
|
|
|
}
|
2015-03-25 07:29:17 +11:00
|
|
|
self.current_index += 1;
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2014-12-02 04:24:15 +11:00
|
|
|
if (output.StateFlags & winapi::DISPLAY_DEVICE_ACTIVE) == 0 ||
|
|
|
|
(output.StateFlags & winapi::DISPLAY_DEVICE_MIRRORING_DRIVER) != 0
|
2014-08-02 07:02:26 +10:00
|
|
|
{
|
|
|
|
// the device is not active
|
|
|
|
// the Win32 api usually returns a lot of inactive devices
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
return Some(output);
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
fn wchar_as_string(wchar: &[winapi::WCHAR]) -> String {
|
|
|
|
String::from_utf16_lossy(wchar)
|
|
|
|
.trim_right_matches(0 as char)
|
|
|
|
.to_string()
|
|
|
|
}
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
/// Win32 implementation of the main `get_available_monitors` function.
|
|
|
|
pub fn get_available_monitors() -> VecDeque<MonitorID> {
|
|
|
|
// return value
|
|
|
|
let mut result = VecDeque::new();
|
|
|
|
|
|
|
|
for adapter in DeviceEnumerator::adapters() {
|
2014-08-02 07:02:26 +10:00
|
|
|
// getting the position
|
2014-08-02 19:17:49 +10:00
|
|
|
let (position, dimensions) = unsafe {
|
2014-12-02 04:24:15 +11:00
|
|
|
let mut dev: winapi::DEVMODEW = mem::zeroed();
|
|
|
|
dev.dmSize = mem::size_of::<winapi::DEVMODEW>() as winapi::WORD;
|
2014-07-31 18:52:05 +10:00
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
if user32::EnumDisplaySettingsExW(adapter.DeviceName.as_ptr(),
|
|
|
|
winapi::ENUM_CURRENT_SETTINGS,
|
2014-07-31 18:52:05 +10:00
|
|
|
&mut dev, 0) == 0
|
|
|
|
{
|
2014-08-02 07:02:26 +10:00
|
|
|
continue;
|
2014-07-31 18:52:05 +10:00
|
|
|
}
|
|
|
|
|
2014-12-02 04:24:15 +11:00
|
|
|
let point: &winapi::POINTL = mem::transmute(&dev.union1);
|
2015-01-13 23:21:36 +11:00
|
|
|
let position = (point.x as u32, point.y as u32);
|
2014-08-02 19:17:49 +10:00
|
|
|
|
2015-01-13 23:21:36 +11:00
|
|
|
let dimensions = (dev.dmPelsWidth as u32, dev.dmPelsHeight as u32);
|
2014-08-02 19:17:49 +10:00
|
|
|
|
|
|
|
(position, dimensions)
|
2014-07-31 18:52:05 +10:00
|
|
|
};
|
|
|
|
|
2015-04-12 17:32:25 +10:00
|
|
|
for (num, monitor) in DeviceEnumerator::monitors(adapter.DeviceName.as_ptr()).enumerate() {
|
2015-03-25 07:29:17 +11:00
|
|
|
// adding to the resulting list
|
|
|
|
result.push_back(MonitorID {
|
|
|
|
adapter_name: adapter.DeviceName,
|
2015-03-26 05:57:38 +11:00
|
|
|
monitor_name: wchar_as_string(&monitor.DeviceName),
|
|
|
|
readable_name: wchar_as_string(&monitor.DeviceString),
|
2015-03-25 07:29:17 +11:00
|
|
|
flags: monitor.StateFlags,
|
2015-04-12 17:32:25 +10:00
|
|
|
primary: (adapter.StateFlags & winapi::DISPLAY_DEVICE_PRIMARY_DEVICE) != 0 &&
|
|
|
|
num == 0,
|
2015-03-25 07:29:17 +11:00
|
|
|
position: position,
|
|
|
|
dimensions: dimensions,
|
|
|
|
});
|
|
|
|
}
|
2014-07-31 18:52:05 +10:00
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2014-08-02 07:02:26 +10:00
|
|
|
/// Win32 implementation of the main `get_primary_monitor` function.
|
2014-07-31 18:52:05 +10:00
|
|
|
pub fn get_primary_monitor() -> MonitorID {
|
2014-08-02 07:02:26 +10:00
|
|
|
// we simply get all available monitors and return the one with the `PRIMARY_DEVICE` flag
|
|
|
|
// TODO: it is possible to query the win32 API for the primary monitor, this should be done
|
|
|
|
// instead
|
2014-09-23 16:01:18 +10:00
|
|
|
for monitor in get_available_monitors().into_iter() {
|
2015-04-12 17:32:25 +10:00
|
|
|
if monitor.primary {
|
|
|
|
return monitor;
|
2014-07-31 18:52:05 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-30 18:14:09 +11:00
|
|
|
panic!("Failed to find the primary monitor")
|
2014-07-31 18:52:05 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MonitorID {
|
2014-08-02 07:02:26 +10:00
|
|
|
/// See the docs if the crate root file.
|
2015-09-21 22:42:05 +10:00
|
|
|
#[inline]
|
2014-07-31 18:52:05 +10:00
|
|
|
pub fn get_name(&self) -> Option<String> {
|
|
|
|
Some(self.readable_name.clone())
|
|
|
|
}
|
|
|
|
|
2015-03-17 07:52:58 +11:00
|
|
|
/// See the docs of the crate root file.
|
2015-09-21 22:42:05 +10:00
|
|
|
#[inline]
|
2015-03-19 08:16:35 +11:00
|
|
|
pub fn get_native_identifier(&self) -> NativeMonitorId {
|
2015-03-25 07:29:17 +11:00
|
|
|
NativeMonitorId::Name(self.monitor_name.clone())
|
2015-03-17 07:52:58 +11:00
|
|
|
}
|
|
|
|
|
2014-08-02 19:17:49 +10:00
|
|
|
/// See the docs if the crate root file.
|
2015-09-21 22:42:05 +10:00
|
|
|
#[inline]
|
2015-01-13 23:21:36 +11:00
|
|
|
pub fn get_dimensions(&self) -> (u32, u32) {
|
2014-08-02 19:17:49 +10:00
|
|
|
// TODO: retreive the dimensions every time this is called
|
|
|
|
self.dimensions
|
|
|
|
}
|
|
|
|
|
2015-03-25 07:29:17 +11:00
|
|
|
/// This is a Win32-only function for `MonitorID` that returns the system name of the adapter
|
|
|
|
/// device.
|
2015-09-21 22:42:05 +10:00
|
|
|
#[inline]
|
2015-03-25 07:29:17 +11:00
|
|
|
pub fn get_adapter_name(&self) -> &[winapi::WCHAR] {
|
2015-03-26 05:57:38 +11:00
|
|
|
&self.adapter_name
|
2014-07-31 18:52:05 +10:00
|
|
|
}
|
|
|
|
|
2014-08-02 07:02:26 +10:00
|
|
|
/// This is a Win32-only function for `MonitorID` that returns the position of the
|
2015-01-02 18:09:16 +11:00
|
|
|
/// monitor on the desktop.
|
2014-08-02 07:02:26 +10:00
|
|
|
/// A window that is positionned at these coordinates will overlap the monitor.
|
2015-09-21 22:42:05 +10:00
|
|
|
#[inline]
|
2015-01-13 23:21:36 +11:00
|
|
|
pub fn get_position(&self) -> (u32, u32) {
|
2014-07-31 18:52:05 +10:00
|
|
|
self.position
|
|
|
|
}
|
|
|
|
}
|