data_device: let the compositor interact with the selection
This commit is contained in:
parent
35645596a8
commit
d41517f85b
|
@ -108,7 +108,12 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
|
||||||
|
|
||||||
let udev_session_id = notifier.register(&mut udev_backend);
|
let udev_session_id = notifier.register(&mut udev_backend);
|
||||||
|
|
||||||
init_data_device(&mut display.borrow_mut(), ::misc::dnd_action_chooser, log.clone());
|
init_data_device(
|
||||||
|
&mut display.borrow_mut(),
|
||||||
|
|_| {},
|
||||||
|
::misc::dnd_action_chooser,
|
||||||
|
log.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let (mut w_seat, _) = Seat::new(&mut display.borrow_mut(), session.seat(), log.clone());
|
let (mut w_seat, _) = Seat::new(&mut display.borrow_mut(), session.seat(), log.clone());
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
|
||||||
|
|
||||||
let (compositor_token, _, _, window_map) = init_shell(display, log.clone());
|
let (compositor_token, _, _, window_map) = init_shell(display, log.clone());
|
||||||
|
|
||||||
init_data_device(display, ::misc::dnd_action_chooser, log.clone());
|
init_data_device(display, |_| {}, ::misc::dnd_action_chooser, log.clone());
|
||||||
|
|
||||||
let (mut seat, _) = Seat::new(display, "winit".into(), log.clone());
|
let (mut seat, _) = Seat::new(display, "winit".into(), log.clone());
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::os::unix::io::RawFd;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use wayland_server::{
|
use wayland_server::{
|
||||||
|
@ -16,9 +17,25 @@ mod dnd_grab;
|
||||||
|
|
||||||
pub use self::data_source::{with_source_metadata, SourceMetadata};
|
pub use self::data_source::{with_source_metadata, SourceMetadata};
|
||||||
|
|
||||||
|
/// Events that are generated by interactions of the clients with the data device
|
||||||
|
pub enum DataDeviceEvent {
|
||||||
|
/// A client has set the selection
|
||||||
|
NewSelection(Option<Resource<wl_data_source::WlDataSource>>),
|
||||||
|
/// A client started a drag'n'drop as response to a user pointer action
|
||||||
|
DnDStarted(Option<Resource<wl_data_source::WlDataSource>>),
|
||||||
|
/// A client requested to read the server-set selection
|
||||||
|
SendSelection {
|
||||||
|
// the requested mime type
|
||||||
|
mime_type: String,
|
||||||
|
// the fd to write into
|
||||||
|
fd: RawFd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
enum Selection {
|
enum Selection {
|
||||||
Empty,
|
Empty,
|
||||||
Client(Resource<wl_data_source::WlDataSource>),
|
Client(Resource<wl_data_source::WlDataSource>),
|
||||||
|
Compositor(SourceMetadata),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SeatData {
|
struct SeatData {
|
||||||
|
@ -109,6 +126,50 @@ impl SeatData {
|
||||||
dd.send(wl_data_device::Event::Selection { id: Some(offer) });
|
dd.send(wl_data_device::Event::Selection { id: Some(offer) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Selection::Compositor(ref meta) => {
|
||||||
|
for dd in &self.known_devices {
|
||||||
|
// skip data devices not belonging to our client
|
||||||
|
if dd.client().map(|c| !c.equals(client)).unwrap_or(true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let log = self.log.clone();
|
||||||
|
let offer_meta = meta.clone();
|
||||||
|
let callback = dd
|
||||||
|
.user_data::<Arc<Mutex<FnMut(DataDeviceEvent) + Send + 'static>>>()
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
// create a corresponding data offer
|
||||||
|
let offer = client
|
||||||
|
.create_resource::<wl_data_offer::WlDataOffer>(dd.version())
|
||||||
|
.unwrap()
|
||||||
|
.implement(
|
||||||
|
move |req, _offer| match req {
|
||||||
|
wl_data_offer::Request::Receive { fd, mime_type } => {
|
||||||
|
// check if the associated mime type is valid
|
||||||
|
if !offer_meta.mime_types.contains(&mime_type) {
|
||||||
|
// deny the receive
|
||||||
|
debug!(log, "Denying a wl_data_offer.receive with invalid source.");
|
||||||
|
let _ = ::nix::unistd::close(fd);
|
||||||
|
} else {
|
||||||
|
(&mut *callback.lock().unwrap())(DataDeviceEvent::SendSelection {
|
||||||
|
mime_type,
|
||||||
|
fd,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => { /* seleciton data offers only care about the `receive` event */ }
|
||||||
|
},
|
||||||
|
None::<fn(_)>,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
// advertize the offer to the client
|
||||||
|
dd.send(wl_data_device::Event::DataOffer { id: offer.clone() });
|
||||||
|
for mime_type in meta.mime_types.iter().cloned() {
|
||||||
|
offer.send(wl_data_offer::Event::Offer { mime_type })
|
||||||
|
}
|
||||||
|
dd.send(wl_data_device::Event::Selection { id: Some(offer) });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,19 +192,22 @@ impl SeatData {
|
||||||
/// available actions (which is the intersection of the actions supported by the source and targets)
|
/// available actions (which is the intersection of the actions supported by the source and targets)
|
||||||
/// and the second argument is the preferred action reported by the target. If no action should be
|
/// and the second argument is the preferred action reported by the target. If no action should be
|
||||||
/// chosen (and thus the drag'n'drop should abort on drop), return `DndAction::empty()`.
|
/// chosen (and thus the drag'n'drop should abort on drop), return `DndAction::empty()`.
|
||||||
pub fn init_data_device<F, L>(
|
pub fn init_data_device<F, C, L>(
|
||||||
display: &mut Display,
|
display: &mut Display,
|
||||||
|
callback: C,
|
||||||
action_choice: F,
|
action_choice: F,
|
||||||
logger: L,
|
logger: L,
|
||||||
) -> Global<wl_data_device_manager::WlDataDeviceManager>
|
) -> Global<wl_data_device_manager::WlDataDeviceManager>
|
||||||
where
|
where
|
||||||
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
||||||
|
C: FnMut(DataDeviceEvent) + Send + 'static,
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "data_device_mgr"));
|
let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "data_device_mgr"));
|
||||||
let action_choice = Arc::new(Mutex::new(action_choice));
|
let action_choice = Arc::new(Mutex::new(action_choice));
|
||||||
|
let callback = Arc::new(Mutex::new(callback));
|
||||||
let global = display.create_global(3, move |new_ddm, _version| {
|
let global = display.create_global(3, move |new_ddm, _version| {
|
||||||
implement_ddm(new_ddm, action_choice.clone(), log.clone());
|
implement_ddm(new_ddm, callback.clone(), action_choice.clone(), log.clone());
|
||||||
});
|
});
|
||||||
|
|
||||||
global
|
global
|
||||||
|
@ -165,13 +229,38 @@ pub fn set_data_device_focus(seat: &Seat, client: Option<Client>) {
|
||||||
seat_data.lock().unwrap().set_focus(client);
|
seat_data.lock().unwrap().set_focus(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_ddm<F>(
|
/// Set a compositor-provided selection for this seat
|
||||||
|
///
|
||||||
|
/// You need to provide the available mime types for this selection.
|
||||||
|
///
|
||||||
|
/// Whenever a client requests to read the selection, your callback will
|
||||||
|
/// receive a `DataDeviceEvent::SendSelection` event.
|
||||||
|
pub fn set_data_device_selection(seat: &Seat, mime_types: Vec<String>) {
|
||||||
|
// 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")),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
let seat_data = seat.user_data().get::<Mutex<SeatData>>().unwrap();
|
||||||
|
seat_data
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_selection(Selection::Compositor(SourceMetadata {
|
||||||
|
mime_types,
|
||||||
|
dnd_action: DndAction::empty(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
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>>,
|
||||||
action_choice: Arc<Mutex<F>>,
|
action_choice: Arc<Mutex<F>>,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
) -> Resource<wl_data_device_manager::WlDataDeviceManager>
|
) -> Resource<wl_data_device_manager::WlDataDeviceManager>
|
||||||
where
|
where
|
||||||
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
||||||
|
C: FnMut(DataDeviceEvent) + Send + 'static,
|
||||||
{
|
{
|
||||||
use self::wl_data_device_manager::Request;
|
use self::wl_data_device_manager::Request;
|
||||||
new_ddm.implement(
|
new_ddm.implement(
|
||||||
|
@ -185,8 +274,13 @@ where
|
||||||
seat.user_data()
|
seat.user_data()
|
||||||
.insert_if_missing(|| Mutex::new(SeatData::new(log.clone())));
|
.insert_if_missing(|| Mutex::new(SeatData::new(log.clone())));
|
||||||
let seat_data = seat.user_data().get::<Mutex<SeatData>>().unwrap();
|
let seat_data = seat.user_data().get::<Mutex<SeatData>>().unwrap();
|
||||||
let data_device =
|
let data_device = implement_data_device(
|
||||||
implement_data_device(id, seat.clone(), action_choice.clone(), log.clone());
|
id,
|
||||||
|
seat.clone(),
|
||||||
|
callback.clone(),
|
||||||
|
action_choice.clone(),
|
||||||
|
log.clone(),
|
||||||
|
);
|
||||||
seat_data.lock().unwrap().known_devices.push(data_device);
|
seat_data.lock().unwrap().known_devices.push(data_device);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -199,16 +293,19 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_data_device<F>(
|
fn implement_data_device<F, C>(
|
||||||
new_dd: NewResource<wl_data_device::WlDataDevice>,
|
new_dd: NewResource<wl_data_device::WlDataDevice>,
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
|
callback: Arc<Mutex<C>>,
|
||||||
action_choice: Arc<Mutex<F>>,
|
action_choice: Arc<Mutex<F>>,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
) -> Resource<wl_data_device::WlDataDevice>
|
) -> Resource<wl_data_device::WlDataDevice>
|
||||||
where
|
where
|
||||||
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
F: FnMut(DndAction, DndAction) -> DndAction + Send + 'static,
|
||||||
|
C: FnMut(DataDeviceEvent) + Send + 'static,
|
||||||
{
|
{
|
||||||
use self::wl_data_device::Request;
|
use self::wl_data_device::Request;
|
||||||
|
let callback2 = callback.clone();
|
||||||
new_dd.implement(
|
new_dd.implement(
|
||||||
move |req, dd| match req {
|
move |req, dd| match req {
|
||||||
Request::StartDrag {
|
Request::StartDrag {
|
||||||
|
@ -221,6 +318,7 @@ where
|
||||||
if let Some(pointer) = seat.get_pointer() {
|
if let Some(pointer) = seat.get_pointer() {
|
||||||
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()));
|
||||||
pointer.set_grab(
|
pointer.set_grab(
|
||||||
dnd_grab::DnDGrab::new(source, origin, seat.clone(), action_choice.clone()),
|
dnd_grab::DnDGrab::new(source, origin, seat.clone(), action_choice.clone()),
|
||||||
serial,
|
serial,
|
||||||
|
@ -239,6 +337,7 @@ where
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
let seat_data = seat.user_data().get::<Mutex<SeatData>>().unwrap();
|
let seat_data = seat.user_data().get::<Mutex<SeatData>>().unwrap();
|
||||||
|
(&mut *callback.lock().unwrap())(DataDeviceEvent::NewSelection(source.clone()));
|
||||||
// The client has kbd focus, it can set the selection
|
// The client has kbd focus, it can set the selection
|
||||||
seat_data
|
seat_data
|
||||||
.lock()
|
.lock()
|
||||||
|
@ -261,6 +360,6 @@ where
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None::<fn(_)>,
|
None::<fn(_)>,
|
||||||
(),
|
callback2 as Arc<Mutex<FnMut(DataDeviceEvent) + Send + 'static>>,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue