use crate::gl::GpuReadback;
use crate::wl::{CapturedImage, Client, Frame, SessionId};
use anyhow::Result;
use std::time::{Duration, Instant};
pub const DEFAULT_GRACE: Duration = Duration::from_secs(5);
#[derive(Clone, Debug)]
pub enum Source {
Output(String),
Toplevel(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum End {
SourceGone,
NeverAppeared,
}
pub struct Step {
pub frames: Vec<Frame>,
pub end: Option<End>,
}
pub struct Stream {
source: Source,
session: Option<SessionId>,
appear_deadline: Instant,
had_session: bool,
}
impl Stream {
pub fn new(source: Source, grace: Duration) -> Self {
Self {
source,
session: None,
appear_deadline: Instant::now() + grace,
had_session: false,
}
}
pub fn step(&mut self, client: &mut Client, budget: Duration) -> Step {
if client.refresh().is_err() {
return self.ended(End::SourceGone);
}
if self.session.is_none() {
match self.open(client) {
Some(id) => {
self.session = Some(id);
self.had_session = true;
}
None if Instant::now() >= self.appear_deadline => {
let why = if self.had_session {
End::SourceGone
} else {
End::NeverAppeared
};
return self.ended(why);
}
None => {}
}
} else if self.is_gone(client) {
return self.ended(End::SourceGone);
}
let (got, failed) = client.poll(budget);
for id in failed {
if self.session.as_ref() == Some(&id) {
self.session = None;
}
client.close_session(&id);
}
Step {
frames: got.into_iter().map(|(_id, f)| f).collect(),
end: None,
}
}
fn open(&self, client: &mut Client) -> Option<SessionId> {
match &self.source {
Source::Output(name) => {
let out = client.outputs().iter().find(|o| o.name == *name).cloned()?;
client.open_output_session(&out).ok()
}
Source::Toplevel(id) => {
let tl = client
.toplevels()
.iter()
.find(|t| t.identifier == *id)
.cloned()?;
client.open_toplevel_session(&tl).ok()
}
}
}
fn is_gone(&self, client: &Client) -> bool {
match &self.source {
Source::Output(name) => !client.outputs().iter().any(|o| o.name == *name),
Source::Toplevel(id) => !client.toplevels().iter().any(|t| t.identifier == *id),
}
}
fn ended(&self, why: End) -> Step {
Step {
frames: Vec::new(),
end: Some(why),
}
}
}
pub fn decode_frame(rb: &mut Option<GpuReadback>, frame: Frame) -> Result<CapturedImage> {
match frame {
Frame::Shm(img) => Ok(img),
Frame::Dmabuf(d) => {
let rb = match rb {
Some(rb) => rb,
None => rb.insert(GpuReadback::new()?),
};
rb.readback(d)
}
}
}