gpui: Fix pre-edit position after applying scale factor (#18214)

wannacu created

before:

![image](https://github.com/user-attachments/assets/20590089-3333-4ca8-a371-b07acfbe43f9)

after:

![image](https://github.com/user-attachments/assets/2d25623e-0602-4d24-b563-64e1d2ec3492)

Release Notes:

- N/A

Change summary

crates/gpui/src/geometry.rs                      | 6 ++++++
crates/gpui/src/platform.rs                      | 6 +++---
crates/gpui/src/platform/linux/wayland/client.rs | 4 ++--
crates/gpui/src/platform/linux/wayland/window.rs | 4 ++--
crates/gpui/src/platform/linux/x11/client.rs     | 5 +++--
crates/gpui/src/platform/linux/x11/window.rs     | 8 ++++----
crates/gpui/src/platform/mac/window.rs           | 7 ++++---
crates/gpui/src/platform/test/window.rs          | 6 +++---
crates/gpui/src/platform/windows/window.rs       | 2 +-
crates/gpui/src/window.rs                        | 4 +++-
10 files changed, 31 insertions(+), 21 deletions(-)

Detailed changes

crates/gpui/src/geometry.rs 🔗

@@ -2612,6 +2612,12 @@ impl From<ScaledPixels> for f64 {
     }
 }
 
+impl From<ScaledPixels> for u32 {
+    fn from(pixels: ScaledPixels) -> Self {
+        pixels.0 as u32
+    }
+}
+
 /// Represents a length in rems, a unit based on the font-size of the window, which can be assigned with [`WindowContext::set_rem_size`][set_rem_size].
 ///
 /// Rems are used for defining lengths that are scalable and consistent across different UI elements.

crates/gpui/src/platform.rs 🔗

@@ -23,8 +23,8 @@ use crate::{
     point, Action, AnyWindowHandle, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds,
     DevicePixels, DispatchEventResult, Font, FontId, FontMetrics, FontRun, ForegroundExecutor,
     GPUSpecs, GlyphId, ImageSource, Keymap, LineLayout, Pixels, PlatformInput, Point,
-    RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Scene, SharedString, Size,
-    SvgSize, Task, TaskLabel, WindowContext, DEFAULT_WINDOW_SIZE,
+    RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, ScaledPixels, Scene,
+    SharedString, Size, SvgSize, Task, TaskLabel, WindowContext, DEFAULT_WINDOW_SIZE,
 };
 use anyhow::Result;
 use async_task::Runnable;
@@ -381,7 +381,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
     fn set_client_inset(&self, _inset: Pixels) {}
     fn gpu_specs(&self) -> Option<GPUSpecs>;
 
-    fn update_ime_position(&self, _bounds: Bounds<Pixels>);
+    fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>);
 
     #[cfg(any(test, feature = "test-support"))]
     fn as_test(&mut self) -> Option<&mut TestWindow> {

crates/gpui/src/platform/linux/wayland/client.rs 🔗

@@ -84,7 +84,7 @@ use crate::{
 use crate::{
     AnyWindowHandle, CursorStyle, DisplayId, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers,
     ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
-    NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScrollDelta,
+    NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScaledPixels, ScrollDelta,
     ScrollWheelEvent, TouchPhase,
 };
 use crate::{LinuxCommon, WindowParams};
@@ -313,7 +313,7 @@ impl WaylandClientStatePtr {
         }
     }
 
-    pub fn update_ime_position(&self, bounds: Bounds<Pixels>) {
+    pub fn update_ime_position(&self, bounds: Bounds<ScaledPixels>) {
         let client = self.get_client();
         let mut state = client.borrow_mut();
         if state.composing || state.text_input.is_none() || state.pre_edit_text.is_some() {

crates/gpui/src/platform/linux/wayland/window.rs 🔗

@@ -26,7 +26,7 @@ use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
 use crate::scene::Scene;
 use crate::{
     px, size, AnyWindowHandle, Bounds, Decorations, GPUSpecs, Globals, Modifiers, Output, Pixels,
-    PlatformDisplay, PlatformInput, Point, PromptLevel, ResizeEdge, Size, Tiling,
+    PlatformDisplay, PlatformInput, Point, PromptLevel, ResizeEdge, ScaledPixels, Size, Tiling,
     WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
     WindowControls, WindowDecorations, WindowParams,
 };
@@ -1010,7 +1010,7 @@ impl PlatformWindow for WaylandWindow {
         }
     }
 
-    fn update_ime_position(&self, bounds: Bounds<Pixels>) {
+    fn update_ime_position(&self, bounds: Bounds<ScaledPixels>) {
         let state = self.borrow();
         state.client.update_ime_position(bounds);
     }

crates/gpui/src/platform/linux/x11/client.rs 🔗

@@ -38,7 +38,8 @@ use crate::platform::{LinuxCommon, PlatformWindow};
 use crate::{
     modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle,
     DisplayId, FileDropEvent, Keystroke, Modifiers, ModifiersChangedEvent, Pixels, Platform,
-    PlatformDisplay, PlatformInput, Point, ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
+    PlatformDisplay, PlatformInput, Point, ScaledPixels, ScrollDelta, Size, TouchPhase,
+    WindowParams, X11Window,
 };
 
 use super::{button_of_key, modifiers_from_state, pressed_button_from_mask};
@@ -188,7 +189,7 @@ impl X11ClientStatePtr {
         }
     }
 
-    pub fn update_ime_position(&self, bounds: Bounds<Pixels>) {
+    pub fn update_ime_position(&self, bounds: Bounds<ScaledPixels>) {
         let client = self.get_client();
         let mut state = client.0.borrow_mut();
         if state.composing || state.ximc.is_none() {

crates/gpui/src/platform/linux/x11/window.rs 🔗

@@ -4,9 +4,9 @@ use crate::{
     platform::blade::{BladeRenderer, BladeSurfaceConfig},
     px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GPUSpecs,
     Modifiers, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
-    PlatformWindow, Point, PromptLevel, ResizeEdge, Scene, Size, Tiling, WindowAppearance,
-    WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowParams,
-    X11ClientStatePtr,
+    PlatformWindow, Point, PromptLevel, ResizeEdge, ScaledPixels, Scene, Size, Tiling,
+    WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind,
+    WindowParams, X11ClientStatePtr,
 };
 
 use blade_graphics as gpu;
@@ -1412,7 +1412,7 @@ impl PlatformWindow for X11Window {
         }
     }
 
-    fn update_ime_position(&self, bounds: Bounds<Pixels>) {
+    fn update_ime_position(&self, bounds: Bounds<ScaledPixels>) {
         let mut state = self.0.state.borrow_mut();
         let client = state.client.clone();
         drop(state);

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

@@ -3,8 +3,9 @@ use crate::{
     platform::PlatformInputHandler, point, px, size, AnyWindowHandle, Bounds, DisplayLink,
     ExternalPaths, FileDropEvent, ForegroundExecutor, KeyDownEvent, Keystroke, Modifiers,
     ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
-    PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptLevel, Size, Timer,
-    WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowKind, WindowParams,
+    PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptLevel,
+    ScaledPixels, Size, Timer, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
+    WindowKind, WindowParams,
 };
 use block::ConcreteBlock;
 use cocoa::{
@@ -1119,7 +1120,7 @@ impl PlatformWindow for MacWindow {
         None
     }
 
-    fn update_ime_position(&self, _bounds: Bounds<Pixels>) {
+    fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>) {
         unsafe {
             let input_context: id = msg_send![class!(NSTextInputContext), currentInputContext];
             let _: () = msg_send![input_context, invalidateCharacterCoordinates];

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

@@ -1,8 +1,8 @@
 use crate::{
     AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DispatchEventResult, GPUSpecs,
     Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
-    Point, Size, TestPlatform, TileId, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
-    WindowParams,
+    Point, ScaledPixels, Size, TestPlatform, TileId, WindowAppearance, WindowBackgroundAppearance,
+    WindowBounds, WindowParams,
 };
 use collections::HashMap;
 use parking_lot::Mutex;
@@ -274,7 +274,7 @@ impl PlatformWindow for TestWindow {
         unimplemented!()
     }
 
-    fn update_ime_position(&self, _bounds: Bounds<Pixels>) {}
+    fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>) {}
 
     fn gpu_specs(&self) -> Option<GPUSpecs> {
         None

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

@@ -685,7 +685,7 @@ impl PlatformWindow for WindowsWindow {
         Some(self.0.state.borrow().renderer.gpu_specs())
     }
 
-    fn update_ime_position(&self, _bounds: Bounds<Pixels>) {
+    fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>) {
         // todo(windows)
     }
 }

crates/gpui/src/window.rs 🔗

@@ -3610,7 +3610,9 @@ impl<'a> WindowContext<'a> {
         self.on_next_frame(|cx| {
             if let Some(mut input_handler) = cx.window.platform_window.take_input_handler() {
                 if let Some(bounds) = input_handler.selected_bounds(cx) {
-                    cx.window.platform_window.update_ime_position(bounds);
+                    cx.window
+                        .platform_window
+                        .update_ime_position(bounds.scale(cx.scale_factor()));
                 }
                 cx.window.platform_window.set_input_handler(input_handler);
             }