1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

Implement paste

This commit is contained in:
Timmy Xiao 2024-01-21 21:45:07 -08:00 committed by Wez Furlong
parent 41eeddb7a1
commit 5d6e7c4f98
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
4 changed files with 87 additions and 11 deletions

View File

@ -1,4 +1,7 @@
use anyhow::{anyhow, Error};
use filedescriptor::{FileDescriptor, Pipe};
use smithay_client_toolkit as toolkit;
use std::os::fd::AsRawFd;
use std::sync::{Arc, Mutex};
use toolkit::reexports::client::protocol::wl_data_offer::WlDataOffer;
@ -25,6 +28,20 @@ impl CopyAndPaste {
Arc::new(Mutex::new(Default::default()))
}
pub(super) fn get_clipboard_data(
&mut self,
_clipboard: Clipboard,
) -> anyhow::Result<FileDescriptor> {
// TODO; primary selection
let offer = self
.data_offer
.as_ref()
.ok_or_else(|| anyhow!("no data offer"))?;
let pipe = Pipe::new().map_err(Error::msg)?;
offer.receive(TEXT_MIME_TYPE.to_string(), pipe.write.as_raw_fd());
Ok(pipe.read)
}
pub(super) fn set_clipboard_data(&mut self, _clipboard: Clipboard, data: String) {
// TODO: primary selection

View File

@ -1,6 +1,5 @@
use std::fs::File;
use std::io::Write;
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd};
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
use anyhow::bail;
use filedescriptor::FileDescriptor;
@ -86,6 +85,7 @@ impl DataOfferHandler for WaylandState {
}
}
// Ignore drag and drop events
fn source_actions(
&mut self,
_conn: &wayland_client::Connection,
@ -93,7 +93,6 @@ impl DataOfferHandler for WaylandState {
_offer: &mut smithay_client_toolkit::data_device_manager::data_offer::DragOffer,
_actions: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
todo!()
}
fn selected_action(
@ -103,7 +102,6 @@ impl DataOfferHandler for WaylandState {
_offer: &mut smithay_client_toolkit::data_device_manager::data_offer::DragOffer,
_actions: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
todo!()
}
}
@ -143,9 +141,10 @@ impl DataSourceHandler for WaylandState {
&mut self,
_conn: &wayland_client::Connection,
_qh: &wayland_client::QueueHandle<Self>,
_source: &wayland_client::protocol::wl_data_source::WlDataSource,
source: &wayland_client::protocol::wl_data_source::WlDataSource,
) {
todo!()
self.copy_paste_source.take();
source.destroy();
}
fn dnd_dropped(

View File

@ -24,7 +24,6 @@ use wayland_client::globals::GlobalList;
use wayland_client::protocol::wl_keyboard::WlKeyboard;
use wayland_client::protocol::wl_output::WlOutput;
use wayland_client::protocol::wl_pointer::WlPointer;
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::wl_surface::WlSurface;
use wayland_client::{delegate_dispatch, Connection, QueueHandle};

View File

@ -1,15 +1,18 @@
use std::any::Any;
use std::cell::{RefCell, RefMut};
use std::convert::TryInto;
use std::io::Read;
use std::os::fd::AsRawFd;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use anyhow::anyhow;
use anyhow::{anyhow, bail};
use async_io::Timer;
use async_trait::async_trait;
use config::ConfigHandle;
use promise::Future;
use filedescriptor::FileDescriptor;
use promise::{Future, Promise};
use raw_window_handle::{
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
WaylandDisplayHandle, WaylandWindowHandle,
@ -362,8 +365,35 @@ impl WindowOps for WaylandWindow {
todo!()
}
fn get_clipboard(&self, _clipboard: Clipboard) -> Future<String> {
todo!()
fn get_clipboard(&self, clipboard: Clipboard) -> Future<String> {
let mut promise = Promise::new();
let future = promise.get_future().unwrap();
let promise = Arc::new(Mutex::new(promise));
WaylandConnection::with_window_inner(self.0, move |inner| {
let read = inner
.copy_and_paste
.lock()
.unwrap()
.get_clipboard_data(clipboard)?;
let promise = Arc::clone(&promise);
std::thread::spawn(move || {
let mut promise = promise.lock().unwrap();
match read_pipe_with_timeout(read) {
Ok(result) => {
// Normalize the text to unix line endings, otherwise
// copying from eg: firefox inserts a lot of blank
// lines, and that is super annoying.
promise.ok(result.replace("\r\n", "\n"));
}
Err(e) => {
log::error!("while reading clipboard: {}", e);
promise.err(anyhow!("{}", e));
}
};
});
Ok(())
});
future
}
fn set_clipboard(&self, clipboard: Clipboard, text: String) {
@ -387,6 +417,37 @@ pub(crate) struct PendingEvent {
pub(crate) window_state: Option<WindowState>,
}
pub(crate) fn read_pipe_with_timeout(mut file: FileDescriptor) -> anyhow::Result<String> {
let mut result = Vec::new();
file.set_non_blocking(true)?;
let mut pfd = libc::pollfd {
fd: file.as_raw_fd(),
events: libc::POLLIN,
revents: 0,
};
let mut buf = [0u8; 8192];
loop {
if unsafe { libc::poll(&mut pfd, 1, 3000) == 1 } {
match file.read(&mut buf) {
Ok(size) if size == 0 => {
break;
}
Ok(size) => {
result.extend_from_slice(&buf[..size]);
}
Err(e) => bail!("error reading from pipe: {}", e),
}
} else {
bail!("timed out reading from pipe");
}
}
Ok(String::from_utf8(result)?)
}
pub struct WaylandWindowInner {
// window_id: usize,
pub(crate) events: WindowEventSender,