Skip to content

Commit

Permalink
WIP client-toolkit/screencopy: improvements to API
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Jan 30, 2025
1 parent 22ff382 commit d249c57
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 57 deletions.
4 changes: 2 additions & 2 deletions client-toolkit/examples/screenshot-screencopy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cosmic_client_toolkit::{
screencopy::{
capture, Formats, ScreencopyFrameData, ScreencopyFrameDataExt, ScreencopyHandler,
Formats, ScreencopyFrameData, ScreencopyFrameDataExt, ScreencopyHandler,
ScreencopySessionData, ScreencopySessionDataExt, ScreencopyState,
},
GlobalData,
Expand Down Expand Up @@ -208,7 +208,7 @@ fn main() {
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(
data.screencopy_state.capturer().create_session(
&source,
zcosmic_screencopy_manager_v2::Options::empty(),
&qh,
Expand Down
79 changes: 79 additions & 0 deletions client-toolkit/src/screencopy/capture_source.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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;

// TODO enum for supported sources

#[derive(Debug)]
pub struct CaptureSourceError;

impl fmt::Display for CaptureSourceError {
// TODO
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
todo!()
}
}

impl Error for CaptureSourceError {}

#[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(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)
}
}

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

impl Drop for WlCaptureSource {
fn drop(&mut self) {
self.0.destroy();
}
}
171 changes: 116 additions & 55 deletions client-toolkit/src/screencopy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

use cosmic_protocols::{
image_source::v1::client::{
zcosmic_output_image_source_manager_v1, zcosmic_toplevel_image_source_manager_v1,
zcosmic_workspace_image_source_manager_v1,
zcosmic_image_source_v1, zcosmic_output_image_source_manager_v1,
zcosmic_toplevel_image_source_manager_v1, zcosmic_workspace_image_source_manager_v1,
},
screencopy::v2::client::{
zcosmic_screencopy_frame_v2, zcosmic_screencopy_manager_v2, zcosmic_screencopy_session_v2,
},
};
use std::{sync::Mutex, time::Duration};
use std::{
sync::{Arc, Mutex, Weak},
time::Duration,
};
use wayland_client::{
globals::GlobalList,
protocol::{wl_buffer, wl_output::Transform, wl_shm},
Expand All @@ -18,6 +21,8 @@ use wayland_client::{

use crate::GlobalData;

mod capture_source;
pub use capture_source::{CaptureSource, CaptureSourceError};
mod dispatch;

#[derive(Clone, Debug)]
Expand All @@ -36,30 +41,6 @@ pub struct Frame {
pub present_time: Option<Duration>,
}

// TODO Better API than standalone function?
pub fn capture<D, U: ScreencopyFrameDataExt + Send + Sync + 'static>(
session: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
buffer: &wl_buffer::WlBuffer,
buffer_damage: &[Rect],
qh: &QueueHandle<D>,
udata: U,
) where
D: Dispatch<zcosmic_screencopy_frame_v2::ZcosmicScreencopyFrameV2, U> + 'static,
{
let frame = session.create_frame(qh, udata);
frame.attach_buffer(buffer);
for Rect {
x,
y,
width,
height,
} in buffer_damage
{
frame.damage_buffer(*x, *y, *width, *height);
}
frame.capture();
}

impl Default for Frame {
fn default() -> Self {
Self {
Expand All @@ -82,18 +63,110 @@ pub struct Formats {
}

#[derive(Debug)]
pub struct ScreencopyState {
pub screencopy_manager: zcosmic_screencopy_manager_v2::ZcosmicScreencopyManagerV2, // XXX pub
pub output_source_manager:
struct CapturerInner {
screencopy_manager: Option<zcosmic_screencopy_manager_v2::ZcosmicScreencopyManagerV2>,
output_source_manager:
Option<zcosmic_output_image_source_manager_v1::ZcosmicOutputImageSourceManagerV1>,
pub toplevel_source_manager:
toplevel_source_manager:
Option<zcosmic_toplevel_image_source_manager_v1::ZcosmicToplevelImageSourceManagerV1>,
pub workspace_source_manager:
workspace_source_manager:
Option<zcosmic_workspace_image_source_manager_v1::ZcosmicWorkspaceImageSourceManagerV1>,
}

impl Drop for CapturerInner {
fn drop(&mut self) {
if let Some(manager) = &self.screencopy_manager {
manager.destroy();
}
if let Some(manager) = &self.output_source_manager {
manager.destroy();
}
if let Some(manager) = &self.toplevel_source_manager {
manager.destroy();
}
if let Some(manager) = &self.workspace_source_manager {
manager.destroy();
}
}
}

#[derive(Clone, Debug)]
pub struct Capturer(Arc<CapturerInner>);

impl Capturer {
// TODO check supported capture types

pub fn create_session<D, U>(
&self,
source: &CaptureSource,
options: zcosmic_screencopy_manager_v2::Options,
qh: &QueueHandle<D>,
udata: U,
) -> Result<CaptureSession, CaptureSourceError>
where
D: 'static,
D: Dispatch<zcosmic_image_source_v1::ZcosmicImageSourceV1, GlobalData>,
D: Dispatch<zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2, U>,
U: ScreencopySessionDataExt + Send + Sync + 'static,
{
let source = source.create_source(self, qh)?;
Ok(CaptureSession(Arc::new(CaptureSessionInner(
self.0
.screencopy_manager
.as_ref()
.unwrap()
.create_session(&source.0, options, qh, udata),
))))
}
}

#[derive(Debug)]
struct CaptureSessionInner(zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2);

impl Drop for CaptureSessionInner {
fn drop(&mut self) {
self.0.destroy();
}
}

#[derive(Clone, Debug)]
pub struct CaptureSession(Arc<CaptureSessionInner>);

impl CaptureSession {
pub fn capture<D, U>(
&self,
buffer: &wl_buffer::WlBuffer,
buffer_damage: &[Rect],
qh: &QueueHandle<D>,
udata: U,
) -> zcosmic_screencopy_frame_v2::ZcosmicScreencopyFrameV2
where
D: Dispatch<zcosmic_screencopy_frame_v2::ZcosmicScreencopyFrameV2, U> + 'static,
U: ScreencopyFrameDataExt + Send + Sync + 'static,
{
let frame = self.0 .0.create_frame(qh, udata);
frame.attach_buffer(buffer);
for Rect {
x,
y,
width,
height,
} in buffer_damage
{
frame.damage_buffer(*x, *y, *width, *height);
}
frame.capture();
frame
}
}

#[derive(Debug)]
pub struct ScreencopyState {
capturer: Capturer,
}

impl ScreencopyState {
pub fn try_new<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Option<Self>
pub fn new<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self
where
D: 'static,
D: Dispatch<zcosmic_screencopy_manager_v2::ZcosmicScreencopyManagerV2, GlobalData>,
Expand All @@ -110,38 +183,23 @@ impl ScreencopyState {
GlobalData,
>,
{
// TODO bind
let screencopy_manager = globals.bind(qh, 1..=1, GlobalData).ok()?;
let screencopy_manager = globals.bind(qh, 1..=1, GlobalData).ok();
let output_source_manager = globals.bind(qh, 1..=1, GlobalData).ok();
let toplevel_source_manager = globals.bind(qh, 1..=1, GlobalData).ok();
let workspace_source_manager = globals.bind(qh, 1..=1, GlobalData).ok();

Some(Self {
let capturer = Capturer(Arc::new(CapturerInner {
screencopy_manager,
output_source_manager,
toplevel_source_manager,
workspace_source_manager,
})
}));

Self { capturer }
}

pub fn new<D>(globals: &GlobalList, qh: &QueueHandle<D>) -> Self
where
D: 'static,
D: Dispatch<zcosmic_screencopy_manager_v2::ZcosmicScreencopyManagerV2, GlobalData>,
D: Dispatch<
zcosmic_output_image_source_manager_v1::ZcosmicOutputImageSourceManagerV1,
GlobalData,
>,
D: Dispatch<
zcosmic_toplevel_image_source_manager_v1::ZcosmicToplevelImageSourceManagerV1,
GlobalData,
>,
D: Dispatch<
zcosmic_workspace_image_source_manager_v1::ZcosmicWorkspaceImageSourceManagerV1,
GlobalData,
>,
{
Self::try_new(globals, qh).unwrap()
pub fn capturer(&self) -> &Capturer {
&self.capturer
}
}

Expand All @@ -152,6 +210,7 @@ pub trait ScreencopyHandler: Sized {
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
// TODO session
session: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
formats: &Formats,
);
Expand All @@ -160,6 +219,7 @@ pub trait ScreencopyHandler: Sized {
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
// TODO session
session: &zcosmic_screencopy_session_v2::ZcosmicScreencopySessionV2,
);

Expand Down Expand Up @@ -187,6 +247,7 @@ pub trait ScreencopySessionDataExt {
#[derive(Default)]
pub struct ScreencopySessionData {
formats: Mutex<Formats>,
// Weak capture session?
}

impl ScreencopySessionDataExt for ScreencopySessionData {
Expand Down

0 comments on commit d249c57

Please sign in to comment.