Destroy screencopy session when not capturing

This commit is contained in:
Ian Douglas Scott 2024-01-24 15:59:18 -08:00
parent b958a13b88
commit 6f1b391b00
3 changed files with 55 additions and 74 deletions

View file

@ -35,9 +35,7 @@ pub struct Capture {
pub buffer: Mutex<Option<Buffer>>,
pub source: CaptureSource,
first_frame: AtomicBool,
running: AtomicBool,
capturing: AtomicBool,
session: zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1,
session: Mutex<Option<zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1>>,
}
impl Capture {
@ -46,13 +44,46 @@ impl Capture {
manager: &zcosmic_screencopy_manager_v1::ZcosmicScreencopyManagerV1,
qh: &QueueHandle<AppData>,
) -> Arc<Capture> {
Arc::new_cyclic(|weak_capture| {
Arc::new(Capture {
buffer: Mutex::new(None),
source,
first_frame: AtomicBool::new(true),
session: Mutex::new(None),
})
}
// Returns `None` if capture is destroyed
// (or if `session` wasn't created with `SessionData`)
pub fn for_session(
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1,
) -> Option<Arc<Self>> {
session.data::<SessionData>()?.capture.upgrade()
}
pub fn running(&self) -> bool {
self.session.lock().unwrap().is_some()
}
pub fn first_frame(&self) -> bool {
self.first_frame.load(Ordering::SeqCst)
}
// Start capturing frames
pub fn start(
self: &Arc<Self>,
manager: &zcosmic_screencopy_manager_v1::ZcosmicScreencopyManagerV1,
qh: &QueueHandle<AppData>,
) {
let mut session = self.session.lock().unwrap();
if session.is_none() {
self.first_frame.store(true, Ordering::SeqCst);
let udata = SessionData {
session_data: Default::default(),
capture: weak_capture.clone(),
capture: Arc::downgrade(self),
};
let session = match &source {
*session = Some(match &self.source {
CaptureSource::Toplevel(toplevel) => manager.capture_toplevel(
toplevel,
zcosmic_screencopy_manager_v1::CursorMode::Hidden,
@ -66,89 +97,44 @@ impl Capture {
qh,
udata,
),
};
Capture {
buffer: Mutex::new(None),
source,
first_frame: AtomicBool::new(true),
running: AtomicBool::new(false),
capturing: AtomicBool::new(false),
session,
}
})
}
// Returns `None` if capture is destroyed
// (or if `session` wasn't created with `SessionData`)
pub fn for_session(
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1,
) -> Option<Arc<Self>> {
session.data::<SessionData>()?.capture.upgrade()
}
pub fn running(&self) -> bool {
self.running.load(Ordering::SeqCst)
}
// Buffer is currently attached and commited for capture by server
pub fn capturing(&self) -> bool {
self.capturing.load(Ordering::SeqCst)
}
pub fn set_capturing(&self, value: bool) {
if value {
self.first_frame.store(false, Ordering::SeqCst);
}
self.capturing.store(value, Ordering::SeqCst);
}
pub fn first_frame(&self) -> bool {
self.first_frame.load(Ordering::SeqCst)
}
// Start capturing frames
pub fn start(&self, conn: &Connection) {
let already_running = self.running.swap(true, Ordering::SeqCst);
let have_buffer = self.buffer.lock().unwrap().is_some();
if have_buffer && !already_running {
self.attach_buffer_and_commit(conn);
});
}
}
// Stop capturing. Can be started again with `start`
pub fn stop(&self) {
self.running.store(false, Ordering::SeqCst);
self.first_frame.store(true, Ordering::SeqCst);
// TODO: Reallocate buffers on re-start
// *self.buffer.lock().unwrap() = None;
if let Some(session) = self.session.lock().unwrap().take() {
session.destroy();
}
*self.buffer.lock().unwrap() = None;
}
pub fn attach_buffer_and_commit(&self, conn: &Connection) {
let session = self.session.lock().unwrap();
let buffer = self.buffer.lock().unwrap();
let buffer = buffer.as_ref().unwrap();
let (Some(session), Some(buffer)) = (session.as_ref(), buffer.as_ref()) else {
return;
};
let node = buffer
.node()
.and_then(|x| x.to_str().map(|x| x.to_string()));
self.session.attach_buffer(&buffer.buffer, node, 0); // XXX age?
session.attach_buffer(&buffer.buffer, node, 0); // XXX age?
if self.first_frame() {
self.session
.commit(zcosmic_screencopy_session_v1::Options::empty());
session.commit(zcosmic_screencopy_session_v1::Options::empty());
} else {
self.session
.commit(zcosmic_screencopy_session_v1::Options::OnDamage);
session.commit(zcosmic_screencopy_session_v1::Options::OnDamage);
}
conn.flush().unwrap();
self.set_capturing(true);
}
}
impl Drop for Capture {
fn drop(&mut self) {
self.session.destroy();
if let Some(session) = self.session.lock().unwrap().as_ref() {
session.destroy();
}
}
}

View file

@ -149,7 +149,7 @@ impl AppData {
let matches = self.matches_capture_filter(source);
let running = capture.running();
if matches {
capture.start(&self.conn);
capture.start(&self.screencopy_state.screencopy_manager, &self.qh);
} else {
capture.stop();
}
@ -165,7 +165,7 @@ impl AppData {
let capture =
Capture::new(source, &self.screencopy_state.screencopy_manager, &self.qh);
if matches {
capture.start(&self.conn);
capture.start(&self.screencopy_state.screencopy_manager, &self.qh);
}
capture
});

View file

@ -34,9 +34,7 @@ impl ScreencopyHandler for AppData {
drop(buffer);
if !capture.running() {
capture.attach_buffer_and_commit(conn);
}
capture.attach_buffer_and_commit(conn);
}
fn ready(
@ -72,8 +70,6 @@ impl ScreencopyHandler for AppData {
}
};
capture.set_capturing(false);
drop(buffer);
// Capture again on damage
@ -90,7 +86,6 @@ impl ScreencopyHandler for AppData {
// TODO
println!("Failed");
if let Some(capture) = Capture::for_session(session) {
capture.set_capturing(false);
capture.stop();
}
}