From a9c189a423d5cb79e2674354c0a3f02a3455c713 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Sat, 1 Nov 2025 14:39:57 +0000 Subject: [PATCH] winit-win32: prevent inner size reported as (0,0) when minimized --- winit-win32/src/event_loop.rs | 10 ++++++++-- winit-win32/src/window.rs | 9 +-------- winit-win32/src/window_state.rs | 5 +++++ winit/examples/application.rs | 22 ++++++++++++++++++++++ winit/src/changelog/unreleased.md | 1 + 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/winit-win32/src/event_loop.rs b/winit-win32/src/event_loop.rs index 7a3a5ecb..3a5720ec 100644 --- a/winit-win32/src/event_loop.rs +++ b/winit-win32/src/event_loop.rs @@ -1301,7 +1301,6 @@ unsafe fn public_window_callback_inner( use winit_core::event::WindowEvent::SurfaceResized; let w = util::loword(lparam as u32) as u32; let h = util::hiword(lparam as u32) as u32; - let physical_size = PhysicalSize::new(w, h); { @@ -1313,7 +1312,14 @@ unsafe fn public_window_callback_inner( w.set_window_flags_in_place(|f| f.set(WindowFlags::MAXIMIZED, maximized)); } } - userdata.send_window_event(window, SurfaceResized(physical_size)); + + let mut state = userdata.window_state_lock(); + if (w, h) != (0, 0) && physical_size != state.surface_size { + // WM_SIZE is received with size (0, 0) when a window is minimized; ignore. + state.surface_size = physical_size; + drop(state); + userdata.send_window_event(window, SurfaceResized(physical_size)); + } result = ProcResult::Value(0); }, diff --git a/winit-win32/src/window.rs b/winit-win32/src/window.rs index a0ffc138..dba95e9b 100644 --- a/winit-win32/src/window.rs +++ b/winit-win32/src/window.rs @@ -509,14 +509,7 @@ impl CoreWindow for Window { } fn surface_size(&self) -> PhysicalSize { - let mut rect: RECT = unsafe { mem::zeroed() }; - if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() { - panic!( - "Unexpected GetClientRect failure: please report this error to \ - rust-windowing/winit" - ) - } - PhysicalSize::new((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32) + self.window_state_lock().surface_size } fn outer_size(&self) -> PhysicalSize { diff --git a/winit-win32/src/window_state.rs b/winit-win32/src/window_state.rs index d1c49c33..ed06d760 100644 --- a/winit-win32/src/window_state.rs +++ b/winit-win32/src/window_state.rs @@ -33,6 +33,9 @@ pub(crate) struct WindowState { pub min_size: Option, pub max_size: Option, + /// The last known size of the window surface + pub surface_size: PhysicalSize, + pub surface_resize_increments: Option, pub window_icon: Option, @@ -166,6 +169,8 @@ impl WindowState { min_size: attributes.min_surface_size, max_size: attributes.max_surface_size, + surface_size: PhysicalSize::default(), + surface_resize_increments: attributes.surface_resize_increments, window_icon: attributes.window_icon.clone(), diff --git a/winit/examples/application.rs b/winit/examples/application.rs index 4842eaa4..dc432bb0 100644 --- a/winit/examples/application.rs +++ b/winit/examples/application.rs @@ -203,6 +203,15 @@ impl Application { Action::DumpMonitors => self.dump_monitors(_event_loop), Action::Message => { info!("User wake up"); + for (id, window) in self.windows.iter() { + if window.emit_surface_size { + let size = window.window.surface_size(); + info!( + "Window {id:?} has physical surface size {}x{}", + size.width, size.height + ); + } + } }, _ => unreachable!("Tried to execute invalid action without `WindowId`"), } @@ -315,6 +324,9 @@ impl Application { window.continuous_redraw = !window.continuous_redraw; window.window.request_redraw(); }, + Action::EmitSurfaceSize => { + window.toggle_emit_surface_size(); + }, } } @@ -615,6 +627,8 @@ struct WindowState { start_time: Instant, /// Redraw continuously continuous_redraw: bool, + /// Periodically emit the surface size + emit_surface_size: bool, /// Cursor position over the window. cursor_position: Option>, /// Window modifiers state. @@ -666,6 +680,7 @@ impl WindowState { theme, animated_fill_color: false, continuous_redraw: false, + emit_surface_size: false, #[cfg(not(android_platform))] start_time: Instant::now(), cursor_position: Default::default(), @@ -738,6 +753,10 @@ impl WindowState { self.window.set_fullscreen(fullscreen); } + fn toggle_emit_surface_size(&mut self) { + self.emit_surface_size = !self.emit_surface_size; + } + /// Cycle through the grab modes ignoring errors. fn cycle_cursor_grab(&mut self) { self.cursor_grab = match self.cursor_grab { @@ -1031,6 +1050,7 @@ enum Action { Message, ToggleAnimatedFillColor, ToggleContinuousRedraw, + EmitSurfaceSize, } impl Action { @@ -1076,6 +1096,7 @@ impl Action { Action::Message => "Prints a message through a user wake up", Action::ToggleAnimatedFillColor => "Toggle animated fill color", Action::ToggleContinuousRedraw => "Toggle continuous redraw", + Action::EmitSurfaceSize => "Periodically print the surface size", } } } @@ -1294,6 +1315,7 @@ const KEY_BINDINGS: &[Binding<&'static str>] = &[ Binding::new("T", ModifiersState::META, Action::CreateNewTab), #[cfg(macos_platform)] Binding::new("O", ModifiersState::CONTROL, Action::CycleOptionAsAlt), + Binding::new("S", ModifiersState::ALT, Action::EmitSurfaceSize), Binding::new("S", ModifiersState::CONTROL, Action::Message), ]; diff --git a/winit/src/changelog/unreleased.md b/winit/src/changelog/unreleased.md index 0178f56b..63db7610 100644 --- a/winit/src/changelog/unreleased.md +++ b/winit/src/changelog/unreleased.md @@ -268,6 +268,7 @@ changelog entry. - On Windows, `Window::theme` will return the correct theme after setting it through `Window::set_theme`. - On Windows, `Window::set_theme` will change the title bar color immediately now. - On Windows 11, prevent incorrect shifting when dragging window onto a monitor with different DPI. +- On Windows, avoid returning `SurfaceResized` with size zero when an application is minimized. Let `Window::surface_size` return the pre-minimization window size even while minimized. - On Web, device events are emitted regardless of cursor type. - On Wayland, `axis_value120` scroll events now generate `MouseScrollDelta::LineDelta` - On X11, mouse scroll button events no longer cause duplicated `WindowEvent::MouseWheel` events.