image-copy: Use abstraction that's now provided by Smithay

This doesn't change much, since the Smithay implementation is based on
the `cosmic-comp` version, but made more generic. We provide our own
implementation for our workspace capture protocol, but otherwise Smithay
handles the boilerplate now.

This should not cause any change in behavior.
This commit is contained in:
Ian Douglas Scott 2026-01-13 18:26:26 -08:00 • committed by Victoria Brekenfeld
parent 0f7e53b600
commit cac7a5aca6
16 changed files with 285 additions and 1536 deletions

View file

@ -1,4 +1,59 @@
use crate::state::State;
use crate::wayland::protocols::image_capture_source::delegate_image_capture_source;
// SPDX-License-Identifier: GPL-3.0-only
delegate_image_capture_source!(State);
use crate::{
state::State,
wayland::protocols::{
image_capture_source::{ImageCaptureSourceKind, delegate_cosmic_image_capture_source},
toplevel_info::window_from_ext,
},
};
use smithay::{
output::Output,
wayland::{
foreign_toplevel_list::ForeignToplevelHandle,
image_capture_source::{
ImageCaptureSource, ImageCaptureSourceHandler, OutputCaptureSourceHandler,
OutputCaptureSourceState, ToplevelCaptureSourceHandler, ToplevelCaptureSourceState,
},
},
};
impl ImageCaptureSourceHandler for State {
fn source_destroyed(&mut self, _source: ImageCaptureSource) {}
}
impl OutputCaptureSourceHandler for State {
fn output_capture_source_state(&mut self) -> &mut OutputCaptureSourceState {
&mut self.common.output_capture_source_state
}
fn output_source_created(&mut self, source: ImageCaptureSource, output: &Output) {
source
.user_data()
.insert_if_missing(|| ImageCaptureSourceKind::Output(output.downgrade()));
}
}
impl ToplevelCaptureSourceHandler for State {
fn toplevel_capture_source_state(&mut self) -> &mut ToplevelCaptureSourceState {
&mut self.common.toplevel_capture_source_state
}
fn toplevel_source_created(
&mut self,
source: ImageCaptureSource,
toplevel: &ForeignToplevelHandle,
) {
let data = match window_from_ext(self, toplevel) {
Some(toplevel) => ImageCaptureSourceKind::Toplevel(toplevel.clone()),
None => ImageCaptureSourceKind::Destroyed,
};
source.user_data().insert_if_missing(|| data);
}
}
smithay::delegate_image_capture_source!(State);
smithay::delegate_output_capture_source!(State);
smithay::delegate_toplevel_capture_source!(State);
delegate_cosmic_image_capture_source!(State);

View file

@ -1,3 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-only
use std::{borrow::Borrow, collections::HashMap, sync::Mutex};
use smithay::{
@ -15,7 +17,15 @@ use smithay::{
output::Output,
reexports::wayland_server::protocol::wl_shm::Format as ShmFormat,
utils::{Buffer as BufferCoords, Point, Size, Transform},
wayland::{dmabuf::get_dmabuf, seat::WaylandFocus},
wayland::{
dmabuf::get_dmabuf,
image_capture_source::ImageCaptureSource,
image_copy_capture::{
BufferConstraints, CursorSession, CursorSessionRef, DmabufConstraints, Frame, FrameRef,
ImageCopyCaptureHandler, ImageCopyCaptureState, Session, SessionRef,
},
seat::WaylandFocus,
},
};
use crate::{
@ -24,45 +34,41 @@ use crate::{
utils::prelude::{
OutputExt, PointExt, PointGlobalExt, PointLocalExt, RectExt, RectLocalExt, SeatExt,
},
wayland::protocols::{
image_capture_source::ImageCaptureSourceData,
screencopy::{
BufferConstraints, CursorSession, CursorSessionRef, DmabufConstraints, Frame, FrameRef,
ScreencopyHandler, ScreencopyState, Session, SessionRef, delegate_screencopy,
},
},
wayland::protocols::image_capture_source::ImageCaptureSourceKind,
};
mod render;
mod user_data;
pub use self::render::*;
use self::user_data::*;
pub use self::user_data::{FrameHolder, ScreencopySessions, SessionData, SessionHolder};
pub use self::user_data::{FrameHolder, ImageCopySessions, SessionData, SessionHolder};
impl ScreencopyHandler for State {
fn screencopy_state(&mut self) -> &mut ScreencopyState {
&mut self.common.screencopy_state
impl ImageCopyCaptureHandler for State {
fn image_copy_capture_state(&mut self) -> &mut ImageCopyCaptureState {
&mut self.common.image_copy_capture_state
}
fn capture_source(&mut self, source: &ImageCaptureSourceData) -> Option<BufferConstraints> {
match source {
ImageCaptureSourceData::Output(weak) => weak
fn capture_constraints(&mut self, source: &ImageCaptureSource) -> Option<BufferConstraints> {
let kind = source.user_data().get::<ImageCaptureSourceKind>().unwrap();
match kind {
ImageCaptureSourceKind::Output(weak) => weak
.upgrade()
.and_then(|output| constraints_for_output(&output, &mut self.backend)),
ImageCaptureSourceData::Workspace(handle) => {
ImageCaptureSourceKind::Workspace(handle) => {
let shell = self.common.shell.read();
let output = shell.workspaces.space_for_handle(handle)?.output();
constraints_for_output(output, &mut self.backend)
}
ImageCaptureSourceData::Toplevel(window) => {
ImageCaptureSourceKind::Toplevel(window) => {
constraints_for_toplevel(window, &mut self.backend)
}
_ => None,
}
}
fn capture_cursor_source(
fn cursor_capture_constraints(
&mut self,
_source: &ImageCaptureSourceData,
_source: &ImageCaptureSource,
) -> Option<BufferConstraints> {
let size = if let Some((geometry, _)) = self
.common
@ -85,8 +91,14 @@ impl ScreencopyHandler for State {
}
fn new_session(&mut self, session: Session) {
match session.source() {
ImageCaptureSourceData::Output(weak) => {
let kind = session
.source()
.user_data()
.get::<ImageCaptureSourceKind>()
.unwrap()
.clone();
match kind {
ImageCaptureSourceKind::Output(weak) => {
let Some(mut output) = weak.upgrade() else {
session.stop();
return;
@ -100,7 +112,7 @@ impl ScreencopyHandler for State {
output.add_session(session);
}
ImageCaptureSourceData::Workspace(handle) => {
ImageCaptureSourceKind::Workspace(handle) => {
let mut shell = self.common.shell.write();
let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else {
session.stop();
@ -114,7 +126,7 @@ impl ScreencopyHandler for State {
});
workspace.add_session(session);
}
ImageCaptureSourceData::Toplevel(mut toplevel) => {
ImageCaptureSourceKind::Toplevel(mut toplevel) => {
let size = toplevel.geometry().size.to_physical(1);
session.user_data().insert_if_missing_threadsafe(|| {
Mutex::new(SessionUserData::new(OutputDamageTracker::new(
@ -125,9 +137,10 @@ impl ScreencopyHandler for State {
});
toplevel.add_session(session);
}
ImageCaptureSourceData::Destroyed => unreachable!(),
ImageCaptureSourceKind::Destroyed => unreachable!(),
}
}
fn new_cursor_session(&mut self, session: CursorSession) {
let (pointer_loc, pointer_size, hotspot) = {
let seat = self.common.shell.read().seats.last_active().clone();
@ -154,8 +167,14 @@ impl ScreencopyHandler for State {
)))
});
match session.source() {
ImageCaptureSourceData::Output(weak) => {
let kind = session
.source()
.user_data()
.get::<ImageCaptureSourceKind>()
.unwrap()
.clone();
match kind {
ImageCaptureSourceKind::Output(weak) => {
let Some(mut output) = weak.upgrade() else {
return;
};
@ -184,7 +203,7 @@ impl ScreencopyHandler for State {
output.add_cursor_session(session);
}
ImageCaptureSourceData::Workspace(handle) => {
ImageCaptureSourceKind::Workspace(handle) => {
let mut shell = self.common.shell.write();
let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else {
return;
@ -215,7 +234,7 @@ impl ScreencopyHandler for State {
workspace.add_cursor_session(session);
}
ImageCaptureSourceData::Toplevel(mut toplevel) => {
ImageCaptureSourceKind::Toplevel(mut toplevel) => {
let shell = self.common.shell.read();
if let Some(element) = shell.element_for_surface(&toplevel) {
if element.has_active_window(&toplevel) {
@ -238,38 +257,44 @@ impl ScreencopyHandler for State {
toplevel.add_cursor_session(session);
}
ImageCaptureSourceData::Destroyed => unreachable!(),
ImageCaptureSourceKind::Destroyed => unreachable!(),
}
}
fn frame(&mut self, session: SessionRef, frame: Frame) {
match session.source() {
ImageCaptureSourceData::Output(weak) => {
fn frame(&mut self, session: &SessionRef, frame: Frame) {
let kind = session
.source()
.user_data()
.get::<ImageCaptureSourceKind>()
.unwrap()
.clone();
match kind {
ImageCaptureSourceKind::Output(weak) => {
let Some(mut output) = weak.upgrade() else {
return;
};
output.add_frame(session, frame);
output.add_frame(session.clone(), frame);
self.backend.schedule_render(&output);
}
ImageCaptureSourceData::Workspace(handle) => {
ImageCaptureSourceKind::Workspace(handle) => {
render_workspace_to_buffer(self, session, frame, handle)
}
ImageCaptureSourceData::Toplevel(toplevel) => {
ImageCaptureSourceKind::Toplevel(toplevel) => {
render_window_to_buffer(self, session, frame, &toplevel)
}
ImageCaptureSourceData::Destroyed => unreachable!(),
ImageCaptureSourceKind::Destroyed => unreachable!(),
}
}
fn cursor_frame(&mut self, session: CursorSessionRef, frame: Frame) {
fn cursor_frame(&mut self, session: &CursorSessionRef, frame: Frame) {
if !session.has_cursor() {
frame.success(Transform::Normal, Vec::new(), self.common.clock.now());
return;
}
let seat = self.common.shell.read().seats.last_active().clone();
render_cursor_to_buffer(self, &session, frame, &seat);
render_cursor_to_buffer(self, session, frame, &seat);
}
fn frame_aborted(&mut self, frame: FrameRef) {
@ -280,13 +305,19 @@ impl ScreencopyHandler for State {
}
fn session_destroyed(&mut self, session: SessionRef) {
match session.source() {
ImageCaptureSourceData::Output(weak) => {
let kind = session
.source()
.user_data()
.get::<ImageCaptureSourceKind>()
.unwrap()
.clone();
match kind {
ImageCaptureSourceKind::Output(weak) => {
if let Some(mut output) = weak.upgrade() {
output.remove_session(&session);
}
}
ImageCaptureSourceData::Workspace(handle) => {
ImageCaptureSourceKind::Workspace(handle) => {
if let Some(workspace) = self
.common
.shell
@ -297,19 +328,25 @@ impl ScreencopyHandler for State {
workspace.remove_session(&session)
}
}
ImageCaptureSourceData::Toplevel(mut toplevel) => toplevel.remove_session(&session),
ImageCaptureSourceData::Destroyed => unreachable!(),
ImageCaptureSourceKind::Toplevel(mut toplevel) => toplevel.remove_session(&session),
ImageCaptureSourceKind::Destroyed => unreachable!(),
}
}
fn cursor_session_destroyed(&mut self, session: CursorSessionRef) {
match session.source() {
ImageCaptureSourceData::Output(weak) => {
let kind = session
.source()
.user_data()
.get::<ImageCaptureSourceKind>()
.unwrap()
.clone();
match kind {
ImageCaptureSourceKind::Output(weak) => {
if let Some(mut output) = weak.upgrade() {
output.remove_cursor_session(&session);
}
}
ImageCaptureSourceData::Workspace(handle) => {
ImageCaptureSourceKind::Workspace(handle) => {
if let Some(workspace) = self
.common
.shell
@ -320,10 +357,10 @@ impl ScreencopyHandler for State {
workspace.remove_cursor_session(&session)
}
}
ImageCaptureSourceData::Toplevel(mut toplevel) => {
ImageCaptureSourceKind::Toplevel(mut toplevel) => {
toplevel.remove_cursor_session(&session)
}
ImageCaptureSourceData::Destroyed => unreachable!(),
ImageCaptureSourceKind::Destroyed => unreachable!(),
}
}
}
@ -413,4 +450,4 @@ fn constraints_for_renderer(
constraints
}
delegate_screencopy!(State);
smithay::delegate_image_copy_capture!(State);

View file

@ -1,3 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-only
use calloop::LoopHandle;
use smithay::{
backend::{
@ -26,6 +28,9 @@ use smithay::{
},
wayland::{
dmabuf::get_dmabuf,
image_copy_capture::{
BufferConstraints, CaptureFailureReason, CursorSessionRef, Frame, SessionRef,
},
seat::WaylandFocus,
shm::{shm_format_to_fourcc, with_buffer_contents, with_buffer_contents_mut},
},
@ -43,13 +48,10 @@ use crate::{
state::{Common, KmsNodes, State},
utils::prelude::{PointExt, PointGlobalExt, RectExt, RectLocalExt, SeatExt},
wayland::{
handlers::screencopy::{
handlers::image_copy_capture::{
SessionData, SessionUserData, constraints_for_output, constraints_for_toplevel,
},
protocols::{
screencopy::{BufferConstraints, CursorSessionRef, FailureReason, Frame, SessionRef},
workspace::WorkspaceHandle,
},
protocols::workspace::WorkspaceHandle,
},
};
@ -165,7 +167,7 @@ where
.map_err(|err| R::Error::from_gles_error(GlesError::BufferAccessError(err)))
.and_then(|x| x)
{
frame.fail(FailureReason::Unknown);
frame.fail(CaptureFailureReason::Unknown);
return Err(err);
}
}
@ -249,7 +251,7 @@ where
)
.map_err(DTError::Rendering),
Err(err) => {
frame.fail(FailureReason::Unknown);
frame.fail(CaptureFailureReason::Unknown);
Err(err)
}
}
@ -257,7 +259,7 @@ where
pub fn render_workspace_to_buffer(
state: &mut State,
session: SessionRef,
session: &SessionRef,
frame: Frame,
handle: WorkspaceHandle,
) {
@ -278,14 +280,14 @@ pub fn render_workspace_to_buffer(
let buffer_size = buffer_dimensions(&buffer).unwrap();
if mode != Some(buffer_size) {
let Some(constraints) = constraints_for_output(&output, &mut state.backend) else {
output.remove_session(&session);
output.remove_session(session);
return;
};
session.update_constraints(constraints);
if let Some(data) = session.user_data().get::<SessionData>() {
*data.lock().unwrap() = SessionUserData::new(OutputDamageTracker::from_output(&output));
}
frame.fail(FailureReason::BufferConstraints);
frame.fail(CaptureFailureReason::BufferConstraints);
return;
}
@ -414,7 +416,7 @@ pub fn render_workspace_to_buffer(
Ok(renderer) => renderer,
Err(err) => {
warn!(?err, "Couldn't use node for screencopy");
frame.fail(FailureReason::Unknown);
frame.fail(CaptureFailureReason::Unknown);
return;
}
};
@ -495,12 +497,12 @@ smithay::render_elements! {
pub fn render_window_to_buffer(
state: &mut State,
session: SessionRef,
session: &SessionRef,
frame: Frame,
toplevel: &CosmicSurface,
) {
if !toplevel.alive() {
toplevel.clone().remove_session(&session);
toplevel.clone().remove_session(session);
return;
}
@ -509,7 +511,7 @@ pub fn render_window_to_buffer(
let buffer_size = buffer_dimensions(&buffer).unwrap();
if buffer_size != geometry.size.to_buffer(1, Transform::Normal) {
let Some(constraints) = constraints_for_toplevel(toplevel, &mut state.backend) else {
toplevel.clone().remove_session(&session);
toplevel.clone().remove_session(session);
return;
};
session.update_constraints(constraints);
@ -518,7 +520,7 @@ pub fn render_window_to_buffer(
*data.lock().unwrap() =
SessionUserData::new(OutputDamageTracker::new(size, 1.0, Transform::Normal));
}
frame.fail(FailureReason::BufferConstraints);
frame.fail(CaptureFailureReason::BufferConstraints);
return;
}
@ -666,7 +668,7 @@ pub fn render_window_to_buffer(
Ok(renderer) => renderer,
Err(err) => {
warn!(?err, "Couldn't use node for screencopy");
frame.fail(FailureReason::Unknown);
frame.fail(CaptureFailureReason::Unknown);
return;
}
};
@ -760,7 +762,7 @@ pub fn render_cursor_to_buffer(
Transform::Normal,
));
}
frame.fail(FailureReason::BufferConstraints);
frame.fail(CaptureFailureReason::BufferConstraints);
return;
}
@ -826,7 +828,7 @@ pub fn render_cursor_to_buffer(
Ok(renderer) => renderer,
Err(err) => {
warn!(?err, "Couldn't use node for screencopy");
frame.fail(FailureReason::Unknown);
frame.fail(CaptureFailureReason::Unknown);
return;
}
};

View file

@ -1,20 +1,20 @@
// SPDX-License-Identifier: GPL-3.0-only
use std::{cell::RefCell, collections::HashMap, sync::Mutex};
use smithay::{
backend::renderer::{damage::OutputDamageTracker, utils::CommitCounter},
output::Output,
reexports::wayland_server::{Resource, Weak, protocol::wl_buffer::WlBuffer},
};
use crate::{
shell::{CosmicSurface, Workspace},
wayland::protocols::screencopy::{
wayland::image_copy_capture::{
CursorSession, CursorSessionRef, Frame, FrameRef, Session, SessionRef,
},
};
type ScreencopySessionsData = RefCell<ScreencopySessions>;
type PendingScreencopyBuffers = Mutex<Vec<(SessionRef, Frame)>>;
use crate::shell::{CosmicSurface, Workspace};
type ImageCopySessionsData = RefCell<ImageCopySessions>;
type PendingImageCopyBuffers = Mutex<Vec<(SessionRef, Frame)>>;
pub type SessionData = Mutex<SessionUserData>;
@ -54,7 +54,7 @@ impl SessionUserData {
}
#[derive(Debug, Default)]
pub struct ScreencopySessions {
pub struct ImageCopySessions {
sessions: Vec<Session>,
cursor_sessions: Vec<CursorSession>,
}
@ -78,9 +78,9 @@ pub trait FrameHolder {
impl SessionHolder for Output {
fn add_session(&mut self, session: Session) {
self.user_data()
.insert_if_missing(ScreencopySessionsData::default);
.insert_if_missing(ImageCopySessionsData::default);
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -89,7 +89,7 @@ impl SessionHolder for Output {
fn remove_session(&mut self, session: &SessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -98,7 +98,7 @@ impl SessionHolder for Output {
fn sessions(&self) -> Vec<SessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()
@ -111,9 +111,9 @@ impl SessionHolder for Output {
fn add_cursor_session(&mut self, session: CursorSession) {
self.user_data()
.insert_if_missing(ScreencopySessionsData::default);
.insert_if_missing(ImageCopySessionsData::default);
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -122,7 +122,7 @@ impl SessionHolder for Output {
fn remove_cursor_session(&mut self, session: &CursorSessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -131,7 +131,7 @@ impl SessionHolder for Output {
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()
@ -146,22 +146,22 @@ impl SessionHolder for Output {
impl FrameHolder for Output {
fn add_frame(&mut self, session: SessionRef, frame: Frame) {
self.user_data()
.insert_if_missing_threadsafe(PendingScreencopyBuffers::default);
.insert_if_missing_threadsafe(PendingImageCopyBuffers::default);
self.user_data()
.get::<PendingScreencopyBuffers>()
.get::<PendingImageCopyBuffers>()
.unwrap()
.lock()
.unwrap()
.push((session, frame));
}
fn remove_frame(&mut self, frame: &FrameRef) {
if let Some(pending) = self.user_data().get::<PendingScreencopyBuffers>() {
if let Some(pending) = self.user_data().get::<PendingImageCopyBuffers>() {
pending.lock().unwrap().retain(|(_, f)| f != frame);
}
}
fn take_pending_frames(&self) -> Vec<(SessionRef, Frame)> {
self.user_data()
.get::<PendingScreencopyBuffers>()
.get::<PendingImageCopyBuffers>()
.map(|pending| std::mem::take(&mut *pending.lock().unwrap()))
.unwrap_or_default()
}
@ -169,14 +169,14 @@ impl FrameHolder for Output {
impl SessionHolder for Workspace {
fn add_session(&mut self, session: Session) {
self.screencopy.sessions.push(session);
self.image_copy.sessions.push(session);
}
fn remove_session(&mut self, session: &SessionRef) {
self.screencopy.sessions.retain(|s| s != session);
self.image_copy.sessions.retain(|s| s != session);
}
fn sessions(&self) -> Vec<SessionRef> {
self.screencopy
self.image_copy
.sessions
.iter()
.map(|s| (*s).clone())
@ -184,14 +184,14 @@ impl SessionHolder for Workspace {
}
fn add_cursor_session(&mut self, session: CursorSession) {
self.screencopy.cursor_sessions.push(session);
self.image_copy.cursor_sessions.push(session);
}
fn remove_cursor_session(&mut self, session: &CursorSessionRef) {
self.screencopy.cursor_sessions.retain(|s| s != session);
self.image_copy.cursor_sessions.retain(|s| s != session);
}
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
self.screencopy
self.image_copy
.cursor_sessions
.iter()
.map(|s| (*s).clone())
@ -202,9 +202,9 @@ impl SessionHolder for Workspace {
impl SessionHolder for CosmicSurface {
fn add_session(&mut self, session: Session) {
self.user_data()
.insert_if_missing(ScreencopySessionsData::default);
.insert_if_missing(ImageCopySessionsData::default);
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -213,7 +213,7 @@ impl SessionHolder for CosmicSurface {
fn remove_session(&mut self, session: &SessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -221,7 +221,7 @@ impl SessionHolder for CosmicSurface {
}
fn sessions(&self) -> Vec<SessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()
@ -234,9 +234,9 @@ impl SessionHolder for CosmicSurface {
fn add_cursor_session(&mut self, session: CursorSession) {
self.user_data()
.insert_if_missing(ScreencopySessionsData::default);
.insert_if_missing(ImageCopySessionsData::default);
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -245,7 +245,7 @@ impl SessionHolder for CosmicSurface {
fn remove_cursor_session(&mut self, session: &CursorSessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -254,7 +254,7 @@ impl SessionHolder for CosmicSurface {
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()

View file

@ -17,6 +17,7 @@ pub mod fractional_scale;
pub mod idle_inhibit;
pub mod idle_notify;
pub mod image_capture_source;
pub mod image_copy_capture;
pub mod input_method;
pub mod keyboard_shortcuts_inhibit;
pub mod layer_shell;
@ -29,7 +30,6 @@ pub mod pointer_gestures;
pub mod presentation;
pub mod primary_selection;
pub mod relative_pointer;
pub mod screencopy;
pub mod seat;
pub mod security_context;
pub mod selection;