1
1
mirror of https://github.com/wez/wezterm.git synced 2024-10-26 15:52:29 +03:00

Implement dispatch_dropped_files

This commit is contained in:
Timmy Xiao 2024-01-22 14:45:18 -08:00 committed by Wez Furlong
parent 5d6e7c4f98
commit 21a6b0636a
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
5 changed files with 100 additions and 71 deletions

View File

@ -9,19 +9,56 @@ use smithay_client_toolkit::data_device_manager::data_device::{
use smithay_client_toolkit::data_device_manager::data_offer::DataOfferHandler;
use smithay_client_toolkit::data_device_manager::data_source::DataSourceHandler;
use smithay_client_toolkit::data_device_manager::WritePipe;
use wayland_client::protocol::wl_data_device_manager::DndAction;
use wayland_client::Proxy;
use crate::wayland::drag_and_drop::SurfaceAndOffer;
use crate::wayland::pointer::PointerUserData;
use crate::wayland::SurfaceUserData;
use super::drag_and_drop::{DragAndDrop, SurfaceAndPipe};
use super::state::WaylandState;
pub(super) const TEXT_MIME_TYPE: &str = "text/plain;charset=utf-8";
pub(super) const URI_MIME_TYPE: &str = "text/uri-list";
impl DataDeviceHandler for WaylandState {
fn enter(
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
_data_device: DataDevice,
data_device: DataDevice,
) {
todo!()
let mut drag_offer = data_device.drag_offer().unwrap();
log::trace!(
"Data offer entered: {:?}, mime_types: {:?}",
drag_offer,
data_device.drag_mime_types()
);
if let Some(m) = data_device
.drag_mime_types()
.iter()
.find(|s| *s == URI_MIME_TYPE)
{
drag_offer.accept_mime_type(*self.last_serial.borrow(), Some(m.clone()));
}
drag_offer.set_actions(DndAction::None | DndAction::Copy, DndAction::None);
let pointer = self.pointer.as_mut().unwrap();
let mut pstate = pointer
.pointer()
.data::<PointerUserData>()
.unwrap()
.state
.lock()
.unwrap();
let offer = drag_offer.inner().clone();
let window_id = SurfaceUserData::from_wl(&drag_offer.surface).window_id;
pstate.drag_and_drop.offer = Some(SurfaceAndOffer { window_id, offer });
}
fn leave(
@ -30,7 +67,17 @@ impl DataDeviceHandler for WaylandState {
_qh: &wayland_client::QueueHandle<Self>,
_data_device: DataDevice,
) {
todo!()
let pointer = self.pointer.as_mut().unwrap();
let mut pstate = pointer
.pointer()
.data::<PointerUserData>()
.unwrap()
.state
.lock()
.unwrap();
if let Some(SurfaceAndOffer { offer, .. }) = pstate.drag_and_drop.offer.take() {
offer.destroy();
}
}
fn motion(
@ -39,7 +86,6 @@ impl DataDeviceHandler for WaylandState {
_qh: &wayland_client::QueueHandle<Self>,
_data_device: DataDevice,
) {
todo!()
}
fn selection(
@ -48,6 +94,7 @@ impl DataDeviceHandler for WaylandState {
_qh: &wayland_client::QueueHandle<Self>,
data_device: DataDevice,
) {
// TODO: handle mime types
if let Some(offer) = data_device.selection_offer() {
if let Some(copy_and_paste) = self.resolve_copy_and_paste() {
copy_and_paste
@ -64,7 +111,23 @@ impl DataDeviceHandler for WaylandState {
_qh: &wayland_client::QueueHandle<Self>,
_data_device: DataDevice,
) {
todo!()
let pointer = self.pointer.as_mut().unwrap();
let mut pstate = pointer
.pointer()
.data::<PointerUserData>()
.unwrap()
.state
.lock()
.unwrap();
let drag_and_drop = &mut pstate.drag_and_drop;
if let Some(SurfaceAndPipe { window_id, read }) = drag_and_drop.create_pipe_for_drop() {
std::thread::spawn(move || {
if let Some(paths) = DragAndDrop::read_paths_from_pipe(read) {
DragAndDrop::dispatch_dropped_files(window_id, paths);
}
});
}
// if let Some(SurfaceAndOffer { offer, .. }) = pstate.drag_and_drop.offer.take() {
}
}

View File

@ -1,46 +1,45 @@
use crate::connection::ConnectionOps;
use crate::wayland::{read_pipe_with_timeout, WaylandConnection};
use crate::wayland::read_pipe_with_timeout;
use crate::ConnectionOps;
use filedescriptor::{FileDescriptor, Pipe};
use smithay_client_toolkit as toolkit;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use toolkit::reexports::client::protocol::wl_data_device::Event as DataDeviceEvent;
use toolkit::reexports::client::protocol::wl_data_offer::WlDataOffer;
use url::Url;
use wayland_client::protocol::wl_data_device_manager::DndAction;
use super::data_device::URI_MIME_TYPE;
use super::WaylandConnection;
#[derive(Default)]
pub struct DragAndDrop {
offer: Option<SurfaceAndOffer>,
pub(super) offer: Option<SurfaceAndOffer>,
}
struct SurfaceAndOffer {
surface_id: u32,
offer: WlDataOffer,
pub(super) struct SurfaceAndOffer {
pub(super) window_id: usize,
pub(super) offer: WlDataOffer,
}
struct SurfaceAndPipe {
surface_id: u32,
read: FileDescriptor,
pub(super) struct SurfaceAndPipe {
pub(super) window_id: usize,
pub(super) read: FileDescriptor,
}
pub const URI_MIME_TYPE: &str = "text/uri-list";
impl DragAndDrop {
/// Takes the current offer, if any, and initiates a receive into a pipe,
/// returning that surface and pipe descriptor.
fn create_pipe_for_drop(&mut self) -> Option<SurfaceAndPipe> {
let SurfaceAndOffer { surface_id, offer } = self.offer.take()?;
pub(super) fn create_pipe_for_drop(&mut self) -> Option<SurfaceAndPipe> {
let SurfaceAndOffer { window_id, offer } = self.offer.take()?;
let pipe = Pipe::new()
.map_err(|err| log::error!("Unable to create pipe: {:#}", err))
.ok()?;
offer.receive(URI_MIME_TYPE.to_string(), pipe.write.as_raw_fd());
let read = pipe.read;
offer.finish();
Some(SurfaceAndPipe { surface_id, read })
Some(SurfaceAndPipe { window_id, read })
}
fn read_paths_from_pipe(read: FileDescriptor) -> Option<Vec<PathBuf>> {
pub(super) fn read_paths_from_pipe(read: FileDescriptor) -> Option<Vec<PathBuf>> {
read_pipe_with_timeout(read)
.map_err(|err| {
log::error!("Error while reading pipe from drop result: {:#}", err);
@ -68,52 +67,14 @@ impl DragAndDrop {
.into()
}
fn dispatch_dropped_files(surface_id: u32, paths: Vec<PathBuf>) {
pub(super) fn dispatch_dropped_files(window_id: usize, paths: Vec<PathBuf>) {
promise::spawn::spawn_into_main_thread(async move {
let conn = WaylandConnection::get().unwrap().wayland();
if let Some(&window_id) = conn.surface_to_window_id.borrow().get(&surface_id) {
if let Some(handle) = conn.window_by_id(window_id) {
let mut inner = handle.borrow_mut();
inner.dispatch_dropped_files(paths);
}
};
if let Some(handle) = conn.window_by_id(window_id) {
let mut inner = handle.borrow_mut();
inner.dispatch_dropped_files(paths);
}
})
.detach();
}
pub fn handle_data_event(&mut self, event: DataDeviceEvent) {
match event {
DataDeviceEvent::Enter {
serial,
surface,
id,
..
} => {
if let Some(offer) = id {
offer.accept(serial, Some(URI_MIME_TYPE.to_string()));
offer.set_actions(DndAction::None | DndAction::Copy, DndAction::None);
self.offer = Some(SurfaceAndOffer {
surface_id: surface.as_ref().id(),
offer,
});
}
}
DataDeviceEvent::Leave => {
if let Some(SurfaceAndOffer { offer, .. }) = self.offer.take() {
offer.destroy();
}
}
DataDeviceEvent::Motion { .. } => {}
DataDeviceEvent::Drop => {
if let Some(SurfaceAndPipe { surface_id, read }) = self.create_pipe_for_drop() {
std::thread::spawn(move || {
if let Some(paths) = Self::read_paths_from_pipe(read) {
Self::dispatch_dropped_files(surface_id, paths);
}
});
}
}
_ => {}
}
}
}

View File

@ -8,7 +8,7 @@ pub use self::window::*;
pub use connection::*;
// pub use output::*;
mod copy_and_paste;
// mod drag_and_drop;
mod drag_and_drop;
// mod frame;
mod data_device;
mod keyboard;

View File

@ -11,6 +11,7 @@ use wayland_client::{Connection, Proxy, QueueHandle};
use wezterm_input_types::MousePress;
use super::copy_and_paste::CopyAndPaste;
use super::drag_and_drop::DragAndDrop;
use super::state::WaylandState;
use super::WaylandConnection;
@ -55,10 +56,9 @@ impl PointerHandler for WaylandState {
}
}
#[derive(Debug)]
pub(super) struct PointerUserData {
pdata: PointerData,
state: Mutex<PointerState>,
pub(super) state: Mutex<PointerState>,
}
impl PointerUserData {
@ -70,10 +70,10 @@ impl PointerUserData {
}
}
#[derive(Debug, Default)]
struct PointerState {
#[derive(Default)]
pub(super) struct PointerState {
active_surface_id: Option<ObjectId>,
// TODO: drag_and_drop: DragAndDrop,
pub(super) drag_and_drop: DragAndDrop,
serial: u32,
}

View File

@ -3,6 +3,7 @@ use std::cell::{RefCell, RefMut};
use std::convert::TryInto;
use std::io::Read;
use std::os::fd::AsRawFd;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
@ -577,6 +578,10 @@ impl WaylandWindowInner {
((pixels as f64) / self.get_dpi_factor()).ceil() as i32
}
pub(super) fn dispatch_dropped_files(&mut self, paths: Vec<PathBuf>) {
self.events.dispatch(WindowEvent::DroppedFile(paths));
}
pub(crate) fn dispatch_pending_mouse(&mut self) {
let pending_mouse = Arc::clone(&self.pending_mouse);