gpui(windows): Move interior mutability down into fields (#44002)

Lukas Wirth created

Windows applications tend to be fairly re-entrant which does not work
well with our current top-level `RefCell` approach. We have worked
around a bunch of panics in the past due to this, but ultimately this
will re-occur (and still does according to sentry) in the future. So
this PR moves all interior mutability down to the fields.

Fixes ZED-1HM
Fixes ZED-3SH
Fixes ZED-1YV
Fixes ZED-29S
Fixes ZED-29X
Fixes ZED-369
Fixes ZED-20W

Release Notes:

- Fixed panics on windows caused by unexpected re-entrancy for interior
mutability

Change summary

crates/gpui/src/geometry.rs                         |   4 
crates/gpui/src/platform/windows/events.rs          | 353 ++++++-------
crates/gpui/src/platform/windows/platform.rs        | 112 ++--
crates/gpui/src/platform/windows/system_settings.rs |  43 
crates/gpui/src/platform/windows/window.rs          | 365 +++++++-------
5 files changed, 441 insertions(+), 436 deletions(-)

Detailed changes

crates/gpui/src/geometry.rs 🔗

@@ -748,7 +748,7 @@ impl Size<Length> {
 /// assert_eq!(bounds.origin, origin);
 /// assert_eq!(bounds.size, size);
 /// ```
-#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
+#[derive(Refineable, Copy, Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
 #[refineable(Debug)]
 #[repr(C)]
 pub struct Bounds<T: Clone + Debug + Default + PartialEq> {
@@ -1676,8 +1676,6 @@ impl Bounds<DevicePixels> {
     }
 }
 
-impl<T: Copy + Clone + Debug + Default + PartialEq> Copy for Bounds<T> {}
-
 /// Represents the edges of a box in a 2D space, such as padding or margin.
 ///
 /// Each field represents the size of the edge on one side of the box: `top`, `right`, `bottom`, and `left`.

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

@@ -116,17 +116,16 @@ impl WindowsWindowInner {
     }
 
     fn handle_move_msg(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
         let origin = logical_point(
             lparam.signed_loword() as f32,
             lparam.signed_hiword() as f32,
-            lock.scale_factor,
+            self.state.scale_factor.get(),
         );
-        lock.origin = origin;
-        let size = lock.logical_size;
+        self.state.origin.set(origin);
+        let size = self.state.logical_size.get();
         let center_x = origin.x.0 + size.width.0 / 2.;
         let center_y = origin.y.0 + size.height.0 / 2.;
-        let monitor_bounds = lock.display.bounds();
+        let monitor_bounds = self.state.display.get().bounds();
         if center_x < monitor_bounds.left().0
             || center_x > monitor_bounds.right().0
             || center_y < monitor_bounds.top().0
@@ -136,42 +135,42 @@ impl WindowsWindowInner {
             let monitor = unsafe { MonitorFromWindow(handle, MONITOR_DEFAULTTONULL) };
             // minimize the window can trigger this event too, in this case,
             // monitor is invalid, we do nothing.
-            if !monitor.is_invalid() && lock.display.handle != monitor {
+            if !monitor.is_invalid() && self.state.display.get().handle != monitor {
                 // we will get the same monitor if we only have one
-                lock.display = WindowsDisplay::new_with_handle(monitor).log_err()?;
+                self.state
+                    .display
+                    .set(WindowsDisplay::new_with_handle(monitor).log_err()?);
             }
         }
-        if let Some(mut callback) = lock.callbacks.moved.take() {
-            drop(lock);
+        if let Some(mut callback) = self.state.callbacks.moved.take() {
             callback();
-            self.state.borrow_mut().callbacks.moved = Some(callback);
+            self.state.callbacks.moved.set(Some(callback));
         }
         Some(0)
     }
 
     fn handle_get_min_max_info_msg(&self, lparam: LPARAM) -> Option<isize> {
-        let lock = self.state.borrow();
-        let min_size = lock.min_size?;
-        let scale_factor = lock.scale_factor;
-        let boarder_offset = lock.border_offset;
-        drop(lock);
+        let min_size = self.state.min_size?;
+        let scale_factor = self.state.scale_factor.get();
+        let boarder_offset = &self.state.border_offset;
+
         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;
+                min_size.width.scale(scale_factor).0 as i32 + boarder_offset.width_offset.get();
             minmax_info.ptMinTrackSize.y =
-                min_size.height.scale(scale_factor).0 as i32 + boarder_offset.height_offset;
+                min_size.height.scale(scale_factor).0 as i32 + boarder_offset.height_offset.get();
         }
         Some(0)
     }
 
     fn handle_size_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
-
         // Don't resize the renderer when the window is minimized, but record that it was minimized so
         // that on restore the swap chain can be recreated via `update_drawable_size_even_if_unchanged`.
         if wparam.0 == SIZE_MINIMIZED as usize {
-            lock.restore_from_minimized = lock.callbacks.request_frame.take();
+            self.state
+                .restore_from_minimized
+                .set(self.state.callbacks.request_frame.take());
             return Some(0);
         }
 
@@ -179,14 +178,16 @@ impl WindowsWindowInner {
         let height = lparam.hiword().max(1) as i32;
         let new_size = size(DevicePixels(width), DevicePixels(height));
 
-        let scale_factor = lock.scale_factor;
+        let scale_factor = self.state.scale_factor.get();
         let mut should_resize_renderer = false;
-        if lock.restore_from_minimized.is_some() {
-            lock.callbacks.request_frame = lock.restore_from_minimized.take();
+        if let Some(restore_from_minimized) = self.state.restore_from_minimized.take() {
+            self.state
+                .callbacks
+                .request_frame
+                .set(Some(restore_from_minimized));
         } else {
             should_resize_renderer = true;
         }
-        drop(lock);
 
         self.handle_size_change(new_size, scale_factor, should_resize_renderer);
         Some(0)
@@ -199,17 +200,19 @@ impl WindowsWindowInner {
         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 && let Err(e) = lock.renderer.resize(device_size) {
+
+        self.state.logical_size.set(new_logical_size);
+        if should_resize_renderer
+            && let Err(e) = self.state.renderer.borrow_mut().resize(device_size)
+        {
             log::error!("Failed to resize renderer, invalidating devices: {}", e);
-            lock.invalidate_devices
+            self.state
+                .invalidate_devices
                 .store(true, std::sync::atomic::Ordering::Release);
         }
-        if let Some(mut callback) = lock.callbacks.resize.take() {
-            drop(lock);
+        if let Some(mut callback) = self.state.callbacks.resize.take() {
             callback(new_logical_size, scale_factor);
-            self.state.borrow_mut().callbacks.resize = Some(callback);
+            self.state.callbacks.resize.set(Some(callback));
         }
     }
 
@@ -254,17 +257,14 @@ impl WindowsWindowInner {
     }
 
     fn handle_close_msg(&self) -> Option<isize> {
-        let mut callback = self.state.borrow_mut().callbacks.should_close.take()?;
+        let mut callback = self.state.callbacks.should_close.take()?;
         let should_close = callback();
-        self.state.borrow_mut().callbacks.should_close = Some(callback);
+        self.state.callbacks.should_close.set(Some(callback));
         if should_close { None } else { Some(0) }
     }
 
     fn handle_destroy_msg(&self, handle: HWND) -> Option<isize> {
-        let callback = {
-            let mut lock = self.state.borrow_mut();
-            lock.callbacks.close.take()
-        };
+        let callback = { self.state.callbacks.close.take() };
         if let Some(callback) = callback {
             callback();
         }
@@ -283,12 +283,10 @@ impl WindowsWindowInner {
     fn handle_mouse_move_msg(&self, handle: HWND, lparam: LPARAM, wparam: WPARAM) -> Option<isize> {
         self.start_tracking_mouse(handle, TME_LEAVE);
 
-        let mut lock = self.state.borrow_mut();
-        let Some(mut func) = lock.callbacks.input.take() else {
+        let Some(mut func) = self.state.callbacks.input.take() else {
             return Some(1);
         };
-        let scale_factor = lock.scale_factor;
-        drop(lock);
+        let scale_factor = self.state.scale_factor.get();
 
         let pressed_button = match MODIFIERKEYS_FLAGS(wparam.loword() as u32) {
             flags if flags.contains(MK_LBUTTON) => Some(MouseButton::Left),
@@ -310,32 +308,32 @@ impl WindowsWindowInner {
             modifiers: current_modifiers(),
         });
         let handled = !func(input).propagate;
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { Some(1) }
     }
 
     fn handle_mouse_leave_msg(&self) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
-        lock.hovered = false;
-        if let Some(mut callback) = lock.callbacks.hovered_status_change.take() {
-            drop(lock);
+        self.state.hovered.set(false);
+        if let Some(mut callback) = self.state.callbacks.hovered_status_change.take() {
             callback(false);
-            self.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
+            self.state
+                .callbacks
+                .hovered_status_change
+                .set(Some(callback));
         }
 
         Some(0)
     }
 
     fn handle_syskeyup_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
-        let input = handle_key_event(wparam, lparam, &mut lock, |keystroke, _| {
+        let input = handle_key_event(wparam, lparam, &self.state, |keystroke, _| {
             PlatformInput::KeyUp(KeyUpEvent { keystroke })
         })?;
-        let mut func = lock.callbacks.input.take()?;
-        drop(lock);
+        let mut func = self.state.callbacks.input.take()?;
+
         func(input);
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         // Always return 0 to indicate that the message was handled, so we could properly handle `ModifiersChanged` event.
         Some(0)
@@ -344,11 +342,10 @@ impl WindowsWindowInner {
     // It's a known bug that you can't trigger `ctrl-shift-0`. See:
     // https://superuser.com/questions/1455762/ctrl-shift-number-key-combination-has-stopped-working-for-a-few-numbers
     fn handle_keydown_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
         let Some(input) = handle_key_event(
             wparam,
             lparam,
-            &mut lock,
+            &self.state,
             |keystroke, prefer_character_input| {
                 PlatformInput::KeyDown(KeyDownEvent {
                     keystroke,
@@ -359,34 +356,31 @@ impl WindowsWindowInner {
         ) else {
             return Some(1);
         };
-        drop(lock);
 
-        let Some(mut func) = self.state.borrow_mut().callbacks.input.take() else {
+        let Some(mut func) = self.state.callbacks.input.take() else {
             return Some(1);
         };
 
         let handled = !func(input).propagate;
 
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { Some(1) }
     }
 
     fn handle_keyup_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
-        let Some(input) = handle_key_event(wparam, lparam, &mut lock, |keystroke, _| {
+        let Some(input) = handle_key_event(wparam, lparam, &self.state, |keystroke, _| {
             PlatformInput::KeyUp(KeyUpEvent { keystroke })
         }) else {
             return Some(1);
         };
 
-        let Some(mut func) = lock.callbacks.input.take() else {
+        let Some(mut func) = self.state.callbacks.input.take() else {
             return Some(1);
         };
-        drop(lock);
 
         let handled = !func(input).propagate;
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { Some(1) }
     }
@@ -407,16 +401,15 @@ impl WindowsWindowInner {
         lparam: LPARAM,
     ) -> Option<isize> {
         unsafe { SetCapture(handle) };
-        let mut lock = self.state.borrow_mut();
-        let Some(mut func) = lock.callbacks.input.take() else {
+
+        let Some(mut func) = self.state.callbacks.input.take() else {
             return Some(1);
         };
         let x = lparam.signed_loword();
         let y = lparam.signed_hiword();
         let physical_point = point(DevicePixels(x as i32), DevicePixels(y as i32));
-        let click_count = lock.click_state.update(button, physical_point);
-        let scale_factor = lock.scale_factor;
-        drop(lock);
+        let click_count = self.state.click_state.update(button, physical_point);
+        let scale_factor = self.state.scale_factor.get();
 
         let input = PlatformInput::MouseDown(MouseDownEvent {
             button,
@@ -426,7 +419,7 @@ impl WindowsWindowInner {
             first_mouse: false,
         });
         let handled = !func(input).propagate;
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { Some(1) }
     }
@@ -438,15 +431,14 @@ impl WindowsWindowInner {
         lparam: LPARAM,
     ) -> Option<isize> {
         unsafe { ReleaseCapture().log_err() };
-        let mut lock = self.state.borrow_mut();
-        let Some(mut func) = lock.callbacks.input.take() else {
+
+        let Some(mut func) = self.state.callbacks.input.take() else {
             return Some(1);
         };
         let x = lparam.signed_loword() as f32;
         let y = lparam.signed_hiword() as f32;
-        let click_count = lock.click_state.current_count;
-        let scale_factor = lock.scale_factor;
-        drop(lock);
+        let click_count = self.state.click_state.current_count.get();
+        let scale_factor = self.state.scale_factor.get();
 
         let input = PlatformInput::MouseUp(MouseUpEvent {
             button,
@@ -455,7 +447,7 @@ impl WindowsWindowInner {
             click_count,
         });
         let handled = !func(input).propagate;
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { Some(1) }
     }
@@ -482,24 +474,23 @@ impl WindowsWindowInner {
         lparam: LPARAM,
     ) -> Option<isize> {
         let modifiers = current_modifiers();
-        let mut lock = self.state.borrow_mut();
-        let Some(mut func) = lock.callbacks.input.take() else {
+
+        let Some(mut func) = self.state.callbacks.input.take() else {
             return Some(1);
         };
-        let scale_factor = lock.scale_factor;
+        let scale_factor = self.state.scale_factor.get();
         let wheel_scroll_amount = match modifiers.shift {
-            true => {
-                self.system_settings()
-                    .mouse_wheel_settings
-                    .wheel_scroll_chars
-            }
-            false => {
-                self.system_settings()
-                    .mouse_wheel_settings
-                    .wheel_scroll_lines
-            }
+            true => self
+                .system_settings()
+                .mouse_wheel_settings
+                .wheel_scroll_chars
+                .get(),
+            false => self
+                .system_settings()
+                .mouse_wheel_settings
+                .wheel_scroll_lines
+                .get(),
         };
-        drop(lock);
 
         let wheel_distance =
             (wparam.signed_hiword() as f32 / WHEEL_DELTA as f32) * wheel_scroll_amount as f32;
@@ -524,7 +515,7 @@ impl WindowsWindowInner {
             touch_phase: TouchPhase::Moved,
         });
         let handled = !func(input).propagate;
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { Some(1) }
     }
@@ -535,16 +526,15 @@ impl WindowsWindowInner {
         wparam: WPARAM,
         lparam: LPARAM,
     ) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
-        let Some(mut func) = lock.callbacks.input.take() else {
+        let Some(mut func) = self.state.callbacks.input.take() else {
             return Some(1);
         };
-        let scale_factor = lock.scale_factor;
+        let scale_factor = self.state.scale_factor.get();
         let wheel_scroll_chars = self
             .system_settings()
             .mouse_wheel_settings
-            .wheel_scroll_chars;
-        drop(lock);
+            .wheel_scroll_chars
+            .get();
 
         let wheel_distance =
             (-wparam.signed_hiword() as f32 / WHEEL_DELTA as f32) * wheel_scroll_chars as f32;
@@ -563,7 +553,7 @@ impl WindowsWindowInner {
             touch_phase: TouchPhase::Moved,
         });
         let handled = !func(event).propagate;
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { Some(1) }
     }
@@ -657,11 +647,11 @@ impl WindowsWindowInner {
         wparam: WPARAM,
         lparam: LPARAM,
     ) -> Option<isize> {
-        if !self.hide_title_bar || self.state.borrow().is_fullscreen() || wparam.0 == 0 {
+        if !self.hide_title_bar || self.state.is_fullscreen() || wparam.0 == 0 {
             return None;
         }
 
-        let is_maximized = self.state.borrow().is_maximized();
+        let is_maximized = self.state.is_maximized();
         let insets = get_client_area_insets(handle, is_maximized, self.windows_version);
         // wparam is TRUE so lparam points to an NCCALCSIZE_PARAMS structure
         let mut params = lparam.0 as *mut NCCALCSIZE_PARAMS;
@@ -676,7 +666,7 @@ impl WindowsWindowInner {
         // used by Chrome. However, it may result in one row of pixels being obscured
         // in our client area. But as Chrome says, "there seems to be no better solution."
         if is_maximized
-            && let Some(ref taskbar_position) = self.system_settings().auto_hide_taskbar_position
+            && let Some(taskbar_position) = self.system_settings().auto_hide_taskbar_position.get()
         {
             // For the auto-hide taskbar, adjust in by 1 pixel on taskbar edge,
             // so the window isn't treated as a "fullscreen app", which would cause
@@ -705,11 +695,9 @@ impl WindowsWindowInner {
         let this = self.clone();
         self.executor
             .spawn(async move {
-                let mut lock = this.state.borrow_mut();
-                if let Some(mut func) = lock.callbacks.active_status_change.take() {
-                    drop(lock);
+                if let Some(mut func) = this.state.callbacks.active_status_change.take() {
                     func(activated);
-                    this.state.borrow_mut().callbacks.active_status_change = Some(func);
+                    this.state.callbacks.active_status_change.set(Some(func));
                 }
             })
             .detach();
@@ -733,12 +721,11 @@ impl WindowsWindowInner {
         lparam: LPARAM,
     ) -> Option<isize> {
         let new_dpi = wparam.loword() as f32;
-        let mut lock = self.state.borrow_mut();
-        let is_maximized = lock.is_maximized();
+
+        let is_maximized = self.state.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);
+        self.state.scale_factor.set(new_scale_factor);
+        self.state.border_offset.update(handle).log_err();
 
         if is_maximized {
             // Get the monitor and its work area at the new DPI
@@ -812,7 +799,7 @@ impl WindowsWindowInner {
         // Because WM_DPICHANGED, WM_MOVE, WM_SIZE will come first, window reposition and resize
         // are handled there.
         // So we only care about if monitor is disconnected.
-        let previous_monitor = self.state.borrow().display;
+        let previous_monitor = self.state.display.get();
         if WindowsDisplay::is_connected(previous_monitor.handle) {
             // we are fine, other display changed
             return None;
@@ -830,24 +817,22 @@ impl WindowsWindowInner {
             return None;
         }
         let new_display = WindowsDisplay::new_with_handle(new_monitor).log_err()?;
-        self.state.borrow_mut().display = new_display;
+        self.state.display.set(new_display);
         Some(0)
     }
 
     fn handle_hit_test_msg(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
-        if !self.is_movable || self.state.borrow().is_fullscreen() {
+        if !self.is_movable || self.state.is_fullscreen() {
             return None;
         }
 
-        let callback = self
-            .state
-            .borrow_mut()
-            .callbacks
-            .hit_test_window_control
-            .take();
+        let callback = self.state.callbacks.hit_test_window_control.take();
         let drag_area = if let Some(mut callback) = callback {
             let area = callback();
-            self.state.borrow_mut().callbacks.hit_test_window_control = Some(callback);
+            self.state
+                .callbacks
+                .hit_test_window_control
+                .set(Some(callback));
             if let Some(area) = area {
                 match area {
                     WindowControlArea::Drag => Some(HTCAPTION as _),
@@ -878,7 +863,7 @@ impl WindowsWindowInner {
         };
 
         unsafe { ScreenToClient(handle, &mut cursor_point).ok().log_err() };
-        if !self.state.borrow().is_maximized() && 0 <= cursor_point.y && cursor_point.y <= frame_y {
+        if !self.state.is_maximized() && 0 <= cursor_point.y && cursor_point.y <= frame_y {
             // x-axis actually goes from -frame_x to 0
             return Some(if cursor_point.x <= 0 {
                 HTTOPLEFT
@@ -902,10 +887,8 @@ impl WindowsWindowInner {
     fn handle_nc_mouse_move_msg(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
         self.start_tracking_mouse(handle, TME_LEAVE | TME_NONCLIENT);
 
-        let mut lock = self.state.borrow_mut();
-        let mut func = lock.callbacks.input.take()?;
-        let scale_factor = lock.scale_factor;
-        drop(lock);
+        let mut func = self.state.callbacks.input.take()?;
+        let scale_factor = self.state.scale_factor.get();
 
         let mut cursor_point = POINT {
             x: lparam.signed_loword().into(),
@@ -918,7 +901,7 @@ impl WindowsWindowInner {
             modifiers: current_modifiers(),
         });
         let handled = !func(input).propagate;
-        self.state.borrow_mut().callbacks.input = Some(func);
+        self.state.callbacks.input.set(Some(func));
 
         if handled { Some(0) } else { None }
     }
@@ -930,17 +913,15 @@ impl WindowsWindowInner {
         wparam: WPARAM,
         lparam: LPARAM,
     ) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
-        if let Some(mut func) = lock.callbacks.input.take() {
-            let scale_factor = lock.scale_factor;
+        if let Some(mut func) = self.state.callbacks.input.take() {
+            let scale_factor = self.state.scale_factor.get();
             let mut cursor_point = POINT {
                 x: lparam.signed_loword().into(),
                 y: lparam.signed_hiword().into(),
             };
             unsafe { ScreenToClient(handle, &mut cursor_point).ok().log_err() };
             let physical_point = point(DevicePixels(cursor_point.x), DevicePixels(cursor_point.y));
-            let click_count = lock.click_state.update(button, physical_point);
-            drop(lock);
+            let click_count = self.state.click_state.update(button, physical_point);
 
             let input = PlatformInput::MouseDown(MouseDownEvent {
                 button,
@@ -951,21 +932,20 @@ impl WindowsWindowInner {
             });
             let result = func(input);
             let handled = !result.propagate || result.default_prevented;
-            self.state.borrow_mut().callbacks.input = Some(func);
+            self.state.callbacks.input.set(Some(func));
 
             if handled {
                 return Some(0);
             }
         } else {
-            drop(lock);
         };
 
         // Since these are handled in handle_nc_mouse_up_msg we must prevent the default window proc
         if button == MouseButton::Left {
             match wparam.0 as u32 {
-                HTMINBUTTON => self.state.borrow_mut().nc_button_pressed = Some(HTMINBUTTON),
-                HTMAXBUTTON => self.state.borrow_mut().nc_button_pressed = Some(HTMAXBUTTON),
-                HTCLOSE => self.state.borrow_mut().nc_button_pressed = Some(HTCLOSE),
+                HTMINBUTTON => self.state.nc_button_pressed.set(Some(HTMINBUTTON)),
+                HTMAXBUTTON => self.state.nc_button_pressed.set(Some(HTMAXBUTTON)),
+                HTCLOSE => self.state.nc_button_pressed.set(Some(HTCLOSE)),
                 _ => return None,
             };
             Some(0)
@@ -981,10 +961,8 @@ impl WindowsWindowInner {
         wparam: WPARAM,
         lparam: LPARAM,
     ) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
-        if let Some(mut func) = lock.callbacks.input.take() {
-            let scale_factor = lock.scale_factor;
-            drop(lock);
+        if let Some(mut func) = self.state.callbacks.input.take() {
+            let scale_factor = self.state.scale_factor.get();
 
             let mut cursor_point = POINT {
                 x: lparam.signed_loword().into(),
@@ -998,16 +976,15 @@ impl WindowsWindowInner {
                 click_count: 1,
             });
             let handled = !func(input).propagate;
-            self.state.borrow_mut().callbacks.input = Some(func);
+            self.state.callbacks.input.set(Some(func));
 
             if handled {
                 return Some(0);
             }
         } else {
-            drop(lock);
         }
 
-        let last_pressed = self.state.borrow_mut().nc_button_pressed.take();
+        let last_pressed = self.state.nc_button_pressed.take();
         if button == MouseButton::Left
             && let Some(last_pressed) = last_pressed
         {
@@ -1017,7 +994,7 @@ impl WindowsWindowInner {
                     true
                 }
                 (HTMAXBUTTON, HTMAXBUTTON) => {
-                    if self.state.borrow().is_maximized() {
+                    if self.state.is_maximized() {
                         unsafe { ShowWindowAsync(handle, SW_NORMAL).ok().log_err() };
                     } else {
                         unsafe { ShowWindowAsync(handle, SW_MAXIMIZE).ok().log_err() };
@@ -1042,17 +1019,16 @@ impl WindowsWindowInner {
     }
 
     fn handle_cursor_changed(&self, lparam: LPARAM) -> Option<isize> {
-        let mut state = self.state.borrow_mut();
-        let had_cursor = state.current_cursor.is_some();
+        let had_cursor = self.state.current_cursor.get().is_some();
 
-        state.current_cursor = if lparam.0 == 0 {
+        self.state.current_cursor.set(if lparam.0 == 0 {
             None
         } else {
             Some(HCURSOR(lparam.0 as _))
-        };
+        });
 
-        if had_cursor != state.current_cursor.is_some() {
-            unsafe { SetCursor(state.current_cursor) };
+        if had_cursor != self.state.current_cursor.get().is_some() {
+            unsafe { SetCursor(self.state.current_cursor.get()) };
         }
 
         Some(0)
@@ -1075,7 +1051,7 @@ impl WindowsWindowInner {
             return None;
         }
         unsafe {
-            SetCursor(self.state.borrow().current_cursor);
+            SetCursor(self.state.current_cursor.get());
         };
         Some(0)
     }
@@ -1087,13 +1063,12 @@ impl WindowsWindowInner {
         lparam: LPARAM,
     ) -> Option<isize> {
         if wparam.0 != 0 {
-            let mut lock = self.state.borrow_mut();
-            let display = lock.display;
-            lock.click_state.system_update(wparam.0);
-            lock.border_offset.update(handle).log_err();
-            // system settings may emit a window message which wants to take the refcell lock, so drop it
-            drop(lock);
-            self.system_settings_mut().update(display, wparam.0);
+            let display = self.state.display.get();
+            self.state.click_state.system_update(wparam.0);
+            self.state.border_offset.update(handle).log_err();
+            // system settings may emit a window message which wants to take the refcell self.state, so drop it
+
+            self.system_settings().update(display, wparam.0);
         } else {
             self.handle_system_theme_changed(handle, lparam)?;
         };
@@ -1116,13 +1091,13 @@ impl WindowsWindowInner {
                 let new_appearance = system_appearance()
                     .context("unable to get system appearance when handling ImmersiveColorSet")
                     .log_err()?;
-                let mut lock = self.state.borrow_mut();
-                if new_appearance != lock.appearance {
-                    lock.appearance = new_appearance;
-                    let mut callback = lock.callbacks.appearance_changed.take()?;
-                    drop(lock);
+
+                if new_appearance != self.state.appearance.get() {
+                    self.state.appearance.set(new_appearance);
+                    let mut callback = self.state.callbacks.appearance_changed.take()?;
+
                     callback();
-                    self.state.borrow_mut().callbacks.appearance_changed = Some(callback);
+                    self.state.callbacks.appearance_changed.set(Some(callback));
                     configure_dwm_dark_mode(handle, new_appearance);
                 }
             }
@@ -1151,10 +1126,14 @@ impl WindowsWindowInner {
     }
 
     fn handle_device_lost(&self, lparam: LPARAM) -> Option<isize> {
-        let mut lock = self.state.borrow_mut();
         let devices = lparam.0 as *const DirectXDevices;
         let devices = unsafe { &*devices };
-        if let Err(err) = lock.renderer.handle_device_lost(&devices) {
+        if let Err(err) = self
+            .state
+            .renderer
+            .borrow_mut()
+            .handle_device_lost(&devices)
+        {
             panic!("Device lost: {err}");
         }
         Some(0)
@@ -1162,18 +1141,18 @@ impl WindowsWindowInner {
 
     #[inline]
     fn draw_window(&self, handle: HWND, force_render: bool) -> Option<isize> {
-        let mut request_frame = self.state.borrow_mut().callbacks.request_frame.take()?;
+        let mut request_frame = self.state.callbacks.request_frame.take()?;
 
         // we are instructing gpui to force render a frame, this will
         // re-populate all the gpu textures for us so we can resume drawing in
         // case we disabled drawing earlier due to a device loss
-        self.state.borrow_mut().renderer.mark_drawable();
+        self.state.renderer.borrow_mut().mark_drawable();
         request_frame(RequestFrameOptions {
             require_presentation: false,
             force_render,
         });
 
-        self.state.borrow_mut().callbacks.request_frame = Some(request_frame);
+        self.state.callbacks.request_frame.set(Some(request_frame));
         unsafe { ValidateRect(Some(handle), None).ok().log_err() };
 
         Some(0)
@@ -1182,16 +1161,16 @@ impl WindowsWindowInner {
     #[inline]
     fn parse_char_message(&self, wparam: WPARAM) -> Option<String> {
         let code_point = wparam.loword();
-        let mut lock = self.state.borrow_mut();
+
         // https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G2630
         match code_point {
             0xD800..=0xDBFF => {
                 // High surrogate, wait for low surrogate
-                lock.pending_surrogate = Some(code_point);
+                self.state.pending_surrogate.set(Some(code_point));
                 None
             }
             0xDC00..=0xDFFF => {
-                if let Some(high_surrogate) = lock.pending_surrogate.take() {
+                if let Some(high_surrogate) = self.state.pending_surrogate.take() {
                     // Low surrogate, combine with pending high surrogate
                     String::from_utf16(&[high_surrogate, code_point]).ok()
                 } else {
@@ -1203,7 +1182,7 @@ impl WindowsWindowInner {
                 }
             }
             _ => {
-                lock.pending_surrogate = None;
+                self.state.pending_surrogate.set(None);
                 char::from_u32(code_point as u32)
                     .filter(|c| !c.is_control())
                     .map(|c| c.to_string())
@@ -1212,9 +1191,8 @@ impl WindowsWindowInner {
     }
 
     fn start_tracking_mouse(&self, handle: HWND, flags: TRACKMOUSEEVENT_FLAGS) {
-        let mut lock = self.state.borrow_mut();
-        if !lock.hovered {
-            lock.hovered = true;
+        if !self.state.hovered.get() {
+            self.state.hovered.set(true);
             unsafe {
                 TrackMouseEvent(&mut TRACKMOUSEEVENT {
                     cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,
@@ -1224,10 +1202,12 @@ impl WindowsWindowInner {
                 })
                 .log_err()
             };
-            if let Some(mut callback) = lock.callbacks.hovered_status_change.take() {
-                drop(lock);
+            if let Some(mut callback) = self.state.callbacks.hovered_status_change.take() {
                 callback(true);
-                self.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
+                self.state
+                    .callbacks
+                    .hovered_status_change
+                    .set(Some(callback));
             }
         }
     }
@@ -1236,9 +1216,9 @@ impl WindowsWindowInner {
     where
         F: FnOnce(&mut PlatformInputHandler) -> R,
     {
-        let mut input_handler = self.state.borrow_mut().input_handler.take()?;
+        let mut input_handler = self.state.input_handler.take()?;
         let result = f(&mut input_handler);
-        self.state.borrow_mut().input_handler = Some(input_handler);
+        self.state.input_handler.set(Some(input_handler));
         Some(result)
     }
 
@@ -1246,12 +1226,11 @@ impl WindowsWindowInner {
     where
         F: FnOnce(&mut PlatformInputHandler, f32) -> Option<R>,
     {
-        let mut lock = self.state.borrow_mut();
-        let mut input_handler = lock.input_handler.take()?;
-        let scale_factor = lock.scale_factor;
-        drop(lock);
+        let mut input_handler = self.state.input_handler.take()?;
+        let scale_factor = self.state.scale_factor.get();
+
         let result = f(&mut input_handler, scale_factor);
-        self.state.borrow_mut().input_handler = Some(input_handler);
+        self.state.input_handler.set(Some(input_handler));
         result
     }
 }
@@ -1259,7 +1238,7 @@ impl WindowsWindowInner {
 fn handle_key_event<F>(
     wparam: WPARAM,
     lparam: LPARAM,
-    state: &mut WindowsWindowState,
+    state: &WindowsWindowState,
     f: F,
 ) -> Option<PlatformInput>
 where
@@ -1272,11 +1251,12 @@ where
         VK_SHIFT | VK_CONTROL | VK_MENU | VK_LMENU | VK_RMENU | VK_LWIN | VK_RWIN => {
             if state
                 .last_reported_modifiers
+                .get()
                 .is_some_and(|prev_modifiers| prev_modifiers == modifiers)
             {
                 return None;
             }
-            state.last_reported_modifiers = Some(modifiers);
+            state.last_reported_modifiers.set(Some(modifiers));
             Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent {
                 modifiers,
                 capslock: current_capslock(),
@@ -1287,11 +1267,12 @@ where
             let capslock = current_capslock();
             if state
                 .last_reported_capslock
+                .get()
                 .is_some_and(|prev_capslock| prev_capslock == capslock)
             {
                 return None;
             }
-            state.last_reported_capslock = Some(capslock);
+            state.last_reported_capslock.set(Some(capslock));
             Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent {
                 modifiers,
                 capslock,

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

@@ -1,5 +1,5 @@
 use std::{
-    cell::RefCell,
+    cell::{Cell, RefCell},
     ffi::OsStr,
     path::{Path, PathBuf},
     rc::{Rc, Weak},
@@ -47,7 +47,7 @@ pub(crate) struct WindowsPlatform {
 }
 
 struct WindowsPlatformInner {
-    state: RefCell<WindowsPlatformState>,
+    state: WindowsPlatformState,
     raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
     // The below members will never change throughout the entire lifecycle of the app.
     validation_number: usize,
@@ -57,22 +57,22 @@ struct WindowsPlatformInner {
 
 pub(crate) struct WindowsPlatformState {
     callbacks: PlatformCallbacks,
-    menus: Vec<OwnedMenu>,
-    jump_list: JumpList,
+    menus: RefCell<Vec<OwnedMenu>>,
+    jump_list: RefCell<JumpList>,
     // NOTE: standard cursor handles don't need to close.
-    pub(crate) current_cursor: Option<HCURSOR>,
-    directx_devices: Option<DirectXDevices>,
+    pub(crate) current_cursor: Cell<Option<HCURSOR>>,
+    directx_devices: RefCell<Option<DirectXDevices>>,
 }
 
 #[derive(Default)]
 struct PlatformCallbacks {
-    open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
-    quit: Option<Box<dyn FnMut()>>,
-    reopen: Option<Box<dyn FnMut()>>,
-    app_menu_action: Option<Box<dyn FnMut(&dyn Action)>>,
-    will_open_app_menu: Option<Box<dyn FnMut()>>,
-    validate_app_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
-    keyboard_layout_change: Option<Box<dyn FnMut()>>,
+    open_urls: Cell<Option<Box<dyn FnMut(Vec<String>)>>>,
+    quit: Cell<Option<Box<dyn FnMut()>>>,
+    reopen: Cell<Option<Box<dyn FnMut()>>>,
+    app_menu_action: Cell<Option<Box<dyn FnMut(&dyn Action)>>>,
+    will_open_app_menu: Cell<Option<Box<dyn FnMut()>>>,
+    validate_app_menu_command: Cell<Option<Box<dyn FnMut(&dyn Action) -> bool>>>,
+    keyboard_layout_change: Cell<Option<Box<dyn FnMut()>>>,
 }
 
 impl WindowsPlatformState {
@@ -84,10 +84,10 @@ impl WindowsPlatformState {
 
         Self {
             callbacks,
-            jump_list,
-            current_cursor,
-            directx_devices,
-            menus: Vec::new(),
+            jump_list: RefCell::new(jump_list),
+            current_cursor: Cell::new(current_cursor),
+            directx_devices: RefCell::new(directx_devices),
+            menus: RefCell::new(Vec::new()),
         }
     }
 }
@@ -194,14 +194,14 @@ impl WindowsPlatform {
         WindowCreationInfo {
             icon: self.icon,
             executor: self.foreground_executor.clone(),
-            current_cursor: self.inner.state.borrow().current_cursor,
+            current_cursor: self.inner.state.current_cursor.get(),
             windows_version: self.windows_version,
             drop_target_helper: self.drop_target_helper.clone(),
             validation_number: self.inner.validation_number,
             main_receiver: self.inner.main_receiver.clone(),
             platform_window_handle: self.handle,
             disable_direct_composition: self.disable_direct_composition,
-            directx_devices: self.inner.state.borrow().directx_devices.clone().unwrap(),
+            directx_devices: self.inner.state.directx_devices.borrow().clone().unwrap(),
             invalidate_devices: self.invalidate_devices.clone(),
         }
     }
@@ -213,9 +213,8 @@ impl WindowsPlatform {
                 actions.push(dock_menu);
             }
         });
-        let mut lock = self.inner.state.borrow_mut();
-        lock.jump_list.dock_menus = actions;
-        update_jump_list(&lock.jump_list).log_err();
+        self.inner.state.jump_list.borrow_mut().dock_menus = actions;
+        update_jump_list(&self.inner.state.jump_list.borrow()).log_err();
     }
 
     fn update_jump_list(
@@ -229,12 +228,10 @@ impl WindowsPlatform {
                 actions.push(dock_menu);
             }
         });
-        let mut lock = self.inner.state.borrow_mut();
-        lock.jump_list.dock_menus = actions;
-        lock.jump_list.recent_workspaces = entries;
-        update_jump_list(&lock.jump_list)
-            .log_err()
-            .unwrap_or_default()
+        let mut jump_list = self.inner.state.jump_list.borrow_mut();
+        jump_list.dock_menus = actions;
+        jump_list.recent_workspaces = entries;
+        update_jump_list(&jump_list).log_err().unwrap_or_default()
     }
 
     fn find_current_active_window(&self) -> Option<HWND> {
@@ -250,7 +247,7 @@ impl WindowsPlatform {
     }
 
     fn begin_vsync_thread(&self) {
-        let mut directx_device = self.inner.state.borrow().directx_devices.clone().unwrap();
+        let mut directx_device = self.inner.state.directx_devices.borrow().clone().unwrap();
         let platform_window: SafeHwnd = self.handle.into();
         let validation_number = self.inner.validation_number;
         let all_windows = Arc::downgrade(&self.raw_window_handles);
@@ -334,9 +331,9 @@ impl Platform for WindowsPlatform {
     fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>) {
         self.inner
             .state
-            .borrow_mut()
             .callbacks
-            .keyboard_layout_change = Some(callback);
+            .keyboard_layout_change
+            .set(Some(callback));
     }
 
     fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
@@ -354,7 +351,7 @@ impl Platform for WindowsPlatform {
         }
 
         self.inner
-            .with_callback(|callbacks| &mut callbacks.quit, |callback| callback());
+            .with_callback(|callbacks| &callbacks.quit, |callback| callback());
     }
 
     fn quit(&self) {
@@ -473,7 +470,7 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) {
-        self.inner.state.borrow_mut().callbacks.open_urls = Some(callback);
+        self.inner.state.callbacks.open_urls.set(Some(callback));
     }
 
     fn prompt_for_paths(
@@ -543,19 +540,19 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_quit(&self, callback: Box<dyn FnMut()>) {
-        self.inner.state.borrow_mut().callbacks.quit = Some(callback);
+        self.inner.state.callbacks.quit.set(Some(callback));
     }
 
     fn on_reopen(&self, callback: Box<dyn FnMut()>) {
-        self.inner.state.borrow_mut().callbacks.reopen = Some(callback);
+        self.inner.state.callbacks.reopen.set(Some(callback));
     }
 
     fn set_menus(&self, menus: Vec<Menu>, _keymap: &Keymap) {
-        self.inner.state.borrow_mut().menus = menus.into_iter().map(|menu| menu.owned()).collect();
+        *self.inner.state.menus.borrow_mut() = menus.into_iter().map(|menu| menu.owned()).collect();
     }
 
     fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
-        Some(self.inner.state.borrow().menus.clone())
+        Some(self.inner.state.menus.borrow().clone())
     }
 
     fn set_dock_menu(&self, menus: Vec<MenuItem>, _keymap: &Keymap) {
@@ -563,19 +560,27 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {
-        self.inner.state.borrow_mut().callbacks.app_menu_action = Some(callback);
+        self.inner
+            .state
+            .callbacks
+            .app_menu_action
+            .set(Some(callback));
     }
 
     fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>) {
-        self.inner.state.borrow_mut().callbacks.will_open_app_menu = Some(callback);
+        self.inner
+            .state
+            .callbacks
+            .will_open_app_menu
+            .set(Some(callback));
     }
 
     fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
         self.inner
             .state
-            .borrow_mut()
             .callbacks
-            .validate_app_menu_command = Some(callback);
+            .validate_app_menu_command
+            .set(Some(callback));
     }
 
     fn app_path(&self) -> Result<PathBuf> {
@@ -589,13 +594,13 @@ impl Platform for WindowsPlatform {
 
     fn set_cursor_style(&self, style: CursorStyle) {
         let hcursor = load_cursor(style);
-        if self.inner.state.borrow_mut().current_cursor.map(|c| c.0) != hcursor.map(|c| c.0) {
+        if self.inner.state.current_cursor.get().map(|c| c.0) != hcursor.map(|c| c.0) {
             self.post_message(
                 WM_GPUI_CURSOR_STYLE_CHANGED,
                 WPARAM(0),
                 LPARAM(hcursor.map_or(0, |c| c.0 as isize)),
             );
-            self.inner.state.borrow_mut().current_cursor = hcursor;
+            self.inner.state.current_cursor.set(hcursor);
         }
     }
 
@@ -721,12 +726,12 @@ impl Platform for WindowsPlatform {
 
 impl WindowsPlatformInner {
     fn new(context: &mut PlatformWindowCreateContext) -> Result<Rc<Self>> {
-        let state = RefCell::new(WindowsPlatformState::new(
+        let state = WindowsPlatformState::new(
             context
                 .directx_devices
                 .take()
                 .context("missing directx devices")?,
-        ));
+        );
         Ok(Rc::new(Self {
             state,
             raw_window_handles: context.raw_window_handles.clone(),
@@ -746,13 +751,13 @@ impl WindowsPlatformInner {
     /// Calls `project` to project to the corresponding callback field, removes it from callbacks, calls `f` with the callback and then puts the callback back.
     fn with_callback<T>(
         &self,
-        project: impl Fn(&mut PlatformCallbacks) -> &mut Option<T>,
+        project: impl Fn(&PlatformCallbacks) -> &Cell<Option<T>>,
         f: impl FnOnce(&mut T),
     ) {
-        let callback = project(&mut self.state.borrow_mut().callbacks).take();
+        let callback = project(&self.state.callbacks).take();
         if let Some(mut callback) = callback {
             f(&mut callback);
-            *project(&mut self.state.borrow_mut().callbacks) = Some(callback)
+            project(&self.state.callbacks).set(Some(callback));
         }
     }
 
@@ -877,8 +882,8 @@ impl WindowsPlatformInner {
     fn handle_dock_action_event(&self, action_idx: usize) -> Option<isize> {
         let Some(action) = self
             .state
-            .borrow_mut()
             .jump_list
+            .borrow()
             .dock_menus
             .get(action_idx)
             .map(|dock_menu| dock_menu.action.boxed_clone())
@@ -887,7 +892,7 @@ impl WindowsPlatformInner {
             return Some(1);
         };
         self.with_callback(
-            |callbacks| &mut callbacks.app_menu_action,
+            |callbacks| &callbacks.app_menu_action,
             |callback| callback(&*action),
         );
         Some(0)
@@ -895,7 +900,7 @@ impl WindowsPlatformInner {
 
     fn handle_keyboard_layout_change(&self) -> Option<isize> {
         self.with_callback(
-            |callbacks| &mut callbacks.keyboard_layout_change,
+            |callbacks| &callbacks.keyboard_layout_change,
             |callback| callback(),
         );
         Some(0)
@@ -904,9 +909,8 @@ impl WindowsPlatformInner {
     fn handle_device_lost(&self, lparam: LPARAM) -> Option<isize> {
         let directx_devices = lparam.0 as *const DirectXDevices;
         let directx_devices = unsafe { &*directx_devices };
-        let mut lock = self.state.borrow_mut();
-        lock.directx_devices.take();
-        lock.directx_devices = Some(directx_devices.clone());
+        self.state.directx_devices.borrow_mut().take();
+        *self.state.directx_devices.borrow_mut() = Some(directx_devices.clone());
 
         Some(0)
     }

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

@@ -1,4 +1,7 @@
-use std::ffi::{c_uint, c_void};
+use std::{
+    cell::Cell,
+    ffi::{c_uint, c_void},
+};
 
 use ::util::ResultExt;
 use windows::Win32::UI::{
@@ -15,18 +18,18 @@ use super::WindowsDisplay;
 
 /// Windows settings pulled from SystemParametersInfo
 /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow
-#[derive(Default, Debug, Clone, Copy)]
+#[derive(Default, Debug, Clone)]
 pub(crate) struct WindowsSystemSettings {
     pub(crate) mouse_wheel_settings: MouseWheelSettings,
-    pub(crate) auto_hide_taskbar_position: Option<AutoHideTaskbarPosition>,
+    pub(crate) auto_hide_taskbar_position: Cell<Option<AutoHideTaskbarPosition>>,
 }
 
-#[derive(Default, Debug, Clone, Copy)]
+#[derive(Default, Debug, Clone)]
 pub(crate) struct MouseWheelSettings {
     /// SEE: SPI_GETWHEELSCROLLCHARS
-    pub(crate) wheel_scroll_chars: u32,
+    pub(crate) wheel_scroll_chars: Cell<u32>,
     /// SEE: SPI_GETWHEELSCROLLLINES
-    pub(crate) wheel_scroll_lines: u32,
+    pub(crate) wheel_scroll_lines: Cell<u32>,
 }
 
 impl WindowsSystemSettings {
@@ -36,12 +39,13 @@ impl WindowsSystemSettings {
         settings
     }
 
-    fn init(&mut self, display: WindowsDisplay) {
+    fn init(&self, display: WindowsDisplay) {
         self.mouse_wheel_settings.update();
-        self.auto_hide_taskbar_position = AutoHideTaskbarPosition::new(display).log_err().flatten();
+        self.auto_hide_taskbar_position
+            .set(AutoHideTaskbarPosition::new(display).log_err().flatten());
     }
 
-    pub(crate) fn update(&mut self, display: WindowsDisplay, wparam: usize) {
+    pub(crate) fn update(&self, display: WindowsDisplay, wparam: usize) {
         match wparam {
             // SPI_SETWORKAREA
             47 => self.update_taskbar_position(display),
@@ -51,22 +55,23 @@ impl WindowsSystemSettings {
         }
     }
 
-    fn update_mouse_wheel_settings(&mut self) {
+    fn update_mouse_wheel_settings(&self) {
         self.mouse_wheel_settings.update();
     }
 
-    fn update_taskbar_position(&mut self, display: WindowsDisplay) {
-        self.auto_hide_taskbar_position = AutoHideTaskbarPosition::new(display).log_err().flatten();
+    fn update_taskbar_position(&self, display: WindowsDisplay) {
+        self.auto_hide_taskbar_position
+            .set(AutoHideTaskbarPosition::new(display).log_err().flatten());
     }
 }
 
 impl MouseWheelSettings {
-    fn update(&mut self) {
+    fn update(&self) {
         self.update_wheel_scroll_chars();
         self.update_wheel_scroll_lines();
     }
 
-    fn update_wheel_scroll_chars(&mut self) {
+    fn update_wheel_scroll_chars(&self) {
         let mut value = c_uint::default();
         let result = unsafe {
             SystemParametersInfoW(
@@ -77,12 +82,12 @@ impl MouseWheelSettings {
             )
         };
 
-        if result.log_err() != None && self.wheel_scroll_chars != value {
-            self.wheel_scroll_chars = value;
+        if result.log_err() != None && self.wheel_scroll_chars.get() != value {
+            self.wheel_scroll_chars.set(value);
         }
     }
 
-    fn update_wheel_scroll_lines(&mut self) {
+    fn update_wheel_scroll_lines(&self) {
         let mut value = c_uint::default();
         let result = unsafe {
             SystemParametersInfoW(
@@ -93,8 +98,8 @@ impl MouseWheelSettings {
             )
         };
 
-        if result.log_err() != None && self.wheel_scroll_lines != value {
-            self.wheel_scroll_lines = value;
+        if result.log_err() != None && self.wheel_scroll_lines.get() != value {
+            self.wheel_scroll_lines.set(value);
         }
     }
 }

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

@@ -1,7 +1,7 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
 use std::{
-    cell::RefCell,
+    cell::{Cell, RefCell},
     num::NonZeroIsize,
     path::PathBuf,
     rc::{Rc, Weak},
@@ -30,43 +30,51 @@ use crate::*;
 
 pub(crate) struct WindowsWindow(pub Rc<WindowsWindowInner>);
 
+impl std::ops::Deref for WindowsWindow {
+    type Target = WindowsWindowInner;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
 pub struct WindowsWindowState {
-    pub origin: Point<Pixels>,
-    pub logical_size: Size<Pixels>,
+    pub origin: Cell<Point<Pixels>>,
+    pub logical_size: Cell<Size<Pixels>>,
     pub min_size: Option<Size<Pixels>>,
-    pub fullscreen_restore_bounds: Bounds<Pixels>,
+    pub fullscreen_restore_bounds: Cell<Bounds<Pixels>>,
     pub border_offset: WindowBorderOffset,
-    pub appearance: WindowAppearance,
-    pub scale_factor: f32,
-    pub restore_from_minimized: Option<Box<dyn FnMut(RequestFrameOptions)>>,
+    pub appearance: Cell<WindowAppearance>,
+    pub scale_factor: Cell<f32>,
+    pub restore_from_minimized: Cell<Option<Box<dyn FnMut(RequestFrameOptions)>>>,
 
     pub callbacks: Callbacks,
-    pub input_handler: Option<PlatformInputHandler>,
-    pub pending_surrogate: Option<u16>,
-    pub last_reported_modifiers: Option<Modifiers>,
-    pub last_reported_capslock: Option<Capslock>,
-    pub hovered: bool,
+    pub input_handler: Cell<Option<PlatformInputHandler>>,
+    pub pending_surrogate: Cell<Option<u16>>,
+    pub last_reported_modifiers: Cell<Option<Modifiers>>,
+    pub last_reported_capslock: Cell<Option<Capslock>>,
+    pub hovered: Cell<bool>,
 
-    pub renderer: DirectXRenderer,
+    pub renderer: RefCell<DirectXRenderer>,
 
     pub click_state: ClickState,
-    pub current_cursor: Option<HCURSOR>,
-    pub nc_button_pressed: Option<u32>,
+    pub current_cursor: Cell<Option<HCURSOR>>,
+    pub nc_button_pressed: Cell<Option<u32>>,
 
-    pub display: WindowsDisplay,
+    pub display: Cell<WindowsDisplay>,
     /// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices
     /// as resizing them has failed, causing us to have lost at least the render target.
     pub invalidate_devices: Arc<AtomicBool>,
-    fullscreen: Option<StyleAndBounds>,
-    initial_placement: Option<WindowOpenStatus>,
+    fullscreen: Cell<Option<StyleAndBounds>>,
+    initial_placement: Cell<Option<WindowOpenStatus>>,
     hwnd: HWND,
 }
 
 pub(crate) struct WindowsWindowInner {
     hwnd: HWND,
     drop_target_helper: IDropTargetHelper,
-    pub(crate) state: RefCell<WindowsWindowState>,
-    system_settings: RefCell<WindowsSystemSettings>,
+    pub(crate) state: WindowsWindowState,
+    system_settings: WindowsSystemSettings,
     pub(crate) handle: AnyWindowHandle,
     pub(crate) hide_title_bar: bool,
     pub(crate) is_movable: bool,
@@ -121,27 +129,27 @@ impl WindowsWindowState {
         let initial_placement = None;
 
         Ok(Self {
-            origin,
-            logical_size,
-            fullscreen_restore_bounds,
+            origin: Cell::new(origin),
+            logical_size: Cell::new(logical_size),
+            fullscreen_restore_bounds: Cell::new(fullscreen_restore_bounds),
             border_offset,
-            appearance,
-            scale_factor,
-            restore_from_minimized,
+            appearance: Cell::new(appearance),
+            scale_factor: Cell::new(scale_factor),
+            restore_from_minimized: Cell::new(restore_from_minimized),
             min_size,
             callbacks,
-            input_handler,
-            pending_surrogate,
-            last_reported_modifiers,
-            last_reported_capslock,
-            hovered,
-            renderer,
+            input_handler: Cell::new(input_handler),
+            pending_surrogate: Cell::new(pending_surrogate),
+            last_reported_modifiers: Cell::new(last_reported_modifiers),
+            last_reported_capslock: Cell::new(last_reported_capslock),
+            hovered: Cell::new(hovered),
+            renderer: RefCell::new(renderer),
             click_state,
-            current_cursor,
-            nc_button_pressed,
-            display,
-            fullscreen,
-            initial_placement,
+            current_cursor: Cell::new(current_cursor),
+            nc_button_pressed: Cell::new(nc_button_pressed),
+            display: Cell::new(display),
+            fullscreen: Cell::new(fullscreen),
+            initial_placement: Cell::new(initial_placement),
             hwnd,
             invalidate_devices,
         })
@@ -149,7 +157,7 @@ impl WindowsWindowState {
 
     #[inline]
     pub(crate) fn is_fullscreen(&self) -> bool {
-        self.fullscreen.is_some()
+        self.fullscreen.get().is_some()
     }
 
     pub(crate) fn is_maximized(&self) -> bool {
@@ -158,8 +166,8 @@ impl WindowsWindowState {
 
     fn bounds(&self) -> Bounds<Pixels> {
         Bounds {
-            origin: self.origin,
-            size: self.logical_size,
+            origin: self.origin.get(),
+            size: self.logical_size.get(),
         }
     }
 
@@ -178,8 +186,8 @@ impl WindowsWindowState {
         (
             calculate_client_rect(
                 placement.rcNormalPosition,
-                self.border_offset,
-                self.scale_factor,
+                &self.border_offset,
+                self.scale_factor.get(),
             ),
             placement.showCmd == SW_SHOWMAXIMIZED.0 as u32,
         )
@@ -189,7 +197,7 @@ impl WindowsWindowState {
         let (bounds, maximized) = self.calculate_window_bounds();
 
         if self.is_fullscreen() {
-            WindowBounds::Fullscreen(self.fullscreen_restore_bounds)
+            WindowBounds::Fullscreen(self.fullscreen_restore_bounds.get())
         } else if maximized {
             WindowBounds::Maximized(bounds)
         } else {
@@ -202,13 +210,13 @@ impl WindowsWindowState {
     /// Currently, GPUI uses the logical size of the app to handle mouse interactions (such as
     /// whether the mouse collides with other elements of GPUI).
     fn content_size(&self) -> Size<Pixels> {
-        self.logical_size
+        self.logical_size.get()
     }
 }
 
 impl WindowsWindowInner {
     fn new(context: &mut WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {
-        let state = RefCell::new(WindowsWindowState::new(
+        let state = WindowsWindowState::new(
             hwnd,
             &context.directx_devices,
             cs,
@@ -218,7 +226,7 @@ impl WindowsWindowInner {
             context.appearance,
             context.disable_direct_composition,
             context.invalidate_devices.clone(),
-        )?);
+        )?;
 
         Ok(Rc::new(Self {
             hwnd,
@@ -232,7 +240,7 @@ impl WindowsWindowInner {
             validation_number: context.validation_number,
             main_receiver: context.main_receiver.clone(),
             platform_window_handle: context.platform_window_handle,
-            system_settings: RefCell::new(WindowsSystemSettings::new(context.display)),
+            system_settings: WindowsSystemSettings::new(context.display),
         }))
     }
 
@@ -240,19 +248,17 @@ impl WindowsWindowInner {
         let this = self.clone();
         self.executor
             .spawn(async move {
-                let mut lock = this.state.borrow_mut();
                 let StyleAndBounds {
                     style,
                     x,
                     y,
                     cx,
                     cy,
-                } = match lock.fullscreen.take() {
+                } = match this.state.fullscreen.take() {
                     Some(state) => state,
                     None => {
-                        let (window_bounds, _) = lock.calculate_window_bounds();
-                        lock.fullscreen_restore_bounds = window_bounds;
-                        drop(lock);
+                        let (window_bounds, _) = this.state.calculate_window_bounds();
+                        this.state.fullscreen_restore_bounds.set(window_bounds);
 
                         let style =
                             WINDOW_STYLE(unsafe { get_window_long(this.hwnd, GWL_STYLE) } as _);
@@ -260,22 +266,20 @@ impl WindowsWindowInner {
                         unsafe { GetWindowRect(this.hwnd, &mut rc) }
                             .context("failed to get window rect")
                             .log_err();
-
-                        lock = this.state.borrow_mut();
-                        let _ = lock.fullscreen.insert(StyleAndBounds {
+                        let _ = this.state.fullscreen.set(Some(StyleAndBounds {
                             style,
                             x: rc.left,
                             y: rc.top,
                             cx: rc.right - rc.left,
                             cy: rc.bottom - rc.top,
-                        });
+                        }));
                         let style = style
                             & !(WS_THICKFRAME
                                 | WS_SYSMENU
                                 | WS_MAXIMIZEBOX
                                 | WS_MINIMIZEBOX
                                 | WS_CAPTION);
-                        let physical_bounds = lock.display.physical_bounds();
+                        let physical_bounds = this.state.display.get().physical_bounds();
                         StyleAndBounds {
                             style,
                             x: physical_bounds.left().0,
@@ -285,7 +289,6 @@ impl WindowsWindowInner {
                         }
                     }
                 };
-                drop(lock);
                 unsafe { set_window_long(this.hwnd, GWL_STYLE, style.0 as isize) };
                 unsafe {
                     SetWindowPos(
@@ -304,7 +307,7 @@ impl WindowsWindowInner {
     }
 
     fn set_window_placement(self: &Rc<Self>) -> Result<()> {
-        let Some(open_status) = self.state.borrow_mut().initial_placement.take() else {
+        let Some(open_status) = self.state.initial_placement.take() else {
             return Ok(());
         };
         match open_status.state {
@@ -328,27 +331,23 @@ impl WindowsWindowInner {
         Ok(())
     }
 
-    pub(crate) fn system_settings(&self) -> std::cell::Ref<'_, WindowsSystemSettings> {
-        self.system_settings.borrow()
-    }
-
-    pub(crate) fn system_settings_mut(&self) -> std::cell::RefMut<'_, WindowsSystemSettings> {
-        self.system_settings.borrow_mut()
+    pub(crate) fn system_settings(&self) -> &WindowsSystemSettings {
+        &self.system_settings
     }
 }
 
 #[derive(Default)]
 pub(crate) struct Callbacks {
-    pub(crate) request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
-    pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
-    pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>,
-    pub(crate) hovered_status_change: Option<Box<dyn FnMut(bool)>>,
-    pub(crate) resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
-    pub(crate) moved: Option<Box<dyn FnMut()>>,
-    pub(crate) should_close: Option<Box<dyn FnMut() -> bool>>,
-    pub(crate) close: Option<Box<dyn FnOnce()>>,
-    pub(crate) hit_test_window_control: Option<Box<dyn FnMut() -> Option<WindowControlArea>>>,
-    pub(crate) appearance_changed: Option<Box<dyn FnMut()>>,
+    pub(crate) request_frame: Cell<Option<Box<dyn FnMut(RequestFrameOptions)>>>,
+    pub(crate) input: Cell<Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>>,
+    pub(crate) active_status_change: Cell<Option<Box<dyn FnMut(bool)>>>,
+    pub(crate) hovered_status_change: Cell<Option<Box<dyn FnMut(bool)>>>,
+    pub(crate) resize: Cell<Option<Box<dyn FnMut(Size<Pixels>, f32)>>>,
+    pub(crate) moved: Cell<Option<Box<dyn FnMut()>>>,
+    pub(crate) should_close: Cell<Option<Box<dyn FnMut() -> bool>>>,
+    pub(crate) close: Cell<Option<Box<dyn FnOnce()>>>,
+    pub(crate) hit_test_window_control: Cell<Option<Box<dyn FnMut() -> Option<WindowControlArea>>>>,
+    pub(crate) appearance_changed: Cell<Option<Box<dyn FnMut()>>>,
 }
 
 struct WindowCreateContext {
@@ -476,21 +475,21 @@ impl WindowsWindow {
 
         register_drag_drop(&this)?;
         configure_dwm_dark_mode(hwnd, appearance);
-        this.state.borrow_mut().border_offset.update(hwnd)?;
+        this.state.border_offset.update(hwnd)?;
         let placement = retrieve_window_placement(
             hwnd,
             display,
             params.bounds,
-            this.state.borrow().scale_factor,
-            this.state.borrow().border_offset,
+            this.state.scale_factor.get(),
+            &this.state.border_offset,
         )?;
         if params.show {
             unsafe { SetWindowPlacement(hwnd, &placement)? };
         } else {
-            this.state.borrow_mut().initial_placement = Some(WindowOpenStatus {
+            this.state.initial_placement.set(Some(WindowOpenStatus {
                 placement,
                 state: WindowOpenState::Windowed,
-            });
+            }));
         }
 
         Ok(Self(this))
@@ -533,15 +532,15 @@ impl Drop for WindowsWindow {
 
 impl PlatformWindow for WindowsWindow {
     fn bounds(&self) -> Bounds<Pixels> {
-        self.0.state.borrow().bounds()
+        self.state.bounds()
     }
 
     fn is_maximized(&self) -> bool {
-        self.0.state.borrow().is_maximized()
+        self.state.is_maximized()
     }
 
     fn window_bounds(&self) -> WindowBounds {
-        self.0.state.borrow().window_bounds()
+        self.state.window_bounds()
     }
 
     /// get the logical size of the app's drawable area.
@@ -549,14 +548,14 @@ impl PlatformWindow for WindowsWindow {
     /// Currently, GPUI uses the logical size of the app to handle mouse interactions (such as
     /// whether the mouse collides with other elements of GPUI).
     fn content_size(&self) -> Size<Pixels> {
-        self.0.state.borrow().content_size()
+        self.state.content_size()
     }
 
     fn resize(&mut self, size: Size<Pixels>) {
         let hwnd = self.0.hwnd;
         let bounds =
             crate::bounds(self.bounds().origin, size).to_device_pixels(self.scale_factor());
-        let rect = calculate_window_rect(bounds, self.0.state.borrow().border_offset);
+        let rect = calculate_window_rect(bounds, &self.state.border_offset);
 
         self.0
             .executor
@@ -579,15 +578,15 @@ impl PlatformWindow for WindowsWindow {
     }
 
     fn scale_factor(&self) -> f32 {
-        self.0.state.borrow().scale_factor
+        self.state.scale_factor.get()
     }
 
     fn appearance(&self) -> WindowAppearance {
-        self.0.state.borrow().appearance
+        self.state.appearance.get()
     }
 
     fn display(&self) -> Option<Rc<dyn PlatformDisplay>> {
-        Some(Rc::new(self.0.state.borrow().display))
+        Some(Rc::new(self.state.display.get()))
     }
 
     fn mouse_position(&self) -> Point<Pixels> {
@@ -612,11 +611,11 @@ impl PlatformWindow for WindowsWindow {
     }
 
     fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
-        self.0.state.borrow_mut().input_handler = Some(input_handler);
+        self.state.input_handler.set(Some(input_handler));
     }
 
     fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
-        self.0.state.borrow_mut().input_handler.take()
+        self.state.input_handler.take()
     }
 
     fn prompt(
@@ -762,7 +761,7 @@ impl PlatformWindow for WindowsWindow {
     }
 
     fn is_hovered(&self) -> bool {
-        self.0.state.borrow().hovered
+        self.state.hovered.get()
     }
 
     fn set_title(&mut self, title: &str) {
@@ -805,8 +804,9 @@ impl PlatformWindow for WindowsWindow {
         unsafe {
             if IsWindowVisible(self.0.hwnd).as_bool() {
                 ShowWindowAsync(self.0.hwnd, SW_MAXIMIZE).ok().log_err();
-            } else if let Some(status) = self.0.state.borrow_mut().initial_placement.as_mut() {
+            } else if let Some(mut status) = self.state.initial_placement.take() {
                 status.state = WindowOpenState::Maximized;
+                self.state.initial_placement.set(Some(status));
             }
         }
     }
@@ -814,61 +814,78 @@ impl PlatformWindow for WindowsWindow {
     fn toggle_fullscreen(&self) {
         if unsafe { IsWindowVisible(self.0.hwnd).as_bool() } {
             self.0.toggle_fullscreen();
-        } else if let Some(status) = self.0.state.borrow_mut().initial_placement.as_mut() {
+        } else if let Some(mut status) = self.state.initial_placement.take() {
             status.state = WindowOpenState::Fullscreen;
+            self.state.initial_placement.set(Some(status));
         }
     }
 
     fn is_fullscreen(&self) -> bool {
-        self.0.state.borrow().is_fullscreen()
+        self.state.is_fullscreen()
     }
 
     fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) {
-        self.0.state.borrow_mut().callbacks.request_frame = Some(callback);
+        self.state.callbacks.request_frame.set(Some(callback));
     }
 
     fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> DispatchEventResult>) {
-        self.0.state.borrow_mut().callbacks.input = Some(callback);
+        self.state.callbacks.input.set(Some(callback));
     }
 
     fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
-        self.0.state.borrow_mut().callbacks.active_status_change = Some(callback);
+        self.0
+            .state
+            .callbacks
+            .active_status_change
+            .set(Some(callback));
     }
 
     fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>) {
-        self.0.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
+        self.0
+            .state
+            .callbacks
+            .hovered_status_change
+            .set(Some(callback));
     }
 
     fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
-        self.0.state.borrow_mut().callbacks.resize = Some(callback);
+        self.state.callbacks.resize.set(Some(callback));
     }
 
     fn on_moved(&self, callback: Box<dyn FnMut()>) {
-        self.0.state.borrow_mut().callbacks.moved = Some(callback);
+        self.state.callbacks.moved.set(Some(callback));
     }
 
     fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>) {
-        self.0.state.borrow_mut().callbacks.should_close = Some(callback);
+        self.state.callbacks.should_close.set(Some(callback));
     }
 
     fn on_close(&self, callback: Box<dyn FnOnce()>) {
-        self.0.state.borrow_mut().callbacks.close = Some(callback);
+        self.state.callbacks.close.set(Some(callback));
     }
 
     fn on_hit_test_window_control(&self, callback: Box<dyn FnMut() -> Option<WindowControlArea>>) {
-        self.0.state.borrow_mut().callbacks.hit_test_window_control = Some(callback);
+        self.0
+            .state
+            .callbacks
+            .hit_test_window_control
+            .set(Some(callback));
     }
 
     fn on_appearance_changed(&self, callback: Box<dyn FnMut()>) {
-        self.0.state.borrow_mut().callbacks.appearance_changed = Some(callback);
+        self.0
+            .state
+            .callbacks
+            .appearance_changed
+            .set(Some(callback));
     }
 
     fn draw(&self, scene: &Scene) {
-        self.0.state.borrow_mut().renderer.draw(scene).log_err();
+        self.state.renderer.borrow_mut().draw(scene).log_err();
     }
 
     fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
-        self.0.state.borrow().renderer.sprite_atlas()
+        self.state.renderer.borrow().sprite_atlas()
     }
 
     fn get_raw_handle(&self) -> HWND {
@@ -876,7 +893,7 @@ impl PlatformWindow for WindowsWindow {
     }
 
     fn gpu_specs(&self) -> Option<GpuSpecs> {
-        self.0.state.borrow().renderer.gpu_specs().log_err()
+        self.state.renderer.borrow().gpu_specs().log_err()
     }
 
     fn update_ime_position(&self, _bounds: Bounds<Pixels>) {
@@ -889,11 +906,9 @@ struct WindowsDragDropHandler(pub Rc<WindowsWindowInner>);
 
 impl WindowsDragDropHandler {
     fn handle_drag_drop(&self, input: PlatformInput) {
-        let mut lock = self.0.state.borrow_mut();
-        if let Some(mut func) = lock.callbacks.input.take() {
-            drop(lock);
+        if let Some(mut func) = self.0.state.callbacks.input.take() {
             func(input);
-            self.0.state.borrow_mut().callbacks.input = Some(func);
+            self.0.state.callbacks.input.set(Some(func));
         }
     }
 }
@@ -937,7 +952,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
                 ScreenToClient(self.0.hwnd, &mut cursor_position)
                     .ok()
                     .log_err();
-                let scale_factor = self.0.state.borrow().scale_factor;
+                let scale_factor = self.0.state.scale_factor.get();
                 let input = PlatformInput::FileDrop(FileDropEvent::Entered {
                     position: logical_point(
                         cursor_position.x as f32,
@@ -975,7 +990,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
                 .ok()
                 .log_err();
         }
-        let scale_factor = self.0.state.borrow().scale_factor;
+        let scale_factor = self.0.state.scale_factor.get();
         let input = PlatformInput::FileDrop(FileDropEvent::Pending {
             position: logical_point(
                 cursor_position.x as f32,
@@ -1017,7 +1032,7 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
                 .ok()
                 .log_err();
         }
-        let scale_factor = self.0.state.borrow().scale_factor;
+        let scale_factor = self.0.state.scale_factor.get();
         let input = PlatformInput::FileDrop(FileDropEvent::Submit {
             position: logical_point(
                 cursor_position.x as f32,
@@ -1031,15 +1046,15 @@ impl IDropTarget_Impl for WindowsDragDropHandler_Impl {
     }
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
 pub(crate) struct ClickState {
-    button: MouseButton,
-    last_click: Instant,
-    last_position: Point<DevicePixels>,
-    double_click_spatial_tolerance_width: i32,
-    double_click_spatial_tolerance_height: i32,
-    double_click_interval: Duration,
-    pub(crate) current_count: usize,
+    button: Cell<MouseButton>,
+    last_click: Cell<Instant>,
+    last_position: Cell<Point<DevicePixels>>,
+    double_click_spatial_tolerance_width: Cell<i32>,
+    double_click_spatial_tolerance_height: Cell<i32>,
+    double_click_interval: Cell<Duration>,
+    pub(crate) current_count: Cell<usize>,
 }
 
 impl ClickState {
@@ -1049,61 +1064,59 @@ impl ClickState {
         let double_click_interval = Duration::from_millis(unsafe { GetDoubleClickTime() } as u64);
 
         ClickState {
-            button: MouseButton::Left,
-            last_click: Instant::now(),
-            last_position: Point::default(),
-            double_click_spatial_tolerance_width,
-            double_click_spatial_tolerance_height,
-            double_click_interval,
-            current_count: 0,
+            button: Cell::new(MouseButton::Left),
+            last_click: Cell::new(Instant::now()),
+            last_position: Cell::new(Point::default()),
+            double_click_spatial_tolerance_width: Cell::new(double_click_spatial_tolerance_width),
+            double_click_spatial_tolerance_height: Cell::new(double_click_spatial_tolerance_height),
+            double_click_interval: Cell::new(double_click_interval),
+            current_count: Cell::new(0),
         }
     }
 
     /// update self and return the needed click count
-    pub fn update(&mut self, button: MouseButton, new_position: Point<DevicePixels>) -> usize {
-        if self.button == button && self.is_double_click(new_position) {
-            self.current_count += 1;
+    pub fn update(&self, button: MouseButton, new_position: Point<DevicePixels>) -> usize {
+        if self.button.get() == button && self.is_double_click(new_position) {
+            self.current_count.update(|it| it + 1);
         } else {
-            self.current_count = 1;
+            self.current_count.set(1);
         }
-        self.last_click = Instant::now();
-        self.last_position = new_position;
-        self.button = button;
+        self.last_click.set(Instant::now());
+        self.last_position.set(new_position);
+        self.button.set(button);
 
-        self.current_count
+        self.current_count.get()
     }
 
-    pub fn system_update(&mut self, wparam: usize) {
+    pub fn system_update(&self, wparam: usize) {
         match wparam {
             // SPI_SETDOUBLECLKWIDTH
-            29 => {
-                self.double_click_spatial_tolerance_width =
-                    unsafe { GetSystemMetrics(SM_CXDOUBLECLK) }
-            }
+            29 => self
+                .double_click_spatial_tolerance_width
+                .set(unsafe { GetSystemMetrics(SM_CXDOUBLECLK) }),
             // SPI_SETDOUBLECLKHEIGHT
-            30 => {
-                self.double_click_spatial_tolerance_height =
-                    unsafe { GetSystemMetrics(SM_CYDOUBLECLK) }
-            }
+            30 => self
+                .double_click_spatial_tolerance_height
+                .set(unsafe { GetSystemMetrics(SM_CYDOUBLECLK) }),
             // SPI_SETDOUBLECLICKTIME
-            32 => {
-                self.double_click_interval =
-                    Duration::from_millis(unsafe { GetDoubleClickTime() } as u64)
-            }
+            32 => self
+                .double_click_interval
+                .set(Duration::from_millis(unsafe { GetDoubleClickTime() } as u64)),
             _ => {}
         }
     }
 
     #[inline]
     fn is_double_click(&self, new_position: Point<DevicePixels>) -> bool {
-        let diff = self.last_position - new_position;
+        let diff = self.last_position.get() - new_position;
 
-        self.last_click.elapsed() < self.double_click_interval
-            && diff.x.0.abs() <= self.double_click_spatial_tolerance_width
-            && diff.y.0.abs() <= self.double_click_spatial_tolerance_height
+        self.last_click.get().elapsed() < self.double_click_interval.get()
+            && diff.x.0.abs() <= self.double_click_spatial_tolerance_width.get()
+            && diff.y.0.abs() <= self.double_click_spatial_tolerance_height.get()
     }
 }
 
+#[derive(Copy, Clone)]
 struct StyleAndBounds {
     style: WINDOW_STYLE,
     x: i32,
@@ -1129,14 +1142,14 @@ struct AccentPolicy {
 
 type Color = (u8, u8, u8, u8);
 
-#[derive(Debug, Default, Clone, Copy)]
+#[derive(Debug, Default, Clone)]
 pub(crate) struct WindowBorderOffset {
-    pub(crate) width_offset: i32,
-    pub(crate) height_offset: i32,
+    pub(crate) width_offset: Cell<i32>,
+    pub(crate) height_offset: Cell<i32>,
 }
 
 impl WindowBorderOffset {
-    pub(crate) fn update(&mut self, hwnd: HWND) -> anyhow::Result<()> {
+    pub(crate) fn update(&self, hwnd: HWND) -> anyhow::Result<()> {
         let window_rect = unsafe {
             let mut rect = std::mem::zeroed();
             GetWindowRect(hwnd, &mut rect)?;
@@ -1147,19 +1160,21 @@ impl WindowBorderOffset {
             GetClientRect(hwnd, &mut rect)?;
             rect
         };
-        self.width_offset =
-            (window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
-        self.height_offset =
-            (window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
+        self.width_offset
+            .set((window_rect.right - window_rect.left) - (client_rect.right - client_rect.left));
+        self.height_offset
+            .set((window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top));
         Ok(())
     }
 }
 
+#[derive(Clone)]
 struct WindowOpenStatus {
     placement: WINDOWPLACEMENT,
     state: WindowOpenState,
 }
 
+#[derive(Clone, Copy)]
 enum WindowOpenState {
     Maximized,
     Fullscreen,
@@ -1269,7 +1284,7 @@ fn register_drag_drop(window: &Rc<WindowsWindowInner>) -> Result<()> {
     Ok(())
 }
 
-fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: WindowBorderOffset) -> RECT {
+fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: &WindowBorderOffset) -> RECT {
     // NOTE:
     // The reason we're not using `AdjustWindowRectEx()` here is
     // that the size reported by this function is incorrect.
@@ -1283,10 +1298,10 @@ fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: WindowBord
         right: bounds.right().0,
         bottom: bounds.bottom().0,
     };
-    let left_offset = border_offset.width_offset / 2;
-    let top_offset = border_offset.height_offset / 2;
-    let right_offset = border_offset.width_offset - left_offset;
-    let bottom_offset = border_offset.height_offset - top_offset;
+    let left_offset = border_offset.width_offset.get() / 2;
+    let top_offset = border_offset.height_offset.get() / 2;
+    let right_offset = border_offset.width_offset.get() - left_offset;
+    let bottom_offset = border_offset.height_offset.get() - top_offset;
     rect.left -= left_offset;
     rect.top -= top_offset;
     rect.right += right_offset;
@@ -1296,13 +1311,13 @@ fn calculate_window_rect(bounds: Bounds<DevicePixels>, border_offset: WindowBord
 
 fn calculate_client_rect(
     rect: RECT,
-    border_offset: WindowBorderOffset,
+    border_offset: &WindowBorderOffset,
     scale_factor: f32,
 ) -> Bounds<Pixels> {
-    let left_offset = border_offset.width_offset / 2;
-    let top_offset = border_offset.height_offset / 2;
-    let right_offset = border_offset.width_offset - left_offset;
-    let bottom_offset = border_offset.height_offset - top_offset;
+    let left_offset = border_offset.width_offset.get() / 2;
+    let top_offset = border_offset.height_offset.get() / 2;
+    let right_offset = border_offset.width_offset.get() - left_offset;
+    let bottom_offset = border_offset.height_offset.get() - top_offset;
     let left = rect.left + left_offset;
     let top = rect.top + top_offset;
     let right = rect.right - right_offset;
@@ -1319,7 +1334,7 @@ fn retrieve_window_placement(
     display: WindowsDisplay,
     initial_bounds: Bounds<Pixels>,
     scale_factor: f32,
-    border_offset: WindowBorderOffset,
+    border_offset: &WindowBorderOffset,
 ) -> Result<WINDOWPLACEMENT> {
     let mut placement = WINDOWPLACEMENT {
         length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
@@ -1429,7 +1444,9 @@ mod tests {
             state.update(MouseButton::Left, point(DevicePixels(0), DevicePixels(0))),
             2
         );
-        state.last_click -= Duration::from_millis(700);
+        state
+            .last_click
+            .update(|it| it - Duration::from_millis(700));
         assert_eq!(
             state.update(MouseButton::Left, point(DevicePixels(0), DevicePixels(0))),
             1