There should no longer be any - read - write - connect - sendmsg - recvmsg - accept calls in the codebase. Previously we were using a mix of io_uring and these calls which had some negative effects: Since we were using the old system calls, we had to set the file descriptors to non-blocking. But our io_uring code did not handle EAGAIN. This lead to programs sometimes being killed when the wayland IO was actually blocking. Now all file descriptors are set to blocking, but io_uring makes it non-blocking from our perspective. The one exception are evdev files because they are read via libinput and libinput uses the old system calls.
109 lines
3.1 KiB
Rust
109 lines
3.1 KiB
Rust
use {
|
|
crate::{
|
|
cli::{GlobalArgs, ScreenshotArgs},
|
|
format::XRGB8888,
|
|
tools::tool_client::{with_tool_client, Handle, ToolClient},
|
|
utils::{errorfmt::ErrorFmt, queue::AsyncQueue},
|
|
video::{
|
|
dmabuf::{DmaBuf, DmaBufPlane},
|
|
drm::Drm,
|
|
gbm::{GbmDevice, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING},
|
|
INVALID_MODIFIER,
|
|
},
|
|
wire::{
|
|
jay_compositor::TakeScreenshot,
|
|
jay_screenshot::{Dmabuf, Error},
|
|
},
|
|
},
|
|
algorithms::qoi::xrgb8888_encode_qoi,
|
|
chrono::Local,
|
|
std::rc::Rc,
|
|
};
|
|
|
|
pub fn main(global: GlobalArgs, args: ScreenshotArgs) {
|
|
with_tool_client(global.log_level.into(), |tc| async move {
|
|
let screenshot = Rc::new(Screenshot {
|
|
tc: tc.clone(),
|
|
args,
|
|
});
|
|
run(screenshot).await;
|
|
});
|
|
}
|
|
|
|
struct Screenshot {
|
|
tc: Rc<ToolClient>,
|
|
args: ScreenshotArgs,
|
|
}
|
|
|
|
async fn run(screenshot: Rc<Screenshot>) {
|
|
let tc = &screenshot.tc;
|
|
let comp = tc.jay_compositor().await;
|
|
let sid = tc.id();
|
|
tc.send(TakeScreenshot {
|
|
self_id: comp,
|
|
id: sid,
|
|
});
|
|
let result = Rc::new(AsyncQueue::new());
|
|
Error::handle(tc, sid, result.clone(), |res, err| {
|
|
res.push(Err(err.msg.to_owned()));
|
|
});
|
|
Dmabuf::handle(tc, sid, result.clone(), |res, buf| {
|
|
res.push(Ok(buf));
|
|
});
|
|
let buf = match result.pop().await {
|
|
Ok(b) => b,
|
|
Err(e) => {
|
|
fatal!("Could not take a screenshot: {}", e);
|
|
}
|
|
};
|
|
let data = buf_to_qoi(&buf);
|
|
let filename = screenshot
|
|
.args
|
|
.filename
|
|
.as_deref()
|
|
.unwrap_or("%Y-%m-%d-%H%M%S_jay.qoi");
|
|
let filename = Local::now().format(filename).to_string();
|
|
if let Err(e) = std::fs::write(&filename, &data) {
|
|
fatal!("Could not write `{}`: {}", filename, ErrorFmt(e));
|
|
}
|
|
}
|
|
|
|
pub fn buf_to_qoi(buf: &Dmabuf) -> Vec<u8> {
|
|
let drm = match Drm::reopen(buf.drm_dev.raw(), false) {
|
|
Ok(drm) => drm,
|
|
Err(e) => {
|
|
fatal!("Could not open the drm device: {}", ErrorFmt(e));
|
|
}
|
|
};
|
|
let gbm = match GbmDevice::new(&drm) {
|
|
Ok(g) => g,
|
|
Err(e) => {
|
|
fatal!("Could not create a gbm device: {}", ErrorFmt(e));
|
|
}
|
|
};
|
|
let dmabuf = DmaBuf {
|
|
width: buf.width as _,
|
|
height: buf.height as _,
|
|
format: XRGB8888,
|
|
modifier: INVALID_MODIFIER,
|
|
planes: vec![DmaBufPlane {
|
|
offset: buf.offset,
|
|
stride: buf.stride,
|
|
fd: buf.fd.clone(),
|
|
}],
|
|
};
|
|
let bo = match gbm.import_dmabuf(&dmabuf, GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING) {
|
|
Ok(bo) => Rc::new(bo),
|
|
Err(e) => {
|
|
fatal!("Could not import screenshot dmabuf: {}", ErrorFmt(e));
|
|
}
|
|
};
|
|
let bo_map = match bo.map() {
|
|
Ok(map) => map,
|
|
Err(e) => {
|
|
fatal!("Could not map dmabuf: {}", ErrorFmt(e));
|
|
}
|
|
};
|
|
let data = unsafe { bo_map.data() };
|
|
xrgb8888_encode_qoi(data, buf.width, buf.height, buf.stride)
|
|
}
|