From b096453a3b663471ee8c07562d06db42ac0e886a Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 11 Jul 2024 14:16:12 -0700 Subject: [PATCH] sctk: Fixes for cursor icon * With multiple windows, `SetCursor` is only sent for the focused window. Fixing a flicker between icons when two windows are using different cursors. * If there is a drag surface, let that surface set the cursor. And not any other. * Set cursor on `enter`, and when switching between CSDs and app area. Fixes https://github.com/pop-os/libcosmic/issues/533. --- sctk/src/application.rs | 15 +++++++++-- sctk/src/event_loop/mod.rs | 5 ++-- sctk/src/event_loop/state.rs | 12 +++++++++ sctk/src/handlers/seat/pointer.rs | 45 ++++++++++--------------------- sctk/src/handlers/seat/seat.rs | 2 ++ 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/sctk/src/application.rs b/sctk/src/application.rs index dc66c363cf..478dba5bc2 100644 --- a/sctk/src/application.rs +++ b/sctk/src/application.rs @@ -929,7 +929,7 @@ where // just draw here immediately and never again for dnd icons // TODO handle scale factor? - let _new_mouse_interaction = user_interface.draw( + let new_mouse_interaction = user_interface.draw( &mut renderer, state.theme(), &Style { @@ -940,6 +940,13 @@ where state.cursor(), ); + mouse_interaction = new_mouse_interaction; + ev_proxy.send_event(Event::SetCursor(mouse_interaction)); + // Pre-emptively remove cursor focus from other surface so they won't set cursor + for state in states.values_mut() { + state.cursor_position = None; + } + let subsurfaces = crate::subsurface_widget::take_subsurfaces(); if let Some(subsurface_state) = subsurface_state.as_mut() { subsurface_state.update_subsurfaces( @@ -1439,7 +1446,11 @@ where } debug.draw_finished(); - if new_mouse_interaction != mouse_interaction { + + // Set cursor if mouse interaction has changed, and surface has pointer focus + if state.cursor_position.is_some() + && new_mouse_interaction != mouse_interaction + { mouse_interaction = new_mouse_interaction; ev_proxy .send_event(Event::SetCursor(mouse_interaction)); diff --git a/sctk/src/event_loop/mod.rs b/sctk/src/event_loop/mod.rs index f5b7fcce1a..36fadfdd91 100644 --- a/sctk/src/event_loop/mod.rs +++ b/sctk/src/event_loop/mod.rs @@ -838,9 +838,10 @@ where }, }, Event::SetCursor(iced_icon) => { - if let Some(ptr) = self.state.seats.get(0).and_then(|s| s.ptr.as_ref()) { + if let Some(seat) = self.state.seats.get_mut(0) { let icon = conversion::cursor_icon(iced_icon); - let _ = ptr.set_cursor(self.wayland_dispatcher.as_source_ref().connection(), icon); + seat.icon = Some(icon); + seat.set_cursor(self.wayland_dispatcher.as_source_ref().connection(), icon); } } diff --git a/sctk/src/event_loop/state.rs b/sctk/src/event_loop/state.rs index 0782ab3ae8..20f0ce15f8 100644 --- a/sctk/src/event_loop/state.rs +++ b/sctk/src/event_loop/state.rs @@ -98,9 +98,21 @@ pub(crate) struct SctkSeat { pub(crate) last_touch_down: Option<(u32, i32, u32)>, // (time, point, serial) pub(crate) _modifiers: Modifiers, pub(crate) data_device: DataDevice, + // Cursor icon currently set (by CSDs, or application) + pub(crate) active_icon: Option, + // Cursor icon set by applicationb pub(crate) icon: Option, } +impl SctkSeat { + pub(crate) fn set_cursor(&mut self, conn: &Connection, icon: CursorIcon) { + if let Some(ptr) = self.ptr.as_ref() { + ptr.set_cursor(conn, icon); + self.active_icon = Some(icon); + } + } +} + #[derive(Debug, Clone)] pub struct SctkWindow { pub(crate) id: window::Id, diff --git a/sctk/src/handlers/seat/pointer.rs b/sctk/src/handlers/seat/pointer.rs index 9777a320e4..eaddf814a0 100644 --- a/sctk/src/handlers/seat/pointer.rs +++ b/sctk/src/handlers/seat/pointer.rs @@ -94,41 +94,24 @@ impl PointerHandler for SctkState { return; } PointerEventKind::Motion { .. } => { - if my_seat.icon != Some(icon) { - let _ = my_seat - .ptr - .as_ref() - .unwrap() - .set_cursor(conn, icon); - my_seat.icon = Some(icon); + if my_seat.active_icon != Some(icon) { + let _ = my_seat.set_cursor(conn, icon); } return; } - PointerEventKind::Enter { .. } => { - my_seat.ptr_focus.replace(e.surface.clone()); - if my_seat.icon != Some(icon) { - let _ = my_seat - .ptr - .as_ref() - .unwrap() - .set_cursor(conn, icon); - my_seat.icon = Some(icon); - } - } - PointerEventKind::Leave { .. } => { - my_seat.ptr_focus.take(); - my_seat.icon = None; - } + PointerEventKind::Enter { .. } => {} + PointerEventKind::Leave { .. } => {} _ => {} } - let _ = my_seat.ptr.as_ref().unwrap().set_cursor(conn, icon); - } else if my_seat.icon.is_some() { - let _ = my_seat - .ptr - .as_ref() - .unwrap() - .set_cursor(conn, CursorIcon::Default); - my_seat.icon = None; + if my_seat.active_icon != Some(icon) { + my_seat.set_cursor(conn, icon); + } + } else if my_seat.active_icon != my_seat.icon { + // Restore cursor that was set by appliction, or default + my_seat.set_cursor( + conn, + my_seat.icon.unwrap_or(CursorIcon::Default), + ); } if is_active { @@ -144,7 +127,7 @@ impl PointerHandler for SctkState { } PointerEventKind::Leave { .. } => { my_seat.ptr_focus.take(); - my_seat.icon = None; + my_seat.active_icon = None; } PointerEventKind::Press { time, diff --git a/sctk/src/handlers/seat/seat.rs b/sctk/src/handlers/seat/seat.rs index adc5e0e842..ce90b7d86f 100644 --- a/sctk/src/handlers/seat/seat.rs +++ b/sctk/src/handlers/seat/seat.rs @@ -43,6 +43,7 @@ where last_kbd_press: None, last_touch_down: None, icon: None, + active_icon: None, }); } @@ -71,6 +72,7 @@ where last_kbd_press: None, last_touch_down: None, icon: None, + active_icon: None, }); self.seats.last_mut().unwrap() }