@@ -1361,32 +1361,14 @@ impl WindowBuilder {
13611361 present_strategy : self . present_strategy ,
13621362 } ;
13631363
1364- // TODO: pos_x and pos_y are only scaled for windows with parents. But they need to be
1365- // scaled for windows without parents too.
1366- let ( mut pos_x, mut pos_y) = match self . position {
1367- Some ( pos) => ( pos. x as i32 , pos. y as i32 ) ,
1368- None => ( CW_USEDEFAULT , CW_USEDEFAULT ) ,
1369- } ;
1370- let scale = Scale :: new ( 1.0 , 1.0 ) ;
1371-
1372- let mut area = ScaledArea :: default ( ) ;
1373- let ( width, height) = self
1374- . size
1375- . map ( |size| {
1376- area = ScaledArea :: from_dp ( size, scale) ;
1377- let size_px = area. size_px ( ) ;
1378- ( size_px. width as i32 , size_px. height as i32 )
1379- } )
1380- . unwrap_or ( ( CW_USEDEFAULT , CW_USEDEFAULT ) ) ;
1381-
1382- let ( hmenu, accels, has_menu) = match self . menu {
1383- Some ( menu) => {
1384- let accels = menu. accels ( ) ;
1385- ( menu. into_hmenu ( ) , accels, true )
1386- }
1387- None => ( 0 as HMENU , None , false ) ,
1388- } ;
1389-
1364+ // TODO: Can we know the DPI of the screen where the window will be created ahead of time?
1365+ // Could probably make a better guess, e.g. if all screens have some non-1.0 ratio.
1366+ // For now we just use 1.0 and fix it after creation, but before showing the window.
1367+ // Unless we have a parent window, in which case we use its scale as our guess.
1368+ let mut scale = Scale :: new ( 1.0 , 1.0 ) ;
1369+ let ( mut width, mut height) = ( CW_USEDEFAULT , CW_USEDEFAULT ) ;
1370+ let ( mut pos_x, mut pos_y) = ( CW_USEDEFAULT , CW_USEDEFAULT ) ;
1371+ let mut parent_pos_dp = None ; // When set, the pos is parent_pos_dp + self.position
13901372 let mut dwStyle = WS_OVERLAPPEDWINDOW ;
13911373 let mut dwExStyle: DWORD = 0 ;
13921374 let mut focusable = true ;
@@ -1399,29 +1381,41 @@ impl WindowBuilder {
13991381 WindowLevel :: Tooltip ( parent_window_handle)
14001382 | WindowLevel :: DropDown ( parent_window_handle)
14011383 | WindowLevel :: Modal ( parent_window_handle) => {
1384+ // Guess the scale will be the same as the parent's
1385+ scale = parent_window_handle. get_scale ( ) . unwrap_or_default ( ) ;
1386+ parent_pos_dp = Some ( parent_window_handle. get_position ( ) ) ;
14021387 parent_hwnd = parent_window_handle. 0 . get_hwnd ( ) ;
14031388 dwStyle = WS_POPUP ;
14041389 dwExStyle = WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW ;
14051390 focusable = false ;
1406- if let Some ( point_in_window_coord) = self . position {
1407- let screen_point = parent_window_handle. get_position ( )
1408- + point_in_window_coord. to_vec2 ( ) ;
1409- let scaled_point = WindowBuilder :: scale_sub_window_position (
1410- screen_point,
1411- parent_window_handle. get_scale ( ) ,
1412- ) ;
1413- pos_x = scaled_point. x as i32 ;
1414- pos_y = scaled_point. y as i32 ;
1415- } else {
1416- warn ! ( "No position provided for subwindow!" ) ;
1417- }
14181391 }
14191392 }
14201393 } else {
14211394 // Default window level
14221395 window_level = WindowLevel :: AppWindow ;
14231396 }
14241397
1398+ // Calculate the window position in pixels
1399+ if let Some ( pos_dp) = self . position {
1400+ ( pos_x, pos_y) = calculate_window_pos ( parent_pos_dp, pos_dp, scale) ;
1401+ }
1402+
1403+ let mut area = ScaledArea :: default ( ) ;
1404+ // Calculate the window size in pixels
1405+ if let Some ( size_dp) = self . size {
1406+ area = ScaledArea :: from_dp ( size_dp, scale) ;
1407+ let size_px = area. size_px ( ) ;
1408+ ( width, height) = ( size_px. width as i32 , size_px. height as i32 ) ;
1409+ }
1410+
1411+ let ( hmenu, accels, has_menu) = match self . menu {
1412+ Some ( menu) => {
1413+ let accels = menu. accels ( ) ;
1414+ ( menu. into_hmenu ( ) , accels, true )
1415+ }
1416+ None => ( 0 as HMENU , None , false ) ,
1417+ } ;
1418+
14251419 let window = WindowState {
14261420 hwnd : Cell :: new ( 0 as HWND ) ,
14271421 scale : Cell :: new ( scale) ,
@@ -1496,24 +1490,39 @@ impl WindowBuilder {
14961490 return Err ( Error :: NullHwnd ) ;
14971491 }
14981492
1499- if let Some ( size_dp) = self . size {
1500- if let Ok ( scale) = handle. get_scale ( ) {
1501- let size_px = size_dp. to_px ( scale) ;
1502- if SetWindowPos (
1503- hwnd,
1504- HWND_TOPMOST ,
1505- 0 ,
1506- 0 ,
1507- size_px. width . round ( ) as i32 ,
1508- size_px. height . round ( ) as i32 ,
1509- SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER ,
1510- ) == 0
1493+ // Now that the window has been created we finally have the correct scale,
1494+ // so we might need to update the window position & size.
1495+ if let Ok ( new_scale) = handle. get_scale ( ) {
1496+ if new_scale != scale {
1497+ scale = new_scale;
1498+ let mut flags =
1499+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER ;
1500+ let mut needs_any_change = false ;
1501+
1502+ // Calculate the window position in pixels
1503+ if let Some ( pos_dp) = self . position {
1504+ ( pos_x, pos_y) = calculate_window_pos ( parent_pos_dp, pos_dp, scale) ;
1505+ flags &= !SWP_NOMOVE ;
1506+ needs_any_change = true ;
1507+ }
1508+
1509+ // Calculate the window size in pixels
1510+ if let Some ( size_dp) = self . size {
1511+ area = ScaledArea :: from_dp ( size_dp, scale) ;
1512+ let size_px = area. size_px ( ) ;
1513+ ( width, height) = ( size_px. width as i32 , size_px. height as i32 ) ;
1514+ flags &= !SWP_NOSIZE ;
1515+ needs_any_change = true ;
1516+ }
1517+
1518+ if needs_any_change
1519+ && SetWindowPos ( hwnd, HWND_TOPMOST , pos_x, pos_y, width, height, flags) == 0
15111520 {
15121521 warn ! (
1513- "failed to resize window: {}" ,
1522+ "failed to update window size/pos : {}" ,
15141523 Error :: Hr ( HRESULT_FROM_WIN32 ( GetLastError ( ) ) )
15151524 ) ;
1516- } ;
1525+ }
15171526 }
15181527 }
15191528
@@ -1537,21 +1546,16 @@ impl WindowBuilder {
15371546 Ok ( handle)
15381547 }
15391548 }
1549+ }
15401550
1541- /// When creating a sub-window, we need to scale its position with respect to its parent.
1542- /// If there is any error while scaling, log it as a warn and show sub-window in top left corner of screen/window.
1543- fn scale_sub_window_position (
1544- un_scaled_sub_window_position : Point ,
1545- parent_window_scale : Result < Scale , crate :: Error > ,
1546- ) -> Point {
1547- match parent_window_scale {
1548- Ok ( s) => un_scaled_sub_window_position. to_px ( s) ,
1549- Err ( e) => {
1550- warn ! ( "Error with scale: {:?}" , e) ;
1551- Point :: new ( 0. , 0. )
1552- }
1553- }
1554- }
1551+ /// Returns a pair of integers representing the pixel values of the position.
1552+ fn calculate_window_pos ( parent_pos_dp : Option < Point > , pos_dp : Point , scale : Scale ) -> ( i32 , i32 ) {
1553+ let pos_px = if let Some ( parent_pos_dp) = parent_pos_dp {
1554+ ( parent_pos_dp + pos_dp. to_vec2 ( ) ) . to_px ( scale)
1555+ } else {
1556+ pos_dp. to_px ( scale)
1557+ } ;
1558+ ( pos_px. x . round ( ) as i32 , pos_px. y . round ( ) as i32 )
15551559}
15561560
15571561/// Attempt to read the registry and see if the system is set to a dark or
0 commit comments