1
0
Fork 0
forked from wry/wry
wry/src/xwayland/xwm/transfer.rs

110 lines
3.3 KiB
Rust

use jay_io_uring::{IoUring, IoUringError};
use {
super::XwmShared,
crate::{
state::State,
utils::{buf::Buf, errorfmt::ErrorFmt, oserror::OsError},
wire_xcon::{ChangeProperty, SelectionNotify},
xcon::{
Xcon,
consts::{ATOM_NONE, PROP_MODE_APPEND},
},
},
std::{rc::Rc, time::Duration},
uapi::{OwnedFd, c},
};
pub(super) struct XToWaylandTransfer {
pub(super) id: u64,
pub(super) data: Buf,
pub(super) fd: Rc<OwnedFd>,
pub(super) state: Rc<State>,
pub(super) shared: Rc<XwmShared>,
}
impl XToWaylandTransfer {
pub(super) async fn run(mut self) {
let timeout = self.state.now() + Duration::from_millis(5000);
let mut pos = 0;
while pos < self.data.len() {
let res = self
.state
.ring
.write(&self.fd, self.data.slice(pos..), Some(timeout));
match res.await {
Ok(n) => pos += n,
Err(IoUringError::OsError(OsError(c::ECANCELED))) => {
log::error!("Transfer timed out");
break;
}
Err(e) => {
log::error!("Could not write to wayland client: {}", ErrorFmt(e));
break;
}
}
}
self.shared.transfers.remove(&self.id);
}
}
pub(super) struct WaylandToXTransfer {
pub(super) id: u64,
pub(super) fd: Rc<OwnedFd>,
pub(super) ring: Rc<IoUring>,
pub(super) c: Rc<Xcon>,
pub(super) window: u32,
pub(super) time: u32,
pub(super) property: u32,
pub(super) ty: u32,
pub(super) selection: u32,
pub(super) shared: Rc<XwmShared>,
}
impl WaylandToXTransfer {
pub(super) async fn run(self) {
let mut success = false;
let mut buf = Buf::new(1024);
loop {
match self.ring.read(&self.fd, buf.clone()).await {
Ok(0) => {
success = true;
break;
}
Ok(n) => {
let cp = ChangeProperty {
mode: PROP_MODE_APPEND,
window: self.window,
property: self.property,
ty: self.ty,
format: 8,
data: &buf[..n],
};
if let Err(e) = self.c.call(&cp).await {
log::error!("Could not append data to property: {}", ErrorFmt(e));
break;
}
}
Err(e) => {
log::error!("Could not read from wayland client: {}", ErrorFmt(e));
break;
}
}
}
let target = match success {
true => self.ty,
false => ATOM_NONE,
};
let sn = SelectionNotify {
time: self.time,
requestor: self.window,
selection: self.selection,
target,
property: self.property,
};
if let Err(e) = self.c.send_event(false, self.window, 0, &sn).await {
log::error!("Could not send event: {}", ErrorFmt(e));
}
self.shared.transfers.remove(&self.id);
}
}