feat: method for peeking dnd offer data
This commit is contained in:
parent
4c65853f51
commit
e84ab6d2d8
3 changed files with 86 additions and 14 deletions
|
|
@ -85,6 +85,18 @@ fn main() {
|
||||||
let s = smithay_clipboard::text::Text::try_from((data, mime_type)).unwrap();
|
let s = smithay_clipboard::text::Text::try_from((data, mime_type)).unwrap();
|
||||||
println!("Received DnD data for {}: {}", id.unwrap_or_default(), s.0);
|
println!("Received DnD data for {}: {}", id.unwrap_or_default(), s.0);
|
||||||
},
|
},
|
||||||
|
smithay_clipboard::dnd::DndEvent::Offer(id, OfferEvent::Motion { x, y }) => {
|
||||||
|
if id != state.offer_hover_id {
|
||||||
|
state.offer_hover_id = id;
|
||||||
|
if let Ok(data) = state.clipboard.peek_offer::<smithay_clipboard::text::Text>(
|
||||||
|
MimeType::Text(smithay_clipboard::mime::Text::TextPlain),
|
||||||
|
) {
|
||||||
|
println!("Peeked the data: {}", data.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Received DnD Motion for {id:?}: at {x}, {y}");
|
||||||
|
},
|
||||||
|
|
||||||
smithay_clipboard::dnd::DndEvent::Offer(id, OfferEvent::Leave) => {
|
smithay_clipboard::dnd::DndEvent::Offer(id, OfferEvent::Leave) => {
|
||||||
if state.internal_dnd {
|
if state.internal_dnd {
|
||||||
if state.pointer_focus {
|
if state.pointer_focus {
|
||||||
|
|
@ -97,12 +109,25 @@ fn main() {
|
||||||
state.clipboard.end_dnd();
|
state.clipboard.end_dnd();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
state.offer_hover_id = None;
|
||||||
println!("Dnd offer left {id:?}.");
|
println!("Dnd offer left {id:?}.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
smithay_clipboard::dnd::DndEvent::Offer(id, OfferEvent::Enter { mime_types, .. }) => {
|
||||||
|
println!("Received DnD Enter for {id:?}");
|
||||||
|
state.offer_hover_id = id;
|
||||||
|
if let Some(mime) = mime_types.get(0) {
|
||||||
|
if let Ok(data) =
|
||||||
|
state.clipboard.peek_offer::<smithay_clipboard::text::Text>(mime.clone())
|
||||||
|
{
|
||||||
|
println!("Peeked the data: {}", data.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
smithay_clipboard::dnd::DndEvent::Source(SourceEvent::Finished) => {
|
smithay_clipboard::dnd::DndEvent::Source(SourceEvent::Finished) => {
|
||||||
println!("Finished sending data.");
|
println!("Finished sending data.");
|
||||||
state.internal_dnd = false;
|
state.internal_dnd = false;
|
||||||
|
state.offer_hover_id = None;
|
||||||
},
|
},
|
||||||
e => {
|
e => {
|
||||||
dbg!(e);
|
dbg!(e);
|
||||||
|
|
@ -172,6 +197,7 @@ fn main() {
|
||||||
internal_dnd: false,
|
internal_dnd: false,
|
||||||
keyboard_focus: false,
|
keyboard_focus: false,
|
||||||
pointer_focus: false,
|
pointer_focus: false,
|
||||||
|
offer_hover_id: None,
|
||||||
loop_handle: event_loop.handle(),
|
loop_handle: event_loop.handle(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -204,6 +230,7 @@ struct SimpleWindow {
|
||||||
internal_dnd: bool,
|
internal_dnd: bool,
|
||||||
keyboard_focus: bool,
|
keyboard_focus: bool,
|
||||||
pointer_focus: bool,
|
pointer_focus: bool,
|
||||||
|
offer_hover_id: Option<u128>,
|
||||||
loop_handle: LoopHandle<'static, SimpleWindow>,
|
loop_handle: LoopHandle<'static, SimpleWindow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||||
use sctk::reexports::client::{Connection, Proxy};
|
use sctk::reexports::client::{Connection, Proxy};
|
||||||
use wayland_backend::client::{InvalidId, ObjectId};
|
use wayland_backend::client::{InvalidId, ObjectId};
|
||||||
|
|
||||||
use crate::mime::{AsMimeTypes, MimeType};
|
use crate::mime::{AllowedMimeTypes, AsMimeTypes, MimeType};
|
||||||
use crate::Clipboard;
|
use crate::Clipboard;
|
||||||
|
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
|
@ -139,6 +139,8 @@ pub enum DndRequest<T> {
|
||||||
content: Box<dyn AsMimeTypes + Send>,
|
content: Box<dyn AsMimeTypes + Send>,
|
||||||
actions: DndAction,
|
actions: DndAction,
|
||||||
},
|
},
|
||||||
|
/// Peek the data of an active DnD offer
|
||||||
|
Peek(MimeType),
|
||||||
/// Set the DnD action chosen by the user.
|
/// Set the DnD action chosen by the user.
|
||||||
SetAction(DndAction),
|
SetAction(DndAction),
|
||||||
/// End an active DnD Source
|
/// End an active DnD Source
|
||||||
|
|
@ -201,6 +203,8 @@ impl<T: RawSurface> Clipboard<T> {
|
||||||
|
|
||||||
/// Register a surface for receiving DnD offers
|
/// Register a surface for receiving DnD offers
|
||||||
/// Rectangles should be provided in order of decreasing priority.
|
/// Rectangles should be provided in order of decreasing priority.
|
||||||
|
/// This method can be called multiple time for a single surface if the
|
||||||
|
/// rectangles change.
|
||||||
pub fn register_dnd_destination(&self, surface: T, rectangles: Vec<DndDestinationRectangle>) {
|
pub fn register_dnd_destination(&self, surface: T, rectangles: Vec<DndDestinationRectangle>) {
|
||||||
let s = DndSurface::new(surface, &self.connection).unwrap();
|
let s = DndSurface::new(surface, &self.connection).unwrap();
|
||||||
|
|
||||||
|
|
@ -215,4 +219,30 @@ impl<T: RawSurface> Clipboard<T> {
|
||||||
.request_sender
|
.request_sender
|
||||||
.send(crate::worker::Command::DndRequest(DndRequest::SetAction(action)));
|
.send(crate::worker::Command::DndRequest(DndRequest::SetAction(action)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Peek at the contents of a DnD offer
|
||||||
|
pub fn peek_offer<D: AllowedMimeTypes + 'static>(
|
||||||
|
&self,
|
||||||
|
mime_type: MimeType,
|
||||||
|
) -> std::io::Result<D> {
|
||||||
|
self.request_sender
|
||||||
|
.send(crate::worker::Command::DndRequest(DndRequest::Peek(mime_type)))
|
||||||
|
.map_err(|_| {
|
||||||
|
std::io::Error::new(std::io::ErrorKind::Other, "Failed to send Peek request.")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.request_receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| {
|
||||||
|
std::io::Error::new(std::io::ErrorKind::Other, "Failed to receive data request.")
|
||||||
|
})
|
||||||
|
.and_then(|ret| {
|
||||||
|
D::try_from(ret?).map_err(|_| {
|
||||||
|
std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
"Failed to convert data to requested type.",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ where
|
||||||
dnd_state.set_actions(self.dnd_state.selected_action, self.dnd_state.selected_action);
|
dnd_state.set_actions(self.dnd_state.selected_action, self.dnd_state.selected_action);
|
||||||
dnd_state.accept_mime_type(dnd_state.serial, Some(mime.to_string()));
|
dnd_state.accept_mime_type(dnd_state.serial, Some(mime.to_string()));
|
||||||
|
|
||||||
_ = self.load_dnd(mime);
|
_ = self.load_dnd(mime, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn offer_enter(
|
pub(crate) fn offer_enter(
|
||||||
|
|
@ -263,6 +263,11 @@ where
|
||||||
self.dnd_state.source_content = None;
|
self.dnd_state.source_content = None;
|
||||||
self.dnd_state.dnd_source = None;
|
self.dnd_state.dnd_source = None;
|
||||||
},
|
},
|
||||||
|
DndRequest::Peek(mime_type) => {
|
||||||
|
if let Err(err) = self.load_dnd(mime_type, true) {
|
||||||
|
_ = self.reply_tx.send(Err(err));
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -341,13 +346,13 @@ where
|
||||||
offer.set_actions(a, a);
|
offer.set_actions(a, a);
|
||||||
|
|
||||||
if let Some(mime_type) = self.dnd_state.selected_mime.clone() {
|
if let Some(mime_type) = self.dnd_state.selected_mime.clone() {
|
||||||
_ = self.load_dnd(mime_type);
|
_ = self.load_dnd(mime_type, false);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load data for the given target.
|
/// Load data for the given target.
|
||||||
pub fn load_dnd(&mut self, mut mime_type: MimeType) -> std::io::Result<()> {
|
pub fn load_dnd(&mut self, mut mime_type: MimeType, peek: bool) -> std::io::Result<()> {
|
||||||
let cur_id = self.cur_id();
|
let cur_id = self.cur_id();
|
||||||
let latest = self
|
let latest = self
|
||||||
.latest_seat
|
.latest_seat
|
||||||
|
|
@ -375,23 +380,33 @@ where
|
||||||
let mut content = Vec::new();
|
let mut content = Vec::new();
|
||||||
let _ = self.loop_handle.insert_source(read_pipe, move |_, file, state| {
|
let _ = self.loop_handle.insert_source(read_pipe, move |_, file, state| {
|
||||||
let file = unsafe { file.get_mut() };
|
let file = unsafe { file.get_mut() };
|
||||||
let Some(tx) = state.dnd_state.sender.as_ref() else {
|
|
||||||
return PostAction::Remove;
|
|
||||||
};
|
|
||||||
loop {
|
loop {
|
||||||
match file.read(&mut reader_buffer) {
|
match file.read(&mut reader_buffer) {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
offer.finish();
|
// only finish if not peeking
|
||||||
let _ = tx.send(DndEvent::Offer(cur_id, OfferEvent::Data {
|
if !peek {
|
||||||
data: mem::take(&mut content),
|
offer.finish();
|
||||||
mime_type: mem::take(&mut mime_type),
|
}
|
||||||
}));
|
|
||||||
|
if peek {
|
||||||
|
_ = state
|
||||||
|
.reply_tx
|
||||||
|
.send(Ok((mem::take(&mut content), mem::take(&mut mime_type))));
|
||||||
|
} else if let Some(tx) = state.dnd_state.sender.as_ref() {
|
||||||
|
let _ = tx.send(DndEvent::Offer(cur_id, OfferEvent::Data {
|
||||||
|
data: mem::take(&mut content),
|
||||||
|
mime_type: mem::take(&mut mime_type),
|
||||||
|
}));
|
||||||
|
}
|
||||||
break PostAction::Remove;
|
break PostAction::Remove;
|
||||||
},
|
},
|
||||||
Ok(n) => content.extend_from_slice(&reader_buffer[..n]),
|
Ok(n) => content.extend_from_slice(&reader_buffer[..n]),
|
||||||
Err(err) if err.kind() == ErrorKind::WouldBlock => break PostAction::Continue,
|
Err(err) if err.kind() == ErrorKind::WouldBlock => break PostAction::Continue,
|
||||||
Err(_) => {
|
Err(err) => {
|
||||||
// let _ = state.dnd_state.sender.unwrap().send(Err(err));
|
if peek {
|
||||||
|
let _ = state.reply_tx.send(Err(err));
|
||||||
|
}
|
||||||
break PostAction::Remove;
|
break PostAction::Remove;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue