diff --git a/src/wayland/core/pointer.rs b/src/wayland/core/pointer.rs index f19434a..525a902 100644 --- a/src/wayland/core/pointer.rs +++ b/src/wayland/core/pointer.rs @@ -1,3 +1,4 @@ +use crate::nodes::items::panel::Geometry; use crate::wayland::core::{seat::fixed_from_f32, surface::Surface}; use mint::Vector2; use std::sync::Arc; @@ -15,6 +16,7 @@ pub struct Pointer { pub id: ObjectId, version: u32, focused_surface: Mutex>, + cursor_surface: Mutex>>, } impl Pointer { pub fn new(id: ObjectId, version: u32) -> Self { @@ -22,6 +24,7 @@ impl Pointer { id, version, focused_surface: Mutex::new(Weak::new()), + cursor_surface: Mutex::new(None), } } @@ -167,19 +170,45 @@ impl Pointer { *focused = Weak::new(); Ok(()) } + + pub async fn cursor_surface(&self) -> Option> { + self.cursor_surface.lock().await.clone() + } } impl WlPointer for Pointer { /// https://wayland.app/protocols/wayland#wl_pointer:request:set_cursor async fn set_cursor( &self, - _client: &mut Client, + client: &mut Client, _sender_id: ObjectId, _serial: u32, - _surface: Option, - _hotspot_x: i32, - _hotspot_y: i32, + surface: Option, + hotspot_x: i32, + hotspot_y: i32, ) -> Result<()> { + if let Some(focused_surface) = self.focused_surface.lock().await.upgrade() + && let Some(panel_item) = focused_surface.panel_item.lock().upgrade() + { + panel_item.set_cursor(surface.and_then(|s| client.get::(s)).map(|s| { + let size = s + .current_state() + .buffer + .map(|b| b.buffer.size()) + .unwrap_or([16; 2].into()); + Geometry { + origin: [-hotspot_x, -hotspot_y].into(), + size: [size.x as u32, size.y as u32].into(), + } + })); + } + let Some(surface) = surface else { + return Ok(()); + }; + let Some(surface) = client.get::(surface) else { + return Ok(()); + }; + self.cursor_surface.lock().await.replace(surface); Ok(()) } diff --git a/src/wayland/core/seat.rs b/src/wayland/core/seat.rs index 81cd1d9..1d2d2c6 100644 --- a/src/wayland/core/seat.rs +++ b/src/wayland/core/seat.rs @@ -154,6 +154,13 @@ impl Seat { } Ok(()) } + + pub async fn cursor_surface(&self) -> Option> { + let Some(pointer) = self.pointer.get() else { + return None; + }; + pointer.cursor_surface().await + } } impl WlSeat for Seat { /// https://wayland.app/protocols/wayland#wl_seat:request:get_pointer diff --git a/src/wayland/xdg/backend.rs b/src/wayland/xdg/backend.rs index 8249440..42b32c2 100644 --- a/src/wayland/xdg/backend.rs +++ b/src/wayland/xdg/backend.rs @@ -1,6 +1,6 @@ use super::toplevel::Toplevel; use crate::{ - core::error::Result, + core::{error::Result, task}, nodes::{ drawable::model::ModelPart, items::panel::{ @@ -9,7 +9,10 @@ use crate::{ }, wayland::{ Message, - core::{seat::SeatMessage, surface::Surface}, + core::{ + seat::{Seat, SeatMessage}, + surface::Surface, + }, }, }; use dashmap::DashMap; @@ -20,14 +23,16 @@ use tracing; #[derive(Debug)] pub struct XdgBackend { + seat: Weak, toplevel: Weak, children: DashMap, ChildInfo)>, } impl XdgBackend { - pub fn new(toplevel: Arc) -> Self { + pub fn new(seat: &Arc, toplevel: &Arc) -> Self { Self { - toplevel: Arc::downgrade(&toplevel), + seat: Arc::downgrade(seat), + toplevel: Arc::downgrade(toplevel), children: DashMap::new(), } } @@ -127,7 +132,18 @@ impl Backend for XdgBackend { }) } - fn apply_cursor_material(&self, _model_part: &Arc) {} + fn apply_cursor_material(&self, model_part: &Arc) { + let model_part = model_part.clone(); + let Some(seat) = self.seat.upgrade() else { + return; + }; + let _ = task::new(|| "apply cursor material", async move { + let Some(cursor) = seat.cursor_surface().await else { + return; + }; + cursor.apply_material(&model_part); + }); + } fn apply_surface_material(&self, surface: SurfaceId, model_part: &Arc) { if let Some(surface) = self.surface_from_id(&surface) { surface.apply_material(model_part); diff --git a/src/wayland/xdg/surface.rs b/src/wayland/xdg/surface.rs index 5b49bb5..6345b18 100644 --- a/src/wayland/xdg/surface.rs +++ b/src/wayland/xdg/surface.rs @@ -80,7 +80,9 @@ impl XdgSurface for Surface { toplevel.reconfigure(client).await?; let toplevel_weak = Arc::downgrade(&toplevel); - let pid = client.get::(ObjectId::DISPLAY).unwrap().pid; + let display = client.get::(ObjectId::DISPLAY).unwrap(); + let seat = Arc::downgrade(display.seat.get().unwrap()); + let pid = display.pid; let configured = self.configured.clone(); self.wl_surface.add_commit_handler(move |surface, state| { let Some(toplevel) = toplevel_weak.upgrade() else { @@ -92,7 +94,7 @@ impl XdgSurface for Surface { && configured.load(std::sync::atomic::Ordering::SeqCst) && state.has_valid_buffer() { - let mapped_inner = MappedInner::create(toplevel.clone(), pid); + let mapped_inner = MappedInner::create(&seat.upgrade().unwrap(), &toplevel, pid); *surface.panel_item.lock() = Arc::downgrade(&mapped_inner.panel_item); mapped_lock.replace(mapped_inner); return false; diff --git a/src/wayland/xdg/toplevel.rs b/src/wayland/xdg/toplevel.rs index 687e486..7f4a496 100644 --- a/src/wayland/xdg/toplevel.rs +++ b/src/wayland/xdg/toplevel.rs @@ -4,7 +4,7 @@ use crate::{ Node, items::panel::{PanelItem, SurfaceId}, }, - wayland::core::surface::Surface, + wayland::core::{seat::Seat, surface::Surface}, }; use mint::Vector2; use parking_lot::Mutex; @@ -21,9 +21,9 @@ pub struct MappedInner { pub panel_item: Arc>, } impl MappedInner { - pub fn create(toplevel: Arc, pid: Option) -> Self { + pub fn create(seat: &Arc, toplevel: &Arc, pid: Option) -> Self { let (panel_item_node, panel_item) = - PanelItem::create(Box::new(XdgBackend::new(toplevel)), pid); + PanelItem::create(Box::new(XdgBackend::new(seat, toplevel)), pid); Self { panel_item_node,