use wayland_client::protocol::{
wl_data_device, wl_data_device_manager, wl_data_offer, wl_seat, wl_surface,
};
use wayland_client::{NewProxy, Proxy, QueueToken};
use wayland_client::protocol::wl_data_device::RequestsTrait as DeviceRequests;
use wayland_client::protocol::wl_data_device_manager::RequestsTrait as MgrRequests;
use wayland_client::protocol::wl_data_source::RequestsTrait as SourceRequests;
use std::sync::{Arc, Mutex};
use super::{DataOffer, DataSource, DndAction};
struct Inner {
selection: Option<DataOffer>,
current_dnd: Option<DataOffer>,
known_offers: Vec<DataOffer>,
}
impl Inner {
fn new_offer(&mut self, offer: NewProxy<wl_data_offer::WlDataOffer>) {
self.known_offers.push(DataOffer::new(offer));
}
fn set_selection(&mut self, offer: Option<Proxy<wl_data_offer::WlDataOffer>>) {
if let Some(offer) = offer {
if let Some(id) = self
.known_offers
.iter()
.position(|o| o.offer.equals(&offer))
{
self.selection = Some(self.known_offers.swap_remove(id));
} else {
panic!("Compositor set an unknown data_offer for selection.");
}
} else {
self.selection = None;
}
}
fn set_dnd(&mut self, offer: Option<Proxy<wl_data_offer::WlDataOffer>>) {
if let Some(offer) = offer {
if let Some(id) = self
.known_offers
.iter()
.position(|o| o.offer.equals(&offer))
{
self.current_dnd = Some(self.known_offers.swap_remove(id));
} else {
panic!("Compositor set an unknown data_offer for selection.");
}
} else {
self.current_dnd = None;
}
}
}
pub struct DataDevice {
device: Proxy<wl_data_device::WlDataDevice>,
inner: Arc<Mutex<Inner>>,
}
pub enum DndEvent<'a> {
Enter {
offer: Option<&'a DataOffer>,
serial: u32,
surface: Proxy<wl_surface::WlSurface>,
x: f64,
y: f64,
},
Motion {
offer: Option<&'a DataOffer>,
time: u32,
x: f64,
y: f64,
},
Leave,
Drop {
offer: Option<&'a DataOffer>,
},
}
fn data_device_implem<Impl>(event: wl_data_device::Event, inner: &mut Inner, implem: &mut Impl)
where
for<'a> Impl: FnMut(DndEvent<'a>),
{
use self::wl_data_device::Event;
match event {
Event::DataOffer { id } => inner.new_offer(id),
Event::Enter {
serial,
surface,
x,
y,
id,
} => {
inner.set_dnd(id);
implem(DndEvent::Enter {
serial,
surface,
x,
y,
offer: inner.current_dnd.as_ref(),
});
}
Event::Motion { time, x, y } => {
implem(DndEvent::Motion {
x,
y,
time,
offer: inner.current_dnd.as_ref(),
});
}
Event::Leave => implem(DndEvent::Leave),
Event::Drop => {
implem(DndEvent::Drop {
offer: inner.current_dnd.as_ref(),
});
}
Event::Selection { id } => inner.set_selection(id),
}
}
impl DataDevice {
pub fn init_for_seat<Impl>(
manager: &Proxy<wl_data_device_manager::WlDataDeviceManager>,
seat: &Proxy<wl_seat::WlSeat>,
mut implem: Impl,
) -> DataDevice
where
for<'a> Impl: FnMut(DndEvent<'a>) + Send + 'static,
{
let inner = Arc::new(Mutex::new(Inner {
selection: None,
current_dnd: None,
known_offers: Vec::new(),
}));
let inner2 = inner.clone();
let device = manager
.get_data_device(seat, move |device| {
device.implement(
move |evt, _| {
let mut inner = inner2.lock().unwrap();
data_device_implem(evt, &mut *inner, &mut implem);
},
(),
)
})
.expect("Invalid data device or seat.");
DataDevice { device, inner }
}
pub unsafe fn init_for_seat_nonsend<Impl>(
manager: &Proxy<wl_data_device_manager::WlDataDeviceManager>,
seat: &Proxy<wl_seat::WlSeat>,
mut implem: Impl,
token: &QueueToken,
) -> DataDevice
where
for<'a> Impl: FnMut(DndEvent<'a>) + Send + 'static,
{
let inner = Arc::new(Mutex::new(Inner {
selection: None,
current_dnd: None,
known_offers: Vec::new(),
}));
let inner2 = inner.clone();
let device = manager
.get_data_device(seat, move |device| {
device.implement_nonsend(
move |evt, _| {
let mut inner = inner2.lock().unwrap();
data_device_implem(evt, &mut *inner, &mut implem);
},
(),
token,
)
})
.expect("Invalid data device or seat.");
DataDevice { device, inner }
}
pub fn start_drag(
&self,
origin: &Proxy<wl_surface::WlSurface>,
source: Option<DataSource>,
actions: DndAction,
icon: Option<&Proxy<wl_surface::WlSurface>>,
serial: u32,
) {
if let Some(source) = source {
source.source.set_actions(actions.to_raw());
self.device
.start_drag(Some(&source.source), origin, icon, serial);
} else {
self.device.start_drag(None, origin, icon, serial);
}
}
pub fn set_selection(&self, source: &Option<DataSource>, serial: u32) {
self.device
.set_selection(source.as_ref().map(|s| &s.source), serial);
}
pub fn with_selection<F, T>(&self, f: F) -> T
where
F: FnOnce(Option<&DataOffer>) -> T,
{
let inner = self.inner.lock().unwrap();
f(inner.selection.as_ref())
}
}
impl Drop for DataDevice {
fn drop(&mut self) {
self.device.release();
}
}