smithay_client_toolkit/data_device_manager/
data_device.rs

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}