diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index 10a461a3..32243184 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -5,7 +5,7 @@ use crate::{ config::{AdaptiveSync, EdidProduct, OutputConfig, OutputState, ScreenFilter}, shell::Shell, utils::prelude::*, - wayland::protocols::screencopy::Frame as ScreencopyFrame, + wayland::protocols::screencopy::Frame, }; use anyhow::{Context, Result}; @@ -65,7 +65,7 @@ pub type GbmDrmOutputManager = DrmOutputManager< GbmFramebufferExporter, Option<( OutputPresentationFeedback, - Receiver<(ScreencopyFrame, Vec>)>, + Receiver<(Frame, Vec>)>, Duration, )>, DrmDeviceFd, diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index b0d39102..5122495a 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -13,7 +13,7 @@ use crate::{ wayland::{ handlers::screencopy::{submit_buffer, FrameHolder, SessionData}, protocols::screencopy::{ - FailureReason, Frame as ScreencopyFrame, Session as ScreencopySession, + FailureReason, Frame as ScreencopyFrame, SessionRef as ScreencopySessionRef, }, }, }; @@ -1024,7 +1024,7 @@ impl SurfaceThreadState { // so let's collect everything we need for screencopy now let mut has_cursor_mode_none = false; let frames: Vec<( - ScreencopySession, + ScreencopySessionRef, ScreencopyFrame, Result<(Option>>, RenderElementStates), OutputNoMode>, )> = self diff --git a/src/input/mod.rs b/src/input/mod.rs index 5a9de2e8..8c0c5e63 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -27,7 +27,7 @@ use crate::{ utils::{float::NextDown, prelude::*, quirks::workspace_overview_is_open}, wayland::{ handlers::screencopy::SessionHolder, - protocols::screencopy::{BufferConstraints, CursorSession}, + protocols::screencopy::{BufferConstraints, CursorSessionRef}, }, }; use calloop::{ @@ -2262,7 +2262,7 @@ impl State { fn cursor_sessions_for_output<'a>( shell: &'a Shell, output: &'a Output, -) -> impl Iterator + 'a { +) -> impl Iterator + 'a { shell .active_space(&output) .into_iter() diff --git a/src/wayland/handlers/screencopy/mod.rs b/src/wayland/handlers/screencopy/mod.rs index 75aed8d4..90673f8e 100644 --- a/src/wayland/handlers/screencopy/mod.rs +++ b/src/wayland/handlers/screencopy/mod.rs @@ -27,8 +27,9 @@ use crate::{ wayland::protocols::{ image_capture_source::ImageCaptureSourceData, screencopy::{ - delegate_screencopy, BufferConstraints, CursorSession, DmabufConstraints, Frame, - ScreencopyHandler, ScreencopyState, Session, + delegate_screencopy, BufferConstraints, CursorSession, CursorSessionRef, + DmabufConstraints, Frame, FrameRef, ScreencopyHandler, ScreencopyState, Session, + SessionRef, }, }, }; @@ -165,7 +166,6 @@ impl ScreencopyHandler for State { match session.source() { ImageCaptureSourceData::Output(weak) => { let Some(mut output) = weak.upgrade() else { - session.stop(); return; }; @@ -196,7 +196,6 @@ impl ScreencopyHandler for State { ImageCaptureSourceData::Workspace(handle) => { let mut shell = self.common.shell.write().unwrap(); let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else { - session.stop(); return; }; @@ -252,11 +251,10 @@ impl ScreencopyHandler for State { } } - fn frame(&mut self, session: Session, frame: Frame) { + fn frame(&mut self, session: SessionRef, frame: Frame) { match session.source() { ImageCaptureSourceData::Output(weak) => { let Some(mut output) = weak.upgrade() else { - session.stop(); // will fail the frame as well return; }; @@ -273,7 +271,7 @@ impl ScreencopyHandler for State { } } - fn cursor_frame(&mut self, session: CursorSession, 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; @@ -290,18 +288,18 @@ impl ScreencopyHandler for State { render_cursor_to_buffer(self, &session, frame, &seat); } - fn frame_aborted(&mut self, frame: Frame) { + fn frame_aborted(&mut self, frame: FrameRef) { let shell = self.common.shell.read().unwrap(); for mut output in shell.outputs().cloned() { - output.remove_frame(&frame) + output.remove_frame(&frame); } } - fn session_destroyed(&mut self, session: Session) { + fn session_destroyed(&mut self, session: SessionRef) { match session.source() { ImageCaptureSourceData::Output(weak) => { if let Some(mut output) = weak.upgrade() { - output.remove_session(session); + output.remove_session(&session); } } ImageCaptureSourceData::Workspace(handle) => { @@ -313,19 +311,19 @@ impl ScreencopyHandler for State { .workspaces .space_for_handle_mut(&handle) { - workspace.remove_session(session) + workspace.remove_session(&session) } } - ImageCaptureSourceData::Toplevel(mut toplevel) => toplevel.remove_session(session), + ImageCaptureSourceData::Toplevel(mut toplevel) => toplevel.remove_session(&session), ImageCaptureSourceData::Destroyed => unreachable!(), } } - fn cursor_session_destroyed(&mut self, session: CursorSession) { + fn cursor_session_destroyed(&mut self, session: CursorSessionRef) { match session.source() { ImageCaptureSourceData::Output(weak) => { if let Some(mut output) = weak.upgrade() { - output.remove_cursor_session(session); + output.remove_cursor_session(&session); } } ImageCaptureSourceData::Workspace(handle) => { @@ -337,11 +335,11 @@ impl ScreencopyHandler for State { .workspaces .space_for_handle_mut(&handle) { - workspace.remove_cursor_session(session) + workspace.remove_cursor_session(&session) } } ImageCaptureSourceData::Toplevel(mut toplevel) => { - toplevel.remove_cursor_session(session) + toplevel.remove_cursor_session(&session) } ImageCaptureSourceData::Destroyed => unreachable!(), } diff --git a/src/wayland/handlers/screencopy/render.rs b/src/wayland/handlers/screencopy/render.rs index 3c7754d7..c2eb7c2e 100644 --- a/src/wayland/handlers/screencopy/render.rs +++ b/src/wayland/handlers/screencopy/render.rs @@ -46,13 +46,13 @@ use crate::{ constraints_for_output, constraints_for_toplevel, SessionData, SessionUserData, }, protocols::{ - screencopy::{BufferConstraints, CursorSession, FailureReason, Frame, Session}, + screencopy::{BufferConstraints, CursorSessionRef, FailureReason, Frame, SessionRef}, workspace::WorkspaceHandle, }, }, }; -use super::super::data_device::get_dnd_icon; +use super::{super::data_device::get_dnd_icon, user_data::SessionHolder}; pub fn submit_buffer( frame: Frame, @@ -205,17 +205,16 @@ where pub fn render_workspace_to_buffer( state: &mut State, - session: Session, + session: SessionRef, frame: Frame, handle: WorkspaceHandle, ) { let shell = state.common.shell.read().unwrap(); let Some(workspace) = shell.workspaces.space_for_handle(&handle) else { - session.stop(); return; }; - let output = workspace.output().clone(); + let mut output = workspace.output().clone(); let idx = shell.workspaces.idx_for_handle(&output, &handle).unwrap(); std::mem::drop(shell); @@ -227,7 +226,7 @@ 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 { - session.stop(); + output.remove_session(&session); return; }; session.update_constraints(constraints); @@ -439,12 +438,12 @@ smithay::render_elements! { pub fn render_window_to_buffer( state: &mut State, - session: Session, + session: SessionRef, frame: Frame, toplevel: &CosmicSurface, ) { if !toplevel.alive() { - session.stop(); + toplevel.clone().remove_session(&session); return; } @@ -453,7 +452,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 { - session.stop(); + toplevel.clone().remove_session(&session); return; }; session.update_constraints(constraints); @@ -663,7 +662,7 @@ pub fn render_window_to_buffer( pub fn render_cursor_to_buffer( state: &mut State, - session: &CursorSession, + session: &CursorSessionRef, frame: Frame, seat: &Seat, ) { diff --git a/src/wayland/handlers/screencopy/user_data.rs b/src/wayland/handlers/screencopy/user_data.rs index 6ef98778..b780b0dd 100644 --- a/src/wayland/handlers/screencopy/user_data.rs +++ b/src/wayland/handlers/screencopy/user_data.rs @@ -1,9 +1,4 @@ -use std::{ - cell::RefCell, - collections::HashMap, - ops::{Deref, DerefMut}, - sync::Mutex, -}; +use std::{cell::RefCell, collections::HashMap, sync::Mutex}; use smithay::{ backend::renderer::{damage::OutputDamageTracker, utils::CommitCounter}, @@ -13,11 +8,13 @@ use smithay::{ use crate::{ shell::{CosmicSurface, Workspace}, - wayland::protocols::screencopy::{CursorSession, FailureReason, Frame, Session}, + wayland::protocols::screencopy::{ + CursorSession, CursorSessionRef, Frame, FrameRef, Session, SessionRef, + }, }; type ScreencopySessionsData = RefCell; -type PendingScreencopyBuffers = Mutex>; +type PendingScreencopyBuffers = Mutex>; pub type SessionData = Mutex; @@ -58,24 +55,24 @@ impl SessionUserData { #[derive(Debug, Default)] pub struct ScreencopySessions { - sessions: Vec, - cursor_sessions: Vec, + sessions: Vec, + cursor_sessions: Vec, } pub trait SessionHolder { fn add_session(&mut self, session: Session); - fn remove_session(&mut self, session: Session); - fn sessions(&self) -> Vec; + fn remove_session(&mut self, session: &SessionRef); + fn sessions(&self) -> Vec; fn add_cursor_session(&mut self, session: CursorSession); - fn remove_cursor_session(&mut self, session: CursorSession); - fn cursor_sessions(&self) -> Vec; + fn remove_cursor_session(&mut self, session: &CursorSessionRef); + fn cursor_sessions(&self) -> Vec; } pub trait FrameHolder { - fn add_frame(&mut self, session: Session, frame: Frame); - fn remove_frame(&mut self, frame: &Frame); - fn take_pending_frames(&self) -> Vec<(Session, Frame)>; + fn add_frame(&mut self, session: SessionRef, frame: Frame); + fn remove_frame(&mut self, frame: &FrameRef); + fn take_pending_frames(&self) -> Vec<(SessionRef, Frame)>; } impl SessionHolder for Output { @@ -87,19 +84,19 @@ impl SessionHolder for Output { .unwrap() .borrow_mut() .sessions - .push(DropableSession(Some(session))); + .push(session); } - fn remove_session(&mut self, session: Session) { + fn remove_session(&mut self, session: &SessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .sessions - .retain(|s| *s != session); + .retain(|s| s != session); } - fn sessions(&self) -> Vec { + fn sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { @@ -107,7 +104,7 @@ impl SessionHolder for Output { .borrow() .sessions .iter() - .flat_map(|s| s.0.clone()) + .map(|s| (*s).clone()) .collect() }) } @@ -120,19 +117,19 @@ impl SessionHolder for Output { .unwrap() .borrow_mut() .cursor_sessions - .push(DropableCursorSession(Some(session))); + .push(session); } - fn remove_cursor_session(&mut self, session: CursorSession) { + fn remove_cursor_session(&mut self, session: &CursorSessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .cursor_sessions - .retain(|s| *s != session); + .retain(|s| s != session); } - fn cursor_sessions(&self) -> Vec { + fn cursor_sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { @@ -140,14 +137,14 @@ impl SessionHolder for Output { .borrow() .cursor_sessions .iter() - .flat_map(|s| s.0.clone()) + .map(|s| (*s).clone()) .collect() }) } } impl FrameHolder for Output { - fn add_frame(&mut self, session: Session, frame: Frame) { + fn add_frame(&mut self, session: SessionRef, frame: Frame) { self.user_data() .insert_if_missing_threadsafe(PendingScreencopyBuffers::default); self.user_data() @@ -155,61 +152,49 @@ impl FrameHolder for Output { .unwrap() .lock() .unwrap() - .push((session, DropableFrame(Some(frame)))); + .push((session, frame)); } - fn remove_frame(&mut self, frame: &Frame) { + fn remove_frame(&mut self, frame: &FrameRef) { if let Some(pending) = self.user_data().get::() { pending.lock().unwrap().retain(|(_, f)| f != frame); } } - fn take_pending_frames(&self) -> Vec<(Session, Frame)> { + fn take_pending_frames(&self) -> Vec<(SessionRef, Frame)> { self.user_data() .get::() - .map(|pending| { - pending - .lock() - .unwrap() - .split_off(0) - .into_iter() - .map(|(s, mut f)| (s, f.0.take().unwrap())) - .collect() - }) + .map(|pending| std::mem::take(&mut *pending.lock().unwrap())) .unwrap_or_default() } } impl SessionHolder for Workspace { fn add_session(&mut self, session: Session) { - self.screencopy - .sessions - .push(DropableSession(Some(session))); + self.screencopy.sessions.push(session); } - fn remove_session(&mut self, session: Session) { - self.screencopy.sessions.retain(|s| *s != session); + fn remove_session(&mut self, session: &SessionRef) { + self.screencopy.sessions.retain(|s| s != session); } - fn sessions(&self) -> Vec { + fn sessions(&self) -> Vec { self.screencopy .sessions .iter() - .flat_map(|s| s.0.clone()) + .map(|s| (*s).clone()) .collect() } fn add_cursor_session(&mut self, session: CursorSession) { - self.screencopy - .cursor_sessions - .push(DropableCursorSession(Some(session))); + self.screencopy.cursor_sessions.push(session); } - fn remove_cursor_session(&mut self, session: CursorSession) { - self.screencopy.cursor_sessions.retain(|s| *s != session); + fn remove_cursor_session(&mut self, session: &CursorSessionRef) { + self.screencopy.cursor_sessions.retain(|s| s != session); } - fn cursor_sessions(&self) -> Vec { + fn cursor_sessions(&self) -> Vec { self.screencopy .cursor_sessions .iter() - .flat_map(|s| s.0.clone()) + .map(|s| (*s).clone()) .collect() } } @@ -223,18 +208,18 @@ impl SessionHolder for CosmicSurface { .unwrap() .borrow_mut() .sessions - .push(DropableSession(Some(session))); + .push(session); } - fn remove_session(&mut self, session: Session) { + fn remove_session(&mut self, session: &SessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .sessions - .retain(|s| *s != session); + .retain(|s| s != session); } - fn sessions(&self) -> Vec { + fn sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { @@ -242,7 +227,7 @@ impl SessionHolder for CosmicSurface { .borrow() .sessions .iter() - .flat_map(|s| s.0.clone()) + .map(|s| (*s).clone()) .collect() }) } @@ -255,19 +240,19 @@ impl SessionHolder for CosmicSurface { .unwrap() .borrow_mut() .cursor_sessions - .push(DropableCursorSession(Some(session))); + .push(session); } - fn remove_cursor_session(&mut self, session: CursorSession) { + fn remove_cursor_session(&mut self, session: &CursorSessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .cursor_sessions - .retain(|s| *s != session); + .retain(|s| s != session); } - fn cursor_sessions(&self) -> Vec { + fn cursor_sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { @@ -275,86 +260,8 @@ impl SessionHolder for CosmicSurface { .borrow() .cursor_sessions .iter() - .flat_map(|s| s.0.clone()) + .map(|s| (*s).clone()) .collect() }) } } - -#[derive(Debug)] -struct DropableSession(Option); -impl Deref for DropableSession { - type Target = Session; - fn deref(&self) -> &Self::Target { - self.0.as_ref().unwrap() - } -} -impl DerefMut for DropableSession { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut().unwrap() - } -} -impl PartialEq for DropableSession { - fn eq(&self, other: &Session) -> bool { - self.0.as_ref().map(|s| s == other).unwrap_or(false) - } -} -impl Drop for DropableSession { - fn drop(&mut self) { - if let Some(s) = self.0.take() { - s.stop(); - } - } -} - -#[derive(Debug)] -struct DropableCursorSession(Option); -impl Deref for DropableCursorSession { - type Target = CursorSession; - fn deref(&self) -> &Self::Target { - self.0.as_ref().unwrap() - } -} -impl DerefMut for DropableCursorSession { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut().unwrap() - } -} -impl PartialEq for DropableCursorSession { - fn eq(&self, other: &CursorSession) -> bool { - self.0.as_ref().map(|s| s == other).unwrap_or(false) - } -} -impl Drop for DropableCursorSession { - fn drop(&mut self) { - if let Some(s) = self.0.take() { - s.stop(); - } - } -} - -#[derive(Debug)] -pub struct DropableFrame(Option); -impl Deref for DropableFrame { - type Target = Frame; - fn deref(&self) -> &Self::Target { - self.0.as_ref().unwrap() - } -} -impl DerefMut for DropableFrame { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut().unwrap() - } -} -impl PartialEq for DropableFrame { - fn eq(&self, other: &Frame) -> bool { - self.0.as_ref().map(|f| f == other).unwrap_or(false) - } -} -impl Drop for DropableFrame { - fn drop(&mut self) { - if let Some(f) = self.0.take() { - f.fail(FailureReason::Unknown); - } - } -} diff --git a/src/wayland/protocols/screencopy.rs b/src/wayland/protocols/screencopy.rs index 26a8a543..85669d05 100644 --- a/src/wayland/protocols/screencopy.rs +++ b/src/wayland/protocols/screencopy.rs @@ -1,4 +1,5 @@ use std::{ + ops, sync::{Arc, Mutex}, time::Duration, }; @@ -37,8 +38,8 @@ use super::image_capture_source::ImageCaptureSourceData; #[derive(Debug)] pub struct ScreencopyState { global: GlobalId, - known_sessions: Vec, - known_cursor_sessions: Vec, + known_sessions: Vec, + known_cursor_sessions: Vec, } impl ScreencopyState { @@ -85,13 +86,13 @@ pub struct DmabufConstraints { } #[derive(Debug, Clone)] -pub struct Session { +pub struct SessionRef { obj: ExtImageCopyCaptureSessionV1, inner: Arc>, user_data: Arc, } -impl PartialEq for Session { +impl PartialEq for SessionRef { fn eq(&self, other: &Self) -> bool { self.obj == other.obj } @@ -103,7 +104,7 @@ struct SessionInner { constraints: Option, draw_cursors: bool, source: ImageCaptureSourceData, - active_frames: Vec, + active_frames: Vec, } impl SessionInner { @@ -118,13 +119,13 @@ impl SessionInner { } } -impl IsAlive for Session { +impl IsAlive for SessionRef { fn alive(&self) -> bool { self.obj.is_alive() } } -impl Session { +impl SessionRef { pub fn update_constraints(&self, constraints: BufferConstraints) { let mut inner = self.inner.lock().unwrap(); @@ -168,16 +169,38 @@ impl Session { pub fn user_data(&self) -> &UserDataMap { &*self.user_data } +} - pub fn stop(self) { - let mut inner = self.inner.lock().unwrap(); +#[derive(Debug)] +pub struct Session(SessionRef); + +impl ops::Deref for Session { + type Target = SessionRef; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl PartialEq for Session { + fn eq(&self, other: &SessionRef) -> bool { + self.0 == *other + } +} + +impl Drop for Session { + fn drop(&mut self) { + let mut inner = self.0.inner.lock().unwrap(); if !self.obj.is_alive() || inner.stopped { return; } for frame in inner.active_frames.drain(..) { - frame.fail(FailureReason::Stopped); + frame + .inner + .lock() + .unwrap() + .fail(&frame.obj, FailureReason::Stopped); } self.obj.stopped(); @@ -186,14 +209,20 @@ impl Session { } } +impl Session { + pub fn stop(self) { + let _ = self; + } +} + #[derive(Debug, Clone)] -pub struct CursorSession { +pub struct CursorSessionRef { obj: ExtImageCopyCaptureCursorSessionV1, inner: Arc>, user_data: Arc, } -impl PartialEq for CursorSession { +impl PartialEq for CursorSessionRef { fn eq(&self, other: &Self) -> bool { self.obj == other.obj } @@ -207,7 +236,7 @@ struct CursorSessionInner { source: ImageCaptureSourceData, position: Option>, hotspot: Point, - active_frames: Vec, + active_frames: Vec, } impl CursorSessionInner { @@ -224,13 +253,13 @@ impl CursorSessionInner { } } -impl IsAlive for CursorSession { +impl IsAlive for CursorSessionRef { fn alive(&self) -> bool { self.obj.is_alive() } } -impl CursorSession { +impl CursorSessionRef { pub fn update_constraints(&self, constrains: BufferConstraints) { let mut inner = self.inner.lock().unwrap(); @@ -319,11 +348,29 @@ impl CursorSession { pub fn user_data(&self) -> &UserDataMap { &*self.user_data } +} - pub fn stop(self) { - let mut inner = self.inner.lock().unwrap(); +#[derive(Debug)] +pub struct CursorSession(CursorSessionRef); - if !self.obj.is_alive() || inner.stopped { +impl ops::Deref for CursorSession { + type Target = CursorSessionRef; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl PartialEq for CursorSession { + fn eq(&self, other: &CursorSessionRef) -> bool { + self.0 == *other + } +} + +impl Drop for CursorSession { + fn drop(&mut self) { + let mut inner = self.0.inner.lock().unwrap(); + + if !self.0.obj.is_alive() || inner.stopped { return; } @@ -333,26 +380,37 @@ impl CursorSession { inner.constraints.take(); for frame in inner.active_frames.drain(..) { - frame.fail(FailureReason::Stopped); + frame + .inner + .lock() + .unwrap() + .fail(&frame.obj, FailureReason::Stopped); } inner.stopped = true; } } -#[derive(Debug)] -pub struct Frame { +impl CursorSession { + pub fn stop(self) { + let _ = self; + } +} + +/// Un-owned reference to a frame +#[derive(Clone, Debug)] +pub struct FrameRef { obj: ExtImageCopyCaptureFrameV1, inner: Arc>, } -impl PartialEq for Frame { +impl PartialEq for FrameRef { fn eq(&self, other: &Self) -> bool { self.obj == other.obj } } -impl Frame { +impl FrameRef { pub fn buffer(&self) -> WlBuffer { self.inner.lock().unwrap().buffer.clone().unwrap() } @@ -364,7 +422,26 @@ impl Frame { pub fn has_failed(&self) -> bool { self.inner.lock().unwrap().failed.is_some() } +} +#[derive(Debug, PartialEq)] +pub struct Frame(FrameRef); + +impl ops::Deref for Frame { + type Target = FrameRef; + + fn deref(&self) -> &FrameRef { + &self.0 + } +} + +impl PartialEq for Frame { + fn eq(&self, other: &FrameRef) -> bool { + self.0 == *other + } +} + +impl Frame { pub fn success( self, transform: impl Into, @@ -372,7 +449,7 @@ impl Frame { presented: impl Into, ) { { - let inner = self.inner.lock().unwrap(); + let inner = self.0.inner.lock().unwrap(); if !inner.capture_requested || inner.failed.is_some() { return; } @@ -390,12 +467,22 @@ impl Frame { let tv_nsec = time.subsec_nanos(); self.obj.presentation_time(tv_sec_hi, tv_sec_lo, tv_nsec); - self.inner.lock().unwrap().ready = true; + self.0.inner.lock().unwrap().ready = true; self.obj.ready() } pub fn fail(self, reason: FailureReason) { - self.inner.lock().unwrap().fail(&self.obj, reason); + self.0.inner.lock().unwrap().fail(&self.obj, reason); + } +} + +impl Drop for Frame { + fn drop(&mut self) { + // Send `fail` is `sucesss` or `fail` not already called + self.inner + .lock() + .unwrap() + .fail(&self.obj, FailureReason::Unknown); } } @@ -404,7 +491,7 @@ struct FrameInner { constraints: Option, buffer: Option, damage: Vec>, - // `SessionInner` contains a `Vec`, so use a weak reference here to + // `SessionInner` contains a `Vec`, so use a weak reference here to // avoid a cycle. obj: Weak, capture_requested: bool, @@ -451,14 +538,14 @@ pub trait ScreencopyHandler { fn new_session(&mut self, session: Session); fn new_cursor_session(&mut self, session: CursorSession); - fn frame(&mut self, session: Session, frame: Frame); - fn cursor_frame(&mut self, session: CursorSession, frame: Frame); + fn frame(&mut self, session: SessionRef, frame: Frame); + fn cursor_frame(&mut self, session: CursorSessionRef, frame: Frame); - fn frame_aborted(&mut self, frame: Frame); - fn session_destroyed(&mut self, session: Session) { + fn frame_aborted(&mut self, frame_handle: FrameRef); + fn session_destroyed(&mut self, session: SessionRef) { let _ = session; } - fn cursor_session_destroyed(&mut self, session: CursorSession) { + fn cursor_session_destroyed(&mut self, session: CursorSessionRef) { let _ = session; } } @@ -546,7 +633,7 @@ where }, ); - let session = Session { + let session = SessionRef { obj, inner: session_data, user_data: Arc::new(UserDataMap::new()), @@ -556,7 +643,7 @@ where .screencopy_state() .known_sessions .push(session.clone()); - state.new_session(session); + state.new_session(Session(session)); return; } } @@ -572,11 +659,11 @@ where inner: session_data.clone(), }, ); - let session = Session { + let session = Session(SessionRef { obj, inner: session_data, user_data: Arc::new(UserDataMap::new()), - }; + }); session.stop(); } ext_image_copy_capture_manager_v1::Request::CreatePointerCursorSession { @@ -598,7 +685,7 @@ where }, ); - let session = CursorSession { + let session = CursorSessionRef { obj, inner: session_data, user_data: Arc::new(UserDataMap::new()), @@ -608,7 +695,7 @@ where .screencopy_state() .known_cursor_sessions .push(session.clone()); - state.new_cursor_session(session); + state.new_cursor_session(CursorSession(session)); return; } } @@ -623,11 +710,11 @@ where inner: session_data.clone(), }, ); - let session = CursorSession { + let session = CursorSession(CursorSessionRef { obj, inner: session_data, user_data: Arc::new(UserDataMap::new()), - }; + }); session.stop(); } _ => {} @@ -675,7 +762,7 @@ where .lock() .unwrap() .active_frames - .push(Frame { obj, inner }); + .push(FrameRef { obj, inner }); } _ => {} } @@ -808,7 +895,7 @@ where .lock() .unwrap() .active_frames - .push(Frame { obj, inner }); + .push(FrameRef { obj, inner }); } _ => {} } @@ -877,155 +964,32 @@ where .push(Rectangle::new((x, y).into(), (width, height).into())); } ext_image_copy_capture_frame_v1::Request::Capture => { - let mut inner = data.inner.lock().unwrap(); + { + let inner = data.inner.lock().unwrap(); - if inner.capture_requested { - resource.post_error( - ext_image_copy_capture_frame_v1::Error::AlreadyCaptured, - "Frame was captured previously", - ); - } - - if inner.buffer.is_none() { - resource.post_error( - ext_image_copy_capture_frame_v1::Error::NoBuffer, - "Attempting to capture frame without a buffer", - ); - } - - inner.capture_requested = true; - - if let Some(reason) = inner.failed { - inner.fail(resource, reason); - return; - } - - if let Some(constraints) = inner.constraints.as_ref() { - let buffer = inner.buffer.as_ref().unwrap(); - match buffer_type(buffer) { - Some(BufferType::Dma) => { - let Some(dma_constraints) = constraints.dma.as_ref() else { - debug!("dma buffer not specified for screencopy"); - inner.fail(resource, FailureReason::BufferConstraints); - return; - }; - - let dmabuf = match get_dmabuf(buffer) { - Ok(buf) => buf, - Err(err) => { - debug!(?err, "Error accessing dma buffer for screencopy"); - inner.fail(resource, FailureReason::Stopped); - return; - } - }; - - let buffer_size = dmabuf.size(); - if buffer_size.w < constraints.size.w - || buffer_size.h < constraints.size.h - { - debug!(?buffer_size, ?constraints.size, "buffer too small for screencopy"); - inner.fail(&resource, FailureReason::BufferConstraints); - return; - } - - let format = dmabuf.format(); - if dma_constraints - .formats - .iter() - .find(|(fourcc, _)| *fourcc == format.code) - .filter(|(_, modifiers)| modifiers.contains(&format.modifier)) - .is_none() - { - debug!( - ?format, - ?dma_constraints, - "unsupported buffer format for screencopy" - ); - inner.fail(&resource, FailureReason::BufferConstraints); - return; - } - } - Some(BufferType::Shm) => { - let buffer_data = match with_buffer_contents(buffer, |_, _, data| data) - { - Ok(data) => data, - Err(err) => { - debug!(?err, "Error accessing shm buffer for screencopy"); - inner.fail(&resource, FailureReason::Unknown); - return; - } - }; - - if buffer_data.width < constraints.size.w - || buffer_data.height < constraints.size.h - { - debug!(?buffer_data, ?constraints.size, "buffer too small for screencopy"); - inner.fail(&resource, FailureReason::BufferConstraints); - return; - } - - if !constraints.shm.contains(&buffer_data.format) { - debug!(?buffer_data.format, ?constraints.shm, "unsupported buffer format for screencopy"); - inner.fail(&resource, FailureReason::BufferConstraints); - return; - } - } - x => { - debug!(?x, "Attempt to screencopy with unsupported buffer type"); - inner.fail(&resource, FailureReason::BufferConstraints); - return; - } + if inner.capture_requested { + resource.post_error( + ext_image_copy_capture_frame_v1::Error::AlreadyCaptured, + "Frame was captured previously", + ); + return; + } + + if inner.buffer.is_none() { + resource.post_error( + ext_image_copy_capture_frame_v1::Error::NoBuffer, + "Attempting to capture frame without a buffer", + ); + return; } - } else { - inner.fail(&resource, FailureReason::Unknown); - return; } - let frame = Frame { + let frame = Frame(FrameRef { obj: resource.clone(), inner: data.inner.clone(), - }; - - let scpy = state.screencopy_state(); - if let Some(session) = scpy - .known_sessions - .iter() - .find(|session| session.obj == inner.obj) - .map(|s| Session { - obj: s.obj.clone(), - inner: s.inner.clone(), - user_data: s.user_data.clone(), - }) - { - if session.inner.lock().unwrap().stopped { - inner.fail(&resource, FailureReason::Stopped); - return; - } - - std::mem::drop(inner); - state.frame(session, frame); - } else if let Some(session) = scpy - .known_cursor_sessions - .iter() - .find(|session| { - session.inner.lock().unwrap().session.as_ref() - == inner.obj.upgrade().ok().as_ref() - }) - .map(|s| CursorSession { - obj: s.obj.clone(), - inner: s.inner.clone(), - user_data: s.user_data.clone(), - }) - { - if session.inner.lock().unwrap().stopped { - inner.fail(&resource, FailureReason::Stopped); - return; - } - - std::mem::drop(inner); - state.cursor_frame(session, frame); - } else { - inner.fail(&resource, FailureReason::Unknown); + }); + if let Err(reason) = capture_frame(state, frame) { + data.inner.lock().unwrap().fail(resource, reason); } } _ => {} @@ -1038,6 +1002,10 @@ where resource: &ExtImageCopyCaptureFrameV1, data: &FrameData, ) { + let frame_ref = FrameRef { + obj: resource.clone(), + inner: data.inner.clone(), + }; { let scpy = state.screencopy_state(); for session in &mut scpy.known_sessions { @@ -1046,7 +1014,7 @@ where .lock() .unwrap() .active_frames - .retain(|frame| frame.obj != *resource); + .retain(|i| *i != frame_ref); } for cursor_session in &mut scpy.known_cursor_sessions { cursor_session @@ -1054,14 +1022,121 @@ where .lock() .unwrap() .active_frames - .retain(|frame| frame.obj != *resource); + .retain(|i| *i != frame_ref); } } - let frame = Frame { - obj: resource.clone(), - inner: data.inner.clone(), - }; - state.frame_aborted(frame); + state.frame_aborted(frame_ref); + } +} + +fn capture_frame(state: &mut D, frame: Frame) -> Result<(), FailureReason> { + let mut inner = frame.0.inner.lock().unwrap(); + + inner.capture_requested = true; + + if let Some(reason) = inner.failed { + return Err(reason); + } + + if let Some(constraints) = inner.constraints.as_ref() { + let buffer = inner.buffer.as_ref().unwrap(); + match buffer_type(buffer) { + Some(BufferType::Dma) => { + let Some(dma_constraints) = constraints.dma.as_ref() else { + debug!("dma buffer not specified for screencopy"); + return Err(FailureReason::BufferConstraints); + }; + + let dmabuf = match get_dmabuf(buffer) { + Ok(buf) => buf, + Err(err) => { + debug!(?err, "Error accessing dma buffer for screencopy"); + return Err(FailureReason::Stopped); + } + }; + + let buffer_size = dmabuf.size(); + if buffer_size.w < constraints.size.w || buffer_size.h < constraints.size.h { + debug!(?buffer_size, ?constraints.size, "buffer too small for screencopy"); + return Err(FailureReason::BufferConstraints); + } + + let format = dmabuf.format(); + if dma_constraints + .formats + .iter() + .find(|(fourcc, _)| *fourcc == format.code) + .filter(|(_, modifiers)| modifiers.contains(&format.modifier)) + .is_none() + { + debug!( + ?format, + ?dma_constraints, + "unsupported buffer format for screencopy" + ); + return Err(FailureReason::BufferConstraints); + } + } + Some(BufferType::Shm) => { + let buffer_data = match with_buffer_contents(buffer, |_, _, data| data) { + Ok(data) => data, + Err(err) => { + debug!(?err, "Error accessing shm buffer for screencopy"); + return Err(FailureReason::Unknown); + } + }; + + if buffer_data.width < constraints.size.w || buffer_data.height < constraints.size.h + { + debug!(?buffer_data, ?constraints.size, "buffer too small for screencopy"); + return Err(FailureReason::BufferConstraints); + } + + if !constraints.shm.contains(&buffer_data.format) { + debug!(?buffer_data.format, ?constraints.shm, "unsupported buffer format for screencopy"); + return Err(FailureReason::BufferConstraints); + } + } + x => { + debug!(?x, "Attempt to screencopy with unsupported buffer type"); + return Err(FailureReason::BufferConstraints); + } + } + } else { + return Err(FailureReason::Unknown); + } + + let scpy = state.screencopy_state(); + if let Some(session) = scpy + .known_sessions + .iter() + .find(|session| session.obj == inner.obj) + .cloned() + { + if session.inner.lock().unwrap().stopped { + return Err(FailureReason::Stopped); + } + + std::mem::drop(inner); + state.frame(session, frame); + Ok(()) + } else if let Some(session) = scpy + .known_cursor_sessions + .iter() + .find(|session| { + session.inner.lock().unwrap().session.as_ref() == inner.obj.upgrade().ok().as_ref() + }) + .cloned() + { + if session.inner.lock().unwrap().stopped { + return Err(FailureReason::Stopped); + } + + std::mem::drop(inner); + state.cursor_frame(session, frame); + Ok(()) + } else { + Err(FailureReason::Unknown) } }