Skip to content

Commit

Permalink
fix(Windows): fix set_inner_size setting a bigger size, closes #194 (
Browse files Browse the repository at this point in the history
…#354)

* fix(Windows): fix `set_inner_size` setting a bigger size, closes #194

* Fix size overflow when dpi changes
  • Loading branch information
amrbashir committed Apr 3, 2022
1 parent 05f7b34 commit 089f387
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changes/windows-set_size-overflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": "patch"
---

On Windows, Fix `Window::set_inner_size` setting a bigger size than requested.
27 changes: 21 additions & 6 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1671,17 +1671,22 @@ unsafe fn public_window_callback_inner<T: 'static>(
let window_state = subclass_input.window_state.lock();

if window_state.min_size.is_some() || window_state.max_size.is_some() {
let is_decorated = window_state
.window_flags()
.contains(WindowFlags::DECORATIONS);
if let Some(min_size) = window_state.min_size {
let min_size = min_size.to_physical(window_state.scale_factor);
let (width, height): (u32, u32) = util::adjust_size(window, min_size).into();
let (width, height): (u32, u32) =
util::adjust_size(window, min_size, is_decorated).into();
(*mmi).ptMinTrackSize = POINT {
x: width as i32,
y: height as i32,
};
}
if let Some(max_size) = window_state.max_size {
let max_size = max_size.to_physical(window_state.scale_factor);
let (width, height): (u32, u32) = util::adjust_size(window, max_size).into();
let (width, height): (u32, u32) =
util::adjust_size(window, max_size, is_decorated).into();
(*mmi).ptMaxTrackSize = POINT {
x: width as i32,
y: height as i32,
Expand All @@ -1705,7 +1710,7 @@ unsafe fn public_window_callback_inner<T: 'static>(
let new_scale_factor = dpi_to_scale_factor(new_dpi_x);
let old_scale_factor: f64;

let allow_resize = {
let (allow_resize, is_decorated) = {
let mut window_state = subclass_input.window_state.lock();
old_scale_factor = window_state.scale_factor;
window_state.scale_factor = new_scale_factor;
Expand All @@ -1715,11 +1720,21 @@ unsafe fn public_window_callback_inner<T: 'static>(
return;
}

window_state.fullscreen.is_none()
&& !window_state.window_flags().contains(WindowFlags::MAXIMIZED)
let window_flags = window_state.window_flags();
(
window_state.fullscreen.is_none() && !window_flags.contains(WindowFlags::MAXIMIZED),
window_flags.contains(WindowFlags::DECORATIONS),
)
};

let style = GetWindowLongW(window, GWL_STYLE) as WINDOW_STYLE;
let mut style = GetWindowLongW(window, GWL_STYLE) as WINDOW_STYLE;
// if the window isn't decorated, remove `WS_SIZEBOX` and `WS_CAPTION` so
// `AdjustWindowRect*` functions doesn't account for the hidden caption and borders and
// calculates a correct size for the client area.
if !is_decorated {
style &= !WS_CAPTION;
style &= !WS_SIZEBOX;
}
let style_ex = GetWindowLongW(window, GWL_EXSTYLE) as WINDOW_EX_STYLE;

// New size as suggested by Windows.
Expand Down
1 change: 1 addition & 0 deletions src/platform_impl/windows/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ impl<T> BufferedEvent<T> {
HWND(window_id.0 .0),
new_inner_size.width as _,
new_inner_size.height as _,
true,
);
}
}
Expand Down
18 changes: 13 additions & 5 deletions src/platform_impl/windows/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,19 @@ pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
Ok(rect)
}

pub fn adjust_size(hwnd: HWND, size: PhysicalSize<u32>) -> PhysicalSize<u32> {
pub fn adjust_size(hwnd: HWND, size: PhysicalSize<u32>, is_decorated: bool) -> PhysicalSize<u32> {
let (width, height): (u32, u32) = size.into();
let rect = RECT {
left: 0,
right: width as i32,
top: 0,
bottom: height as i32,
};
let rect = adjust_window_rect(hwnd, rect).unwrap_or(rect);
let rect = adjust_window_rect(hwnd, rect, is_decorated).unwrap_or(rect);
PhysicalSize::new((rect.right - rect.left) as _, (rect.bottom - rect.top) as _)
}

pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) {
pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32, is_decorated: bool) {
unsafe {
let rect = adjust_window_rect(
window,
Expand All @@ -110,6 +110,7 @@ pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) {
bottom: y as i32,
right: x as i32,
},
is_decorated,
)
.expect("adjust_window_rect failed");

Expand All @@ -128,9 +129,16 @@ pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) {
}
}

pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option<RECT> {
pub fn adjust_window_rect(hwnd: HWND, rect: RECT, is_decorated: bool) -> Option<RECT> {
unsafe {
let style = GetWindowLongW(hwnd, GWL_STYLE) as WINDOW_STYLE;
let mut style = GetWindowLongW(hwnd, GWL_STYLE) as WINDOW_STYLE;
// if the window isn't decorated, remove `WS_SIZEBOX` and `WS_CAPTION` so
// `AdjustWindowRect*` functions doesn't account for the hidden caption and borders and
// calculates a correct size for the client area.
if !is_decorated {
style &= !WS_CAPTION;
style &= !WS_SIZEBOX;
}
let style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE) as WINDOW_EX_STYLE;
adjust_window_rect_with_styles(hwnd, style, style_ex, rect)
}
Expand Down
8 changes: 7 additions & 1 deletion src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,14 +252,20 @@ impl Window {
let (width, height) = size.to_physical::<u32>(scale_factor).into();

let window_state = Arc::clone(&self.window_state);

let is_decorated = window_state
.lock()
.window_flags
.contains(WindowFlags::DECORATIONS);

let window = self.window.clone();
self.thread_executor.execute_in_thread(move || {
WindowState::set_window_flags(window_state.lock(), window.0, |f| {
f.set(WindowFlags::MAXIMIZED, false)
});
});

util::set_inner_size_physical(self.window.0, width, height);
util::set_inner_size_physical(self.window.0, width, height, is_decorated);
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/windows/window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ impl WindowFlags {
style_ex |= WS_EX_ACCEPTFILES;

if self.contains(WindowFlags::RESIZABLE) {
style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
}
if self.contains(WindowFlags::DECORATIONS) {
style_ex |= WS_EX_WINDOWEDGE;
Expand Down

0 comments on commit 089f387

Please sign in to comment.