diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 7439faaacb042dbf6c3004c737a650eb77d14051..1103bfe3e890a645e0909bb829861556c6bd3565 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -95,6 +95,7 @@ impl Globals { pub(crate) struct WaylandClientState { globals: Globals, + wl_pointer: Option, // Surface to Window mapping windows: HashMap, // Output to scale mapping @@ -240,6 +241,7 @@ impl WaylandClient { let mut state = Rc::new(RefCell::new(WaylandClientState { globals, + wl_pointer: None, output_scales: outputs, windows: HashMap::default(), common, @@ -343,7 +345,15 @@ impl LinuxClient for WaylandClient { } .to_string(); - self.0.borrow_mut().cursor_icon_name = cursor_icon_name; + let mut state = self.0.borrow_mut(); + state.cursor_icon_name = cursor_icon_name.clone(); + if state.mouse_focused_window.is_some() { + let wl_pointer = state + .wl_pointer + .clone() + .expect("window is focused by pointer"); + state.cursor.set_icon(&wl_pointer, &cursor_icon_name); + } } fn with_common(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R { @@ -403,6 +413,7 @@ impl Dispatch for WaylandClientStat version, } => match &interface[..] { "wl_seat" => { + state.wl_pointer = None; registry.bind::(name, wl_seat_version(version), qh, ()); } "wl_output" => { @@ -582,7 +593,9 @@ impl Dispatch for WaylandClientStatePtr { seat.get_keyboard(qh, ()); } if capabilities.contains(wl_seat::Capability::Pointer) { - seat.get_pointer(qh, ()); + let client = state.get_client(); + let mut state = client.borrow_mut(); + state.wl_pointer = Some(seat.get_pointer(qh, ())); } } } @@ -789,10 +802,11 @@ impl Dispatch for WaylandClientStatePtr { if let Some(window) = get_window(&mut state, &surface.id()) { state.enter_token = Some(()); state.mouse_focused_window = Some(window.clone()); + state.cursor.mark_dirty(); state.cursor.set_serial_id(serial); state .cursor - .set_icon(&wl_pointer, Some(cursor_icon_name.as_str())); + .set_icon(&wl_pointer, cursor_icon_name.as_str()); drop(state); window.set_focused(true); } @@ -823,9 +837,6 @@ impl Dispatch for WaylandClientStatePtr { return; } state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32))); - state - .cursor - .set_icon(&wl_pointer, Some(cursor_icon_name.as_str())); if let Some(window) = state.mouse_focused_window.clone() { let input = PlatformInput::MouseMove(MouseMoveEvent { diff --git a/crates/gpui/src/platform/linux/wayland/cursor.rs b/crates/gpui/src/platform/linux/wayland/cursor.rs index 4a1de5f2e026d63c8341c7f733f8443dd0fb2508..b2b9bccd7ff1967b9270de8fb6076be8fc61648b 100644 --- a/crates/gpui/src/platform/linux/wayland/cursor.rs +++ b/crates/gpui/src/platform/linux/wayland/cursor.rs @@ -8,7 +8,7 @@ use wayland_cursor::{CursorImageBuffer, CursorTheme}; pub(crate) struct Cursor { theme: Option, - current_icon_name: String, + current_icon_name: Option, surface: WlSurface, serial_id: u32, } @@ -24,19 +24,29 @@ impl Cursor { pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self { Self { theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(), - current_icon_name: "default".to_string(), + current_icon_name: None, surface: globals.compositor.create_surface(&globals.qh, ()), serial_id: 0, } } + pub fn mark_dirty(&mut self) { + self.current_icon_name = None; + } + pub fn set_serial_id(&mut self, serial_id: u32) { self.serial_id = serial_id; } - pub fn set_icon(&mut self, wl_pointer: &WlPointer, mut cursor_icon_name: Option<&str>) { - let mut cursor_icon_name = cursor_icon_name.unwrap_or("default"); - if self.current_icon_name != cursor_icon_name { + pub fn set_icon(&mut self, wl_pointer: &WlPointer, mut cursor_icon_name: &str) { + let need_update = self + .current_icon_name + .as_ref() + .map_or(true, |current_icon_name| { + current_icon_name != cursor_icon_name + }); + + if need_update { if let Some(theme) = &mut self.theme { let mut buffer: Option<&CursorImageBuffer>; @@ -68,7 +78,7 @@ impl Cursor { self.surface.damage(0, 0, width as i32, height as i32); self.surface.commit(); - self.current_icon_name = cursor_icon_name.to_string(); + self.current_icon_name = Some(cursor_icon_name.to_string()); } } else { log::warn!("Linux: Wayland: Unable to load cursor themes");