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