diff --git a/crates/gpui/src/geometry.rs b/crates/gpui/src/geometry.rs index fa6f90b9ac9949ed7b5444e13045aaef6f9c0224..859ecb3d0e6c7b5c33f5765ce4c6295cef7fd566 100644 --- a/crates/gpui/src/geometry.rs +++ b/crates/gpui/src/geometry.rs @@ -748,7 +748,7 @@ impl Size { /// 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 { @@ -1676,8 +1676,6 @@ impl Bounds { } } -impl Copy for Bounds {} - /// 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`. diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 8a012789cf8198186c95f3e1702bc23e9b8897ee..e6fa6006eb95ec45f1634cb72ef63e2f622455a7 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -116,17 +116,16 @@ impl WindowsWindowInner { } fn handle_move_msg(&self, handle: HWND, lparam: LPARAM) -> Option { - 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 { - 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 { - 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 { - 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 { - 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 { 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 { - 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 { - 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 { - 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 { - 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 { 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 { 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 { 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 { - 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 { - 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 { 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 { - 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 { 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 { - 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 { - 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 { - 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 { 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 { - 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 { - 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 { 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::() 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, { - 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( wparam: WPARAM, lparam: LPARAM, - state: &mut WindowsWindowState, + state: &WindowsWindowState, f: F, ) -> Option 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, diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 396708fb347380a168b56d7ff7e0a9129bdd3af3..af0cb89ecc94da70cc42c8d4c397aeb2a811d6fb 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/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, + state: WindowsPlatformState, raw_window_handles: std::sync::Weak>>, // 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, - jump_list: JumpList, + menus: RefCell>, + jump_list: RefCell, // NOTE: standard cursor handles don't need to close. - pub(crate) current_cursor: Option, - directx_devices: Option, + pub(crate) current_cursor: Cell>, + directx_devices: RefCell>, } #[derive(Default)] struct PlatformCallbacks { - open_urls: Option)>>, - quit: Option>, - reopen: Option>, - app_menu_action: Option>, - will_open_app_menu: Option>, - validate_app_menu_command: Option bool>>, - keyboard_layout_change: Option>, + open_urls: Cell)>>>, + quit: Cell>>, + reopen: Cell>>, + app_menu_action: Cell>>, + will_open_app_menu: Cell>>, + validate_app_menu_command: Cell bool>>>, + keyboard_layout_change: Cell>>, } 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 { @@ -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) { self.inner .state - .borrow_mut() .callbacks - .keyboard_layout_change = Some(callback); + .keyboard_layout_change + .set(Some(callback)); } fn run(&self, on_finish_launching: Box) { @@ -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)>) { - 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) { - self.inner.state.borrow_mut().callbacks.quit = Some(callback); + self.inner.state.callbacks.quit.set(Some(callback)); } fn on_reopen(&self, callback: Box) { - self.inner.state.borrow_mut().callbacks.reopen = Some(callback); + self.inner.state.callbacks.reopen.set(Some(callback)); } fn set_menus(&self, menus: Vec, _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> { - Some(self.inner.state.borrow().menus.clone()) + Some(self.inner.state.menus.borrow().clone()) } fn set_dock_menu(&self, menus: Vec, _keymap: &Keymap) { @@ -563,19 +560,27 @@ impl Platform for WindowsPlatform { } fn on_app_menu_action(&self, callback: Box) { - 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) { - 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 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 { @@ -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> { - 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( &self, - project: impl Fn(&mut PlatformCallbacks) -> &mut Option, + project: impl Fn(&PlatformCallbacks) -> &Cell>, 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 { 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 { 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 { 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) } diff --git a/crates/gpui/src/platform/windows/system_settings.rs b/crates/gpui/src/platform/windows/system_settings.rs index b2bd289cd00979541f0176a4ccea6a52143b9ddd..f5ef5ce31ec23b69d1f009792c693e248d404b8e 100644 --- a/crates/gpui/src/platform/windows/system_settings.rs +++ b/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, + pub(crate) auto_hide_taskbar_position: Cell>, } -#[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, /// SEE: SPI_GETWHEELSCROLLLINES - pub(crate) wheel_scroll_lines: u32, + pub(crate) wheel_scroll_lines: Cell, } 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); } } } diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 334f0519f15a608a8b36b3610c88fb456a4a8f5b..7ef92b4150e69424b68e9417dda377aa7f2e9cc0 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/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); +impl std::ops::Deref for WindowsWindow { + type Target = WindowsWindowInner; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + pub struct WindowsWindowState { - pub origin: Point, - pub logical_size: Size, + pub origin: Cell>, + pub logical_size: Cell>, pub min_size: Option>, - pub fullscreen_restore_bounds: Bounds, + pub fullscreen_restore_bounds: Cell>, pub border_offset: WindowBorderOffset, - pub appearance: WindowAppearance, - pub scale_factor: f32, - pub restore_from_minimized: Option>, + pub appearance: Cell, + pub scale_factor: Cell, + pub restore_from_minimized: Cell>>, pub callbacks: Callbacks, - pub input_handler: Option, - pub pending_surrogate: Option, - pub last_reported_modifiers: Option, - pub last_reported_capslock: Option, - pub hovered: bool, + pub input_handler: Cell>, + pub pending_surrogate: Cell>, + pub last_reported_modifiers: Cell>, + pub last_reported_capslock: Cell>, + pub hovered: Cell, - pub renderer: DirectXRenderer, + pub renderer: RefCell, pub click_state: ClickState, - pub current_cursor: Option, - pub nc_button_pressed: Option, + pub current_cursor: Cell>, + pub nc_button_pressed: Cell>, - pub display: WindowsDisplay, + pub display: Cell, /// 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, - fullscreen: Option, - initial_placement: Option, + fullscreen: Cell>, + initial_placement: Cell>, hwnd: HWND, } pub(crate) struct WindowsWindowInner { hwnd: HWND, drop_target_helper: IDropTargetHelper, - pub(crate) state: RefCell, - system_settings: RefCell, + 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 { 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 { - self.logical_size + self.logical_size.get() } } impl WindowsWindowInner { fn new(context: &mut WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result> { - 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) -> 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>, - pub(crate) input: Option DispatchEventResult>>, - pub(crate) active_status_change: Option>, - pub(crate) hovered_status_change: Option>, - pub(crate) resize: Option, f32)>>, - pub(crate) moved: Option>, - pub(crate) should_close: Option bool>>, - pub(crate) close: Option>, - pub(crate) hit_test_window_control: Option Option>>, - pub(crate) appearance_changed: Option>, + pub(crate) request_frame: Cell>>, + pub(crate) input: Cell DispatchEventResult>>>, + pub(crate) active_status_change: Cell>>, + pub(crate) hovered_status_change: Cell>>, + pub(crate) resize: Cell, f32)>>>, + pub(crate) moved: Cell>>, + pub(crate) should_close: Cell bool>>>, + pub(crate) close: Cell>>, + pub(crate) hit_test_window_control: Cell Option>>>, + pub(crate) appearance_changed: Cell>>, } 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 { - 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 { - self.0.state.borrow().content_size() + self.state.content_size() } fn resize(&mut self, size: Size) { 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> { - Some(Rc::new(self.0.state.borrow().display)) + Some(Rc::new(self.state.display.get())) } fn mouse_position(&self) -> Point { @@ -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 { - 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) { - self.0.state.borrow_mut().callbacks.request_frame = Some(callback); + self.state.callbacks.request_frame.set(Some(callback)); } fn on_input(&self, callback: Box 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) { - 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) { - 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, f32)>) { - self.0.state.borrow_mut().callbacks.resize = Some(callback); + self.state.callbacks.resize.set(Some(callback)); } fn on_moved(&self, callback: Box) { - self.0.state.borrow_mut().callbacks.moved = Some(callback); + self.state.callbacks.moved.set(Some(callback)); } fn on_should_close(&self, callback: Box 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) { - 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 Option>) { - 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) { - 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 { - 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 { - self.0.state.borrow().renderer.gpu_specs().log_err() + self.state.renderer.borrow().gpu_specs().log_err() } fn update_ime_position(&self, _bounds: Bounds) { @@ -889,11 +906,9 @@ struct WindowsDragDropHandler(pub Rc); 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, - double_click_spatial_tolerance_width: i32, - double_click_spatial_tolerance_height: i32, - double_click_interval: Duration, - pub(crate) current_count: usize, + button: Cell, + last_click: Cell, + last_position: Cell>, + double_click_spatial_tolerance_width: Cell, + double_click_spatial_tolerance_height: Cell, + double_click_interval: Cell, + pub(crate) current_count: Cell, } 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) -> usize { - if self.button == button && self.is_double_click(new_position) { - self.current_count += 1; + pub fn update(&self, button: MouseButton, new_position: Point) -> 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) -> 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, + pub(crate) height_offset: Cell, } 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) -> Result<()> { Ok(()) } -fn calculate_window_rect(bounds: Bounds, border_offset: WindowBorderOffset) -> RECT { +fn calculate_window_rect(bounds: Bounds, 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, 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, border_offset: WindowBord fn calculate_client_rect( rect: RECT, - border_offset: WindowBorderOffset, + border_offset: &WindowBorderOffset, scale_factor: f32, ) -> Bounds { - 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, scale_factor: f32, - border_offset: WindowBorderOffset, + border_offset: &WindowBorderOffset, ) -> Result { let mut placement = WINDOWPLACEMENT { length: std::mem::size_of::() 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