Fix blurry cursor on Wayland at a scale other than 100% (#17496)

Sergio Nonide created

Closes #13258

Release Notes:

- Fixed blurry mouse cursor on wayland when the screen scale is other
than 100%

Before:
![Screenshot from 2024-09-06
14-38-30](https://github.com/user-attachments/assets/e4553503-ecea-4b53-b80d-43732d34fa62)

After:
![Screenshot from 2024-09-06
14-38-56](https://github.com/user-attachments/assets/ce563d3a-2b44-44b9-9f59-f0042609924e)

Change summary

crates/gpui/src/platform/linux/wayland/client.rs |  3 +
crates/gpui/src/platform/linux/wayland/cursor.rs | 33 ++++++++++++++---
2 files changed, 28 insertions(+), 8 deletions(-)

Detailed changes

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

@@ -476,7 +476,8 @@ impl WaylandClient {
             .as_ref()
             .map(|primary_selection_manager| primary_selection_manager.get_device(&seat, &qh, ()));
 
-        let mut cursor = Cursor::new(&conn, &globals, 24);
+        // FIXME: Determine the scaling factor dynamically by the compositor
+        let mut cursor = Cursor::new(&conn, &globals, 24, 2);
 
         handle
             .insert_source(XDPEventSource::new(&common.background_executor), {

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

@@ -11,6 +11,7 @@ pub(crate) struct Cursor {
     theme_name: Option<String>,
     surface: WlSurface,
     size: u32,
+    scale: u32,
     shm: WlShm,
     connection: Connection,
 }
@@ -23,7 +24,7 @@ impl Drop for Cursor {
 }
 
 impl Cursor {
-    pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
+    pub fn new(connection: &Connection, globals: &Globals, size: u32, scale: u32) -> Self {
         Self {
             theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
             theme_name: None,
@@ -31,6 +32,7 @@ impl Cursor {
             shm: globals.shm.clone(),
             connection: connection.clone(),
             size,
+            scale,
         }
     }
 
@@ -38,14 +40,18 @@ impl Cursor {
         if let Some(size) = size {
             self.size = size;
         }
-        if let Some(theme) =
-            CursorTheme::load_from_name(&self.connection, self.shm.clone(), theme_name, self.size)
-                .log_err()
+        if let Some(theme) = CursorTheme::load_from_name(
+            &self.connection,
+            self.shm.clone(),
+            theme_name,
+            self.size * self.scale,
+        )
+        .log_err()
         {
             self.theme = Some(theme);
             self.theme_name = Some(theme_name.to_string());
         } else if let Some(theme) =
-            CursorTheme::load(&self.connection, self.shm.clone(), self.size).log_err()
+            CursorTheme::load(&self.connection, self.shm.clone(), self.size * self.scale).log_err()
         {
             self.theme = Some(theme);
             self.theme_name = None;
@@ -91,9 +97,22 @@ impl Cursor {
                 let (width, height) = buffer.dimensions();
                 let (hot_x, hot_y) = buffer.hotspot();
 
-                wl_pointer.set_cursor(serial_id, Some(&self.surface), hot_x as i32, hot_y as i32);
+                let scaled_width = width / self.scale;
+                let scaled_height = height / self.scale;
+                let scaled_hot_x = hot_x / self.scale;
+                let scaled_hot_y = hot_y / self.scale;
+
+                self.surface.set_buffer_scale(self.scale as i32);
+
+                wl_pointer.set_cursor(
+                    serial_id,
+                    Some(&self.surface),
+                    scaled_hot_x as i32,
+                    scaled_hot_y as i32,
+                );
                 self.surface.attach(Some(&buffer), 0, 0);
-                self.surface.damage(0, 0, width as i32, height as i32);
+                self.surface
+                    .damage(0, 0, scaled_width as i32, scaled_height as i32);
                 self.surface.commit();
             }
         } else {