Skip to content

Commit ef936e0

Browse files
authored
Respect scale when setting window position during creation. (#2296)
1 parent 52d5529 commit ef936e0

File tree

1 file changed

+70
-66
lines changed

1 file changed

+70
-66
lines changed

druid-shell/src/backend/windows/window.rs

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)