Skip to content

Commit

Permalink
Windows: implement resize increments (#3623)
Browse files Browse the repository at this point in the history
  • Loading branch information
tetrahedron341 authored Apr 21, 2024
1 parent be79e89 commit babbb71
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 17 deletions.
2 changes: 1 addition & 1 deletion FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Legend:
|Window decorations |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|✔️ |
|Window decorations toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|Window resizing |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |✔️ |
|Window resize increments | |✔️ |✔️ ||**N/A**|**N/A**|**N/A**|**N/A** |
|Window resize increments |✔️ |✔️ |✔️ ||**N/A**|**N/A**|**N/A**|**N/A** |
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |✔️ |
|Window blur ||||✔️ |**N/A**|**N/A**|N/A ||
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
Expand Down
3 changes: 2 additions & 1 deletion src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ changelog entry.
- On macOS, add services menu.
- On Windows, add `with_title_text_color`, and `with_corner_preference` on
`WindowAttributesExtWindows`.
- On Windows, implement resize increments.

### Changed

Expand Down Expand Up @@ -253,4 +254,4 @@ changelog entry.
- On Web, fix setting cursor icon overriding cursor visibility.
- On Windows, fix cursor not confined to center of window when grabbed and hidden.
- On macOS, fix sequence of mouse events being out of order when dragging on the trackpad.
- On Wayland, fix decoration glitch on close with some compositors
- On Wayland, fix decoration glitch on close with some compositors.
116 changes: 105 additions & 11 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,19 @@ use windows_sys::Win32::{
HTCAPTION, HTCLIENT, MINMAXINFO, MNC_CLOSE, MSG, NCCALCSIZE_PARAMS, PM_REMOVE, PT_PEN,
PT_TOUCH, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED,
SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS,
WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENTERSIZEMOVE,
WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION,
WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT, WM_INPUT_DEVICE_CHANGE,
WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN,
WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE,
WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN,
WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR,
WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP,
WM_TOUCH, WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP,
WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT,
WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
WMSZ_BOTTOM, WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP,
WMSZ_TOPLEFT, WMSZ_TOPRIGHT, WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY,
WM_DPICHANGED, WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION,
WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT,
WM_INPUT_DEVICE_CHANGE, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN,
WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE,
WM_MOUSEWHEEL, WM_NCACTIVATE, WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY,
WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN, WM_POINTERUP, WM_POINTERUPDATE,
WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE,
WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TOUCH, WM_WINDOWPOSCHANGED,
WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, WS_EX_LAYERED,
WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP,
WS_VISIBLE,
},
},
};
Expand Down Expand Up @@ -1352,6 +1354,98 @@ unsafe fn public_window_callback_inner(
result = ProcResult::Value(0);
}

WM_SIZING => {
/// Calculate the amount to add to round `value` to the nearest multiple of `increment`.
fn snap_to_nearest_increment_delta(value: i32, increment: i32) -> i32 {
let half_one = increment / 2;
let half_two = increment - half_one;
half_one - (value - half_two) % increment
}

let scale_factor = userdata.window_state_lock().scale_factor;
let Some(inc) = userdata
.window_state_lock()
.resize_increments
.map(|inc| inc.to_physical(scale_factor))
.filter(|inc| inc.width > 0 && inc.height > 0)
else {
result = ProcResult::Value(0);
return;
};

let side = wparam as u32;
// The desired new size of the window, decorations included.
let rect = unsafe { &mut *(lparam as *mut RECT) };

// We need to calculate the dimensions of the window decorations to get the true
// size of the window's contents
let adj_rect = userdata
.window_state_lock()
.window_flags
.adjust_rect(window, *rect)
.unwrap_or(*rect);
let deco_width = rect.left - adj_rect.left + adj_rect.right - rect.right;
let deco_height = rect.top - adj_rect.top + adj_rect.bottom - rect.bottom;

let width = rect.right - rect.left - deco_width;
let height = rect.bottom - rect.top - deco_height;

let mut width_delta = snap_to_nearest_increment_delta(width, inc.width);
let mut height_delta = snap_to_nearest_increment_delta(height, inc.height);

// Windows won't bound check the value of `rect` after we're done here, so we
// have to check manually. If the width/height we snap to would go out of bounds, just
// set it equal to the min/max bound.
let min_size = userdata
.window_state_lock()
.min_size
.map(|size| size.to_physical(scale_factor));
let max_size = userdata
.window_state_lock()
.max_size
.map(|size| size.to_physical(scale_factor));
let final_width = width + width_delta;
let final_height = height + height_delta;
if let Some(min_size) = min_size {
if final_width < min_size.width {
width_delta += min_size.width - final_width;
}
if final_height < min_size.height {
height_delta += min_size.height - final_height;
}
}
if let Some(max_size) = max_size {
if final_width > max_size.width {
width_delta -= final_width - max_size.width;
}
if final_height > max_size.height {
height_delta -= final_height - max_size.height;
}
}

match side {
WMSZ_LEFT | WMSZ_BOTTOMLEFT | WMSZ_TOPLEFT => {
rect.left -= width_delta;
}
WMSZ_RIGHT | WMSZ_BOTTOMRIGHT | WMSZ_TOPRIGHT => {
rect.right += width_delta;
}
_ => {}
}

match side {
WMSZ_TOP | WMSZ_TOPLEFT | WMSZ_TOPRIGHT => {
rect.top -= height_delta;
}
WMSZ_BOTTOM | WMSZ_BOTTOMLEFT | WMSZ_BOTTOMRIGHT => {
rect.bottom += height_delta;
}
_ => {}
}

result = ProcResult::DefWindowProc(wparam);
}

WM_MENUCHAR => {
result = ProcResult::Value((MNC_CLOSE << 16) as isize);
}
Expand Down
9 changes: 7 additions & 2 deletions src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,16 @@ impl Window {

#[inline]
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
None
let w = self.window_state_lock();
let scale_factor = w.scale_factor;
w.resize_increments
.map(|size| size.to_physical(scale_factor))
}

#[inline]
pub fn set_resize_increments(&self, _increments: Option<Size>) {}
pub fn set_resize_increments(&self, increments: Option<Size>) {
self.window_state_lock().resize_increments = increments;
}

#[inline]
pub fn set_resizable(&self, resizable: bool) {
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/windows/window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub(crate) struct WindowState {
pub min_size: Option<Size>,
pub max_size: Option<Size>,

pub resize_increments: Option<Size>,

pub window_icon: Option<Icon>,
pub taskbar_icon: Option<Icon>,

Expand Down Expand Up @@ -155,6 +157,8 @@ impl WindowState {
min_size: attributes.min_inner_size,
max_size: attributes.max_inner_size,

resize_increments: attributes.resize_increments,

window_icon: attributes.window_icon.clone(),
taskbar_icon: None,

Expand Down
4 changes: 2 additions & 2 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ impl Window {
///
/// ## Platform-specific
///
/// - **iOS / Android / Web / Wayland / Windows / Orbital:** Always returns [`None`].
/// - **iOS / Android / Web / Wayland / Orbital:** Always returns [`None`].
#[inline]
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
let _span = tracing::debug_span!("winit::Window::resize_increments",).entered();
Expand All @@ -908,7 +908,7 @@ impl Window {
/// ## Platform-specific
///
/// - **macOS:** Increments are converted to logical size and then macOS rounds them to whole numbers.
/// - **Wayland / Windows:** Not implemented.
/// - **Wayland:** Not implemented.
/// - **iOS / Android / Web / Orbital:** Unsupported.
#[inline]
pub fn set_resize_increments<S: Into<Size>>(&self, increments: Option<S>) {
Expand Down

0 comments on commit babbb71

Please sign in to comment.