1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

windows: account for dpi in window size

On Windows, to set a window's size, in addition to the size of the
client area, the width and height of the window's "frame" must be
included in the dimensions passed to SetWindowPos() which burdens us in
needing to know the exact size of the window frame so that we can
properly account for its dimensions.  Previously, we used
AdjustWindowRect() to account for the frame's dimensions, but the size
of a window's frame can change depending on the DPI of the monitor on
which it is placed, and it appears that neither AdjustWindowRect() nor
AdjustWindowRectEx() account for this automatically.  Instead, we use
AdjustWindowRectExForDpi(), passing in the window's DPI, so that we
properly calculate the window's size.
This commit is contained in:
Jeffrey Knockel 2024-02-04 10:23:56 -05:00 committed by Wez Furlong
parent bed5141d6e
commit b03b833a4d

View File

@ -38,6 +38,7 @@ use winapi::shared::winerror::S_OK;
use winapi::um::imm::*;
use winapi::um::libloaderapi::GetModuleHandleW;
use winapi::um::shellapi::{DragAcceptFiles, DragFinish, DragQueryFileW, HDROP};
use winapi::um::shellscalingapi::{GetDpiForMonitor, MDT_EFFECTIVE_DPI};
use winapi::um::sysinfoapi::{GetTickCount, GetVersionExW};
use winapi::um::uxtheme::{
CloseThemeData, GetThemeFont, GetThemeSysFont, OpenThemeData, SetWindowTheme,
@ -142,14 +143,19 @@ fn rect_height(r: &RECT) -> i32 {
r.bottom - r.top
}
fn adjust_client_to_window_dimensions(style: u32, width: usize, height: usize) -> (i32, i32) {
fn adjust_client_to_window_dimensions(
style: u32,
width: usize,
height: usize,
dpi: u32,
) -> (i32, i32) {
let mut rect = RECT {
left: 0,
top: 0,
right: width as _,
bottom: height as _,
};
unsafe { AdjustWindowRect(&mut rect, style, 0) };
unsafe { AdjustWindowRectExForDpi(&mut rect, style, 0, 0, dpi) };
(rect_width(&rect), rect_height(&rect))
}
@ -390,6 +396,15 @@ fn decorations_to_style(decorations: WindowDecorations) -> u32 {
}
}
fn get_primary_monitor_dpi() -> u32 {
let primary = unsafe { MonitorFromWindow(null_mut(), MONITOR_DEFAULTTOPRIMARY) };
assert!(!primary.is_null(), "MonitorFromWindow() returned NULL");
let mut dpi_x = USER_DEFAULT_SCREEN_DPI as u32;
let mut dpi_y = USER_DEFAULT_SCREEN_DPI as u32;
unsafe { GetDpiForMonitor(primary, MDT_EFFECTIVE_DPI, &mut dpi_x, &mut dpi_y) };
dpi_x
}
impl Window {
fn create_window(
config: ConfigHandle,
@ -427,8 +442,9 @@ impl Window {
let decorations = config.window_decorations;
let style = decorations_to_style(decorations);
let frame_dpi = get_primary_monitor_dpi();
let (width, height) =
adjust_client_to_window_dimensions(style, geometry.width, geometry.height);
adjust_client_to_window_dimensions(style, geometry.width, geometry.height, frame_dpi);
let (x, y) = match (geometry.x, geometry.y) {
(Some(x), Some(y)) => (x, y),
@ -879,10 +895,12 @@ impl WindowOps for Window {
let decorations = inner.config.window_decorations;
promise::spawn::spawn(async move {
log::trace!("set_inner_size called with {width}x{height}");
let frame_dpi = unsafe { GetDpiForWindow(hwnd.0) };
let (width, height) = adjust_client_to_window_dimensions(
decorations_to_style(decorations),
width,
height,
frame_dpi,
);
let window_state = get_window_state(hwnd.0);
if window_state.can_resize() {