feat(wayland): add ability to hide the cursor over a surface
also now the surfaces say what the cursor over them should look like, previously one cursor shape was selected globally for the seat
This commit is contained in:
parent
65e9faa43c
commit
aca94cf2af
7 changed files with 111 additions and 9 deletions
|
|
@ -177,13 +177,41 @@ impl SctkEventLoop {
|
|||
}
|
||||
}
|
||||
crate::platform_specific::Action::SetCursor(
|
||||
surface,
|
||||
icon,
|
||||
) => {
|
||||
if let Some(seat) = state.seats.get_mut(0) {
|
||||
state.record_cursor(surface.clone(), |r| {
|
||||
r.icon = Some(icon);
|
||||
r.hidden = false;
|
||||
});
|
||||
if let Some(seat) = state
|
||||
.seats
|
||||
.get_mut(0)
|
||||
.filter(|s| s.is_over(&surface))
|
||||
{
|
||||
seat.icon = Some(icon);
|
||||
seat.hidden = false;
|
||||
seat.set_cursor(&state.connection, icon);
|
||||
}
|
||||
}
|
||||
crate::platform_specific::Action::SetCursorVisible(
|
||||
surface,
|
||||
visible,
|
||||
) => {
|
||||
state.record_cursor(surface.clone(), |r| {
|
||||
r.hidden = !visible;
|
||||
});
|
||||
if let Some(seat) = state
|
||||
.seats
|
||||
.get_mut(0)
|
||||
.filter(|s| s.is_over(&surface))
|
||||
{
|
||||
seat.set_cursor_visible(
|
||||
&state.connection,
|
||||
visible,
|
||||
);
|
||||
}
|
||||
}
|
||||
crate::platform_specific::Action::RequestRedraw(
|
||||
id,
|
||||
) => {
|
||||
|
|
@ -383,6 +411,7 @@ impl SctkEventLoop {
|
|||
touch_points: HashMap::new(),
|
||||
sctk_events: Vec::new(),
|
||||
frame_status: HashMap::new(),
|
||||
cursor_requests: HashMap::new(),
|
||||
fractional_scaling_manager,
|
||||
viewporter_state,
|
||||
compositor_updates: Default::default(),
|
||||
|
|
|
|||
|
|
@ -123,6 +123,13 @@ use wayland_protocols::{
|
|||
|
||||
pub static TOKEN_CTR: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
/// The requested cursor for a surface
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub(crate) struct CursorRequest {
|
||||
pub(crate) icon: Option<CursorIcon>,
|
||||
pub(crate) hidden: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SctkSeat {
|
||||
pub(crate) seat: WlSeat,
|
||||
|
|
@ -139,6 +146,8 @@ pub(crate) struct SctkSeat {
|
|||
pub(crate) active_icon: Option<CursorIcon>,
|
||||
// Cursor icon set by application
|
||||
pub(crate) icon: Option<CursorIcon>,
|
||||
// Application asked for cursor to hide
|
||||
pub(crate) hidden: bool,
|
||||
}
|
||||
|
||||
impl SctkSeat {
|
||||
|
|
@ -148,6 +157,35 @@ impl SctkSeat {
|
|||
self.active_icon = Some(icon);
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the pointer currently over `surface`.
|
||||
pub(crate) fn is_over(&self, surface: &ObjectId) -> bool {
|
||||
self.ptr_focus.as_ref().is_some_and(|s| &s.id() == surface)
|
||||
}
|
||||
|
||||
/// Set cursor visibility over this surfaces.
|
||||
pub(crate) fn set_cursor_visible(
|
||||
&mut self,
|
||||
conn: &Connection,
|
||||
visible: bool,
|
||||
) {
|
||||
let Some(ptr) = self.ptr.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.hidden = !visible;
|
||||
|
||||
if visible {
|
||||
let icon = self.icon.unwrap_or(CursorIcon::Default);
|
||||
_ = ptr.set_cursor(conn, icon);
|
||||
self.active_icon = Some(icon);
|
||||
} else {
|
||||
// Ignoring the error
|
||||
// It only fails when the pointer is not on our surface (due to serial error)
|
||||
_ = ptr.hide_cursor();
|
||||
self.active_icon = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -471,6 +509,7 @@ pub struct SctkState {
|
|||
pub(crate) session_lock_state: SessionLockState,
|
||||
pub(crate) session_lock: Option<SessionLock>,
|
||||
pub(crate) id_map: HashMap<ObjectId, core::window::Id>,
|
||||
pub(crate) cursor_requests: HashMap<ObjectId, CursorRequest>,
|
||||
pub(crate) to_commit: HashMap<core::window::Id, WlSurface>,
|
||||
pub(crate) destroyed: HashSet<core::window::Id>,
|
||||
pub(crate) pending_popup: Option<(SctkPopupSettings, usize)>,
|
||||
|
|
@ -573,6 +612,17 @@ pub(crate) fn receive_frame(
|
|||
}
|
||||
|
||||
impl SctkState {
|
||||
/// What a surface wants the pointer over it to be.
|
||||
pub(crate) fn record_cursor(
|
||||
&mut self,
|
||||
surface: ObjectId,
|
||||
amend: impl FnOnce(&mut CursorRequest),
|
||||
) {
|
||||
self.cursor_requests
|
||||
.retain(|id, _| id == &surface || self.id_map.contains_key(id));
|
||||
amend(self.cursor_requests.entry(surface).or_default());
|
||||
}
|
||||
|
||||
pub fn request_redraw(&mut self, surface: &WlSurface) {
|
||||
let e = self
|
||||
.frame_status
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl PointerHandler for SctkState {
|
|||
|
||||
// track events, but only forward for the active seat
|
||||
for e in events {
|
||||
if my_seat.active_icon != my_seat.icon {
|
||||
if !my_seat.hidden && my_seat.active_icon != my_seat.icon {
|
||||
// Restore cursor that was set by appliction, or default
|
||||
my_seat.set_cursor(
|
||||
conn,
|
||||
|
|
@ -60,10 +60,19 @@ impl PointerHandler for SctkState {
|
|||
match e.kind {
|
||||
PointerEventKind::Enter { .. } => {
|
||||
_ = my_seat.ptr_focus.replace(e.surface.clone());
|
||||
if let Some(want) =
|
||||
self.cursor_requests.get(&e.surface.id())
|
||||
{
|
||||
my_seat.icon = want.icon;
|
||||
my_seat.set_cursor_visible(conn, !want.hidden);
|
||||
}
|
||||
}
|
||||
PointerEventKind::Leave { .. } => {
|
||||
_ = my_seat.ptr_focus.take();
|
||||
_ = my_seat.active_icon = None;
|
||||
// The next surface the pointer lands on decides what it
|
||||
// looks like there
|
||||
my_seat.hidden = false;
|
||||
}
|
||||
PointerEventKind::Press {
|
||||
time,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ impl SeatHandler for SctkState {
|
|||
last_touch_down: None,
|
||||
icon: None,
|
||||
active_icon: None,
|
||||
hidden: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +66,7 @@ impl SeatHandler for SctkState {
|
|||
last_touch_down: None,
|
||||
icon: None,
|
||||
active_icon: None,
|
||||
hidden: false,
|
||||
});
|
||||
self.seats.last_mut().unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ use winit::window::ImePurpose;
|
|||
|
||||
pub(crate) enum Action {
|
||||
Action(iced_runtime::platform_specific::wayland::Action),
|
||||
SetCursor(CursorIcon),
|
||||
SetCursor(ObjectId, CursorIcon),
|
||||
SetCursorVisible(ObjectId, bool),
|
||||
RequestRedraw(ObjectId),
|
||||
TrackWindow(Arc<dyn winit::window::Window>, window::Id),
|
||||
ResizeWindow(window::Id),
|
||||
|
|
@ -48,9 +49,14 @@ impl std::fmt::Debug for Action {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Action(arg0) => f.debug_tuple("Action").field(arg0).finish(),
|
||||
Self::SetCursor(arg0) => {
|
||||
f.debug_tuple("SetCursor").field(arg0).finish()
|
||||
Self::SetCursor(arg0, arg1) => {
|
||||
f.debug_tuple("SetCursor").field(arg0).field(arg1).finish()
|
||||
}
|
||||
Self::SetCursorVisible(arg0, arg1) => f
|
||||
.debug_tuple("SetCursorVisible")
|
||||
.field(arg0)
|
||||
.field(arg1)
|
||||
.finish(),
|
||||
Self::RequestRedraw(arg0) => {
|
||||
f.debug_tuple("RequestRedraw").field(arg0).finish()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,10 @@ impl winit::window::Window for SctkWinitWindow {
|
|||
fn set_cursor(&self, cursor: winit_core::cursor::Cursor) {
|
||||
match cursor {
|
||||
winit_core::cursor::Cursor::Icon(icon) => {
|
||||
_ = self.tx.send(Action::SetCursor(icon));
|
||||
_ = self.tx.send(Action::SetCursor(
|
||||
self.surface.wl_surface().id(),
|
||||
icon,
|
||||
));
|
||||
}
|
||||
winit_core::cursor::Cursor::Custom(_) => {
|
||||
// TODO
|
||||
|
|
@ -92,7 +95,10 @@ impl winit::window::Window for SctkWinitWindow {
|
|||
}
|
||||
|
||||
fn set_cursor_visible(&self, visible: bool) {
|
||||
// TODO
|
||||
_ = self.tx.send(Action::SetCursorVisible(
|
||||
self.surface.wl_surface().id(),
|
||||
visible,
|
||||
));
|
||||
}
|
||||
|
||||
fn surface_size(&self) -> winit::dpi::PhysicalSize<u32> {
|
||||
|
|
|
|||
|
|
@ -291,11 +291,11 @@ where
|
|||
pub fn update_mouse(&mut self, interaction: mouse::Interaction) {
|
||||
if interaction != self.mouse_interaction {
|
||||
if let Some(icon) = conversion::mouse_interaction(interaction) {
|
||||
self.raw.set_cursor(icon.into());
|
||||
|
||||
if self.mouse_interaction == mouse::Interaction::Hidden {
|
||||
self.raw.set_cursor_visible(true);
|
||||
}
|
||||
|
||||
self.raw.set_cursor(icon.into());
|
||||
} else {
|
||||
self.raw.set_cursor_visible(false);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue