use std::time::{Duration, Instant};
use wlr_capture::wl;
const ROUND: Duration = Duration::from_millis(33);
const APPEAR_GRACE: Duration = Duration::from_secs(5);
pub enum PipMsg {
Shm { w: usize, h: usize, rgba: Vec<u8> },
Dmabuf { frame: wl::DmabufFrame },
Gone,
}
pub fn capture_thread(identifier: String, mut sink: impl FnMut(PipMsg) -> bool) {
let mut client = match wl::Client::connect() {
Ok(c) => c,
Err(e) => {
eprintln!("wlr-pip: {e:#}");
sink(PipMsg::Gone);
return;
}
};
let mut session: Option<wl::SessionId> = None;
let appear_deadline = Instant::now() + APPEAR_GRACE;
loop {
if client.refresh().is_err() {
sink(PipMsg::Gone);
return;
}
let present = client
.toplevels()
.iter()
.any(|t| t.identifier == identifier);
if session.is_none() {
match client
.toplevels()
.iter()
.find(|t| t.identifier == identifier)
.cloned()
{
Some(t) => {
if let Ok(id) = client.open_toplevel_session(&t) {
session = Some(id);
}
}
None if Instant::now() >= appear_deadline => {
sink(PipMsg::Gone);
return;
}
None => {}
}
} else if !present {
sink(PipMsg::Gone);
return;
}
let (frames, failed) = client.poll(ROUND);
for (_id, frame) in frames {
let msg = match frame {
wl::Frame::Shm(img) => PipMsg::Shm {
w: img.width as usize,
h: img.height as usize,
rgba: img.rgba,
},
wl::Frame::Dmabuf(frame) => PipMsg::Dmabuf { frame },
};
if !sink(msg) {
return; }
}
for id in failed {
if session.as_ref() == Some(&id) {
session = None;
}
client.close_session(&id);
}
}
}