1use std::sync::{Arc, Mutex};
2
3use crate::reexports::client::{
4 event_created_child, protocol::wl_seat::WlSeat, Connection, Dispatch, Proxy, QueueHandle,
5};
6use crate::reexports::protocols::wp::primary_selection::zv1::client::{
7 zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1,
8 zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1,
9};
10
11use super::{
12 offer::{PrimarySelectionOffer, PrimarySelectionOfferData},
13 PrimarySelectionManagerState,
14};
15
16pub trait PrimarySelectionDeviceHandler: Sized {
17 /// The new selection is received.
18 ///
19 /// The given primary selection device could be used to identify [`PrimarySelectionDevice`].
20 fn selection(
21 &mut self,
22 conn: &Connection,
23 qh: &QueueHandle<Self>,
24 primary_selection_device: &ZwpPrimarySelectionDeviceV1,
25 );
26}
27
28#[derive(Debug)]
29pub struct PrimarySelectionDevice {
30 pub(crate) device: ZwpPrimarySelectionDeviceV1,
31}
32
33impl PrimarySelectionDevice {
34 /// Remove the currently active selection.
35 ///
36 /// The passed `serial` is the serial of the input event.
37 pub fn unset_selection(&self, serial: u32) {
38 self.device.set_selection(None, serial);
39 }
40
41 /// Get the underlying data.
42 pub fn data(&self) -> &PrimarySelectionDeviceData {
43 self.device.data::<PrimarySelectionDeviceData>().unwrap()
44 }
45
46 pub fn inner(&self) -> &ZwpPrimarySelectionDeviceV1 {
47 &self.device
48 }
49}
50
51impl Drop for PrimarySelectionDevice {
52 fn drop(&mut self) {
53 self.device.destroy();
54 }
55}
56
57impl<State> Dispatch<ZwpPrimarySelectionDeviceV1, PrimarySelectionDeviceData, State>
58 for PrimarySelectionManagerState
59where
60 State: Dispatch<ZwpPrimarySelectionDeviceV1, PrimarySelectionDeviceData>
61 + Dispatch<ZwpPrimarySelectionOfferV1, PrimarySelectionOfferData>
62 + PrimarySelectionDeviceHandler
63 + 'static,
64{
65 event_created_child!(State, ZwpPrimarySelectionDeviceV1, [
66 0 => (ZwpPrimarySelectionOfferV1, PrimarySelectionOfferData::default())
67 ]);
68
69 fn event(
70 state: &mut State,
71 proxy: &ZwpPrimarySelectionDeviceV1,
72 event: <ZwpPrimarySelectionDeviceV1 as wayland_client::Proxy>::Event,
73 data: &PrimarySelectionDeviceData,
74 conn: &Connection,
75 qhandle: &QueueHandle<State>,
76 ) {
77 use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_v1::Event;
78 let mut data = data.inner.lock().unwrap();
79 match event {
80 Event::DataOffer { offer } => {
81 // Try to resist faulty compositors.
82 if let Some(pending_offer) = data.pending_offer.take() {
83 pending_offer.destroy();
84 }
85
86 data.pending_offer = Some(offer);
87 }
88 Event::Selection { id } => {
89 // We must drop the current offer regardless.
90 if let Some(offer) = data.offer.take() {
91 offer.destroy();
92 }
93
94 if id == data.pending_offer {
95 data.offer = data.pending_offer.take();
96 } else {
97 // Remove the pending offer, assign the new delivered one.
98 if let Some(offer) = data.pending_offer.take() {
99 offer.destroy()
100 }
101
102 data.offer = id;
103 }
104
105 // Release the user data lock before calling into user.
106 drop(data);
107
108 state.selection(conn, qhandle, proxy);
109 }
110 _ => unreachable!(),
111 }
112 }
113}
114
115/// The user data associated with the [`ZwpPrimarySelectionDeviceV1`].
116#[derive(Debug)]
117pub struct PrimarySelectionDeviceData {
118 /// The seat associated with this device.
119 seat: WlSeat,
120 /// The inner mutable storage.
121 inner: Arc<Mutex<PrimarySelectionDeviceDataInner>>,
122}
123
124impl PrimarySelectionDeviceData {
125 pub(crate) fn new(seat: WlSeat) -> Self {
126 Self { seat, inner: Default::default() }
127 }
128
129 /// The seat used to create this primary selection device.
130 pub fn seat(&self) -> &WlSeat {
131 &self.seat
132 }
133
134 /// The active selection offer.
135 pub fn selection_offer(&self) -> Option<PrimarySelectionOffer> {
136 self.inner
137 .lock()
138 .unwrap()
139 .offer
140 .as_ref()
141 .map(|offer: &{unknown}| PrimarySelectionOffer { offer: offer.clone() })
142 }
143}
144
145#[derive(Debug, Default)]
146struct PrimarySelectionDeviceDataInner {
147 /// The offer is valid until either `NULL` or new selection is received via the
148 /// `selection` event.
149 offer: Option<ZwpPrimarySelectionOfferV1>,
150 /// The offer we've got in `offer` event, but not finished it in `selection`.
151 pending_offer: Option<ZwpPrimarySelectionOfferV1>,
152}
153