windows: Handle scale factor change while window is maximized (#35686)

Max Brunsfeld created

Fixes https://github.com/zed-industries/zed/issues/33257

Previously, the scale-factor-change-handling logic relied on
`SetWindowPos` enqueuing a `WM_SIZE` window event. But that does not
happen when the window is maximized. So when the scale factor changed,
maximized windows neglected to call their `resize` callback, and would
misinterpret the positions of mouse events.

This PR adds special logic for maximized windows, to ensure that the
size is updated appropriately.

Release Notes:

- N/A

Change summary

crates/gpui/src/platform/windows/events.rs | 38 ++++++++++++++++++++---
1 file changed, 32 insertions(+), 6 deletions(-)

Detailed changes

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

@@ -174,20 +174,37 @@ impl WindowsWindowInner {
         let width = lparam.loword().max(1) as i32;
         let height = lparam.hiword().max(1) as i32;
         let new_size = size(DevicePixels(width), DevicePixels(height));
+
         let scale_factor = lock.scale_factor;
+        let mut should_resize_renderer = false;
         if lock.restore_from_minimized.is_some() {
             lock.callbacks.request_frame = lock.restore_from_minimized.take();
         } else {
-            lock.renderer.resize(new_size).log_err();
+            should_resize_renderer = true;
+        }
+        drop(lock);
+
+        self.handle_size_change(new_size, scale_factor, should_resize_renderer);
+        Some(0)
+    }
+
+    fn handle_size_change(
+        &self,
+        device_size: Size<DevicePixels>,
+        scale_factor: f32,
+        should_resize_renderer: bool,
+    ) {
+        let new_logical_size = device_size.to_pixels(scale_factor);
+        let mut lock = self.state.borrow_mut();
+        lock.logical_size = new_logical_size;
+        if should_resize_renderer {
+            lock.renderer.resize(device_size).log_err();
         }
-        let new_size = new_size.to_pixels(scale_factor);
-        lock.logical_size = new_size;
         if let Some(mut callback) = lock.callbacks.resize.take() {
             drop(lock);
-            callback(new_size, scale_factor);
+            callback(new_logical_size, scale_factor);
             self.state.borrow_mut().callbacks.resize = Some(callback);
         }
-        Some(0)
     }
 
     fn handle_size_move_loop(&self, handle: HWND) -> Option<isize> {
@@ -747,7 +764,9 @@ impl WindowsWindowInner {
     ) -> Option<isize> {
         let new_dpi = wparam.loword() as f32;
         let mut lock = self.state.borrow_mut();
-        lock.scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
+        let is_maximized = lock.is_maximized();
+        let new_scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
+        lock.scale_factor = new_scale_factor;
         lock.border_offset.update(handle).log_err();
         drop(lock);
 
@@ -771,6 +790,13 @@ impl WindowsWindowInner {
             .log_err();
         }
 
+        // When maximized, SetWindowPos doesn't send WM_SIZE, so we need to manually
+        // update the size and call the resize callback
+        if is_maximized {
+            let device_size = size(DevicePixels(width), DevicePixels(height));
+            self.handle_size_change(device_size, new_scale_factor, true);
+        }
+
         Some(0)
     }