wayland: Add screencopy protocol handler

This commit is contained in:
Victoria Brekenfeld 2022-10-28 18:34:08 +02:00
parent ff32f48f39
commit dd100d65e4
4 changed files with 655 additions and 37 deletions

81
Cargo.lock generated
View file

@ -309,7 +309,7 @@ dependencies = [
"smithay-egui", "smithay-egui",
"thiserror", "thiserror",
"wayland-backend", "wayland-backend",
"wayland-scanner 0.30.0-beta.10", "wayland-scanner 0.30.0-beta.12",
"xcursor", "xcursor",
"xdg", "xdg",
"xkbcommon 0.4.1", "xkbcommon 0.4.1",
@ -318,12 +318,12 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-protocols" name = "cosmic-protocols"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#3ff11df30ef551e1ccbdcb091930fe0d72266195" source = "git+https://github.com/pop-os/cosmic-protocols?branch=screencopy#e96daeceac966b6d21c79f2ebcc4b9934a69fa75"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"wayland-backend", "wayland-backend",
"wayland-protocols 0.30.0-beta.10", "wayland-protocols 0.30.0-beta.12",
"wayland-scanner 0.30.0-beta.10", "wayland-scanner 0.30.0-beta.12",
"wayland-server", "wayland-server",
] ]
@ -1048,6 +1048,19 @@ dependencies = [
"memoffset", "memoffset",
] ]
[[package]]
name = "nix"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
dependencies = [
"autocfg",
"bitflags",
"cfg-if",
"libc",
"memoffset",
]
[[package]] [[package]]
name = "nohash-hasher" name = "nohash-hasher"
version = "0.2.0" version = "0.2.0"
@ -1490,11 +1503,12 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]] [[package]]
name = "smithay" name = "smithay"
version = "0.3.0" version = "0.3.0"
source = "git+https://github.com/Smithay//smithay?rev=625cbca5#625cbca54981021000d5a33c1bdc711056ff6000" source = "git+https://github.com/Smithay//smithay?rev=0c7dbfa8#0c7dbfa830496df064a721f9cbbff6b474e6a268"
dependencies = [ dependencies = [
"appendlist", "appendlist",
"bitflags", "bitflags",
"calloop", "calloop",
"cc",
"cgmath", "cgmath",
"downcast-rs", "downcast-rs",
"drm", "drm",
@ -1511,6 +1525,7 @@ dependencies = [
"libseat", "libseat",
"nix 0.24.2", "nix 0.24.2",
"once_cell", "once_cell",
"pkg-config",
"rand", "rand",
"scan_fmt", "scan_fmt",
"slog", "slog",
@ -1520,11 +1535,11 @@ dependencies = [
"udev", "udev",
"wayland-backend", "wayland-backend",
"wayland-egl", "wayland-egl",
"wayland-protocols 0.30.0-beta.10", "wayland-protocols 0.30.0-beta.12",
"wayland-protocols-misc", "wayland-protocols-misc",
"wayland-protocols-wlr", "wayland-protocols-wlr",
"wayland-server", "wayland-server",
"wayland-sys 0.30.0-beta.10", "wayland-sys 0.30.0-beta.12",
"winit", "winit",
"x11rb", "x11rb",
"xkbcommon 0.5.0", "xkbcommon 0.5.0",
@ -1791,17 +1806,17 @@ checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]] [[package]]
name = "wayland-backend" name = "wayland-backend"
version = "0.1.0-beta.10" version = "0.1.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30c089c872513a8dcc2b5cc26209d83f5ffab1841d8c7973edf2583620ebc018" checksum = "2fe32234ad38fee0755aeec26db486a4b788dd3cc2c9dc86ceda31bb38a53f32"
dependencies = [ dependencies = [
"cc", "cc",
"downcast-rs", "downcast-rs",
"io-lifetimes", "io-lifetimes",
"nix 0.24.2", "nix 0.25.0",
"scoped-tls", "scoped-tls",
"smallvec", "smallvec",
"wayland-sys 0.30.0-beta.10", "wayland-sys 0.30.0-beta.12",
] ]
[[package]] [[package]]
@ -1845,13 +1860,13 @@ dependencies = [
[[package]] [[package]]
name = "wayland-egl" name = "wayland-egl"
version = "0.30.0-beta.10" version = "0.30.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6cb5591d75142e1b180691df4d27f164a09abbd6efc7cba9b119ca40646809c" checksum = "cfc1309ddfeabd942c09c21e9db2ed3de81b84d0ea7ebcdd2e503a0be0fe9c5f"
dependencies = [ dependencies = [
"thiserror", "thiserror",
"wayland-backend", "wayland-backend",
"wayland-sys 0.30.0-beta.10", "wayland-sys 0.30.0-beta.12",
] ]
[[package]] [[package]]
@ -1868,39 +1883,39 @@ dependencies = [
[[package]] [[package]]
name = "wayland-protocols" name = "wayland-protocols"
version = "0.30.0-beta.10" version = "0.30.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60406a2fb43ff670ece4976cdd0537bbcd1e583b54c3cd9a1b61065e966df0a7" checksum = "ca770dc814b3c93db1b4ba12a5bdfe899f8d68f9b4b06fc31e53959261cd0c39"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"wayland-backend", "wayland-backend",
"wayland-scanner 0.30.0-beta.10", "wayland-scanner 0.30.0-beta.12",
"wayland-server", "wayland-server",
] ]
[[package]] [[package]]
name = "wayland-protocols-misc" name = "wayland-protocols-misc"
version = "0.1.0-beta.10" version = "0.1.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653c3e200343bcfae719b668959efb9475bf9fcf43591cccfead308d32d67049" checksum = "25bfcd2c16bed3540d1c5662d97708ac4f14d92b7b5c52c85860cdc17a96a126"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"wayland-backend", "wayland-backend",
"wayland-protocols 0.30.0-beta.10", "wayland-protocols 0.30.0-beta.12",
"wayland-scanner 0.30.0-beta.10", "wayland-scanner 0.30.0-beta.12",
"wayland-server", "wayland-server",
] ]
[[package]] [[package]]
name = "wayland-protocols-wlr" name = "wayland-protocols-wlr"
version = "0.1.0-beta.10" version = "0.1.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1cfe42e0cfcce47a421844ee82e49316cfab3ec6bcbb3a1076a0a2dd6c8d61e" checksum = "8795f1c689bce3845292c1d84b8866fa65d1d1845e76769b13f71cadeb8b5853"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"wayland-backend", "wayland-backend",
"wayland-protocols 0.30.0-beta.10", "wayland-protocols 0.30.0-beta.12",
"wayland-scanner 0.30.0-beta.10", "wayland-scanner 0.30.0-beta.12",
"wayland-server", "wayland-server",
] ]
@ -1917,9 +1932,9 @@ dependencies = [
[[package]] [[package]]
name = "wayland-scanner" name = "wayland-scanner"
version = "0.30.0-beta.10" version = "0.30.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1398566f240c3ef845bdfd310c8ee6ba800d4db695d007f23f2190eeedfff93" checksum = "87def40ed0bc26c3eff1498812543b6d55bbd13b93e36d368052b7390a57c4ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quick-xml", "quick-xml",
@ -1929,16 +1944,16 @@ dependencies = [
[[package]] [[package]]
name = "wayland-server" name = "wayland-server"
version = "0.30.0-beta.10" version = "0.30.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "030557c71dfa3d7e0d0b5975bbdfee2eee319fde3e4c420cde63474c61331347" checksum = "8d54b4a800b230f4fb0f42cae245cc0aaa02bf14bf7c1c3a5e1a822d05fd2cb3"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"downcast-rs", "downcast-rs",
"nix 0.24.2", "nix 0.25.0",
"thiserror", "thiserror",
"wayland-backend", "wayland-backend",
"wayland-scanner 0.30.0-beta.10", "wayland-scanner 0.30.0-beta.12",
] ]
[[package]] [[package]]
@ -1954,9 +1969,9 @@ dependencies = [
[[package]] [[package]]
name = "wayland-sys" name = "wayland-sys"
version = "0.30.0-beta.10" version = "0.30.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bacc6b678c3350910e5ad6c057b7503666080952c4ece0a7e8958fd33937b1f5" checksum = "1117fe4570fe063122ba2b1b1e39e56fb1a73921d395f9288af06af0dd1c7f55"
dependencies = [ dependencies = [
"dlib", "dlib",
"libc", "libc",

View file

@ -29,9 +29,9 @@ indexmap = "1.8.0"
xdg = "^2.1" xdg = "^2.1"
ron = "0.7" ron = "0.7"
libsystemd = "0.5" libsystemd = "0.5"
wayland-backend = "=0.1.0-beta.10" wayland-backend = "=0.1.0-beta.12"
wayland-scanner = "=0.30.0-beta.10" wayland-scanner = "=0.30.0-beta.12"
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] } cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "screencopy", default-features = false, features = ["server"] }
[dependencies.smithay] [dependencies.smithay]
version = "0.3" version = "0.3"
@ -61,4 +61,4 @@ debug = true
lto = "fat" lto = "fat"
[patch."https://github.com/Smithay/smithay.git"] [patch."https://github.com/Smithay/smithay.git"]
smithay = { git = "https://github.com/Smithay//smithay", rev = "625cbca5" } smithay = { git = "https://github.com/Smithay//smithay", rev = "0c7dbfa8" }

View file

@ -3,6 +3,7 @@
pub mod drm; pub mod drm;
//pub mod export_dmabuf; //pub mod export_dmabuf;
pub mod output_configuration; pub mod output_configuration;
pub mod screencopy;
pub mod toplevel_info; pub mod toplevel_info;
pub mod toplevel_management; pub mod toplevel_management;
pub mod workspace; pub mod workspace;

View file

@ -0,0 +1,602 @@
// SPDX-License-Identifier: GPL-3.0-only
use std::{
sync::{Arc, Mutex},
time::Duration,
};
use cosmic_protocols::screencopy::v1::server::{
zcosmic_screencopy_manager_v1::{self, CursorMode, ZcosmicScreencopyManagerV1},
zcosmic_screencopy_session_v1::{self, FailureReason, InputType, ZcosmicScreencopySessionV1},
};
use smithay::{
backend::{
allocator::Fourcc as DrmFourcc,
drm::{DrmNode, NodeType},
},
desktop::Window,
reexports::wayland_server::{
protocol::{
wl_buffer::WlBuffer, wl_output::WlOutput, wl_seat::WlSeat, wl_shm::Format as ShmFormat,
},
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
},
utils::{user_data::UserDataMap, Buffer, Point, Rectangle, Size, Transform},
};
use wayland_backend::{protocol::WEnum, server::GlobalId};
use super::{
toplevel_info::window_from_handle,
workspace::{WorkspaceHandle, WorkspaceHandler},
};
/// Screencopy global state
pub struct ScreencopyState {
global: GlobalId,
}
pub struct ScreencopyGlobalData {
cursor_modes: Vec<CursorMode>,
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
}
impl ScreencopyState {
/// Create a new screencopy global
pub fn new<D, I, F>(
display: &DisplayHandle,
cursor_modes: I,
client_filter: F,
) -> ScreencopyState
where
D: GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData>
+ Dispatch<ZcosmicScreencopyManagerV1, ()>
+ Dispatch<ZcosmicScreencopySessionV1, ()>
+ ScreencopyHandler
+ WorkspaceHandler
+ 'static,
I: IntoIterator<Item = CursorMode>,
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
{
ScreencopyState {
global: display.create_global::<D, ZcosmicScreencopyManagerV1, _>(
1,
ScreencopyGlobalData {
cursor_modes: Vec::from_iter(cursor_modes),
filter: Box::new(client_filter),
},
),
}
}
/// Returns the screencopy global id
pub fn global(&self) -> GlobalId {
self.global.clone()
}
}
#[derive(Debug)]
pub enum BufferInfo {
Shm {
format: ShmFormat,
size: Size<i32, Buffer>,
stride: u32,
},
Dmabuf {
node: DrmNode,
format: DrmFourcc,
size: Size<i32, Buffer>,
},
}
#[derive(Debug)]
pub struct SessionDataInnerInner {
gone: bool,
pending_buffer: Option<BufferParams>,
aux: AuxData,
}
impl SessionDataInnerInner {
pub fn is_cursor(&self) -> bool {
match self.aux {
AuxData::Cursor { .. } => true,
_ => false,
}
}
}
#[derive(Debug)]
enum AuxData {
Normal { cursor_sessions: Vec<CursorSession> },
Cursor { seat: WlSeat },
}
impl AuxData {
pub fn seat(&self) -> &WlSeat {
match self {
AuxData::Cursor { seat } => seat,
_ => unreachable!("Unwrapped seat from aux data"),
}
}
pub fn cursor_sessions(&self) -> &[CursorSession] {
match self {
AuxData::Normal { cursor_sessions } => &cursor_sessions,
_ => unreachable!("Unwrapped cursor_session from aux data"),
}
}
}
#[derive(Debug)]
pub struct SessionDataInner {
inner: Mutex<SessionDataInnerInner>,
user_data: UserDataMap,
}
pub type SessionData = Arc<SessionDataInner>;
#[derive(Debug, Clone)]
pub struct Session {
obj: ZcosmicScreencopySessionV1,
data: SessionData,
}
impl PartialEq for Session {
fn eq(&self, other: &Self) -> bool {
self.obj == other.obj
}
}
impl Session {
pub fn cursor_enter(&self, seat: &WlSeat, input_type: InputType) {
self.obj.cursor_enter(seat, input_type)
}
pub fn cursor_info(
&self,
seat: &WlSeat,
input_type: InputType,
geometry: Rectangle<i32, Buffer>,
offset: Point<i32, Buffer>,
) {
self.obj.cursor_info(
seat,
input_type,
geometry.loc.x,
geometry.loc.y,
geometry.size.w,
geometry.size.h,
offset.x,
offset.y,
);
let data = self.data.inner.lock().unwrap();
for cursor_session in data.aux.cursor_sessions() {
cursor_session.obj.cursor_info(
seat,
input_type,
geometry.loc.x,
geometry.loc.y,
geometry.size.w,
geometry.size.h,
offset.x,
offset.y,
);
}
}
pub fn cursor_leave(&self, seat: &WlSeat, input_type: InputType) {
self.obj.cursor_leave(seat, input_type)
}
pub fn cursor_sessions(&self) -> impl Iterator<Item = CursorSession> {
self.data
.inner
.lock()
.unwrap()
.aux
.cursor_sessions()
.iter()
.cloned()
.collect::<Vec<_>>()
.into_iter()
}
pub fn commit_buffer(
&self,
transform: Transform,
damage: Vec<Rectangle<i32, Buffer>>,
time: Option<Duration>,
) {
self.obj.transform(transform.into());
for rect in damage {
self.obj.damage(
rect.loc.x as u32,
rect.loc.y as u32,
rect.size.w as u32,
rect.size.h as u32,
);
}
if let Some(time) = time {
let tv_sec_hi = (time.as_secs() >> 32) as u32;
let tv_sec_lo = (time.as_secs() & 0xFFFFFFFF) as u32;
self.obj
.commit_time(tv_sec_hi, tv_sec_lo, time.subsec_nanos());
}
self.obj.ready()
}
pub fn failed(&self, reason: FailureReason) {
self.obj.failed(reason);
self.data.inner.lock().unwrap().gone = true;
}
pub fn user_data(&self) -> &UserDataMap {
&self.data.user_data
}
}
#[derive(Debug, Clone)]
pub struct CursorSession {
obj: ZcosmicScreencopySessionV1,
data: SessionData,
}
impl PartialEq for CursorSession {
fn eq(&self, other: &Self) -> bool {
self.obj == other.obj
}
}
impl CursorSession {
pub fn seat(&self) -> WlSeat {
self.data.inner.lock().unwrap().aux.seat().clone()
}
pub fn buffer_waiting(&self) -> Option<BufferParams> {
self.data.inner.lock().unwrap().pending_buffer.take()
}
pub fn commit_buffer<'a>(
&self,
transform: Transform,
damage: impl Iterator<Item = &'a Rectangle<i32, Buffer>> + 'a,
) {
self.obj.transform(transform.into());
for rect in damage {
self.obj.damage(
rect.loc.x as u32,
rect.loc.y as u32,
rect.size.w as u32,
rect.size.h as u32,
);
}
}
pub fn failed(&self, reason: FailureReason) {
self.obj.failed(reason);
self.data.inner.lock().unwrap().gone = true;
}
pub fn user_data(&self) -> &UserDataMap {
&self.data.user_data
}
}
#[derive(Debug)]
pub struct BufferParams {
pub buffer: WlBuffer,
pub node: Option<DrmNode>,
pub age: u32,
}
pub trait ScreencopyHandler {
fn capture_output(
&mut self,
output: WlOutput,
cursor: CursorMode,
session: Session,
) -> Vec<BufferInfo>;
fn capture_workspace(
&mut self,
workspace: WorkspaceHandle,
output: WlOutput,
cursor: CursorMode,
session: Session,
) -> Vec<BufferInfo>;
fn capture_toplevel(
&mut self,
toplevel: Window,
cursor: CursorMode,
session: Session,
) -> Vec<BufferInfo>;
fn capture_cursor(&mut self, session: CursorSession) -> Vec<BufferInfo>;
fn buffer_attached(&mut self, session: Session, buffer: BufferParams, on_damage: bool);
fn session_destroyed(&mut self, session: Session);
}
impl<D> GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData, D> for ScreencopyState
where
D: GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData>
+ Dispatch<ZcosmicScreencopyManagerV1, ()>
+ Dispatch<ZcosmicScreencopySessionV1, SessionData>
+ ScreencopyHandler
+ WorkspaceHandler
+ 'static,
{
fn bind(
_state: &mut D,
_handle: &DisplayHandle,
_client: &Client,
resource: New<ZcosmicScreencopyManagerV1>,
global_data: &ScreencopyGlobalData,
data_init: &mut DataInit<'_, D>,
) {
let global = data_init.init(resource, ());
for mode in &global_data.cursor_modes {
global.supported_cursor_mode(*mode);
}
}
fn can_view(client: Client, global_data: &ScreencopyGlobalData) -> bool {
(global_data.filter)(&client)
}
}
fn init_session<D>(
data_init: &mut DataInit<'_, D>,
session: New<ZcosmicScreencopySessionV1>,
cursor: WEnum<CursorMode>,
) -> Option<(Session, CursorMode)>
where
D: GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData>
+ Dispatch<ZcosmicScreencopyManagerV1, ()>
+ Dispatch<ZcosmicScreencopySessionV1, SessionData>
+ ScreencopyHandler
+ WorkspaceHandler
+ 'static,
{
let data = Arc::new(SessionDataInner {
inner: Mutex::new(SessionDataInnerInner {
gone: false,
pending_buffer: None,
aux: AuxData::Normal {
cursor_sessions: Vec::new(),
},
}),
user_data: UserDataMap::new(),
});
let session = data_init.init(session, data.clone());
let cursor_mode = match cursor.into_result() {
Ok(mode) => mode,
Err(err) => {
slog_scope::warn!("Client did send unknown cursor mode: {}", err);
session.failed(FailureReason::UnknownInput);
return None;
}
};
let session = Session { obj: session, data };
Some((session, cursor_mode))
}
impl<D> Dispatch<ZcosmicScreencopyManagerV1, (), D> for ScreencopyState
where
D: GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData>
+ Dispatch<ZcosmicScreencopyManagerV1, ()>
+ Dispatch<ZcosmicScreencopySessionV1, SessionData>
+ ScreencopyHandler
+ WorkspaceHandler
+ 'static,
{
fn request(
state: &mut D,
_client: &Client,
_resource: &ZcosmicScreencopyManagerV1,
request: <ZcosmicScreencopyManagerV1 as smithay::reexports::wayland_server::Resource>::Request,
_data: &(),
_dhandle: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
zcosmic_screencopy_manager_v1::Request::CaptureOutput {
session,
output,
cursor,
} => {
let (session, cursor_mode) = match init_session(data_init, session, cursor) {
Some(result) => result,
None => {
return;
}
};
let formats = state.capture_output(output, cursor_mode, session.clone());
if !session.data.inner.lock().unwrap().gone {
send_formats(&session.obj, formats);
}
}
zcosmic_screencopy_manager_v1::Request::CaptureToplevel {
session,
toplevel,
cursor,
} => {
let (session, cursor_mode) = match init_session(data_init, session, cursor) {
Some(result) => result,
None => {
return;
}
};
match window_from_handle(toplevel) {
Some(window) => {
let formats = state.capture_toplevel(window, cursor_mode, session.clone());
if !session.data.inner.lock().unwrap().gone {
send_formats(&session.obj, formats);
}
}
None => {
session.obj.failed(FailureReason::ToplevelDestroyed);
return;
}
}
}
zcosmic_screencopy_manager_v1::Request::CaptureWorkspace {
session,
workspace,
output,
cursor,
} => {
let (session, cursor_mode) = match init_session(data_init, session, cursor) {
Some(result) => result,
None => {
return;
}
};
match state.workspace_state().workspace_handle(&workspace) {
Some(handle) => {
let formats =
state.capture_workspace(handle, output, cursor_mode, session.clone());
if !session.data.inner.lock().unwrap().gone {
send_formats(&session.obj, formats);
}
}
None => {
session.failed(FailureReason::InvalidOutput);
return;
}
}
}
_ => {}
}
}
}
impl<D> Dispatch<ZcosmicScreencopySessionV1, SessionData, D> for ScreencopyState
where
D: GlobalDispatch<ZcosmicScreencopyManagerV1, ScreencopyGlobalData>
+ Dispatch<ZcosmicScreencopyManagerV1, ()>
+ Dispatch<ZcosmicScreencopySessionV1, SessionData>
+ ScreencopyHandler
+ 'static,
{
fn request(
state: &mut D,
_client: &Client,
resource: &ZcosmicScreencopySessionV1,
request: <ZcosmicScreencopySessionV1 as Resource>::Request,
data: &SessionData,
_dhandle: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
zcosmic_screencopy_session_v1::Request::CaptureCursor { session, seat } => {
{
let resource_data = data.inner.lock().unwrap();
if resource_data.is_cursor() || resource_data.gone {
resource.failed(FailureReason::Unspec);
return;
}
}
let data = Arc::new(SessionDataInner {
inner: Mutex::new(SessionDataInnerInner {
gone: false,
pending_buffer: None,
aux: AuxData::Cursor { seat },
}),
user_data: UserDataMap::new(),
});
let session = data_init.init(session, data.clone());
let cursor_session = CursorSession { obj: session, data };
let formats = state.capture_cursor(cursor_session.clone());
if !cursor_session.data.inner.lock().unwrap().gone {
send_formats(&cursor_session.obj, formats);
}
}
zcosmic_screencopy_session_v1::Request::AttachBuffer { buffer, node, age } => {
if data.inner.lock().unwrap().gone {
resource.failed(FailureReason::Unspec);
return;
}
let params = BufferParams {
buffer,
node: node.and_then(|p| DrmNode::from_path(p).ok()),
age,
};
data.inner.lock().unwrap().pending_buffer = Some(params);
}
zcosmic_screencopy_session_v1::Request::Commit { options } => {
{
let resource_data = data.inner.lock().unwrap();
if resource_data.is_cursor() || resource_data.gone {
resource.failed(FailureReason::Unspec);
return;
}
}
if let Some(buffer) = data.inner.lock().unwrap().pending_buffer.take() {
let session = Session {
obj: resource.clone(),
data: data.clone(),
};
state.buffer_attached(
session,
buffer,
options
.into_result()
.ok()
.map(|v| v.contains(zcosmic_screencopy_session_v1::Options::OnDamage))
.unwrap_or(false),
);
} else {
resource.failed(FailureReason::InvalidBuffer);
}
}
zcosmic_screencopy_session_v1::Request::Destroy => {
data.inner.lock().unwrap().gone = true;
}
_ => {}
}
}
}
fn send_formats(session: &ZcosmicScreencopySessionV1, formats: Vec<BufferInfo>) {
for format in formats {
match format {
BufferInfo::Dmabuf { node, format, size } => {
if let Some(node_path) = node
.dev_path_with_type(NodeType::Render)
.or_else(|| node.dev_path())
{
session.buffer_info(
zcosmic_screencopy_session_v1::BufferType::Dmabuf,
Some(node_path.as_os_str().to_string_lossy().into_owned()),
format as u32,
size.w as u32,
size.h as u32,
0,
);
}
}
BufferInfo::Shm {
format,
size,
stride,
} => session.buffer_info(
zcosmic_screencopy_session_v1::BufferType::WlShm,
None,
format as u32,
size.w as u32,
size.h as u32,
stride,
),
}
}
session.init_done();
}