windows: Fix `window_min_size` (#29118)

angelrecovery and 张小白 created

Closes #29117

This makes `window_min_size` work by using the `WM_GETMINMAXINFO` window
message.


Release Notes:

- N/A

---------

Co-authored-by: 张小白 <364772080@qq.com>

Change summary

crates/gpui/src/platform/windows/events.rs | 24 ++++++++++++++++++++++++
crates/gpui/src/platform/windows/window.rs | 10 ++++++++--
2 files changed, 32 insertions(+), 2 deletions(-)

Detailed changes

crates/gpui/src/platform/windows/events.rs 🔗

@@ -39,6 +39,7 @@ pub(crate) fn handle_msg(
         WM_CREATE => handle_create_msg(handle, state_ptr),
         WM_MOVE => handle_move_msg(handle, lparam, state_ptr),
         WM_SIZE => handle_size_msg(wparam, lparam, state_ptr),
+        WM_GETMINMAXINFO => handle_get_min_max_info_msg(lparam, state_ptr),
         WM_ENTERSIZEMOVE | WM_ENTERMENULOOP => handle_size_move_loop(handle),
         WM_EXITSIZEMOVE | WM_EXITMENULOOP => handle_size_move_loop_exit(handle),
         WM_TIMER => handle_timer_msg(handle, wparam, state_ptr),
@@ -140,6 +141,29 @@ fn handle_move_msg(
     Some(0)
 }
 
+fn handle_get_min_max_info_msg(
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let lock = state_ptr.state.borrow();
+    if let Some(min_size) = lock.min_size {
+        let scale_factor = lock.scale_factor;
+        let boarder_offset = lock.border_offset;
+        drop(lock);
+
+        unsafe {
+            let minmax_info = &mut *(lparam.0 as *mut MINMAXINFO);
+            minmax_info.ptMinTrackSize.x =
+                min_size.width.scale(scale_factor).0 as i32 + boarder_offset.width_offset;
+            minmax_info.ptMinTrackSize.y =
+                min_size.height.scale(scale_factor).0 as i32 + boarder_offset.height_offset;
+        }
+        Some(0)
+    } else {
+        None
+    }
+}
+
 fn handle_size_msg(
     wparam: WPARAM,
     lparam: LPARAM,

crates/gpui/src/platform/windows/window.rs 🔗

@@ -34,6 +34,7 @@ pub(crate) struct WindowsWindow(pub Rc<WindowsWindowStatePtr>);
 pub struct WindowsWindowState {
     pub origin: Point<Pixels>,
     pub logical_size: Size<Pixels>,
+    pub min_size: Option<Size<Pixels>>,
     pub fullscreen_restore_bounds: Bounds<Pixels>,
     pub border_offset: WindowBorderOffset,
     pub scale_factor: f32,
@@ -79,6 +80,7 @@ impl WindowsWindowState {
         current_cursor: Option<HCURSOR>,
         display: WindowsDisplay,
         gpu_context: &BladeContext,
+        min_size: Option<Size<Pixels>>,
     ) -> Result<Self> {
         let scale_factor = {
             let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
@@ -113,6 +115,7 @@ impl WindowsWindowState {
             border_offset,
             scale_factor,
             restore_from_minimized,
+            min_size,
             callbacks,
             input_handler,
             system_key_handled,
@@ -229,6 +232,7 @@ impl WindowsWindowStatePtr {
             context.current_cursor,
             context.display,
             context.gpu_context,
+            context.min_size,
         )?);
 
         Ok(Rc::new_cyclic(|this| Self {
@@ -350,6 +354,7 @@ struct WindowCreateContext<'a> {
     display: WindowsDisplay,
     transparent: bool,
     is_movable: bool,
+    min_size: Option<Size<Pixels>>,
     executor: ForegroundExecutor,
     current_cursor: Option<HCURSOR>,
     windows_version: WindowsVersion,
@@ -412,6 +417,7 @@ impl WindowsWindow {
             display,
             transparent: true,
             is_movable: params.is_movable,
+            min_size: params.window_min_size,
             executor,
             current_cursor,
             windows_version,
@@ -1025,8 +1031,8 @@ type Color = (u8, u8, u8, u8);
 
 #[derive(Debug, Default, Clone, Copy)]
 pub(crate) struct WindowBorderOffset {
-    width_offset: i32,
-    height_offset: i32,
+    pub(crate) width_offset: i32,
+    pub(crate) height_offset: i32,
 }
 
 impl WindowBorderOffset {