// SPDX-License-Identifier: GPL-3.0-only use crate::state::State; use smithay::{ delegate_data_device, input::{ pointer::{CursorImageStatus, CursorImageSurfaceData}, Seat, }, reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface}, utils::{IsAlive, Logical, Point}, wayland::{ compositor::{self, SurfaceAttributes}, selection::data_device::{ ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, }, }, }; use std::sync::Mutex; #[derive(Debug, Clone)] pub struct DnDIcon { pub surface: WlSurface, pub offset: Point, } pub fn get_dnd_icon(seat: &Seat) -> Option { let userdata = seat.user_data(); userdata .get::>>() .and_then(|x| x.lock().unwrap().clone()) .filter(|icon| icon.surface.alive()) } pub fn on_commit(surface: &WlSurface, seat: &Seat) { let userdata = seat.user_data(); let Some(mut guard) = userdata .get::>>() .map(|guard| guard.lock().unwrap()) else { return; }; let Some(icon) = guard.as_mut() else { return; }; if &icon.surface == surface { compositor::with_states(surface, |states| { let buffer_delta = states .cached_state .get::() .current() .buffer_delta .take() .unwrap_or_default(); icon.offset += buffer_delta; }); } } impl ClientDndGrabHandler for State { fn started( &mut self, _source: Option, icon: Option, seat: Seat, ) { let user_data = seat.user_data(); user_data.insert_if_missing_threadsafe::>, _>(|| Default::default()); let offset = seat .user_data() .get::>() .map(|guard| { if let CursorImageStatus::Surface(ref surface) = *guard.lock().unwrap() { compositor::with_states(surface, |states| { let hotspot = states .data_map .get::() .unwrap() .lock() .unwrap() .hotspot; Point::from((-hotspot.x, -hotspot.y)) }) } else { (0, 0).into() } }) .unwrap_or_default(); *user_data .get::>>() .unwrap() .lock() .unwrap() = icon.map(|surface| DnDIcon { surface, offset }) } fn dropped(&mut self, _target: Option, _validated: bool, seat: Seat) { seat.user_data() .get::>>() .unwrap() .lock() .unwrap() .take(); } } impl ServerDndGrabHandler for State {} impl DataDeviceHandler for State { fn data_device_state(&self) -> &DataDeviceState { &self.common.data_device_state } } delegate_data_device!(State);