| 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 | |