use wayland_client::{
protocol::{wl_data_device_manager, wl_data_source},
Attached, DispatchData,
};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::{fs, io};
#[derive(Debug)]
pub struct DataSource {
pub(crate) source: wl_data_source::WlDataSource,
}
#[derive(Debug)]
pub enum DataSourceEvent {
Send {
mime_type: String,
pipe: WritePipe,
},
Target {
mime_type: Option<String>,
},
Action {
action: wl_data_device_manager::DndAction,
},
Cancelled,
Dropped,
Finished,
}
fn data_source_impl<Impl>(
evt: wl_data_source::Event,
source: &wl_data_source::WlDataSource,
implem: &mut Impl,
ddata: DispatchData,
) where
Impl: FnMut(DataSourceEvent, DispatchData),
{
use self::wl_data_source::Event;
let event = match evt {
Event::Target { mime_type } => DataSourceEvent::Target { mime_type },
Event::Send { mime_type, fd } => {
DataSourceEvent::Send { mime_type, pipe: unsafe { FromRawFd::from_raw_fd(fd) } }
}
Event::Action { dnd_action } => DataSourceEvent::Action { action: dnd_action },
Event::Cancelled => {
source.destroy();
DataSourceEvent::Cancelled
}
Event::DndDropPerformed => DataSourceEvent::Dropped,
Event::DndFinished => {
source.destroy();
DataSourceEvent::Finished
}
_ => unreachable!(),
};
implem(event, ddata);
}
impl DataSource {
pub fn new<F, S, It>(
mgr: &Attached<wl_data_device_manager::WlDataDeviceManager>,
mime_types: It,
mut callback: F,
) -> DataSource
where
F: FnMut(DataSourceEvent, DispatchData) + 'static,
S: Into<String>,
It: IntoIterator<Item = S>,
{
let source = mgr.create_data_source();
source.quick_assign(move |source, evt, dispatch_data| {
data_source_impl(evt, &source, &mut callback, dispatch_data)
});
for mime in mime_types {
source.offer(mime.into());
}
DataSource { source: source.detach() }
}
}
#[derive(Debug)]
pub struct WritePipe {
file: fs::File,
}
impl io::Write for WritePipe {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.file.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.file.flush()
}
}
impl FromRawFd for WritePipe {
unsafe fn from_raw_fd(fd: RawFd) -> WritePipe {
WritePipe { file: FromRawFd::from_raw_fd(fd) }
}
}
impl AsRawFd for WritePipe {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl IntoRawFd for WritePipe {
fn into_raw_fd(self) -> RawFd {
self.file.into_raw_fd()
}
}