cosmic-screencopy-v2 (#288)

This commit is contained in:
Ian Douglas Scott 2024-03-25 12:03:53 -07:00 committed by Jeremy Soller
parent 608d7837b5
commit 8128b6cf89
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
3 changed files with 241 additions and 194 deletions

318
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -21,10 +21,10 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
anyhow = "1.0.81" anyhow = "1.0.81"
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "e65fa5e" } cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "1cc4a13" }
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [ cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [
"client", "client",
], rev = "e65fa5e" } ], rev = "1cc4a13" }
cosmic-time = { git = "https://github.com/pop-os/cosmic-time", default-features = false, features = [ cosmic-time = { git = "https://github.com/pop-os/cosmic-time", default-features = false, features = [
"libcosmic", "libcosmic",
"once_cell", "once_cell",

View file

@ -24,14 +24,16 @@ use cosmic::{
self, self,
cosmic_protocols::{ cosmic_protocols::{
self, self,
screencopy::v1::client::{ image_source::v1::client::zcosmic_toplevel_image_source_manager_v1::ZcosmicToplevelImageSourceManagerV1,
zcosmic_screencopy_manager_v1, zcosmic_screencopy_session_v1, screencopy::v2::client::{
zcosmic_screencopy_frame_v2, zcosmic_screencopy_manager_v2,
zcosmic_screencopy_session_v2,
}, },
toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
}, },
screencopy::{ screencopy::{
BufferInfo, ScreencopyHandler, ScreencopySessionData, ScreencopySessionDataExt, capture, Formats, Frame, ScreencopyFrameData, ScreencopyFrameDataExt,
ScreencopyState, ScreencopyHandler, ScreencopySessionData, ScreencopySessionDataExt, ScreencopyState,
}, },
sctk::shm::{Shm, ShmHandler}, sctk::shm::{Shm, ShmHandler},
wayland_client::{ wayland_client::{
@ -55,8 +57,8 @@ use wayland_client::{globals::registry_queue_init, Connection, QueueHandle};
#[derive(Default)] #[derive(Default)]
struct SessionInner { struct SessionInner {
buffer_infos: Option<Vec<BufferInfo>>, formats: Option<Formats>,
res: Option<Result<(), WEnum<zcosmic_screencopy_session_v1::FailureReason>>>, res: Option<Result<(), WEnum<zcosmic_screencopy_frame_v2::FailureReason>>>,
} }
// TODO: dmabuf? need to handle modifier negotation // TODO: dmabuf? need to handle modifier negotation
@ -72,9 +74,14 @@ struct SessionData {
session_data: ScreencopySessionData, session_data: ScreencopySessionData,
} }
struct FrameData {
frame_data: ScreencopyFrameData,
session: zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
}
impl Session { impl Session {
pub fn for_session( pub fn for_session(
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1, session: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
) -> Option<&Self> { ) -> Option<&Self> {
Some(&session.data::<SessionData>()?.session) Some(&session.data::<SessionData>()?.session)
} }
@ -96,6 +103,13 @@ impl ScreencopySessionDataExt for SessionData {
&self.session_data &self.session_data
} }
} }
impl ScreencopyFrameDataExt for FrameData {
fn screencopy_frame_data(&self) -> &ScreencopyFrameData {
&self.frame_data
}
}
struct AppData { struct AppData {
exit: bool, exit: bool,
tx: UnboundedSender<WaylandUpdate>, tx: UnboundedSender<WaylandUpdate>,
@ -113,7 +127,8 @@ struct CaptureData {
qh: QueueHandle<AppData>, qh: QueueHandle<AppData>,
conn: Connection, conn: Connection,
wl_shm: WlShm, wl_shm: WlShm,
screencopy_manager: zcosmic_screencopy_manager_v1::ZcosmicScreencopyManagerV1, screencopy_manager: zcosmic_screencopy_manager_v2::ZcosmicScreencopyManagerV2,
toplevel_source_manager: ZcosmicToplevelImageSourceManagerV1,
} }
impl CaptureData { impl CaptureData {
@ -131,9 +146,12 @@ impl CaptureData {
let overlay_cursor = if overlay_cursor { 1 } else { 0 }; let overlay_cursor = if overlay_cursor { 1 } else { 0 };
let session = Arc::new(Session::default()); let session = Arc::new(Session::default());
let screencopy_session = self.screencopy_manager.capture_toplevel( let image_source = self
&source, .toplevel_source_manager
zcosmic_screencopy_manager_v1::CursorMode::Hidden, // XXX take into account adventised capabilities .create_source(&source, &self.qh, ());
let screencopy_session = self.screencopy_manager.create_session(
&image_source,
zcosmic_screencopy_manager_v2::Options::empty(),
&self.qh, &self.qh,
SessionData { SessionData {
session: session.clone(), session: session.clone(),
@ -142,23 +160,24 @@ impl CaptureData {
); );
self.conn.flush().unwrap(); self.conn.flush().unwrap();
let buffer_infos = session let formats = session
.wait_while(|data| data.buffer_infos.is_none()) .wait_while(|data| data.formats.is_none())
.buffer_infos .formats
.take() .take()
.unwrap(); .unwrap();
let (width, height) = formats.buffer_size;
// XXX // XXX
let Some(buffer_info) = buffer_infos.iter().find(|x| { if !formats
x.type_ == WEnum::Value(zcosmic_screencopy_session_v1::BufferType::WlShm) .shm_formats
&& x.format == wl_shm::Format::Abgr8888.into() .contains(&wl_shm::Format::Abgr8888.into())
}) else { {
tracing::error!("No suitable buffer format found"); tracing::error!("No suitable buffer format found");
tracing::warn!("Available formats: {:#?}", buffer_infos); tracing::warn!("Available formats: {:#?}", formats);
return None; return None;
}; };
let buf_len = buffer_info.stride * buffer_info.height; let buf_len = width * height * 4;
if let Some(len) = len { if let Some(len) = len {
if len != buf_len { if len != buf_len {
return None; return None;
@ -170,16 +189,24 @@ impl CaptureData {
.create_pool(fd.as_fd(), buf_len as i32, &self.qh, ()); .create_pool(fd.as_fd(), buf_len as i32, &self.qh, ());
let buffer = pool.create_buffer( let buffer = pool.create_buffer(
0, 0,
buffer_info.width as i32, width as i32,
buffer_info.height as i32, height as i32,
buffer_info.stride as i32, width as i32 * 4,
wl_shm::Format::Abgr8888, wl_shm::Format::Abgr8888,
&self.qh, &self.qh,
(), (),
); );
screencopy_session.attach_buffer(&buffer, None, 0); // XXX age? capture(
screencopy_session.commit(zcosmic_screencopy_session_v1::Options::empty()); &screencopy_session,
&buffer,
&[],
&self.qh,
FrameData {
frame_data: Default::default(),
session: screencopy_session.clone(),
},
);
self.conn.flush().unwrap(); self.conn.flush().unwrap();
// TODO: wait for server to release buffer? // TODO: wait for server to release buffer?
@ -194,11 +221,7 @@ impl CaptureData {
//std::thread::sleep(std::time::Duration::from_millis(16)); //std::thread::sleep(std::time::Duration::from_millis(16));
if res.is_ok() { if res.is_ok() {
Some(ShmImage { Some(ShmImage { fd, width, height })
fd,
width: buffer_info.width,
height: buffer_info.height,
})
} else { } else {
None None
} }
@ -277,6 +300,11 @@ impl AppData {
conn: self.conn.clone(), conn: self.conn.clone(),
wl_shm: self.shm_state.wl_shm().clone(), wl_shm: self.shm_state.wl_shm().clone(),
screencopy_manager: self.screencopy_state.screencopy_manager.clone(), screencopy_manager: self.screencopy_state.screencopy_manager.clone(),
toplevel_source_manager: self
.screencopy_state
.toplevel_source_manager
.clone()
.unwrap(),
}; };
std::thread::spawn(move || { std::thread::spawn(move || {
use std::ffi::CStr; use std::ffi::CStr;
@ -488,11 +516,11 @@ impl ScreencopyHandler for AppData {
&mut self, &mut self,
_conn: &Connection, _conn: &Connection,
_qh: &QueueHandle<Self>, _qh: &QueueHandle<Self>,
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1, session: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
buffer_infos: &[BufferInfo], formats: &Formats,
) { ) {
Session::for_session(session).unwrap().update(|data| { Session::for_session(session).unwrap().update(|data| {
data.buffer_infos = Some(buffer_infos.to_vec()); data.formats = Some(formats.clone());
}); });
} }
@ -500,8 +528,10 @@ impl ScreencopyHandler for AppData {
&mut self, &mut self,
_conn: &Connection, _conn: &Connection,
_qh: &QueueHandle<Self>, _qh: &QueueHandle<Self>,
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1, screencopy_frame: &zcosmic_screencopy_frame_v2::ZcosmicScreencopyFrameV2,
_frame: Frame,
) { ) {
let session = &screencopy_frame.data::<FrameData>().unwrap().session;
Session::for_session(session).unwrap().update(|data| { Session::for_session(session).unwrap().update(|data| {
data.res = Some(Ok(())); data.res = Some(Ok(()));
}); });
@ -512,15 +542,24 @@ impl ScreencopyHandler for AppData {
&mut self, &mut self,
_conn: &Connection, _conn: &Connection,
_qh: &QueueHandle<Self>, _qh: &QueueHandle<Self>,
session: &zcosmic_screencopy_session_v1::ZcosmicScreencopySessionV1, screencopy_frame: &zcosmic_screencopy_frame_v2::ZcosmicScreencopyFrameV2,
reason: WEnum<zcosmic_screencopy_session_v1::FailureReason>, reason: WEnum<zcosmic_screencopy_frame_v2::FailureReason>,
) { ) {
// TODO send message to thread // TODO send message to thread
let session = &screencopy_frame.data::<FrameData>().unwrap().session;
Session::for_session(session).unwrap().update(|data| { Session::for_session(session).unwrap().update(|data| {
data.res = Some(Err(reason)); data.res = Some(Err(reason));
}); });
session.destroy(); session.destroy();
} }
fn stopped(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_session: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
) {
}
} }
impl Dispatch<wl_shm_pool::WlShmPool, ()> for AppData { impl Dispatch<wl_shm_pool::WlShmPool, ()> for AppData {
@ -552,4 +591,4 @@ sctk::delegate_seat!(AppData);
sctk::delegate_registry!(AppData); sctk::delegate_registry!(AppData);
cctk::delegate_toplevel_info!(AppData); cctk::delegate_toplevel_info!(AppData);
cctk::delegate_toplevel_manager!(AppData); cctk::delegate_toplevel_manager!(AppData);
cctk::delegate_screencopy!(AppData, session: [SessionData]); cctk::delegate_screencopy!(AppData, session: [SessionData], frame: [FrameData]);