Skip to content

Commit

Permalink
client-toolkit/screencopy: Improvements to API
Browse files Browse the repository at this point in the history
This adds a `CaptureSource` enum, similar to what cosmic-workspaces and
xdg-desktop-portal-cosmic, to construct session without directly
accessing manager types. It also adds a ref-counted `CaptureSession`
that destroys the session when the last reference is dropped.

This is a step towards abstracting support for the upstream
`ext-image-copy-capture-v1`. Otherwise it just reduces the code required
by callers a little bit, but more high level helpers should probably
be added as well.
  • Loading branch information
ids1024 committed Jan 31, 2025
1 parent 22ff382 commit 7c5f0ce
Show file tree
Hide file tree
Showing 4 changed files with 268 additions and 102 deletions.
63 changes: 27 additions & 36 deletions client-toolkit/examples/screenshot-screencopy.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use cosmic_client_toolkit::{
screencopy::{
capture, Formats, ScreencopyFrameData, ScreencopyFrameDataExt, ScreencopyHandler,
ScreencopySessionData, ScreencopySessionDataExt, ScreencopyState,
},
GlobalData,
use cosmic_client_toolkit::screencopy::{
CaptureSession, CaptureSource, Formats, ScreencopyFrameData, ScreencopyFrameDataExt,
ScreencopyHandler, ScreencopySessionData, ScreencopySessionDataExt, ScreencopyState,
};
use cosmic_protocols::screencopy::v2::client::{
zcosmic_screencopy_frame_v2, zcosmic_screencopy_manager_v2, zcosmic_screencopy_session_v2,
zcosmic_screencopy_frame_v2, zcosmic_screencopy_manager_v2,
};
use sctk::{
output::{OutputHandler, OutputState},
Expand Down Expand Up @@ -82,7 +79,7 @@ impl ScreencopyHandler for AppData {
&mut self,
_: &Connection,
qh: &QueueHandle<Self>,
session: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
session: &CaptureSession,
formats: &Formats,
) {
let (width, height) = formats.buffer_size;
Expand All @@ -97,8 +94,7 @@ impl ScreencopyHandler for AppData {
(),
qh,
);
capture(
session,
session.capture(
&wl_buffer,
&[],
qh,
Expand All @@ -111,13 +107,7 @@ impl ScreencopyHandler for AppData {
);
}

fn stopped(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
) {
}
fn stopped(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &CaptureSession) {}

fn ready(
&mut self,
Expand Down Expand Up @@ -198,26 +188,27 @@ fn main() {

event_queue.roundtrip(&mut data).unwrap();

let output_source_manager = data
.screencopy_state
.output_source_manager
.as_ref()
.unwrap();
let mut num_outputs = 0;
for output in data.output_state.outputs() {
num_outputs += 1;
let info = data.output_state.info(&output).unwrap();
let source = output_source_manager.create_source(&output, &qh, GlobalData);
data.screencopy_state.screencopy_manager.create_session(
&source,
zcosmic_screencopy_manager_v2::Options::empty(),
&qh,
SessionData {
output_name: info.name.clone().unwrap(),
session_data: ScreencopySessionData::default(),
},
);
}
let _sessions = data
.output_state
.outputs()
.map(|output| {
num_outputs += 1;
let info = data.output_state.info(&output).unwrap();
data.screencopy_state
.capturer()
.create_session(
&CaptureSource::Output(output),
zcosmic_screencopy_manager_v2::Options::empty(),
&qh,
SessionData {
output_name: info.name.clone().unwrap(),
session_data: ScreencopySessionData::default(),
},
)
.unwrap()
})
.collect::<Vec<_>>();

while data.outputs_done < num_outputs {
event_queue.blocking_dispatch(&mut data).unwrap();
Expand Down
91 changes: 91 additions & 0 deletions client-toolkit/src/screencopy/capture_source.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use cosmic_protocols::{
image_source::v1::client::zcosmic_image_source_v1,
toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
workspace::v1::client::zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
};
use std::{error::Error, fmt};
use wayland_client::{protocol::wl_output, Dispatch, QueueHandle};

use super::Capturer;
use crate::GlobalData;

#[derive(Debug)]
pub struct CaptureSourceError(CaptureSourceKind);

impl fmt::Display for CaptureSourceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "capture kind '{:?}' unsupported by compositor", self.0)
}
}

impl Error for CaptureSourceError {}

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum CaptureSourceKind {
Output,
CosmicToplevel,
CosmicWorkspace,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum CaptureSource {
Output(wl_output::WlOutput),
// TODO: when adding ext protocol
// Toplevel(ExtForeignToplevelHandleV1),
CosmicToplevel(ZcosmicToplevelHandleV1),
CosmicWorkspace(ZcosmicWorkspaceHandleV1),
}

impl CaptureSource {
pub fn kind(&self) -> CaptureSourceKind {
match self {
Self::Output(_) => CaptureSourceKind::Output,
Self::CosmicToplevel(_) => CaptureSourceKind::CosmicToplevel,
Self::CosmicWorkspace(_) => CaptureSourceKind::CosmicWorkspace,
}
}

pub(crate) fn create_source<D>(
&self,
capturer: &Capturer,
qh: &QueueHandle<D>,
) -> Result<WlCaptureSource, CaptureSourceError>
where
D: 'static,
D: Dispatch<zcosmic_image_source_v1::ZcosmicImageSourceV1, GlobalData>,
{
match self {
CaptureSource::Output(output) => {
if let Some(manager) = &capturer.0.output_source_manager {
return Ok(WlCaptureSource(
manager.create_source(output, qh, GlobalData),
));
}
}
CaptureSource::CosmicToplevel(toplevel) => {
if let Some(manager) = &capturer.0.toplevel_source_manager {
return Ok(WlCaptureSource(
manager.create_source(toplevel, qh, GlobalData),
));
}
}
CaptureSource::CosmicWorkspace(workspace) => {
if let Some(manager) = &capturer.0.workspace_source_manager {
return Ok(WlCaptureSource(
manager.create_source(workspace, qh, GlobalData),
));
}
}
}
Err(CaptureSourceError(self.kind()))
}
}

// TODO name?
pub(crate) struct WlCaptureSource(pub(crate) zcosmic_image_source_v1::ZcosmicImageSourceV1);

impl Drop for WlCaptureSource {
fn drop(&mut self) {
self.0.destroy();
}
}
25 changes: 22 additions & 3 deletions client-toolkit/src/screencopy/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use std::time::Duration;
use wayland_client::{protocol::wl_shm, Connection, Dispatch, QueueHandle};

use super::{
Rect, ScreencopyFrameDataExt, ScreencopyHandler, ScreencopySessionDataExt, ScreencopyState,
CaptureSession, Rect, ScreencopyFrameDataExt, ScreencopyHandler, ScreencopySessionDataExt,
ScreencopyState,
};
use crate::GlobalData;

Expand Down Expand Up @@ -73,10 +74,28 @@ where
.push((format, modifiers));
}
zcosmic_screencopy_session_v2::Event::Done => {
app_data.init_done(conn, qh, session, &formats.lock().unwrap());
if let Some(session) = udata
.screencopy_session_data()
.session
.get()
.unwrap()
.upgrade()
.map(CaptureSession)
{
app_data.init_done(conn, qh, &session, &formats.lock().unwrap());
}
}
zcosmic_screencopy_session_v2::Event::Stopped => {
app_data.stopped(conn, qh, session);
if let Some(session) = udata
.screencopy_session_data()
.session
.get()
.unwrap()
.upgrade()
.map(CaptureSession)
{
app_data.stopped(conn, qh, &session);
}
session.destroy();
}
_ => unreachable!(),
Expand Down
Loading

0 comments on commit 7c5f0ce

Please sign in to comment.