@@ -6,15 +6,16 @@ use winapi::um::winuser::{
66 AdjustWindowRectEx , CreateWindowExW , DefWindowProcW , DispatchMessageW ,
77 GetMessageW , GetWindowLongPtrW , PostMessageW , RegisterClassW , SetTimer ,
88 SetWindowLongPtrW , TranslateMessage , UnregisterClassW , LoadCursorW ,
9- DestroyWindow ,
9+ DestroyWindow , SetProcessDpiAwarenessContext , SetWindowPos ,
10+ GetDpiForWindow ,
1011 CS_OWNDC , GWLP_USERDATA , IDC_ARROW ,
1112 MSG , WM_CLOSE , WM_CREATE , WM_MOUSEMOVE , WM_SHOWWINDOW , WM_TIMER , WM_NCDESTROY ,
1213 WNDCLASSW , WS_CAPTION , WS_CHILD , WS_CLIPSIBLINGS , WS_MAXIMIZEBOX , WS_MINIMIZEBOX ,
1314 WS_POPUPWINDOW , WS_SIZEBOX , WS_VISIBLE , WM_DPICHANGED , WM_CHAR , WM_SYSCHAR , WM_KEYDOWN ,
14- WM_SYSKEYDOWN , WM_KEYUP , WM_SYSKEYUP , WM_INPUTLANGCHANGE ,
15+ WM_SYSKEYDOWN , WM_KEYUP , WM_SYSKEYUP , WM_INPUTLANGCHANGE , WM_SIZE ,
1516 GET_XBUTTON_WPARAM , WM_LBUTTONDOWN , WM_LBUTTONUP , WM_MBUTTONDOWN , WM_MBUTTONUP ,
1617 WM_RBUTTONDOWN , WM_RBUTTONUP , WM_XBUTTONDOWN , WM_XBUTTONUP , XBUTTON1 , XBUTTON2 ,
17- SetCapture , GetCapture , ReleaseCapture , IsWindow ,
18+ SetCapture , GetCapture , ReleaseCapture , IsWindow , SWP_NOZORDER , SWP_NOMOVE
1819} ;
1920
2021use std:: cell:: RefCell ;
@@ -30,7 +31,7 @@ use raw_window_handle::{
3031
3132use crate :: {
3233 Event , MouseButton , MouseEvent , WindowEvent ,
33- WindowHandler , WindowInfo , WindowOpenOptions , WindowScalePolicy , PhyPoint ,
34+ WindowHandler , WindowInfo , WindowOpenOptions , WindowScalePolicy , PhyPoint , PhySize
3435} ;
3536
3637use super :: keyboard:: KeyboardState ;
@@ -152,9 +153,6 @@ unsafe extern "system" fn wnd_proc(
152153 // return 0;
153154 return DefWindowProcW ( hwnd, msg, wparam, lparam) ;
154155 }
155- WM_DPICHANGED => {
156- // TODO: Notify app of DPI change
157- } ,
158156 WM_CHAR | WM_SYSCHAR | WM_KEYDOWN | WM_SYSKEYDOWN | WM_KEYUP
159157 | WM_SYSKEYUP | WM_INPUTLANGCHANGE => {
160158 let opt_event = ( & * window_state_ptr) . borrow_mut ( )
@@ -171,6 +169,70 @@ unsafe extern "system" fn wnd_proc(
171169 return 0 ;
172170 }
173171 }
172+ WM_SIZE => {
173+ let width = ( lparam & 0xFFFF ) as u16 as u32 ;
174+ let height = ( ( lparam >> 16 ) & 0xFFFF ) as u16 as u32 ;
175+
176+ let mut window_state = ( & * window_state_ptr) . borrow_mut ( ) ;
177+
178+ window_state. window_info = WindowInfo :: from_physical_size (
179+ PhySize { width, height } ,
180+ window_state. window_info . scale ( ) ,
181+ ) ;
182+
183+ let window_info = window_state. window_info ;
184+
185+ window_state. handler . on_event (
186+ & mut window,
187+ Event :: Window ( WindowEvent :: Resized ( window_info) ) ,
188+ ) ;
189+ }
190+ WM_DPICHANGED => {
191+ // To avoid weirdness with the realtime borrow checker.
192+ let new_rect = {
193+ let mut window_state = ( & * window_state_ptr) . borrow_mut ( ) ;
194+
195+ if let WindowScalePolicy :: SystemScaleFactor = window_state. scale_policy {
196+ let dpi = ( wparam & 0xFFFF ) as u16 as u32 ;
197+ let scale_factor = dpi as f64 / 96.0 ;
198+
199+ window_state. window_info = WindowInfo :: from_logical_size (
200+ window_state. window_info . logical_size ( ) ,
201+ scale_factor,
202+ ) ;
203+
204+ Some ( (
205+ RECT {
206+ left : 0 ,
207+ top : 0 ,
208+ // todo: check if usize fits into i32
209+ right : window_state. window_info . physical_size ( ) . width as i32 ,
210+ bottom : window_state. window_info . physical_size ( ) . height as i32 ,
211+ } ,
212+ window_state. dw_style ,
213+ ) )
214+ } else {
215+ None
216+ }
217+ } ;
218+ if let Some ( ( mut new_rect, dw_style) ) = new_rect {
219+ // Convert this desired "client rectangle" size to the actual "window rectangle"
220+ // size (Because of course you have to do that).
221+ AdjustWindowRectEx ( & mut new_rect, dw_style, 0 , 0 ) ;
222+
223+ // Windows makes us resize the window manually. This will trigger another `WM_SIZE` event,
224+ // which we can then send the user the new scale factor.
225+ SetWindowPos (
226+ hwnd,
227+ hwnd,
228+ new_rect. left as i32 ,
229+ new_rect. top as i32 ,
230+ new_rect. right - new_rect. left ,
231+ new_rect. bottom - new_rect. top ,
232+ SWP_NOZORDER | SWP_NOMOVE ,
233+ ) ;
234+ }
235+ }
174236 WM_NCDESTROY => {
175237 let window_state = Box :: from_raw ( window_state_ptr) ;
176238 unregister_wnd_class ( window_state. borrow ( ) . window_class ) ;
@@ -219,6 +281,8 @@ struct WindowState {
219281 keyboard_state : KeyboardState ,
220282 mouse_button_counter : usize ,
221283 handler : Box < dyn WindowHandler > ,
284+ scale_policy : WindowScalePolicy ,
285+ dw_style : u32 ,
222286}
223287
224288pub struct Window {
@@ -299,7 +363,7 @@ impl Window {
299363 // todo: manage error ^
300364
301365 let scaling = match options. scale {
302- WindowScalePolicy :: SystemScaleFactor => get_scaling ( ) . unwrap_or ( 1.0 ) ,
366+ WindowScalePolicy :: SystemScaleFactor => 1.0 ,
303367 WindowScalePolicy :: ScaleFactor ( scale) => scale
304368 } ;
305369
@@ -347,17 +411,69 @@ impl Window {
347411
348412 let handler = Box :: new ( build ( & mut crate :: Window :: new ( & mut Window { hwnd } ) ) ) ;
349413
350- let window_state = Box :: new ( RefCell :: new ( WindowState {
414+ let mut window_state = Box :: new ( RefCell :: new ( WindowState {
351415 window_class,
352416 window_info,
353417 keyboard_state : KeyboardState :: new ( ) ,
354418 mouse_button_counter : 0 ,
355419 handler,
420+ scale_policy : options. scale ,
421+ dw_style : flags,
356422 } ) ) ;
357423
424+ // Only works on Windows 10 unfortunately.
425+ SetProcessDpiAwarenessContext (
426+ winapi:: shared:: windef:: DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ,
427+ ) ;
428+
429+ // Now we can get the actual dpi of the window.
430+ let new_rect = if let WindowScalePolicy :: SystemScaleFactor = options. scale {
431+ // Only works on Windows 10 unfortunately.
432+ let dpi = GetDpiForWindow ( hwnd) ;
433+ let scale_factor = dpi as f64 / 96.0 ;
434+
435+ let mut window_state = window_state. get_mut ( ) ;
436+ if window_state. window_info . scale ( ) != scale_factor {
437+ window_state. window_info = WindowInfo :: from_logical_size (
438+ window_state. window_info . logical_size ( ) ,
439+ scale_factor,
440+ ) ;
441+
442+ Some ( RECT {
443+ left : 0 ,
444+ top : 0 ,
445+ // todo: check if usize fits into i32
446+ right : window_state. window_info . physical_size ( ) . width as i32 ,
447+ bottom : window_state. window_info . physical_size ( ) . height as i32 ,
448+ } )
449+ } else {
450+ None
451+ }
452+ } else {
453+ None
454+ } ;
455+
358456 SetWindowLongPtrW ( hwnd, GWLP_USERDATA , Box :: into_raw ( window_state) as * const _ as _ ) ;
359457 SetTimer ( hwnd, WIN_FRAME_TIMER , 15 , None ) ;
360458
459+ if let Some ( mut new_rect) = new_rect {
460+ // Convert this desired"client rectangle" size to the actual "window rectangle"
461+ // size (Because of course you have to do that).
462+ AdjustWindowRectEx ( & mut new_rect, flags, 0 , 0 ) ;
463+
464+ // Windows makes us resize the window manually. This will trigger another `WM_SIZE` event,
465+ // which we can then send the user the new scale factor.
466+ SetWindowPos (
467+ hwnd,
468+ hwnd,
469+ new_rect. left as i32 ,
470+ new_rect. top as i32 ,
471+ new_rect. right - new_rect. left ,
472+ new_rect. bottom - new_rect. top ,
473+ SWP_NOZORDER | SWP_NOMOVE ,
474+ ) ;
475+ }
476+
361477 hwnd
362478 }
363479 }
@@ -370,9 +486,4 @@ unsafe impl HasRawWindowHandle for Window {
370486 ..WindowsHandle :: empty ( )
371487 } )
372488 }
373- }
374-
375- fn get_scaling ( ) -> Option < f64 > {
376- // TODO: find system scaling
377- None
378- }
489+ }
0 commit comments