// 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}, wayland::image_copy_capture::{ CursorSession, CursorSessionRef, Frame, FrameRef, Session, SessionRef, }, }; use crate::shell::{CosmicSurface, Workspace}; type ImageCopySessionsData = RefCell; type PendingImageCopyBuffers = Mutex>; pub type SessionData = Mutex; pub struct SessionUserData { pub dt: OutputDamageTracker, commit_counter: CommitCounter, buffer_age: HashMap, CommitCounter>, } impl SessionUserData { pub fn new(tracker: OutputDamageTracker) -> SessionUserData { SessionUserData { dt: tracker, commit_counter: CommitCounter::default(), buffer_age: HashMap::new(), } } pub fn age_for_buffer(&mut self, buffer: &WlBuffer) -> usize { self.buffer_age.retain(|k, _| k.upgrade().is_ok()); let weak = buffer.downgrade(); let age = self .commit_counter .distance(self.buffer_age.get(&weak).copied()) .unwrap_or(0); self.buffer_age.insert(weak, self.commit_counter); self.commit_counter.increment(); age } pub fn reset(&mut self) { self.commit_counter = CommitCounter::default(); self.buffer_age.clear(); } } #[derive(Debug, Default)] pub struct ImageCopySessions { sessions: Vec, cursor_sessions: Vec, } pub trait SessionHolder { fn add_session(&mut self, session: Session); 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: &CursorSessionRef); fn cursor_sessions(&self) -> Vec; } pub trait FrameHolder { 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 { fn add_session(&mut self, session: Session) { self.user_data() .insert_if_missing(ImageCopySessionsData::default); self.user_data() .get::() .unwrap() .borrow_mut() .sessions .push(session); } fn remove_session(&mut self, session: &SessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .sessions .retain(|s| s != session); } fn sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() .sessions .iter() .map(|s| (*s).clone()) .collect() }) } fn add_cursor_session(&mut self, session: CursorSession) { self.user_data() .insert_if_missing(ImageCopySessionsData::default); self.user_data() .get::() .unwrap() .borrow_mut() .cursor_sessions .push(session); } fn remove_cursor_session(&mut self, session: &CursorSessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .cursor_sessions .retain(|s| s != session); } fn cursor_sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() .cursor_sessions .iter() .map(|s| (*s).clone()) .collect() }) } } impl FrameHolder for Output { fn add_frame(&mut self, session: SessionRef, frame: Frame) { self.user_data() .insert_if_missing_threadsafe(PendingImageCopyBuffers::default); self.user_data() .get::() .unwrap() .lock() .unwrap() .push((session, 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<(SessionRef, Frame)> { self.user_data() .get::() .map(|pending| std::mem::take(&mut *pending.lock().unwrap())) .unwrap_or_default() } } impl SessionHolder for Workspace { fn add_session(&mut self, session: Session) { self.image_copy.sessions.push(session); } fn remove_session(&mut self, session: &SessionRef) { self.image_copy.sessions.retain(|s| s != session); } fn sessions(&self) -> Vec { self.image_copy .sessions .iter() .map(|s| (*s).clone()) .collect() } fn add_cursor_session(&mut self, session: CursorSession) { self.image_copy.cursor_sessions.push(session); } fn remove_cursor_session(&mut self, session: &CursorSessionRef) { self.image_copy.cursor_sessions.retain(|s| s != session); } fn cursor_sessions(&self) -> Vec { self.image_copy .cursor_sessions .iter() .map(|s| (*s).clone()) .collect() } } impl SessionHolder for CosmicSurface { fn add_session(&mut self, session: Session) { self.user_data() .insert_if_missing(ImageCopySessionsData::default); self.user_data() .get::() .unwrap() .borrow_mut() .sessions .push(session); } fn remove_session(&mut self, session: &SessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .sessions .retain(|s| s != session); } fn sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() .sessions .iter() .map(|s| (*s).clone()) .collect() }) } fn add_cursor_session(&mut self, session: CursorSession) { self.user_data() .insert_if_missing(ImageCopySessionsData::default); self.user_data() .get::() .unwrap() .borrow_mut() .cursor_sessions .push(session); } fn remove_cursor_session(&mut self, session: &CursorSessionRef) { self.user_data() .get::() .unwrap() .borrow_mut() .cursor_sessions .retain(|s| s != session); } fn cursor_sessions(&self) -> Vec { self.user_data() .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() .cursor_sessions .iter() .map(|s| (*s).clone()) .collect() }) } }