1 | use std::{ |
2 | ops::DerefMut, |
3 | sync::{Arc, Mutex}, |
4 | }; |
5 | |
6 | use wayland_client::protocol::wl_surface::WlSurface; |
7 | |
8 | use 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 | |
21 | use 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. |
29 | pub 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)] |
81 | pub struct DataDevice { |
82 | pub(crate) device: WlDataDevice, |
83 | } |
84 | |
85 | impl 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 | |
100 | impl Drop for DataDevice { |
101 | fn drop(&mut self) { |
102 | if self.device.version() >= 2 { |
103 | self.device.release() |
104 | } |
105 | } |
106 | } |
107 | |
108 | impl<D> Dispatch<wl_data_device::WlDataDevice, DataDeviceData, D> for DataDeviceManagerState |
109 | where |
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)] |
224 | pub 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 | |
231 | impl 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)] |
259 | pub(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 | |