use { super::OutputNode, crate::{ cmm::cmm_description::ColorDescription, gfx_api::{AcquireSync, BufferResv, GfxTexture, ReleaseSync}, ifs::{jay_screencast::JayScreencast, wl_buffer::WlBufferStorage}, utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt}, }, std::{ops::Deref, rc::Rc}, }; impl OutputNode { pub fn captures_changed(&self) { for ws in self.workspaces.iter() { ws.update_has_captures(); } } pub fn screencast_changed(&self) { self.captures_changed(); } pub fn add_screencast(&self, sc: &Rc) { self.screencasts.set((sc.client.id, sc.id), sc.clone()); self.captures_changed(); } pub fn remove_screencast(&self, sc: &JayScreencast) { self.screencasts.remove(&(sc.client.id, sc.id)); self.captures_changed(); } pub fn perform_screencopies( &self, tex: &Rc, cd: &Rc, resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, render_hardware_cursor: bool, x_off: i32, y_off: i32, size: Option<(i32, i32)>, ) { if let Some(workspace) = self.workspace.get() { if !workspace.may_capture.get() { return; } } self.perform_wlr_screencopies( tex, cd, resv, acquire_sync, release_sync, render_hardware_cursor, x_off, y_off, size, ); for sc in self.screencasts.lock().values() { sc.copy_texture( self, tex, cd, resv, acquire_sync, release_sync, render_hardware_cursor, x_off, y_off, size, ); } for sc in self.ext_copy_sessions.lock().values() { sc.copy_texture( self, tex, cd, resv, acquire_sync, release_sync, render_hardware_cursor, x_off, y_off, size, ); } } pub fn perform_wlr_screencopies( &self, tex: &Rc, cd: &Rc, resv: Option<&Rc>, acquire_sync: &AcquireSync, release_sync: ReleaseSync, render_hardware_cursors: bool, x_off: i32, y_off: i32, size: Option<(i32, i32)>, ) { if self.screencopies.is_empty() { return; } let now = self.state.now(); for capture in self.screencopies.lock().drain_values() { let wl_buffer = match capture.buffer.take() { Some(b) => b, _ => { log::warn!("Capture frame is pending but has no buffer attached"); capture.send_failed(); continue; } }; if wl_buffer.destroyed() { capture.send_failed(); continue; } let mut ready = true; if let Some(storage) = wl_buffer.storage.borrow_mut().deref() { match storage { WlBufferStorage::Shm { mem, stride, .. } => { let res = self.state.perform_shm_screencopy( tex, cd, acquire_sync, self.global.pos.get(), x_off, y_off, size, &capture, mem, *stride, wl_buffer.format, self.global.persistent.transform.get(), self.global.persistent.scale.get(), ); match res { Ok(p) => { ready = p.is_none(); capture.pending.set(p); } Err(e) => { log::warn!("Could not perform shm screencopy: {}", ErrorFmt(e)); capture.send_failed(); continue; } } } WlBufferStorage::Dmabuf { fb, .. } => { let fb = match fb { Some(fb) => fb, _ => { log::warn!("Capture buffer has no framebuffer"); capture.send_failed(); continue; } }; let res = self.state.perform_screencopy( tex, resv, acquire_sync, release_sync, cd, &fb, AcquireSync::Implicit, ReleaseSync::Implicit, self.global.persistent.transform.get(), self.state.color_manager.srgb_gamma22(), self.global.pos.get(), render_hardware_cursors, x_off - capture.rect.x1(), y_off - capture.rect.y1(), size, self.global.persistent.transform.get(), self.global.persistent.scale.get(), ); if let Err(e) = res { log::warn!("Could not perform screencopy: {}", ErrorFmt(e)); capture.send_failed(); continue; } } } } if capture.with_damage.get() { capture.send_damage(); } if ready { capture.send_ready(now.0.tv_sec as _, now.0.tv_nsec as _); } } self.captures_changed(); } }