mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
Use EnumDisplayMonitors to enumerate monitors on Windows (#327)
* Use EnumDisplayMonitors to enumerate monitors on Windows * Add requested changes
This commit is contained in:
parent
d10312c6b1
commit
760e588627
|
@ -9,6 +9,9 @@
|
||||||
- `MonitorId::get_position` now returns `(i32, i32)` instead of `(u32, u32)`.
|
- `MonitorId::get_position` now returns `(i32, i32)` instead of `(u32, u32)`.
|
||||||
- Rewrite of the wayland backend to use wayland-client-0.11
|
- Rewrite of the wayland backend to use wayland-client-0.11
|
||||||
- Support for dead keys on wayland for keyboard utf8 input
|
- Support for dead keys on wayland for keyboard utf8 input
|
||||||
|
- Monitor enumeration on Windows is now implemented using `EnumDisplayMonitors` instead of
|
||||||
|
`EnumDisplayDevices`. This changes the value returned by `MonitorId::get_name()`.
|
||||||
|
- On Windows added `MonitorIdExt::hmonitor` method
|
||||||
|
|
||||||
# Version 0.8.3 (2017-10-11)
|
# Version 0.8.3 (2017-10-11)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![cfg(target_os = "windows")]
|
#![cfg(target_os = "windows")]
|
||||||
|
|
||||||
|
use std::os::raw::c_void;
|
||||||
use libc;
|
use libc;
|
||||||
use MonitorId;
|
use MonitorId;
|
||||||
use Window;
|
use Window;
|
||||||
|
@ -37,8 +38,11 @@ impl WindowBuilderExt for WindowBuilder {
|
||||||
|
|
||||||
/// Additional methods on `MonitorId` that are specific to Windows.
|
/// Additional methods on `MonitorId` that are specific to Windows.
|
||||||
pub trait MonitorIdExt {
|
pub trait MonitorIdExt {
|
||||||
/// Returns the name of the monitor specific to the Win32 API.
|
/// Returns the name of the monitor adapter specific to the Win32 API.
|
||||||
fn native_id(&self) -> String;
|
fn native_id(&self) -> String;
|
||||||
|
|
||||||
|
/// Returns the handle of the monitor - `HMONITOR`.
|
||||||
|
fn hmonitor(&self) -> *mut c_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonitorIdExt for MonitorId {
|
impl MonitorIdExt for MonitorId {
|
||||||
|
@ -46,4 +50,9 @@ impl MonitorIdExt for MonitorId {
|
||||||
fn native_id(&self) -> String {
|
fn native_id(&self) -> String {
|
||||||
self.inner.get_native_identifier()
|
self.inner.get_native_identifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn hmonitor(&self) -> *mut c_void {
|
||||||
|
self.inner.get_hmonitor() as *mut _
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use winapi;
|
||||||
use user32;
|
use user32;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem;
|
use std::{mem, ptr};
|
||||||
|
|
||||||
use super::EventsLoop;
|
use super::EventsLoop;
|
||||||
|
|
||||||
|
@ -12,16 +12,12 @@ pub struct MonitorId {
|
||||||
/// The system name of the adapter.
|
/// The system name of the adapter.
|
||||||
adapter_name: [winapi::WCHAR; 32],
|
adapter_name: [winapi::WCHAR; 32],
|
||||||
|
|
||||||
|
/// Monitor handle.
|
||||||
|
hmonitor: HMonitor,
|
||||||
|
|
||||||
/// The system name of the monitor.
|
/// The system name of the monitor.
|
||||||
monitor_name: String,
|
monitor_name: String,
|
||||||
|
|
||||||
/// Name to give to the user.
|
|
||||||
readable_name: String,
|
|
||||||
|
|
||||||
/// See the `StateFlags` element here:
|
|
||||||
/// http://msdn.microsoft.com/en-us/library/dd183569(v=vs.85).aspx
|
|
||||||
flags: winapi::DWORD,
|
|
||||||
|
|
||||||
/// True if this is the primary monitor.
|
/// True if this is the primary monitor.
|
||||||
primary: bool,
|
primary: bool,
|
||||||
|
|
||||||
|
@ -32,59 +28,19 @@ pub struct MonitorId {
|
||||||
|
|
||||||
/// The current resolution in pixels on the monitor.
|
/// The current resolution in pixels on the monitor.
|
||||||
dimensions: (u32, u32),
|
dimensions: (u32, u32),
|
||||||
|
|
||||||
|
/// DPI scaling factor.
|
||||||
|
hidpi_factor: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceEnumerator {
|
// Send is not implemented for HMONITOR, we have to wrap it and implement it manually.
|
||||||
parent_device: *const winapi::WCHAR,
|
// For more info see:
|
||||||
current_index: u32,
|
// https://github.com/retep998/winapi-rs/issues/360
|
||||||
}
|
// https://github.com/retep998/winapi-rs/issues/396
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct HMonitor(winapi::HMONITOR);
|
||||||
|
|
||||||
impl DeviceEnumerator {
|
unsafe impl Send for HMonitor {}
|
||||||
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
|
|
||||||
{
|
|
||||||
// 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
|
|
||||||
{
|
|
||||||
// the device is not active
|
|
||||||
// the Win32 api usually returns a lot of inactive devices
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(output);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wchar_as_string(wchar: &[winapi::WCHAR]) -> String {
|
fn wchar_as_string(wchar: &[winapi::WCHAR]) -> String {
|
||||||
String::from_utf16_lossy(wchar)
|
String::from_utf16_lossy(wchar)
|
||||||
|
@ -92,51 +48,45 @@ fn wchar_as_string(wchar: &[winapi::WCHAR]) -> String {
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn monitor_enum_proc(hmonitor: winapi::HMONITOR, _: winapi::HDC, place: winapi::LPRECT, data: winapi::LPARAM) -> winapi::BOOL {
|
||||||
|
let monitors = data as *mut VecDeque<MonitorId>;
|
||||||
|
|
||||||
|
let place = *place;
|
||||||
|
let position = (place.left as i32, place.top as i32);
|
||||||
|
let dimensions = ((place.right - place.left) as u32, (place.bottom - place.top) as u32);
|
||||||
|
|
||||||
|
let mut monitor_info: winapi::MONITORINFOEXW = mem::zeroed();
|
||||||
|
monitor_info.cbSize = mem::size_of::<winapi::MONITORINFOEXW>() as winapi::DWORD;
|
||||||
|
if user32::GetMonitorInfoW(hmonitor, &mut monitor_info as *mut winapi::MONITORINFOEXW as *mut winapi::MONITORINFO) == 0 {
|
||||||
|
// Some error occurred, just skip this monitor and go on.
|
||||||
|
return winapi::TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*monitors).push_back(MonitorId {
|
||||||
|
adapter_name: monitor_info.szDevice,
|
||||||
|
hmonitor: HMonitor(hmonitor),
|
||||||
|
monitor_name: wchar_as_string(&monitor_info.szDevice),
|
||||||
|
primary: monitor_info.dwFlags & winapi::MONITORINFOF_PRIMARY != 0,
|
||||||
|
position,
|
||||||
|
dimensions,
|
||||||
|
hidpi_factor: 1.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TRUE means continue enumeration.
|
||||||
|
winapi::TRUE
|
||||||
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
||||||
// return value
|
unsafe {
|
||||||
let mut result = VecDeque::new();
|
let mut result: VecDeque<MonitorId> = VecDeque::new();
|
||||||
|
user32::EnumDisplayMonitors(ptr::null_mut(), ptr::null_mut(), Some(monitor_enum_proc), &mut result as *mut _ as winapi::LPARAM);
|
||||||
for adapter in DeviceEnumerator::adapters() {
|
|
||||||
// getting the position
|
|
||||||
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 i32, point.y as i32);
|
|
||||||
|
|
||||||
let dimensions = (dev.dmPelsWidth as u32, dev.dmPelsHeight as u32);
|
|
||||||
|
|
||||||
(position, dimensions)
|
|
||||||
};
|
|
||||||
|
|
||||||
for (num, monitor) in DeviceEnumerator::monitors(adapter.DeviceName.as_ptr()).enumerate() {
|
|
||||||
// adding to the resulting list
|
|
||||||
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
|
result
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_primary_monitor(&self) -> MonitorId {
|
pub fn get_primary_monitor(&self) -> MonitorId {
|
||||||
// we simply get all available monitors and return the one with the `PRIMARY_DEVICE` flag
|
// we simply get all available monitors and return the one with the `MONITORINFOF_PRIMARY` flag
|
||||||
// TODO: it is possible to query the win32 API for the primary monitor, this should be done
|
// TODO: it is possible to query the win32 API for the primary monitor, this should be done
|
||||||
// instead
|
// instead
|
||||||
for monitor in self.get_available_monitors().into_iter() {
|
for monitor in self.get_available_monitors().into_iter() {
|
||||||
|
@ -153,7 +103,7 @@ impl MonitorId {
|
||||||
/// See the docs if the crate root file.
|
/// See the docs if the crate root file.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_name(&self) -> Option<String> {
|
pub fn get_name(&self) -> Option<String> {
|
||||||
Some(self.readable_name.clone())
|
Some(self.monitor_name.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See the docs of the crate root file.
|
/// See the docs of the crate root file.
|
||||||
|
@ -162,10 +112,16 @@ impl MonitorId {
|
||||||
self.monitor_name.clone()
|
self.monitor_name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See the docs if the crate root file.
|
/// See the docs of the crate root file.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_hmonitor(&self) -> winapi::HMONITOR {
|
||||||
|
self.hmonitor.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See the docs of the crate root file.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_dimensions(&self) -> (u32, u32) {
|
pub fn get_dimensions(&self) -> (u32, u32) {
|
||||||
// TODO: retreive the dimensions every time this is called
|
// TODO: retrieve the dimensions every time this is called
|
||||||
self.dimensions
|
self.dimensions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +140,6 @@ impl MonitorId {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_hidpi_factor(&self) -> f32 {
|
pub fn get_hidpi_factor(&self) -> f32 {
|
||||||
1.0
|
self.hidpi_factor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue