Skip to main content

smithay_client_toolkit/primary_selection/
device.rs

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