Skip to main content

wl_clipboard_rs/
data_control.rs

1//! Abstraction over ext/wlr-data-control.
2
3use std::os::fd::BorrowedFd;
4
5use ext::ext_data_control_device_v1::ExtDataControlDeviceV1;
6use ext::ext_data_control_manager_v1::ExtDataControlManagerV1;
7use ext::ext_data_control_offer_v1::ExtDataControlOfferV1;
8use ext::ext_data_control_source_v1::ExtDataControlSourceV1;
9use wayland_client::protocol::wl_seat::WlSeat;
10use wayland_client::{Dispatch, Proxy as _, QueueHandle};
11use wayland_protocols::ext::data_control::v1::client as ext;
12use wayland_protocols_wlr::data_control::v1::client as zwlr;
13use zwlr::zwlr_data_control_device_v1::ZwlrDataControlDeviceV1;
14use zwlr::zwlr_data_control_manager_v1::ZwlrDataControlManagerV1;
15use zwlr::zwlr_data_control_offer_v1::ZwlrDataControlOfferV1;
16use zwlr::zwlr_data_control_source_v1::ZwlrDataControlSourceV1;
17
18#[derive(Clone)]
19pub enum Manager {
20    Zwlr(ZwlrDataControlManagerV1),
21    Ext(ExtDataControlManagerV1),
22}
23
24#[derive(Clone)]
25pub enum Device {
26    Zwlr(ZwlrDataControlDeviceV1),
27    Ext(ExtDataControlDeviceV1),
28}
29
30#[derive(Clone)]
31pub enum Source {
32    Zwlr(ZwlrDataControlSourceV1),
33    Ext(ExtDataControlSourceV1),
34}
35
36#[derive(Clone, PartialEq, Eq, Hash)]
37pub enum Offer {
38    Zwlr(ZwlrDataControlOfferV1),
39    Ext(ExtDataControlOfferV1),
40}
41
42impl Manager {
43    pub fn get_data_device<D, U>(&self, seat: &WlSeat, qh: &QueueHandle<D>, udata: U) -> Device
44    where
45        D: Dispatch<ZwlrDataControlDeviceV1, U> + 'static,
46        D: Dispatch<ExtDataControlDeviceV1, U> + 'static,
47        U: Send + Sync + 'static,
48    {
49        match self {
50            Manager::Zwlr(manager) => Device::Zwlr(manager.get_data_device(seat, qh, udata)),
51            Manager::Ext(manager) => Device::Ext(manager.get_data_device(seat, qh, udata)),
52        }
53    }
54
55    pub fn create_data_source<D>(&self, qh: &QueueHandle<D>) -> Source
56    where
57        D: Dispatch<ZwlrDataControlSourceV1, ()> + 'static,
58        D: Dispatch<ExtDataControlSourceV1, ()> + 'static,
59    {
60        match self {
61            Manager::Zwlr(manager) => Source::Zwlr(manager.create_data_source(qh, ())),
62            Manager::Ext(manager) => Source::Ext(manager.create_data_source(qh, ())),
63        }
64    }
65}
66
67impl Device {
68    pub fn destroy(&self) {
69        match self {
70            Device::Zwlr(device) => device.destroy(),
71            Device::Ext(device) => device.destroy(),
72        }
73    }
74
75    #[track_caller]
76    pub fn set_selection(&self, source: Option<&Source>) {
77        match self {
78            Device::Zwlr(device) => device.set_selection(source.map(Source::zwlr)),
79            Device::Ext(device) => device.set_selection(source.map(Source::ext)),
80        }
81    }
82
83    #[track_caller]
84    pub fn set_primary_selection(&self, source: Option<&Source>) {
85        match self {
86            Device::Zwlr(device) => device.set_primary_selection(source.map(Source::zwlr)),
87            Device::Ext(device) => device.set_primary_selection(source.map(Source::ext)),
88        }
89    }
90}
91
92impl Source {
93    pub fn destroy(&self) {
94        match self {
95            Source::Zwlr(source) => source.destroy(),
96            Source::Ext(source) => source.destroy(),
97        }
98    }
99
100    pub fn offer(&self, mime_type: String) {
101        match self {
102            Source::Zwlr(source) => source.offer(mime_type),
103            Source::Ext(source) => source.offer(mime_type),
104        }
105    }
106
107    pub fn is_alive(&self) -> bool {
108        match self {
109            Source::Zwlr(source) => source.is_alive(),
110            Source::Ext(source) => source.is_alive(),
111        }
112    }
113
114    #[track_caller]
115    pub fn zwlr(&self) -> &ZwlrDataControlSourceV1 {
116        if let Self::Zwlr(v) = self {
117            v
118        } else {
119            panic!("tried to convert non-Zwlr Source to Zwlr")
120        }
121    }
122
123    #[track_caller]
124    pub fn ext(&self) -> &ExtDataControlSourceV1 {
125        if let Self::Ext(v) = self {
126            v
127        } else {
128            panic!("tried to convert non-Ext Source to Ext")
129        }
130    }
131}
132
133impl Offer {
134    pub fn destroy(&self) {
135        match self {
136            Offer::Zwlr(offer) => offer.destroy(),
137            Offer::Ext(offer) => offer.destroy(),
138        }
139    }
140
141    pub fn receive(&self, mime_type: String, fd: BorrowedFd) {
142        match self {
143            Offer::Zwlr(offer) => offer.receive(mime_type, fd),
144            Offer::Ext(offer) => offer.receive(mime_type, fd),
145        }
146    }
147}
148
149impl From<ZwlrDataControlSourceV1> for Source {
150    fn from(v: ZwlrDataControlSourceV1) -> Self {
151        Self::Zwlr(v)
152    }
153}
154
155impl From<ExtDataControlSourceV1> for Source {
156    fn from(v: ExtDataControlSourceV1) -> Self {
157        Self::Ext(v)
158    }
159}
160
161impl From<ZwlrDataControlOfferV1> for Offer {
162    fn from(v: ZwlrDataControlOfferV1) -> Self {
163        Self::Zwlr(v)
164    }
165}
166
167impl From<ExtDataControlOfferV1> for Offer {
168    fn from(v: ExtDataControlOfferV1) -> Self {
169        Self::Ext(v)
170    }
171}
172
173// Some mildly cursed macros to avoid code duplication.
174macro_rules! impl_dispatch_manager {
175    ($handler:ty => [$($iface:ty),*]) => {
176        $(
177            impl Dispatch<$iface, ()> for $handler {
178                fn event(
179                    _state: &mut Self,
180                    _proxy: &$iface,
181                    _event: <$iface as wayland_client::Proxy>::Event,
182                    _data: &(),
183                    _conn: &wayland_client::Connection,
184                    _qhandle: &wayland_client::QueueHandle<Self>,
185                ) {
186                }
187            }
188        )*
189    };
190
191    ($handler:ty) => {
192        impl_dispatch_manager!($handler => [
193            wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_manager_v1::ZwlrDataControlManagerV1,
194            wayland_protocols::ext::data_control::v1::client::ext_data_control_manager_v1::ExtDataControlManagerV1
195        ]);
196    };
197}
198pub(crate) use impl_dispatch_manager;
199
200macro_rules! impl_dispatch_device {
201    ($handler:ty, $udata:ty, $code:expr => [$(($iface:ty, $opcode:path, $offer:ty)),*]) => {
202        $(
203            impl Dispatch<$iface, $udata> for $handler {
204                fn event(
205                    state: &mut Self,
206                    _proxy: &$iface,
207                    event: <$iface as wayland_client::Proxy>::Event,
208                    data: &$udata,
209                    _conn: &wayland_client::Connection,
210                    _qhandle: &wayland_client::QueueHandle<Self>,
211                ) {
212                    type Event = <$iface as wayland_client::Proxy>::Event;
213
214                    ($code)(state, event, data)
215                }
216
217                event_created_child!($handler, $iface, [
218                    $opcode => ($offer, ()),
219                ]);
220            }
221        )*
222    };
223
224    ($handler:ty, $udata:ty, $code:expr) => {
225        impl_dispatch_device!($handler, $udata, $code => [
226            (
227                wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_device_v1::ZwlrDataControlDeviceV1,
228                wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_device_v1::EVT_DATA_OFFER_OPCODE,
229                wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_offer_v1::ZwlrDataControlOfferV1
230            ),
231            (
232                wayland_protocols::ext::data_control::v1::client::ext_data_control_device_v1::ExtDataControlDeviceV1,
233                wayland_protocols::ext::data_control::v1::client::ext_data_control_device_v1::EVT_DATA_OFFER_OPCODE,
234                wayland_protocols::ext::data_control::v1::client::ext_data_control_offer_v1::ExtDataControlOfferV1
235            )
236        ]);
237    };
238}
239pub(crate) use impl_dispatch_device;
240
241macro_rules! impl_dispatch_source {
242    ($handler:ty, $code:expr => [$($iface:ty),*]) => {
243        $(
244            impl Dispatch<$iface, ()> for $handler {
245                fn event(
246                    state: &mut Self,
247                    proxy: &$iface,
248                    event: <$iface as wayland_client::Proxy>::Event,
249                    _data: &(),
250                    _conn: &wayland_client::Connection,
251                    _qhandle: &wayland_client::QueueHandle<Self>,
252                ) {
253                    type Event = <$iface as wayland_client::Proxy>::Event;
254
255                    let source = $crate::data_control::Source::from(proxy.clone());
256                    ($code)(state, source, event)
257                }
258            }
259        )*
260    };
261
262    ($handler:ty, $code:expr) => {
263        impl_dispatch_source!($handler, $code => [
264            wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_source_v1::ZwlrDataControlSourceV1,
265            wayland_protocols::ext::data_control::v1::client::ext_data_control_source_v1::ExtDataControlSourceV1
266        ]);
267    };
268}
269pub(crate) use impl_dispatch_source;
270
271macro_rules! impl_dispatch_offer {
272    ($handler:ty, $code:expr => [$($iface:ty),*]) => {
273        $(
274            impl Dispatch<$iface, ()> for $handler {
275                fn event(
276                    state: &mut Self,
277                    proxy: &$iface,
278                    event: <$iface as wayland_client::Proxy>::Event,
279                    _data: &(),
280                    _conn: &wayland_client::Connection,
281                    _qhandle: &wayland_client::QueueHandle<Self>,
282                ) {
283                    type Event = <$iface as wayland_client::Proxy>::Event;
284
285                    let offer = $crate::data_control::Offer::from(proxy.clone());
286                    ($code)(state, offer, event)
287                }
288            }
289        )*
290    };
291
292    ($handler:ty, $code:expr) => {
293        impl_dispatch_offer!($handler, $code => [
294            wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_offer_v1::ZwlrDataControlOfferV1,
295            wayland_protocols::ext::data_control::v1::client::ext_data_control_offer_v1::ExtDataControlOfferV1
296        ]);
297    };
298
299    ($handler:ty) => {
300        impl_dispatch_offer!($handler, |_, _, _: Event| ());
301    };
302}
303pub(crate) use impl_dispatch_offer;