1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use crate::error::GlobalError;
use crate::globals::{GlobalData, ProvidesBoundGlobal};
use crate::reexports::client::{
    globals::{BindError, GlobalList},
    protocol::{
        wl_data_device,
        wl_data_device_manager::{self, DndAction, WlDataDeviceManager},
        wl_data_source::WlDataSource,
        wl_seat::WlSeat,
    },
    Connection, Dispatch, Proxy, QueueHandle,
};

pub mod data_device;
pub mod data_offer;
pub mod data_source;
mod read_pipe;
mod write_pipe;

pub use read_pipe::*;
pub use write_pipe::*;

use data_device::{DataDevice, DataDeviceData};
use data_source::{CopyPasteSource, DataSourceData, DragSource};

#[derive(Debug)]
pub struct DataDeviceManagerState {
    manager: WlDataDeviceManager,
}

impl DataDeviceManagerState {
    pub fn bind<State>(globals: &GlobalList, qh: &QueueHandle<State>) -> Result<Self, BindError>
    where
        State: Dispatch<WlDataDeviceManager, GlobalData, State> + 'static,
    {
        let manager = globals.bind(qh, 1..=3, GlobalData)?;
        Ok(Self { manager })
    }

    pub fn data_device_manager(&self) -> &WlDataDeviceManager {
        &self.manager
    }

    /// creates a data source for copy paste
    pub fn create_copy_paste_source<D, T: ToString>(
        &self,
        qh: &QueueHandle<D>,
        mime_types: impl IntoIterator<Item = T>,
    ) -> CopyPasteSource
    where
        D: Dispatch<WlDataSource, DataSourceData> + 'static,
    {
        CopyPasteSource { inner: self.create_data_source(qh, mime_types, None) }
    }

    /// creates a data source for drag and drop
    pub fn create_drag_and_drop_source<D, T: ToString>(
        &self,
        qh: &QueueHandle<D>,
        mime_types: impl IntoIterator<Item = T>,
        dnd_actions: DndAction,
    ) -> DragSource
    where
        D: Dispatch<WlDataSource, DataSourceData> + 'static,
    {
        DragSource { inner: self.create_data_source(qh, mime_types, Some(dnd_actions)) }
    }

    /// creates a data source
    fn create_data_source<D, T: ToString>(
        &self,
        qh: &QueueHandle<D>,
        mime_types: impl IntoIterator<Item = T>,
        dnd_actions: Option<DndAction>,
    ) -> WlDataSource
    where
        D: Dispatch<WlDataSource, DataSourceData> + 'static,
    {
        let source = self.manager.create_data_source(qh, Default::default());

        for mime in mime_types {
            source.offer(mime.to_string());
        }

        if self.manager.version() >= 3 {
            if let Some(dnd_actions) = dnd_actions {
                source.set_actions(dnd_actions);
            }
        }

        source
    }

    /// create a new data device for a given seat
    pub fn get_data_device<D>(&self, qh: &QueueHandle<D>, seat: &WlSeat) -> DataDevice
    where
        D: Dispatch<wl_data_device::WlDataDevice, DataDeviceData> + 'static,
    {
        let data = DataDeviceData::new(seat.clone());
        DataDevice { device: self.manager.get_data_device(seat, qh, data) }
    }
}

impl ProvidesBoundGlobal<WlDataDeviceManager, 3> for DataDeviceManagerState {
    fn bound_global(&self) -> Result<WlDataDeviceManager, GlobalError> {
        Ok(self.manager.clone())
    }
}

impl<D> Dispatch<wl_data_device_manager::WlDataDeviceManager, GlobalData, D>
    for DataDeviceManagerState
where
    D: Dispatch<wl_data_device_manager::WlDataDeviceManager, GlobalData>,
{
    fn event(
        _state: &mut D,
        _proxy: &wl_data_device_manager::WlDataDeviceManager,
        _event: <wl_data_device_manager::WlDataDeviceManager as wayland_client::Proxy>::Event,
        _data: &GlobalData,
        _conn: &Connection,
        _qhandle: &QueueHandle<D>,
    ) {
        unreachable!("wl_data_device_manager has no events")
    }
}

#[macro_export]
macro_rules! delegate_data_device {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
            [
                $crate::reexports::client::protocol::wl_data_device_manager::WlDataDeviceManager: $crate::globals::GlobalData
            ] => $crate::data_device_manager::DataDeviceManagerState);
        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
            [
                $crate::reexports::client::protocol::wl_data_offer::WlDataOffer: $crate::data_device_manager::data_offer::DataOfferData
            ] => $crate::data_device_manager::DataDeviceManagerState);
        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
            [
                $crate::reexports::client::protocol::wl_data_source::WlDataSource: $crate::data_device_manager::data_source::DataSourceData
            ] => $crate::data_device_manager::DataDeviceManagerState
        );
        $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
            [
                $crate::reexports::client::protocol::wl_data_device::WlDataDevice: $crate::data_device_manager::data_device::DataDeviceData
            ] => $crate::data_device_manager::DataDeviceManagerState
        );
    };
}