// SPDX-License-Identifier: GPL-3.0-only use crate::{state::State, utils::prelude::SeatExt}; use smithay::{ delegate_data_device, input::{ Seat, pointer::{CursorImageStatus, CursorImageSurfaceData}, }, 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 = if let CursorImageStatus::Surface(ref surface) = seat.cursor_image_status() { 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() }; *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(&mut self) -> &mut DataDeviceState { &mut self.common.data_device_state } } delegate_data_device!(State);