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