Skip to content

Commit 3a8411a

Browse files
pedrohgmacedokchibisov
authored andcommitted
wayland: implement resize increments
1 parent 9ebbb95 commit 3a8411a

File tree

4 files changed

+71
-5
lines changed

4 files changed

+71
-5
lines changed

src/changelog/unreleased.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ changelog entry.
4040

4141
## Unreleased
4242

43+
### Added
44+
45+
- On Wayland, add `Window::set_resize_increments`.
46+
4347
### Fixed
4448

4549
- On macOS, fixed crash when dragging non-file content onto window.

src/platform_impl/linux/wayland/window/mod.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ impl Window {
166166
Cursor::Custom(cursor) => window_state.set_custom_cursor(cursor),
167167
}
168168

169+
// Apply resize increments.
170+
if let Some(increments) = attributes.resize_increments {
171+
let increments = increments.to_logical(window_state.scale_factor());
172+
window_state.set_resize_increments(Some(increments));
173+
}
174+
169175
// Activate the window when the token is passed.
170176
if let (Some(xdg_activation), Some(token)) =
171177
(xdg_activation.as_ref(), attributes.platform_specific.activation_token)
@@ -333,12 +339,19 @@ impl Window {
333339

334340
#[inline]
335341
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
336-
None
342+
let window_state = self.window_state.lock().unwrap();
343+
let scale_factor = window_state.scale_factor();
344+
window_state
345+
.resize_increments()
346+
.map(|size| super::logical_to_physical_rounded(size, scale_factor))
337347
}
338348

339349
#[inline]
340-
pub fn set_resize_increments(&self, _increments: Option<Size>) {
341-
warn!("`set_resize_increments` is not implemented for Wayland");
350+
pub fn set_resize_increments(&self, increments: Option<Size>) {
351+
let mut window_state = self.window_state.lock().unwrap();
352+
let scale_factor = window_state.scale_factor();
353+
let increments = increments.map(|size| size.to_logical(scale_factor));
354+
window_state.set_resize_increments(increments);
342355
}
343356

344357
#[inline]

src/platform_impl/linux/wayland/window/state.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ pub struct WindowState {
127127
/// Min size.
128128
min_inner_size: LogicalSize<u32>,
129129
max_inner_size: Option<LogicalSize<u32>>,
130+
resize_increments: Option<LogicalSize<u32>>,
130131

131132
/// The size of the window when no states were applied to it. The primary use for it
132133
/// is to fallback to original window size, before it was maximized, if the compositor
@@ -202,6 +203,7 @@ impl WindowState {
202203
last_configure: None,
203204
max_inner_size: None,
204205
min_inner_size: MIN_WINDOW_SIZE,
206+
resize_increments: None,
205207
pointer_constraints,
206208
pointers: Default::default(),
207209
queue_handle: queue_handle.clone(),
@@ -340,6 +342,42 @@ impl WindowState {
340342
.unwrap_or(new_size.height);
341343
}
342344

345+
// Apply size increments.
346+
//
347+
// We conditionally apply increments to avoid conflicts with the compositor's layout rules:
348+
// 1. If the window is floating (constrain == true), we snap to increments to ensure the
349+
// app's grid alignment.
350+
// 2. If the user is interactively resizing (is_resizing), we snap the size to provide
351+
// feedback.
352+
//
353+
// However, we MUST NOT snap if the compositor enforces a specific size (constrain == false,
354+
// or states like Maximized/Tiled). Snapping in these cases (e.g. corner tiling) would
355+
// shrink the window below the allocated area, creating visible gaps between valid
356+
// windows or screen edges.
357+
if (constrain || configure.is_resizing())
358+
&& !configure.is_maximized()
359+
&& !configure.is_fullscreen()
360+
&& !configure.is_tiled()
361+
{
362+
if let Some(increments) = self.resize_increments {
363+
// We use min size as a base size for the increments, similar to how X11 does it.
364+
//
365+
// This ensures that we can always reach the min size and the increments are
366+
// calculated from it.
367+
let (delta_width, delta_height) = (
368+
new_size.width.saturating_sub(self.min_inner_size.width),
369+
new_size.height.saturating_sub(self.min_inner_size.height),
370+
);
371+
372+
let width = self.min_inner_size.width
373+
+ (delta_width / increments.width) * increments.width;
374+
let height = self.min_inner_size.height
375+
+ (delta_height / increments.height) * increments.height;
376+
377+
new_size = (width, height).into();
378+
}
379+
}
380+
343381
let new_state = configure.state;
344382
let old_state = self.last_configure.as_ref().map(|configure| configure.state);
345383

@@ -725,6 +763,18 @@ impl WindowState {
725763
self.selected_cursor = SelectedCursor::Custom(cursor);
726764
}
727765

766+
/// Set the resize increments of the window.
767+
pub fn set_resize_increments(&mut self, increments: Option<LogicalSize<u32>>) {
768+
self.resize_increments = increments;
769+
// NOTE: We don't update the window size here, because it will be done on the next resize
770+
// or configure event.
771+
}
772+
773+
/// Get the resize increments of the window.
774+
pub fn resize_increments(&self) -> Option<LogicalSize<u32>> {
775+
self.resize_increments
776+
}
777+
728778
fn apply_custom_cursor(&self, cursor: &CustomCursor) {
729779
self.apply_on_pointer(|pointer, data| {
730780
let surface = pointer.surface();

src/window.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ impl Window {
884884
///
885885
/// ## Platform-specific
886886
///
887-
/// - **iOS / Android / Web / Wayland / Orbital:** Always returns [`None`].
887+
/// - **iOS / Android / Web / Orbital:** Always returns [`None`].
888888
#[inline]
889889
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
890890
let _span = tracing::debug_span!("winit::Window::resize_increments",).entered();
@@ -900,7 +900,6 @@ impl Window {
900900
///
901901
/// - **macOS:** Increments are converted to logical size and then macOS rounds them to whole
902902
/// numbers.
903-
/// - **Wayland:** Not implemented.
904903
/// - **iOS / Android / Web / Orbital:** Unsupported.
905904
#[inline]
906905
pub fn set_resize_increments<S: Into<Size>>(&self, increments: Option<S>) {

0 commit comments

Comments
 (0)