use std::{cell::RefCell, rc::Rc};
use wayland_client::{
protocol::{wl_data_device_manager, wl_registry, wl_seat},
Attached, DispatchData,
};
pub use wayland_client::protocol::wl_data_device_manager::DndAction;
mod device;
mod offer;
mod source;
pub use self::device::{DataDevice, DndEvent};
pub use self::offer::{DataOffer, ReadPipe};
pub use self::source::{DataSource, DataSourceEvent, WritePipe};
type DDCallback = dyn FnMut(wl_seat::WlSeat, DndEvent, DispatchData);
enum DDInner {
Ready {
mgr: Attached<wl_data_device_manager::WlDataDeviceManager>,
devices: Vec<(wl_seat::WlSeat, DataDevice)>,
callback: Rc<RefCell<Box<DDCallback>>>,
},
Pending {
seats: Vec<wl_seat::WlSeat>,
},
}
impl DDInner {
fn init_dd_mgr(&mut self, mgr: Attached<wl_data_device_manager::WlDataDeviceManager>) {
let seats = if let DDInner::Pending { seats } = self {
::std::mem::replace(seats, Vec::new())
} else {
log::warn!("Ignoring second wl_data_device_manager.");
return;
};
let mut devices = Vec::new();
let callback = Rc::new(RefCell::new(Box::new(|_, _: DndEvent, _: DispatchData| {})
as Box<dyn FnMut(_, DndEvent, DispatchData)>));
for seat in seats {
let cb = callback.clone();
let my_seat = seat.clone();
let device = DataDevice::init_for_seat(&mgr, &seat, move |event, dispatch_data| {
(&mut *cb.borrow_mut())(my_seat.clone(), event, dispatch_data);
});
devices.push((seat.clone(), device));
}
*self = DDInner::Ready { mgr, devices, callback };
}
fn new_seat(&mut self, seat: &wl_seat::WlSeat) {
match self {
DDInner::Ready { mgr, devices, callback } => {
if devices.iter().any(|(s, _)| s == seat) {
return;
}
let cb = callback.clone();
let my_seat = seat.clone();
let device = DataDevice::init_for_seat(mgr, seat, move |event, dispatch_data| {
(&mut *cb.borrow_mut())(my_seat.clone(), event, dispatch_data);
});
devices.push((seat.clone(), device));
}
DDInner::Pending { seats } => {
seats.push(seat.clone());
}
}
}
fn remove_seat(&mut self, seat: &wl_seat::WlSeat) {
match self {
DDInner::Ready { devices, .. } => devices.retain(|(s, _)| s != seat),
DDInner::Pending { seats } => seats.retain(|s| s != seat),
}
}
fn get_mgr(&self) -> Option<Attached<wl_data_device_manager::WlDataDeviceManager>> {
match self {
DDInner::Ready { mgr, .. } => Some(mgr.clone()),
DDInner::Pending { .. } => None,
}
}
fn set_callback<F: FnMut(wl_seat::WlSeat, DndEvent, DispatchData) + 'static>(
&mut self,
cb: F,
) -> Result<(), ()> {
match self {
DDInner::Ready { callback, .. } => {
*(callback.borrow_mut()) = Box::new(cb);
Ok(())
}
DDInner::Pending { .. } => Err(()),
}
}
fn with_device<F: FnOnce(&DataDevice)>(&self, seat: &wl_seat::WlSeat, f: F) -> Result<(), ()> {
match self {
DDInner::Pending { .. } => Err(()),
DDInner::Ready { devices, .. } => {
for (s, device) in devices {
if s == seat {
f(device);
return Ok(());
}
}
Err(())
}
}
}
}
pub struct DataDeviceHandler {
inner: Rc<RefCell<DDInner>>,
_listener: crate::seat::SeatListener,
}
impl DataDeviceHandler {
pub fn init<S>(seat_handler: &mut S) -> DataDeviceHandler
where
S: crate::seat::SeatHandling,
{
let inner = Rc::new(RefCell::new(DDInner::Pending { seats: Vec::new() }));
let seat_inner = inner.clone();
let listener = seat_handler.listen(move |seat, seat_data, _| {
if seat_data.defunct {
seat_inner.borrow_mut().remove_seat(&seat);
} else {
seat_inner.borrow_mut().new_seat(&seat)
}
});
DataDeviceHandler { inner, _listener: listener }
}
}
impl crate::environment::GlobalHandler<wl_data_device_manager::WlDataDeviceManager>
for DataDeviceHandler
{
fn created(
&mut self,
registry: Attached<wl_registry::WlRegistry>,
id: u32,
version: u32,
_: DispatchData,
) {
let version = std::cmp::min(version, 3);
let ddmgr = registry.bind::<wl_data_device_manager::WlDataDeviceManager>(version, id);
self.inner.borrow_mut().init_dd_mgr((*ddmgr).clone());
}
fn get(&self) -> Option<Attached<wl_data_device_manager::WlDataDeviceManager>> {
self.inner.borrow().get_mgr()
}
}
pub trait DataDeviceHandling {
fn set_callback<F: FnMut(wl_seat::WlSeat, DndEvent, DispatchData) + 'static>(
&mut self,
callback: F,
) -> Result<(), ()>;
fn with_device<F: FnOnce(&DataDevice)>(&self, seat: &wl_seat::WlSeat, f: F) -> Result<(), ()>;
}
impl DataDeviceHandling for DataDeviceHandler {
fn set_callback<F: FnMut(wl_seat::WlSeat, DndEvent, DispatchData) + 'static>(
&mut self,
callback: F,
) -> Result<(), ()> {
self.inner.borrow_mut().set_callback(callback)
}
fn with_device<F: FnOnce(&DataDevice)>(&self, seat: &wl_seat::WlSeat, f: F) -> Result<(), ()> {
self.inner.borrow().with_device(seat, f)
}
}
impl<E> crate::environment::Environment<E>
where
E: crate::environment::GlobalHandler<wl_data_device_manager::WlDataDeviceManager>,
{
pub fn new_data_source<F>(&self, mime_types: Vec<String>, callback: F) -> DataSource
where
F: FnMut(DataSourceEvent, DispatchData) + 'static,
{
let ddmgr = self.require_global::<wl_data_device_manager::WlDataDeviceManager>();
DataSource::new(&ddmgr, mime_types, callback)
}
}
impl<E> crate::environment::Environment<E>
where
E: DataDeviceHandling,
{
pub fn set_data_device_callback<F: FnMut(wl_seat::WlSeat, DndEvent, DispatchData) + 'static>(
&mut self,
callback: F,
) -> Result<(), ()> {
self.with_inner(|inner| inner.set_callback(callback))
}
pub fn with_data_device<F: FnOnce(&DataDevice)>(
&self,
seat: &wl_seat::WlSeat,
f: F,
) -> Result<(), ()> {
self.with_inner(|inner| inner.with_device(seat, f))
}
}