-
Notifications
You must be signed in to change notification settings - Fork 95
Expand file tree
/
Copy pathwin32_window.rs
More file actions
122 lines (108 loc) · 4.04 KB
/
win32_window.rs
File metadata and controls
122 lines (108 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::PhySize;
use std::convert::TryFrom;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;
use winapi::shared::minwindef::{ATOM, DWORD};
use winapi::shared::windef::{HWND, RECT};
use winapi::um::winuser::{
AdjustWindowRectEx, CreateWindowExW, GetDpiForWindow, SetWindowPos, SWP_NOACTIVATE, SWP_NOMOVE,
SWP_NOZORDER, USER_DEFAULT_SCREEN_DPI, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX,
WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
};
// TODO: handle proper destruction of this window during errors/panics/etc.
pub(crate) struct Win32Window {
pub handle: HWND,
style_flags: DWORD,
}
impl Win32Window {
pub fn create(window_class: ATOM, title: &str, size: PhySize, parent: Option<HWND>) -> Self {
let mut title: Vec<u16> = OsStr::new(title).encode_wide().collect();
title.push(0);
let style_flags = if parent.is_some() {
WS_CHILD | WS_VISIBLE
} else {
WS_POPUPWINDOW
| WS_CAPTION
| WS_VISIBLE
| WS_SIZEBOX
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPSIBLINGS
};
let size = client_size_to_window_size(size, style_flags);
// TODO: handle errors
let hwnd = unsafe {
CreateWindowExW(
0,
window_class as _,
title.as_ptr(),
style_flags,
0,
0,
size.width as i32,
size.height as i32,
parent.unwrap_or(null_mut()),
null_mut(),
null_mut(),
null_mut(),
)
};
Win32Window { style_flags, handle: hwnd }
}
/// Resizes the window.
///
/// This *will* immediately trigger a WM_SIZE event.
pub fn resize(&self, size: PhySize) {
let window_size = client_size_to_window_size(size, self.style_flags);
unsafe {
SetWindowPos(
self.handle,
null_mut(), // Ignored by SWP_NOZORDER
0, // Ignored by SWP_NOMOVE
0, // Ignored by SWP_NOMOVE
window_size.width as i32,
window_size.height as i32,
SWP_NOZORDER | SWP_NOMOVE,
);
}
}
/// Sets both the position and size of the window, according to a given raw RECT.
///
/// This *will* immediately trigger a WM_SIZE event.
pub fn set_raw_pos(&self, rect: &RECT) {
unsafe {
SetWindowPos(
self.handle,
null_mut(), // Ignored by SWP_NOZORDER
rect.left,
rect.top,
rect.right.saturating_sub(rect.left),
rect.bottom.saturating_sub(rect.top),
SWP_NOZORDER | SWP_NOACTIVATE,
);
}
}
/// Returns current the scale factor of the monitor the window is currently on.
pub fn current_scale_factor(&self) -> f64 {
// FIXME: Only works on Windows 10.
let dpi = unsafe { GetDpiForWindow(self.handle) };
dpi as f64 / USER_DEFAULT_SCREEN_DPI as f64
}
}
pub fn client_size_to_window_size(size: PhySize, window_flags: DWORD) -> PhySize {
let mut rect = RECT {
left: 0,
top: 0,
// In case the provided size overflows an i32, which would imply it is ridiculously large.
right: i32::try_from(size.width).unwrap(),
bottom: i32::try_from(size.height).unwrap(),
};
// SAFETY: the provided rect pointer is guaranteed to be valid by the mutable reference.
unsafe { AdjustWindowRectEx(&mut rect, window_flags, 0, 0) };
// These checks are made just in case AdjustWindowRectEx sends back invalid values.
// Because this is so unlikely, we can afford to just panic here.
let width = rect.right.saturating_sub(rect.left);
let height = rect.bottom.saturating_sub(rect.top);
PhySize { width: u32::try_from(width).unwrap(), height: u32::try_from(height).unwrap() }
}