1 use winapi::shared::minwindef::{BOOL, DWORD, LPARAM, TRUE};
2 use winapi::shared::windef::{HDC, HMONITOR, HWND, LPRECT, POINT};
3 use winapi::um::winnt::LONG;
4 use winapi::um::winuser;
5
6 use std::{mem, ptr};
7 use std::collections::VecDeque;
8
9 use super::{EventsLoop, util};
10 use dpi::{PhysicalPosition, PhysicalSize};
11 use platform::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi};
12 use platform::platform::window::Window;
13
14 /// Win32 implementation of the main `MonitorId` object.
15 #[derive(Debug, Clone)]
16 pub struct MonitorId {
17 /// Monitor handle.
18 hmonitor: HMonitor,
19 /// The system name of the monitor.
20 monitor_name: String,
21 /// True if this is the primary monitor.
22 primary: bool,
23 /// The position of the monitor in pixels on the desktop.
24 ///
25 /// A window that is positioned at these coordinates will overlap the monitor.
26 position: (i32, i32),
27 /// The current resolution in pixels on the monitor.
28 dimensions: (u32, u32),
29 /// DPI scale factor.
30 hidpi_factor: f64,
31 }
32
33 // Send is not implemented for HMONITOR, we have to wrap it and implement it manually.
34 // For more info see:
35 // https://github.com/retep998/winapi-rs/issues/360
36 // https://github.com/retep998/winapi-rs/issues/396
37 #[derive(Debug, Clone)]
38 struct HMonitor(HMONITOR);
39
40 unsafe impl Send for HMonitor {}
41
monitor_enum_proc( hmonitor: HMONITOR, _hdc: HDC, _place: LPRECT, data: LPARAM, ) -> BOOL42 unsafe extern "system" fn monitor_enum_proc(
43 hmonitor: HMONITOR,
44 _hdc: HDC,
45 _place: LPRECT,
46 data: LPARAM,
47 ) -> BOOL {
48 let monitors = data as *mut VecDeque<MonitorId>;
49 (*monitors).push_back(MonitorId::from_hmonitor(hmonitor));
50 TRUE // continue enumeration
51 }
52
get_available_monitors() -> VecDeque<MonitorId>53 pub fn get_available_monitors() -> VecDeque<MonitorId> {
54 let mut monitors: VecDeque<MonitorId> = VecDeque::new();
55 unsafe {
56 winuser::EnumDisplayMonitors(
57 ptr::null_mut(),
58 ptr::null_mut(),
59 Some(monitor_enum_proc),
60 &mut monitors as *mut _ as LPARAM,
61 );
62 }
63 monitors
64 }
65
get_primary_monitor() -> MonitorId66 pub fn get_primary_monitor() -> MonitorId {
67 const ORIGIN: POINT = POINT { x: 0, y: 0 };
68 let hmonitor = unsafe {
69 winuser::MonitorFromPoint(ORIGIN, winuser::MONITOR_DEFAULTTOPRIMARY)
70 };
71 MonitorId::from_hmonitor(hmonitor)
72 }
73
74 impl EventsLoop {
75 // TODO: Investigate opportunities for caching
get_available_monitors(&self) -> VecDeque<MonitorId>76 pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
77 get_available_monitors()
78 }
79
get_current_monitor(hwnd: HWND) -> MonitorId80 pub fn get_current_monitor(hwnd: HWND) -> MonitorId {
81 let hmonitor = unsafe {
82 winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST)
83 };
84 MonitorId::from_hmonitor(hmonitor)
85 }
86
get_primary_monitor(&self) -> MonitorId87 pub fn get_primary_monitor(&self) -> MonitorId {
88 get_primary_monitor()
89 }
90 }
91
92 impl Window {
get_available_monitors(&self) -> VecDeque<MonitorId>93 pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
94 get_available_monitors()
95 }
96
get_primary_monitor(&self) -> MonitorId97 pub fn get_primary_monitor(&self) -> MonitorId {
98 get_primary_monitor()
99 }
100 }
101
get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, util::WinError>102 pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, util::WinError> {
103 let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::uninitialized() };
104 monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
105 let status = unsafe {
106 winuser::GetMonitorInfoW(
107 hmonitor,
108 &mut monitor_info as *mut winuser::MONITORINFOEXW as *mut winuser::MONITORINFO,
109 )
110 };
111 if status == 0 {
112 Err(util::WinError::from_last_error())
113 } else {
114 Ok(monitor_info)
115 }
116 }
117
118 impl MonitorId {
from_hmonitor(hmonitor: HMONITOR) -> Self119 pub(crate) fn from_hmonitor(hmonitor: HMONITOR) -> Self {
120 let monitor_info = get_monitor_info(hmonitor).expect("`GetMonitorInfoW` failed");
121 let place = monitor_info.rcMonitor;
122 let dimensions = (
123 (place.right - place.left) as u32,
124 (place.bottom - place.top) as u32,
125 );
126 MonitorId {
127 hmonitor: HMonitor(hmonitor),
128 monitor_name: util::wchar_ptr_to_string(monitor_info.szDevice.as_ptr()),
129 primary: util::has_flag(monitor_info.dwFlags, winuser::MONITORINFOF_PRIMARY),
130 position: (place.left as i32, place.top as i32),
131 dimensions,
132 hidpi_factor: dpi_to_scale_factor(get_monitor_dpi(hmonitor).unwrap_or(96)),
133 }
134 }
135
contains_point(&self, point: &POINT) -> bool136 pub(crate) fn contains_point(&self, point: &POINT) -> bool {
137 let left = self.position.0 as LONG;
138 let right = left + self.dimensions.0 as LONG;
139 let top = self.position.1 as LONG;
140 let bottom = top + self.dimensions.1 as LONG;
141 point.x >= left && point.x <= right && point.y >= top && point.y <= bottom
142 }
143
144 #[inline]
get_name(&self) -> Option<String>145 pub fn get_name(&self) -> Option<String> {
146 Some(self.monitor_name.clone())
147 }
148
149 #[inline]
get_native_identifier(&self) -> String150 pub fn get_native_identifier(&self) -> String {
151 self.monitor_name.clone()
152 }
153
154 #[inline]
get_hmonitor(&self) -> HMONITOR155 pub fn get_hmonitor(&self) -> HMONITOR {
156 self.hmonitor.0
157 }
158
159 #[inline]
get_dimensions(&self) -> PhysicalSize160 pub fn get_dimensions(&self) -> PhysicalSize {
161 self.dimensions.into()
162 }
163
164 #[inline]
get_position(&self) -> PhysicalPosition165 pub fn get_position(&self) -> PhysicalPosition {
166 self.position.into()
167 }
168
169 #[inline]
get_hidpi_factor(&self) -> f64170 pub fn get_hidpi_factor(&self) -> f64 {
171 self.hidpi_factor
172 }
173 }
174