diff --git a/src/wayland/capture.rs b/src/wayland/capture.rs index 612f364..e85d423 100644 --- a/src/wayland/capture.rs +++ b/src/wayland/capture.rs @@ -35,9 +35,7 @@ pub struct Capture { pub buffer: Mutex>, pub source: CaptureSource, first_frame: AtomicBool, - running: AtomicBool, - capturing: AtomicBool, - session: zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1, + session: Mutex>, } impl Capture { @@ -46,13 +44,46 @@ impl Capture { manager: &zcosmic_screencopy_manager_v1::ZcosmicScreencopyManagerV1, qh: &QueueHandle, ) -> Arc { - 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> { + session.data::()?.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, + manager: &zcosmic_screencopy_manager_v1::ZcosmicScreencopyManagerV1, + qh: &QueueHandle, + ) { + 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> { - session.data::()?.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(); + } } } diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 5d6b5a9..fdbdad5 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -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 }); diff --git a/src/wayland/screencopy.rs b/src/wayland/screencopy.rs index b852ed1..3739df3 100644 --- a/src/wayland/screencopy.rs +++ b/src/wayland/screencopy.rs @@ -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(); } }