data_device: let the compositor generate DnD grabs
This commit is contained in:
parent
d41517f85b
commit
41f1b37834
|
@ -10,25 +10,23 @@ use wayland_server::{
|
||||||
|
|
||||||
use wayland::seat::{AxisFrame, PointerGrab, PointerInnerHandle, Seat};
|
use wayland::seat::{AxisFrame, PointerGrab, PointerInnerHandle, Seat};
|
||||||
|
|
||||||
use super::{with_source_metadata, SeatData};
|
use super::{with_source_metadata, DataDeviceData, SeatData};
|
||||||
|
|
||||||
pub(crate) struct DnDGrab<F: 'static> {
|
pub(crate) struct DnDGrab {
|
||||||
data_source: Option<Resource<wl_data_source::WlDataSource>>,
|
data_source: Option<Resource<wl_data_source::WlDataSource>>,
|
||||||
current_focus: Option<Resource<wl_surface::WlSurface>>,
|
current_focus: Option<Resource<wl_surface::WlSurface>>,
|
||||||
pending_offers: Vec<Resource<wl_data_offer::WlDataOffer>>,
|
pending_offers: Vec<Resource<wl_data_offer::WlDataOffer>>,
|
||||||
offer_data: Option<Arc<Mutex<OfferData>>>,
|
offer_data: Option<Arc<Mutex<OfferData>>>,
|
||||||
origin: Resource<wl_surface::WlSurface>,
|
origin: Resource<wl_surface::WlSurface>,
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
action_choice: Arc<Mutex<F>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: 'static> DnDGrab<F> {
|
impl DnDGrab {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
source: Option<Resource<wl_data_source::WlDataSource>>,
|
source: Option<Resource<wl_data_source::WlDataSource>>,
|
||||||
origin: Resource<wl_surface::WlSurface>,
|
origin: Resource<wl_surface::WlSurface>,
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
action_choice: Arc<Mutex<F>>,
|
) -> DnDGrab {
|
||||||
) -> DnDGrab<F> {
|
|
||||||
DnDGrab {
|
DnDGrab {
|
||||||
data_source: source,
|
data_source: source,
|
||||||
current_focus: None,
|
current_focus: None,
|
||||||
|
@ -36,15 +34,11 @@ impl<F: 'static> DnDGrab<F> {
|
||||||
offer_data: None,
|
offer_data: None,
|
||||||
origin,
|
origin,
|
||||||
seat,
|
seat,
|
||||||
action_choice,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> PointerGrab for DnDGrab<F>
|
impl PointerGrab for DnDGrab {
|
||||||
where
|
|
||||||
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
|
||||||
{
|
|
||||||
fn motion(
|
fn motion(
|
||||||
&mut self,
|
&mut self,
|
||||||
_handle: &mut PointerInnerHandle,
|
_handle: &mut PointerInnerHandle,
|
||||||
|
@ -99,6 +93,11 @@ where
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|d| d.same_client_as(&surface))
|
.filter(|d| d.same_client_as(&surface))
|
||||||
{
|
{
|
||||||
|
let action_choice = device
|
||||||
|
.user_data::<DataDeviceData>()
|
||||||
|
.unwrap()
|
||||||
|
.action_choice
|
||||||
|
.clone();
|
||||||
// create a data offer
|
// create a data offer
|
||||||
let offer = client
|
let offer = client
|
||||||
.create_resource::<wl_data_offer::WlDataOffer>(device.version())
|
.create_resource::<wl_data_offer::WlDataOffer>(device.version())
|
||||||
|
@ -107,7 +106,7 @@ where
|
||||||
offer,
|
offer,
|
||||||
source.clone(),
|
source.clone(),
|
||||||
offer_data.clone(),
|
offer_data.clone(),
|
||||||
self.action_choice.clone(),
|
action_choice,
|
||||||
)
|
)
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
// advertize the offer to the client
|
// advertize the offer to the client
|
||||||
|
@ -233,15 +232,12 @@ struct OfferData {
|
||||||
chosen_action: DndAction,
|
chosen_action: DndAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_dnd_data_offer<F>(
|
fn implement_dnd_data_offer(
|
||||||
offer: NewResource<wl_data_offer::WlDataOffer>,
|
offer: NewResource<wl_data_offer::WlDataOffer>,
|
||||||
source: Resource<wl_data_source::WlDataSource>,
|
source: Resource<wl_data_source::WlDataSource>,
|
||||||
offer_data: Arc<Mutex<OfferData>>,
|
offer_data: Arc<Mutex<OfferData>>,
|
||||||
action_choice: Arc<Mutex<F>>,
|
action_choice: Arc<Mutex<FnMut(DndAction, DndAction) -> DndAction + Send + 'static>>,
|
||||||
) -> Resource<wl_data_offer::WlDataOffer>
|
) -> Resource<wl_data_offer::WlDataOffer> {
|
||||||
where
|
|
||||||
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
|
||||||
{
|
|
||||||
use self::wl_data_offer::Request;
|
use self::wl_data_offer::Request;
|
||||||
offer.implement(
|
offer.implement(
|
||||||
move |req, offer| {
|
move |req, offer| {
|
||||||
|
|
|
@ -14,8 +14,10 @@ use wayland::seat::Seat;
|
||||||
|
|
||||||
mod data_source;
|
mod data_source;
|
||||||
mod dnd_grab;
|
mod dnd_grab;
|
||||||
|
mod server_dnd_grab;
|
||||||
|
|
||||||
pub use self::data_source::{with_source_metadata, SourceMetadata};
|
pub use self::data_source::{with_source_metadata, SourceMetadata};
|
||||||
|
pub use self::server_dnd_grab::ServerDndEvent;
|
||||||
|
|
||||||
/// Events that are generated by interactions of the clients with the data device
|
/// Events that are generated by interactions of the clients with the data device
|
||||||
pub enum DataDeviceEvent {
|
pub enum DataDeviceEvent {
|
||||||
|
@ -25,9 +27,9 @@ pub enum DataDeviceEvent {
|
||||||
DnDStarted(Option<Resource<wl_data_source::WlDataSource>>),
|
DnDStarted(Option<Resource<wl_data_source::WlDataSource>>),
|
||||||
/// A client requested to read the server-set selection
|
/// A client requested to read the server-set selection
|
||||||
SendSelection {
|
SendSelection {
|
||||||
// the requested mime type
|
/// the requested mime type
|
||||||
mime_type: String,
|
mime_type: String,
|
||||||
// the fd to write into
|
/// the fd to write into
|
||||||
fd: RawFd,
|
fd: RawFd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -134,10 +136,7 @@ impl SeatData {
|
||||||
}
|
}
|
||||||
let log = self.log.clone();
|
let log = self.log.clone();
|
||||||
let offer_meta = meta.clone();
|
let offer_meta = meta.clone();
|
||||||
let callback = dd
|
let callback = dd.user_data::<DataDeviceData>().unwrap().callback.clone();
|
||||||
.user_data::<Arc<Mutex<FnMut(DataDeviceEvent) + Send + 'static>>>()
|
|
||||||
.unwrap()
|
|
||||||
.clone();
|
|
||||||
// create a corresponding data offer
|
// create a corresponding data offer
|
||||||
let offer = client
|
let offer = client
|
||||||
.create_resource::<wl_data_offer::WlDataOffer>(dd.version())
|
.create_resource::<wl_data_offer::WlDataOffer>(dd.version())
|
||||||
|
@ -252,6 +251,29 @@ pub fn set_data_device_selection(seat: &Seat, mime_types: Vec<String>) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start a drag'n'drop from a ressource controlled by the compositor
|
||||||
|
///
|
||||||
|
/// You'll receive events generated by the interaction of clients with your
|
||||||
|
/// drag'n'drop in the provided callback.
|
||||||
|
pub fn start_dnd<C>(seat: &Seat, serial: u32, metadata: SourceMetadata, callback: C)
|
||||||
|
where
|
||||||
|
C: FnMut(ServerDndEvent) + Send + 'static,
|
||||||
|
{
|
||||||
|
// TODO: same question as in set_data_device_focus
|
||||||
|
seat.user_data().insert_if_missing(|| {
|
||||||
|
Mutex::new(SeatData::new(
|
||||||
|
seat.arc.log.new(o!("smithay_module" => "data_device_mgr")),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
if let Some(pointer) = seat.get_pointer() {
|
||||||
|
pointer.set_grab(
|
||||||
|
server_dnd_grab::ServerDnDGrab::new(metadata, seat.clone(), Arc::new(Mutex::new(callback))),
|
||||||
|
serial,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn implement_ddm<F, C>(
|
fn implement_ddm<F, C>(
|
||||||
new_ddm: NewResource<wl_data_device_manager::WlDataDeviceManager>,
|
new_ddm: NewResource<wl_data_device_manager::WlDataDeviceManager>,
|
||||||
callback: Arc<Mutex<C>>,
|
callback: Arc<Mutex<C>>,
|
||||||
|
@ -293,6 +315,11 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DataDeviceData {
|
||||||
|
callback: Arc<Mutex<FnMut(DataDeviceEvent) + Send + 'static>>,
|
||||||
|
action_choice: Arc<Mutex<FnMut(DndAction, DndAction) -> DndAction + Send + 'static>>,
|
||||||
|
}
|
||||||
|
|
||||||
fn implement_data_device<F, C>(
|
fn implement_data_device<F, C>(
|
||||||
new_dd: NewResource<wl_data_device::WlDataDevice>,
|
new_dd: NewResource<wl_data_device::WlDataDevice>,
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
|
@ -305,7 +332,10 @@ where
|
||||||
C: FnMut(DataDeviceEvent) + Send + 'static,
|
C: FnMut(DataDeviceEvent) + Send + 'static,
|
||||||
{
|
{
|
||||||
use self::wl_data_device::Request;
|
use self::wl_data_device::Request;
|
||||||
let callback2 = callback.clone();
|
let dd_data = DataDeviceData {
|
||||||
|
callback: callback.clone(),
|
||||||
|
action_choice,
|
||||||
|
};
|
||||||
new_dd.implement(
|
new_dd.implement(
|
||||||
move |req, dd| match req {
|
move |req, dd| match req {
|
||||||
Request::StartDrag {
|
Request::StartDrag {
|
||||||
|
@ -319,10 +349,7 @@ where
|
||||||
if pointer.has_grab(serial) {
|
if pointer.has_grab(serial) {
|
||||||
// The StartDrag is in response to a pointer implicit grab, all is good
|
// The StartDrag is in response to a pointer implicit grab, all is good
|
||||||
(&mut *callback.lock().unwrap())(DataDeviceEvent::DnDStarted(source.clone()));
|
(&mut *callback.lock().unwrap())(DataDeviceEvent::DnDStarted(source.clone()));
|
||||||
pointer.set_grab(
|
pointer.set_grab(dnd_grab::DnDGrab::new(source, origin, seat.clone()), serial);
|
||||||
dnd_grab::DnDGrab::new(source, origin, seat.clone(), action_choice.clone()),
|
|
||||||
serial,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,6 +387,6 @@ where
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None::<fn(_)>,
|
None::<fn(_)>,
|
||||||
callback2 as Arc<Mutex<FnMut(DataDeviceEvent) + Send + 'static>>,
|
dd_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,320 @@
|
||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use wayland_server::{
|
||||||
|
protocol::{wl_data_device, wl_data_device_manager::DndAction, wl_data_offer, wl_pointer, wl_surface},
|
||||||
|
NewResource, Resource,
|
||||||
|
};
|
||||||
|
|
||||||
|
use wayland::seat::{AxisFrame, PointerGrab, PointerInnerHandle, Seat};
|
||||||
|
|
||||||
|
use super::{DataDeviceData, SeatData};
|
||||||
|
|
||||||
|
/// Event generated by the interactions of clients with a server innitiated drag'n'drop
|
||||||
|
pub enum ServerDndEvent {
|
||||||
|
/// The client chose an action
|
||||||
|
Action(DndAction),
|
||||||
|
/// The DnD resource was dropped by the user
|
||||||
|
///
|
||||||
|
/// After that, the client can still interract with your ressource
|
||||||
|
Dropped,
|
||||||
|
/// The Dnd was cancelled
|
||||||
|
///
|
||||||
|
/// The client can no longer interact
|
||||||
|
Cancelled,
|
||||||
|
/// The client requested for data to be sent
|
||||||
|
Send {
|
||||||
|
/// The requested mime type
|
||||||
|
mime_type: String,
|
||||||
|
/// The FD to write into
|
||||||
|
fd: RawFd,
|
||||||
|
},
|
||||||
|
/// The client has finished interacting with the resource
|
||||||
|
///
|
||||||
|
/// This can only happen after the resource was dropped.
|
||||||
|
Finished,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ServerDnDGrab<C: 'static> {
|
||||||
|
metadata: super::SourceMetadata,
|
||||||
|
current_focus: Option<Resource<wl_surface::WlSurface>>,
|
||||||
|
pending_offers: Vec<Resource<wl_data_offer::WlDataOffer>>,
|
||||||
|
offer_data: Option<Arc<Mutex<OfferData>>>,
|
||||||
|
seat: Seat,
|
||||||
|
callback: Arc<Mutex<C>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: 'static> ServerDnDGrab<C> {
|
||||||
|
pub(crate) fn new(
|
||||||
|
metadata: super::SourceMetadata,
|
||||||
|
seat: Seat,
|
||||||
|
callback: Arc<Mutex<C>>,
|
||||||
|
) -> ServerDnDGrab<C> {
|
||||||
|
ServerDnDGrab {
|
||||||
|
metadata,
|
||||||
|
current_focus: None,
|
||||||
|
pending_offers: Vec::with_capacity(1),
|
||||||
|
offer_data: None,
|
||||||
|
seat,
|
||||||
|
callback,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> PointerGrab for ServerDnDGrab<C>
|
||||||
|
where
|
||||||
|
C: FnMut(ServerDndEvent) + Send + 'static,
|
||||||
|
{
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
_handle: &mut PointerInnerHandle,
|
||||||
|
location: (f64, f64),
|
||||||
|
focus: Option<(Resource<wl_surface::WlSurface>, (f64, f64))>,
|
||||||
|
serial: u32,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
let (x, y) = location;
|
||||||
|
let seat_data = self
|
||||||
|
.seat
|
||||||
|
.user_data()
|
||||||
|
.get::<Mutex<SeatData>>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
if focus.as_ref().map(|&(ref s, _)| s) != self.current_focus.as_ref() {
|
||||||
|
// focus changed, we need to make a leave if appropriate
|
||||||
|
if let Some(surface) = self.current_focus.take() {
|
||||||
|
for device in &seat_data.known_devices {
|
||||||
|
if device.same_client_as(&surface) {
|
||||||
|
device.send(wl_data_device::Event::Leave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// disable the offers
|
||||||
|
self.pending_offers.clear();
|
||||||
|
if let Some(offer_data) = self.offer_data.take() {
|
||||||
|
offer_data.lock().unwrap().active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((surface, (sx, sy))) = focus {
|
||||||
|
// early return if the surface is no longer valid
|
||||||
|
let client = match surface.client() {
|
||||||
|
Some(c) => c,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
if self.current_focus.is_none() {
|
||||||
|
// We entered a new surface, send the data offer
|
||||||
|
let offer_data = Arc::new(Mutex::new(OfferData {
|
||||||
|
active: true,
|
||||||
|
dropped: false,
|
||||||
|
accepted: true,
|
||||||
|
chosen_action: DndAction::empty(),
|
||||||
|
}));
|
||||||
|
for device in seat_data
|
||||||
|
.known_devices
|
||||||
|
.iter()
|
||||||
|
.filter(|d| d.same_client_as(&surface))
|
||||||
|
{
|
||||||
|
let action_choice = device
|
||||||
|
.user_data::<DataDeviceData>()
|
||||||
|
.unwrap()
|
||||||
|
.action_choice
|
||||||
|
.clone();
|
||||||
|
// create a data offer
|
||||||
|
let offer = client
|
||||||
|
.create_resource::<wl_data_offer::WlDataOffer>(device.version())
|
||||||
|
.map(|offer| {
|
||||||
|
implement_dnd_data_offer(
|
||||||
|
offer,
|
||||||
|
self.metadata.clone(),
|
||||||
|
offer_data.clone(),
|
||||||
|
self.callback.clone(),
|
||||||
|
action_choice,
|
||||||
|
)
|
||||||
|
}).unwrap();
|
||||||
|
// advertize the offer to the client
|
||||||
|
device.send(wl_data_device::Event::DataOffer { id: offer.clone() });
|
||||||
|
for mime_type in self.metadata.mime_types.iter().cloned() {
|
||||||
|
offer.send(wl_data_offer::Event::Offer { mime_type })
|
||||||
|
}
|
||||||
|
offer.send(wl_data_offer::Event::SourceActions {
|
||||||
|
source_actions: self.metadata.dnd_action.to_raw(),
|
||||||
|
});
|
||||||
|
device.send(wl_data_device::Event::Enter {
|
||||||
|
serial,
|
||||||
|
x: x - sx,
|
||||||
|
y: y - sy,
|
||||||
|
surface: surface.clone(),
|
||||||
|
id: Some(offer.clone()),
|
||||||
|
});
|
||||||
|
self.pending_offers.push(offer);
|
||||||
|
}
|
||||||
|
self.offer_data = Some(offer_data);
|
||||||
|
self.current_focus = Some(surface);
|
||||||
|
} else {
|
||||||
|
// make a move
|
||||||
|
for device in &seat_data.known_devices {
|
||||||
|
if device.same_client_as(&surface) {
|
||||||
|
device.send(wl_data_device::Event::Motion {
|
||||||
|
time,
|
||||||
|
x: x - sx,
|
||||||
|
y: y - sy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
handle: &mut PointerInnerHandle,
|
||||||
|
_button: u32,
|
||||||
|
_state: wl_pointer::ButtonState,
|
||||||
|
serial: u32,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
if handle.current_pressed().len() == 0 {
|
||||||
|
// the user dropped, proceed to the drop
|
||||||
|
let seat_data = self
|
||||||
|
.seat
|
||||||
|
.user_data()
|
||||||
|
.get::<Mutex<SeatData>>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
let validated = if let Some(ref data) = self.offer_data {
|
||||||
|
let data = data.lock().unwrap();
|
||||||
|
data.accepted && (!data.chosen_action.is_empty())
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if let Some(ref surface) = self.current_focus {
|
||||||
|
for device in &seat_data.known_devices {
|
||||||
|
if device.same_client_as(surface) {
|
||||||
|
if validated {
|
||||||
|
device.send(wl_data_device::Event::Drop);
|
||||||
|
} else {
|
||||||
|
device.send(wl_data_device::Event::Leave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ref offer_data) = self.offer_data {
|
||||||
|
let mut data = offer_data.lock().unwrap();
|
||||||
|
if validated {
|
||||||
|
data.dropped = true;
|
||||||
|
} else {
|
||||||
|
data.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut callback = self.callback.lock().unwrap();
|
||||||
|
(&mut *callback)(ServerDndEvent::Dropped);
|
||||||
|
if !validated {
|
||||||
|
(&mut *callback)(ServerDndEvent::Cancelled);
|
||||||
|
}
|
||||||
|
// in all cases abandon the drop
|
||||||
|
// no more buttons are pressed, release the grab
|
||||||
|
handle.unset_grab(serial, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(&mut self, handle: &mut PointerInnerHandle, details: AxisFrame) {
|
||||||
|
// we just forward the axis events as is
|
||||||
|
handle.axis(details);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OfferData {
|
||||||
|
active: bool,
|
||||||
|
dropped: bool,
|
||||||
|
accepted: bool,
|
||||||
|
chosen_action: DndAction,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn implement_dnd_data_offer<C>(
|
||||||
|
offer: NewResource<wl_data_offer::WlDataOffer>,
|
||||||
|
metadata: super::SourceMetadata,
|
||||||
|
offer_data: Arc<Mutex<OfferData>>,
|
||||||
|
callback: Arc<Mutex<C>>,
|
||||||
|
action_choice: Arc<Mutex<FnMut(DndAction, DndAction) -> DndAction + Send + 'static>>,
|
||||||
|
) -> Resource<wl_data_offer::WlDataOffer>
|
||||||
|
where
|
||||||
|
C: FnMut(ServerDndEvent) + Send + 'static,
|
||||||
|
{
|
||||||
|
use self::wl_data_offer::Request;
|
||||||
|
offer.implement(
|
||||||
|
move |req, offer| {
|
||||||
|
let mut data = offer_data.lock().unwrap();
|
||||||
|
match req {
|
||||||
|
Request::Accept { serial: _, mime_type } => {
|
||||||
|
if let Some(mtype) = mime_type {
|
||||||
|
data.accepted = metadata.mime_types.contains(&mtype);
|
||||||
|
} else {
|
||||||
|
data.accepted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Request::Receive { mime_type, fd } => {
|
||||||
|
// check if the source and associated mime type is still valid
|
||||||
|
if metadata.mime_types.contains(&mime_type) && data.active {
|
||||||
|
(&mut *callback.lock().unwrap())(ServerDndEvent::Send { mime_type, fd });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Request::Destroy => {}
|
||||||
|
Request::Finish => {
|
||||||
|
if !data.active {
|
||||||
|
offer.post_error(
|
||||||
|
wl_data_offer::Error::InvalidFinish as u32,
|
||||||
|
"Cannot finish a data offer that is no longer active.".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !data.accepted {
|
||||||
|
offer.post_error(
|
||||||
|
wl_data_offer::Error::InvalidFinish as u32,
|
||||||
|
"Cannot finish a data offer that has not been accepted.".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !data.dropped {
|
||||||
|
offer.post_error(
|
||||||
|
wl_data_offer::Error::InvalidFinish as u32,
|
||||||
|
"Cannot finish a data offer that has not been dropped.".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if data.chosen_action.is_empty() {
|
||||||
|
offer.post_error(
|
||||||
|
wl_data_offer::Error::InvalidFinish as u32,
|
||||||
|
"Cannot finish a data offer with no valid action.".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(&mut *callback.lock().unwrap())(ServerDndEvent::Finished);
|
||||||
|
data.active = false;
|
||||||
|
}
|
||||||
|
Request::SetActions {
|
||||||
|
dnd_actions,
|
||||||
|
preferred_action,
|
||||||
|
} => {
|
||||||
|
let preferred_action = DndAction::from_bits_truncate(preferred_action);
|
||||||
|
if ![DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&preferred_action) {
|
||||||
|
offer.post_error(
|
||||||
|
wl_data_offer::Error::InvalidAction as u32,
|
||||||
|
"Invalid preferred action.".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let possible_actions = metadata.dnd_action & DndAction::from_bits_truncate(dnd_actions);
|
||||||
|
data.chosen_action =
|
||||||
|
(&mut *action_choice.lock().unwrap())(possible_actions, preferred_action);
|
||||||
|
// check that the user provided callback respects that one precise action should be chosen
|
||||||
|
debug_assert!(
|
||||||
|
[DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&data.chosen_action)
|
||||||
|
);
|
||||||
|
offer.send(wl_data_offer::Event::Action {
|
||||||
|
dnd_action: data.chosen_action.to_raw(),
|
||||||
|
});
|
||||||
|
(&mut *callback.lock().unwrap())(ServerDndEvent::Action(data.chosen_action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None::<fn(_)>,
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue