use wayland_client::protocol::wl_data_device_manager::DndAction;
use wayland_client::protocol::wl_data_offer;
use wayland_client::{NewProxy, Proxy};
use wayland_client::protocol::wl_data_offer::RequestsTrait as OfferRequests;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::sync::{Arc, Mutex};
use std::{fs, io};
struct Inner {
mime_types: Vec<String>,
actions: DndAction,
current_action: DndAction,
serial: u32,
}
pub struct DataOffer {
pub(crate) offer: Proxy<wl_data_offer::WlDataOffer>,
inner: Arc<Mutex<Inner>>,
}
impl DataOffer {
pub(crate) fn new(offer: NewProxy<wl_data_offer::WlDataOffer>) -> DataOffer {
let inner = Arc::new(Mutex::new(Inner {
mime_types: Vec::new(),
actions: DndAction::None,
current_action: DndAction::None,
serial: 0,
}));
let inner2 = inner.clone();
let offer = offer.implement(
move |event, _| {
use self::wl_data_offer::Event;
let mut inner = inner2.lock().unwrap();
match event {
Event::Offer { mime_type } => {
inner.mime_types.push(mime_type);
}
Event::SourceActions { source_actions } => {
inner.actions = DndAction::from_bits_truncate(source_actions);
}
Event::Action { dnd_action } => {
inner.current_action = DndAction::from_bits_truncate(dnd_action);
}
}
},
(),
);
DataOffer { offer, inner }
}
pub fn with_mime_types<F, T>(&self, f: F) -> T
where
F: FnOnce(&[String]) -> T,
{
let inner = self.inner.lock().unwrap();
f(&inner.mime_types)
}
pub fn get_available_actions(&self) -> DndAction {
self.inner.lock().unwrap().actions
}
pub fn get_current_action(&self) -> DndAction {
self.inner.lock().unwrap().current_action
}
pub fn accept(&self, mime_type: Option<String>) {
let serial = self.inner.lock().unwrap().serial;
self.offer.accept(serial, mime_type);
}
pub fn receive(&self, mime_type: String) -> Result<ReadPipe, ()> {
use nix::fcntl::OFlag;
use nix::unistd::{close, pipe2};
let (readfd, writefd) = pipe2(OFlag::O_CLOEXEC).map_err(|_| ())?;
self.offer.receive(mime_type, writefd);
if let Err(err) = close(writefd) {
eprintln!("[SCTK] Data offer: failed to close write pipe: {}", err);
}
Ok(unsafe { FromRawFd::from_raw_fd(readfd) })
}
pub fn set_actions(&self, supported: DndAction, preferred: DndAction) {
self.offer
.set_actions(supported.to_raw(), preferred.to_raw());
}
pub fn finish(&self) {
self.offer.finish();
self.offer.destroy();
}
}
impl Drop for DataOffer {
fn drop(&mut self) {
self.offer.destroy();
}
}
pub struct ReadPipe {
file: fs::File,
}
impl io::Read for ReadPipe {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.file.read(buf)
}
}
impl FromRawFd for ReadPipe {
unsafe fn from_raw_fd(fd: RawFd) -> ReadPipe {
ReadPipe {
file: FromRawFd::from_raw_fd(fd),
}
}
}
impl AsRawFd for ReadPipe {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl IntoRawFd for ReadPipe {
fn into_raw_fd(self) -> RawFd {
self.file.into_raw_fd()
}
}