1use std::{
2 ops::DerefMut,
3 sync::{Arc, Mutex},
4};
5
6use wayland_client::protocol::wl_surface::WlSurface;
7
8use crate::{
9 data_device_manager::data_offer::DataDeviceOffer,
10 reexports::client::{
11 event_created_child,
12 protocol::{
13 wl_data_device::{self, WlDataDevice},
14 wl_data_offer::{self, WlDataOffer},
15 wl_seat::WlSeat,
16 },
17 Connection, Dispatch, Proxy, QueueHandle,
18 },
19};
20
21use super::{
22 data_offer::{DataOfferData, DataOfferHandler, DragOffer, SelectionOffer},
23 DataDeviceManagerState,
24};
25
26/// Handler trait for DataDevice events.
27///
28/// The functions defined in this trait are called as DataDevice events are received from the compositor.
29pub trait DataDeviceHandler: Sized {
30 // Introduces a new data offer
31 // ASHLEY left out because the data offer will be introduced to the user once the type is known
32 // either through the enter method or the selection method.
33 // fn data_offer(
34 // &mut self,
35 // conn: &Connection,
36 // qh: &QueueHandle<Self>,
37 // data_device: DataDevice,
38 // offer: WlDataOffer,
39 // );
40
41 /// The data device pointer has entered a surface at the provided location
42 fn enter(
43 &mut self,
44 conn: &Connection,
45 qh: &QueueHandle<Self>,
46 data_device: &WlDataDevice,
47 x: f64,
48 y: f64,
49 wl_surface: &WlSurface,
50 );
51
52 /// The drag and drop pointer has left the surface and the session ends.
53 /// The offer will be destroyed unless it was previously dropped.
54 /// In the case of a dropped offer, the client must destroy it manually after it is finished.
55 fn leave(&mut self, conn: &Connection, qh: &QueueHandle<Self>, data_device: &WlDataDevice);
56
57 /// Drag and Drop motion.
58 fn motion(
59 &mut self,
60 conn: &Connection,
61 qh: &QueueHandle<Self>,
62 data_device: &WlDataDevice,
63 x: f64,
64 y: f64,
65 );
66
67 /// Advertises a new selection.
68 fn selection(&mut self, conn: &Connection, qh: &QueueHandle<Self>, data_device: &WlDataDevice);
69
70 /// Drop performed.
71 /// After the next data offer action event, data may be able to be received, unless the action is "ask".
72 fn drop_performed(
73 &mut self,
74 conn: &Connection,
75 qh: &QueueHandle<Self>,
76 data_device: &WlDataDevice,
77 );
78}
79
80#[derive(Debug, Eq, PartialEq)]
81pub struct DataDevice {
82 pub(crate) device: WlDataDevice,
83}
84
85impl DataDevice {
86 pub fn data(&self) -> &DataDeviceData {
87 self.device.data().unwrap()
88 }
89
90 /// Unset the selection of the provided data device as a response to the event with with provided serial.
91 pub fn unset_selection(&self, serial: u32) {
92 self.device.set_selection(None, serial);
93 }
94
95 pub fn inner(&self) -> &WlDataDevice {
96 &self.device
97 }
98}
99
100impl Drop for DataDevice {
101 fn drop(&mut self) {
102 if self.device.version() >= 2 {
103 self.device.release()
104 }
105 }
106}
107
108impl<D> Dispatch<wl_data_device::WlDataDevice, DataDeviceData, D> for DataDeviceManagerState
109where
110 D: Dispatch<wl_data_device::WlDataDevice, DataDeviceData>
111 + Dispatch<wl_data_offer::WlDataOffer, DataOfferData>
112 + DataDeviceHandler
113 + DataOfferHandler
114 + 'static,
115{
116 event_created_child!(D, WlDataDevice, [
117 0 => (WlDataOffer, Default::default())
118 ]);
119
120 fn event(
121 state: &mut D,
122 data_device: &wl_data_device::WlDataDevice,
123 event: wl_data_device::Event,
124 data: &DataDeviceData,
125 conn: &Connection,
126 qh: &QueueHandle<D>,
127 ) {
128 use wayland_client::protocol::wl_data_device::Event;
129 let mut inner = data.inner.lock().unwrap();
130
131 match event {
132 Event::DataOffer { id } => {
133 inner.undetermined_offers.push(id.clone());
134 let data = id.data::<DataOfferData>().unwrap();
135 data.init_undetermined_offer(&id);
136 }
137 Event::Enter { serial, surface, x, y, id } => {
138 // XXX the spec isn't clear here.
139 if let Some(offer) = inner.drag_offer.take() {
140 offer.destroy();
141 }
142
143 if let Some(offer) = id {
144 if let Some(i) = inner.undetermined_offers.iter().position(|o| o == &offer) {
145 inner.undetermined_offers.remove(i);
146 }
147
148 let data = offer.data::<DataOfferData>().unwrap();
149 data.to_dnd_offer(serial, surface.clone(), x, y, None);
150
151 inner.drag_offer = Some(offer.clone());
152 }
153 // XXX Drop done here to prevent Mutex deadlocks.
154 drop(inner);
155 state.enter(conn, qh, data_device, x, y, &surface);
156 }
157 Event::Leave => {
158 // We must destroy the offer we've got on enter.
159 if let Some(offer) = inner.drag_offer.take() {
160 let data = offer.data::<DataOfferData>().unwrap();
161 if !data.leave() {
162 inner.drag_offer = Some(offer);
163 }
164 }
165 // XXX Drop done here to prevent Mutex deadlocks.
166 drop(inner);
167 state.leave(conn, qh, data_device);
168 }
169 Event::Motion { time, x, y } => {
170 if let Some(offer) = inner.drag_offer.take() {
171 let data = offer.data::<DataOfferData>().unwrap();
172 // Update the data offer location.
173 data.motion(x, y, time);
174 inner.drag_offer = Some(offer);
175 }
176
177 // XXX Drop done here to prevent Mutex deadlocks.
178 drop(inner);
179 state.motion(conn, qh, data_device, x, y);
180 }
181 Event::Drop => {
182 if let Some(offer) = inner.drag_offer.take() {
183 let data = offer.data::<DataOfferData>().unwrap();
184
185 let mut drag_inner = data.inner.lock().unwrap();
186
187 if let DataDeviceOffer::Drag(ref mut o) = drag_inner.deref_mut().offer {
188 o.dropped = true;
189 }
190 drop(drag_inner);
191
192 inner.drag_offer = Some(offer);
193 }
194 // XXX Drop done here to prevent Mutex deadlocks.
195 drop(inner);
196 // Pass the info about the drop to the user.
197 state.drop_performed(conn, qh, data_device);
198 }
199 Event::Selection { id } => {
200 // We must drop the current offer regardless.
201 if let Some(offer) = inner.selection_offer.take() {
202 offer.destroy();
203 }
204
205 if let Some(offer) = id {
206 if let Some(i) = inner.undetermined_offers.iter().position(|o| o == &offer) {
207 inner.undetermined_offers.remove(i);
208 }
209
210 let data = offer.data::<DataOfferData>().unwrap();
211 data.to_selection_offer();
212 inner.selection_offer = Some(offer.clone());
213 // XXX Drop done here to prevent Mutex deadlocks.
214 drop(inner);
215 state.selection(conn, qh, data_device);
216 }
217 }
218 _ => unreachable!(),
219 }
220 }
221}
222
223#[derive(Debug)]
224pub struct DataDeviceData {
225 /// The seat associated with this device.
226 pub(crate) seat: WlSeat,
227 /// The inner mutable storage.
228 pub(crate) inner: Arc<Mutex<DataDeviceInner>>,
229}
230
231impl DataDeviceData {
232 pub(crate) fn new(seat: WlSeat) -> Self {
233 Self { seat, inner: Default::default() }
234 }
235
236 /// Get the seat associated with this data device.
237 pub fn seat(&self) -> &WlSeat {
238 &self.seat
239 }
240
241 /// Get the active dnd offer if it exists.
242 pub fn drag_offer(&self) -> Option<DragOffer> {
243 self.inner.lock().unwrap().drag_offer.as_ref().and_then(|offer| {
244 let data = offer.data::<DataOfferData>().unwrap();
245 data.as_drag_offer()
246 })
247 }
248
249 /// Get the active selection offer if it exists.
250 pub fn selection_offer(&self) -> Option<SelectionOffer> {
251 self.inner.lock().unwrap().selection_offer.as_ref().and_then(|offer| {
252 let data = offer.data::<DataOfferData>().unwrap();
253 data.as_selection_offer()
254 })
255 }
256}
257
258#[derive(Debug, Default)]
259pub(crate) struct DataDeviceInner {
260 /// the active dnd offer and its data
261 pub drag_offer: Option<WlDataOffer>,
262 /// the active selection offer and its data
263 pub selection_offer: Option<WlDataOffer>,
264 /// the active undetermined offers and their data
265 pub undetermined_offers: Vec<WlDataOffer>,
266}
267