protocols/screencopy: Make frame/session send stopped/fail on drop
Previously, `Frame` was stored in KMS frame udata, but in some cases the udata was dropped without a capture happening, and `Frame` did not implement `Drop`, so `fail` was never sent. Instead, rename `DropableFrame` to `Frame` and `Frame` to `FrameRef`, so we can have a single instance of `Frame`, that will send `fail` on drop. This guarantees either `.success` or `.fail` are send, as long as its not leaked. This seems to fix https://github.com/pop-os/cosmic-comp/issues/1305. xdg-desktop-portal-cosmic prints an error, buy retries (as it should for an `Unknown` error; though maybe there should be a retry limit) and the session continues working. (Not sure if it should be sending `failed`, or queing it with the next frame so it can send `success` to the client, but this works and is desirable as a failsafe anyway.) `Session` and `CursorSession` are similiarly updated. `.fail()`, `.success()`, and `.stop()` now consume `Frame`/`Session`/`CursorSession`. So to stop a session, it is now necessary to call `.remove_session()`, but then simply dropping with send `.stop()`. Factoring out some `Request::Capture` handling into a `capture_frame` function seems to clean up error handling and such a bit.
This commit is contained in:
parent
9c7033df10
commit
194d5c8967
7 changed files with 346 additions and 367 deletions
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
config::{AdaptiveSync, EdidProduct, OutputConfig, OutputState, ScreenFilter},
|
config::{AdaptiveSync, EdidProduct, OutputConfig, OutputState, ScreenFilter},
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::protocols::screencopy::Frame as ScreencopyFrame,
|
wayland::protocols::screencopy::Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
@ -65,7 +65,7 @@ pub type GbmDrmOutputManager = DrmOutputManager<
|
||||||
GbmFramebufferExporter<DrmDeviceFd>,
|
GbmFramebufferExporter<DrmDeviceFd>,
|
||||||
Option<(
|
Option<(
|
||||||
OutputPresentationFeedback,
|
OutputPresentationFeedback,
|
||||||
Receiver<(ScreencopyFrame, Vec<Rectangle<i32, BufferCoords>>)>,
|
Receiver<(Frame, Vec<Rectangle<i32, BufferCoords>>)>,
|
||||||
Duration,
|
Duration,
|
||||||
)>,
|
)>,
|
||||||
DrmDeviceFd,
|
DrmDeviceFd,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::screencopy::{submit_buffer, FrameHolder, SessionData},
|
handlers::screencopy::{submit_buffer, FrameHolder, SessionData},
|
||||||
protocols::screencopy::{
|
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
|
// so let's collect everything we need for screencopy now
|
||||||
let mut has_cursor_mode_none = false;
|
let mut has_cursor_mode_none = false;
|
||||||
let frames: Vec<(
|
let frames: Vec<(
|
||||||
ScreencopySession,
|
ScreencopySessionRef,
|
||||||
ScreencopyFrame,
|
ScreencopyFrame,
|
||||||
Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), OutputNoMode>,
|
Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), OutputNoMode>,
|
||||||
)> = self
|
)> = self
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ use crate::{
|
||||||
utils::{float::NextDown, prelude::*, quirks::workspace_overview_is_open},
|
utils::{float::NextDown, prelude::*, quirks::workspace_overview_is_open},
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::screencopy::SessionHolder,
|
handlers::screencopy::SessionHolder,
|
||||||
protocols::screencopy::{BufferConstraints, CursorSession},
|
protocols::screencopy::{BufferConstraints, CursorSessionRef},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use calloop::{
|
use calloop::{
|
||||||
|
|
@ -2262,7 +2262,7 @@ impl State {
|
||||||
fn cursor_sessions_for_output<'a>(
|
fn cursor_sessions_for_output<'a>(
|
||||||
shell: &'a Shell,
|
shell: &'a Shell,
|
||||||
output: &'a Output,
|
output: &'a Output,
|
||||||
) -> impl Iterator<Item = CursorSession> + 'a {
|
) -> impl Iterator<Item = CursorSessionRef> + 'a {
|
||||||
shell
|
shell
|
||||||
.active_space(&output)
|
.active_space(&output)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,9 @@ use crate::{
|
||||||
wayland::protocols::{
|
wayland::protocols::{
|
||||||
image_capture_source::ImageCaptureSourceData,
|
image_capture_source::ImageCaptureSourceData,
|
||||||
screencopy::{
|
screencopy::{
|
||||||
delegate_screencopy, BufferConstraints, CursorSession, DmabufConstraints, Frame,
|
delegate_screencopy, BufferConstraints, CursorSession, CursorSessionRef,
|
||||||
ScreencopyHandler, ScreencopyState, Session,
|
DmabufConstraints, Frame, FrameRef, ScreencopyHandler, ScreencopyState, Session,
|
||||||
|
SessionRef,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -165,7 +166,6 @@ impl ScreencopyHandler for State {
|
||||||
match session.source() {
|
match session.source() {
|
||||||
ImageCaptureSourceData::Output(weak) => {
|
ImageCaptureSourceData::Output(weak) => {
|
||||||
let Some(mut output) = weak.upgrade() else {
|
let Some(mut output) = weak.upgrade() else {
|
||||||
session.stop();
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -196,7 +196,6 @@ impl ScreencopyHandler for State {
|
||||||
ImageCaptureSourceData::Workspace(handle) => {
|
ImageCaptureSourceData::Workspace(handle) => {
|
||||||
let mut shell = self.common.shell.write().unwrap();
|
let mut shell = self.common.shell.write().unwrap();
|
||||||
let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else {
|
let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else {
|
||||||
session.stop();
|
|
||||||
return;
|
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() {
|
match session.source() {
|
||||||
ImageCaptureSourceData::Output(weak) => {
|
ImageCaptureSourceData::Output(weak) => {
|
||||||
let Some(mut output) = weak.upgrade() else {
|
let Some(mut output) = weak.upgrade() else {
|
||||||
session.stop(); // will fail the frame as well
|
|
||||||
return;
|
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() {
|
if !session.has_cursor() {
|
||||||
frame.success(Transform::Normal, Vec::new(), self.common.clock.now());
|
frame.success(Transform::Normal, Vec::new(), self.common.clock.now());
|
||||||
return;
|
return;
|
||||||
|
|
@ -290,18 +288,18 @@ impl ScreencopyHandler for State {
|
||||||
render_cursor_to_buffer(self, &session, frame, &seat);
|
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();
|
let shell = self.common.shell.read().unwrap();
|
||||||
for mut output in shell.outputs().cloned() {
|
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() {
|
match session.source() {
|
||||||
ImageCaptureSourceData::Output(weak) => {
|
ImageCaptureSourceData::Output(weak) => {
|
||||||
if let Some(mut output) = weak.upgrade() {
|
if let Some(mut output) = weak.upgrade() {
|
||||||
output.remove_session(session);
|
output.remove_session(&session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImageCaptureSourceData::Workspace(handle) => {
|
ImageCaptureSourceData::Workspace(handle) => {
|
||||||
|
|
@ -313,19 +311,19 @@ impl ScreencopyHandler for State {
|
||||||
.workspaces
|
.workspaces
|
||||||
.space_for_handle_mut(&handle)
|
.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!(),
|
ImageCaptureSourceData::Destroyed => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor_session_destroyed(&mut self, session: CursorSession) {
|
fn cursor_session_destroyed(&mut self, session: CursorSessionRef) {
|
||||||
match session.source() {
|
match session.source() {
|
||||||
ImageCaptureSourceData::Output(weak) => {
|
ImageCaptureSourceData::Output(weak) => {
|
||||||
if let Some(mut output) = weak.upgrade() {
|
if let Some(mut output) = weak.upgrade() {
|
||||||
output.remove_cursor_session(session);
|
output.remove_cursor_session(&session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImageCaptureSourceData::Workspace(handle) => {
|
ImageCaptureSourceData::Workspace(handle) => {
|
||||||
|
|
@ -337,11 +335,11 @@ impl ScreencopyHandler for State {
|
||||||
.workspaces
|
.workspaces
|
||||||
.space_for_handle_mut(&handle)
|
.space_for_handle_mut(&handle)
|
||||||
{
|
{
|
||||||
workspace.remove_cursor_session(session)
|
workspace.remove_cursor_session(&session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImageCaptureSourceData::Toplevel(mut toplevel) => {
|
ImageCaptureSourceData::Toplevel(mut toplevel) => {
|
||||||
toplevel.remove_cursor_session(session)
|
toplevel.remove_cursor_session(&session)
|
||||||
}
|
}
|
||||||
ImageCaptureSourceData::Destroyed => unreachable!(),
|
ImageCaptureSourceData::Destroyed => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,13 @@ use crate::{
|
||||||
constraints_for_output, constraints_for_toplevel, SessionData, SessionUserData,
|
constraints_for_output, constraints_for_toplevel, SessionData, SessionUserData,
|
||||||
},
|
},
|
||||||
protocols::{
|
protocols::{
|
||||||
screencopy::{BufferConstraints, CursorSession, FailureReason, Frame, Session},
|
screencopy::{BufferConstraints, CursorSessionRef, FailureReason, Frame, SessionRef},
|
||||||
workspace::WorkspaceHandle,
|
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<R>(
|
pub fn submit_buffer<R>(
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
|
|
@ -205,17 +205,16 @@ where
|
||||||
|
|
||||||
pub fn render_workspace_to_buffer(
|
pub fn render_workspace_to_buffer(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
session: Session,
|
session: SessionRef,
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
handle: WorkspaceHandle,
|
handle: WorkspaceHandle,
|
||||||
) {
|
) {
|
||||||
let shell = state.common.shell.read().unwrap();
|
let shell = state.common.shell.read().unwrap();
|
||||||
let Some(workspace) = shell.workspaces.space_for_handle(&handle) else {
|
let Some(workspace) = shell.workspaces.space_for_handle(&handle) else {
|
||||||
session.stop();
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = workspace.output().clone();
|
let mut output = workspace.output().clone();
|
||||||
let idx = shell.workspaces.idx_for_handle(&output, &handle).unwrap();
|
let idx = shell.workspaces.idx_for_handle(&output, &handle).unwrap();
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
|
|
||||||
|
|
@ -227,7 +226,7 @@ pub fn render_workspace_to_buffer(
|
||||||
let buffer_size = buffer_dimensions(&buffer).unwrap();
|
let buffer_size = buffer_dimensions(&buffer).unwrap();
|
||||||
if mode != Some(buffer_size) {
|
if mode != Some(buffer_size) {
|
||||||
let Some(constraints) = constraints_for_output(&output, &mut state.backend) else {
|
let Some(constraints) = constraints_for_output(&output, &mut state.backend) else {
|
||||||
session.stop();
|
output.remove_session(&session);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
session.update_constraints(constraints);
|
session.update_constraints(constraints);
|
||||||
|
|
@ -439,12 +438,12 @@ smithay::render_elements! {
|
||||||
|
|
||||||
pub fn render_window_to_buffer(
|
pub fn render_window_to_buffer(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
session: Session,
|
session: SessionRef,
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
toplevel: &CosmicSurface,
|
toplevel: &CosmicSurface,
|
||||||
) {
|
) {
|
||||||
if !toplevel.alive() {
|
if !toplevel.alive() {
|
||||||
session.stop();
|
toplevel.clone().remove_session(&session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -453,7 +452,7 @@ pub fn render_window_to_buffer(
|
||||||
let buffer_size = buffer_dimensions(&buffer).unwrap();
|
let buffer_size = buffer_dimensions(&buffer).unwrap();
|
||||||
if buffer_size != geometry.size.to_buffer(1, Transform::Normal) {
|
if buffer_size != geometry.size.to_buffer(1, Transform::Normal) {
|
||||||
let Some(constraints) = constraints_for_toplevel(toplevel, &mut state.backend) else {
|
let Some(constraints) = constraints_for_toplevel(toplevel, &mut state.backend) else {
|
||||||
session.stop();
|
toplevel.clone().remove_session(&session);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
session.update_constraints(constraints);
|
session.update_constraints(constraints);
|
||||||
|
|
@ -663,7 +662,7 @@ pub fn render_window_to_buffer(
|
||||||
|
|
||||||
pub fn render_cursor_to_buffer(
|
pub fn render_cursor_to_buffer(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
session: &CursorSession,
|
session: &CursorSessionRef,
|
||||||
frame: Frame,
|
frame: Frame,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
use std::{
|
use std::{cell::RefCell, collections::HashMap, sync::Mutex};
|
||||||
cell::RefCell,
|
|
||||||
collections::HashMap,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
sync::Mutex,
|
|
||||||
};
|
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{damage::OutputDamageTracker, utils::CommitCounter},
|
backend::renderer::{damage::OutputDamageTracker, utils::CommitCounter},
|
||||||
|
|
@ -13,11 +8,13 @@ use smithay::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::{CosmicSurface, Workspace},
|
shell::{CosmicSurface, Workspace},
|
||||||
wayland::protocols::screencopy::{CursorSession, FailureReason, Frame, Session},
|
wayland::protocols::screencopy::{
|
||||||
|
CursorSession, CursorSessionRef, Frame, FrameRef, Session, SessionRef,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type ScreencopySessionsData = RefCell<ScreencopySessions>;
|
type ScreencopySessionsData = RefCell<ScreencopySessions>;
|
||||||
type PendingScreencopyBuffers = Mutex<Vec<(Session, DropableFrame)>>;
|
type PendingScreencopyBuffers = Mutex<Vec<(SessionRef, Frame)>>;
|
||||||
|
|
||||||
pub type SessionData = Mutex<SessionUserData>;
|
pub type SessionData = Mutex<SessionUserData>;
|
||||||
|
|
||||||
|
|
@ -58,24 +55,24 @@ impl SessionUserData {
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ScreencopySessions {
|
pub struct ScreencopySessions {
|
||||||
sessions: Vec<DropableSession>,
|
sessions: Vec<Session>,
|
||||||
cursor_sessions: Vec<DropableCursorSession>,
|
cursor_sessions: Vec<CursorSession>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SessionHolder {
|
pub trait SessionHolder {
|
||||||
fn add_session(&mut self, session: Session);
|
fn add_session(&mut self, session: Session);
|
||||||
fn remove_session(&mut self, session: Session);
|
fn remove_session(&mut self, session: &SessionRef);
|
||||||
fn sessions(&self) -> Vec<Session>;
|
fn sessions(&self) -> Vec<SessionRef>;
|
||||||
|
|
||||||
fn add_cursor_session(&mut self, session: CursorSession);
|
fn add_cursor_session(&mut self, session: CursorSession);
|
||||||
fn remove_cursor_session(&mut self, session: CursorSession);
|
fn remove_cursor_session(&mut self, session: &CursorSessionRef);
|
||||||
fn cursor_sessions(&self) -> Vec<CursorSession>;
|
fn cursor_sessions(&self) -> Vec<CursorSessionRef>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FrameHolder {
|
pub trait FrameHolder {
|
||||||
fn add_frame(&mut self, session: Session, frame: Frame);
|
fn add_frame(&mut self, session: SessionRef, frame: Frame);
|
||||||
fn remove_frame(&mut self, frame: &Frame);
|
fn remove_frame(&mut self, frame: &FrameRef);
|
||||||
fn take_pending_frames(&self) -> Vec<(Session, Frame)>;
|
fn take_pending_frames(&self) -> Vec<(SessionRef, Frame)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionHolder for Output {
|
impl SessionHolder for Output {
|
||||||
|
|
@ -87,19 +84,19 @@ impl SessionHolder for Output {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.sessions
|
.sessions
|
||||||
.push(DropableSession(Some(session)));
|
.push(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_session(&mut self, session: Session) {
|
fn remove_session(&mut self, session: &SessionRef) {
|
||||||
self.user_data()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.sessions
|
.sessions
|
||||||
.retain(|s| *s != session);
|
.retain(|s| s != session);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sessions(&self) -> Vec<Session> {
|
fn sessions(&self) -> Vec<SessionRef> {
|
||||||
self.user_data()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.map_or(Vec::new(), |sessions| {
|
.map_or(Vec::new(), |sessions| {
|
||||||
|
|
@ -107,7 +104,7 @@ impl SessionHolder for Output {
|
||||||
.borrow()
|
.borrow()
|
||||||
.sessions
|
.sessions
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| s.0.clone())
|
.map(|s| (*s).clone())
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -120,19 +117,19 @@ impl SessionHolder for Output {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.cursor_sessions
|
.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()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.cursor_sessions
|
.cursor_sessions
|
||||||
.retain(|s| *s != session);
|
.retain(|s| s != session);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor_sessions(&self) -> Vec<CursorSession> {
|
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
|
||||||
self.user_data()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.map_or(Vec::new(), |sessions| {
|
.map_or(Vec::new(), |sessions| {
|
||||||
|
|
@ -140,14 +137,14 @@ impl SessionHolder for Output {
|
||||||
.borrow()
|
.borrow()
|
||||||
.cursor_sessions
|
.cursor_sessions
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| s.0.clone())
|
.map(|s| (*s).clone())
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameHolder for Output {
|
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()
|
self.user_data()
|
||||||
.insert_if_missing_threadsafe(PendingScreencopyBuffers::default);
|
.insert_if_missing_threadsafe(PendingScreencopyBuffers::default);
|
||||||
self.user_data()
|
self.user_data()
|
||||||
|
|
@ -155,61 +152,49 @@ impl FrameHolder for Output {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.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::<PendingScreencopyBuffers>() {
|
if let Some(pending) = self.user_data().get::<PendingScreencopyBuffers>() {
|
||||||
pending.lock().unwrap().retain(|(_, f)| f != frame);
|
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()
|
self.user_data()
|
||||||
.get::<PendingScreencopyBuffers>()
|
.get::<PendingScreencopyBuffers>()
|
||||||
.map(|pending| {
|
.map(|pending| std::mem::take(&mut *pending.lock().unwrap()))
|
||||||
pending
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.split_off(0)
|
|
||||||
.into_iter()
|
|
||||||
.map(|(s, mut f)| (s, f.0.take().unwrap()))
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionHolder for Workspace {
|
impl SessionHolder for Workspace {
|
||||||
fn add_session(&mut self, session: Session) {
|
fn add_session(&mut self, session: Session) {
|
||||||
self.screencopy
|
self.screencopy.sessions.push(session);
|
||||||
.sessions
|
|
||||||
.push(DropableSession(Some(session)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_session(&mut self, session: Session) {
|
fn remove_session(&mut self, session: &SessionRef) {
|
||||||
self.screencopy.sessions.retain(|s| *s != session);
|
self.screencopy.sessions.retain(|s| s != session);
|
||||||
}
|
}
|
||||||
fn sessions(&self) -> Vec<Session> {
|
fn sessions(&self) -> Vec<SessionRef> {
|
||||||
self.screencopy
|
self.screencopy
|
||||||
.sessions
|
.sessions
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| s.0.clone())
|
.map(|s| (*s).clone())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_cursor_session(&mut self, session: CursorSession) {
|
fn add_cursor_session(&mut self, session: CursorSession) {
|
||||||
self.screencopy
|
self.screencopy.cursor_sessions.push(session);
|
||||||
.cursor_sessions
|
|
||||||
.push(DropableCursorSession(Some(session)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_cursor_session(&mut self, session: CursorSession) {
|
fn remove_cursor_session(&mut self, session: &CursorSessionRef) {
|
||||||
self.screencopy.cursor_sessions.retain(|s| *s != session);
|
self.screencopy.cursor_sessions.retain(|s| s != session);
|
||||||
}
|
}
|
||||||
fn cursor_sessions(&self) -> Vec<CursorSession> {
|
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
|
||||||
self.screencopy
|
self.screencopy
|
||||||
.cursor_sessions
|
.cursor_sessions
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| s.0.clone())
|
.map(|s| (*s).clone())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,18 +208,18 @@ impl SessionHolder for CosmicSurface {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.sessions
|
.sessions
|
||||||
.push(DropableSession(Some(session)));
|
.push(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_session(&mut self, session: Session) {
|
fn remove_session(&mut self, session: &SessionRef) {
|
||||||
self.user_data()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.sessions
|
.sessions
|
||||||
.retain(|s| *s != session);
|
.retain(|s| s != session);
|
||||||
}
|
}
|
||||||
fn sessions(&self) -> Vec<Session> {
|
fn sessions(&self) -> Vec<SessionRef> {
|
||||||
self.user_data()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.map_or(Vec::new(), |sessions| {
|
.map_or(Vec::new(), |sessions| {
|
||||||
|
|
@ -242,7 +227,7 @@ impl SessionHolder for CosmicSurface {
|
||||||
.borrow()
|
.borrow()
|
||||||
.sessions
|
.sessions
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| s.0.clone())
|
.map(|s| (*s).clone())
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -255,19 +240,19 @@ impl SessionHolder for CosmicSurface {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.cursor_sessions
|
.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()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.cursor_sessions
|
.cursor_sessions
|
||||||
.retain(|s| *s != session);
|
.retain(|s| s != session);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursor_sessions(&self) -> Vec<CursorSession> {
|
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
|
||||||
self.user_data()
|
self.user_data()
|
||||||
.get::<ScreencopySessionsData>()
|
.get::<ScreencopySessionsData>()
|
||||||
.map_or(Vec::new(), |sessions| {
|
.map_or(Vec::new(), |sessions| {
|
||||||
|
|
@ -275,86 +260,8 @@ impl SessionHolder for CosmicSurface {
|
||||||
.borrow()
|
.borrow()
|
||||||
.cursor_sessions
|
.cursor_sessions
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| s.0.clone())
|
.map(|s| (*s).clone())
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct DropableSession(Option<Session>);
|
|
||||||
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<Session> 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<CursorSession>);
|
|
||||||
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<CursorSession> 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<Frame>);
|
|
||||||
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<Frame> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
ops,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
@ -37,8 +38,8 @@ use super::image_capture_source::ImageCaptureSourceData;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ScreencopyState {
|
pub struct ScreencopyState {
|
||||||
global: GlobalId,
|
global: GlobalId,
|
||||||
known_sessions: Vec<Session>,
|
known_sessions: Vec<SessionRef>,
|
||||||
known_cursor_sessions: Vec<CursorSession>,
|
known_cursor_sessions: Vec<CursorSessionRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScreencopyState {
|
impl ScreencopyState {
|
||||||
|
|
@ -85,13 +86,13 @@ pub struct DmabufConstraints {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Session {
|
pub struct SessionRef {
|
||||||
obj: ExtImageCopyCaptureSessionV1,
|
obj: ExtImageCopyCaptureSessionV1,
|
||||||
inner: Arc<Mutex<SessionInner>>,
|
inner: Arc<Mutex<SessionInner>>,
|
||||||
user_data: Arc<UserDataMap>,
|
user_data: Arc<UserDataMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Session {
|
impl PartialEq for SessionRef {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.obj == other.obj
|
self.obj == other.obj
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +104,7 @@ struct SessionInner {
|
||||||
constraints: Option<BufferConstraints>,
|
constraints: Option<BufferConstraints>,
|
||||||
draw_cursors: bool,
|
draw_cursors: bool,
|
||||||
source: ImageCaptureSourceData,
|
source: ImageCaptureSourceData,
|
||||||
active_frames: Vec<Frame>,
|
active_frames: Vec<FrameRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionInner {
|
impl SessionInner {
|
||||||
|
|
@ -118,13 +119,13 @@ impl SessionInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsAlive for Session {
|
impl IsAlive for SessionRef {
|
||||||
fn alive(&self) -> bool {
|
fn alive(&self) -> bool {
|
||||||
self.obj.is_alive()
|
self.obj.is_alive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl SessionRef {
|
||||||
pub fn update_constraints(&self, constraints: BufferConstraints) {
|
pub fn update_constraints(&self, constraints: BufferConstraints) {
|
||||||
let mut inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
|
||||||
|
|
@ -168,16 +169,38 @@ impl Session {
|
||||||
pub fn user_data(&self) -> &UserDataMap {
|
pub fn user_data(&self) -> &UserDataMap {
|
||||||
&*self.user_data
|
&*self.user_data
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stop(self) {
|
#[derive(Debug)]
|
||||||
let mut inner = self.inner.lock().unwrap();
|
pub struct Session(SessionRef);
|
||||||
|
|
||||||
|
impl ops::Deref for Session {
|
||||||
|
type Target = SessionRef;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<SessionRef> 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 {
|
if !self.obj.is_alive() || inner.stopped {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for frame in inner.active_frames.drain(..) {
|
for frame in inner.active_frames.drain(..) {
|
||||||
frame.fail(FailureReason::Stopped);
|
frame
|
||||||
|
.inner
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.fail(&frame.obj, FailureReason::Stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.obj.stopped();
|
self.obj.stopped();
|
||||||
|
|
@ -186,14 +209,20 @@ impl Session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Session {
|
||||||
|
pub fn stop(self) {
|
||||||
|
let _ = self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CursorSession {
|
pub struct CursorSessionRef {
|
||||||
obj: ExtImageCopyCaptureCursorSessionV1,
|
obj: ExtImageCopyCaptureCursorSessionV1,
|
||||||
inner: Arc<Mutex<CursorSessionInner>>,
|
inner: Arc<Mutex<CursorSessionInner>>,
|
||||||
user_data: Arc<UserDataMap>,
|
user_data: Arc<UserDataMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for CursorSession {
|
impl PartialEq for CursorSessionRef {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.obj == other.obj
|
self.obj == other.obj
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +236,7 @@ struct CursorSessionInner {
|
||||||
source: ImageCaptureSourceData,
|
source: ImageCaptureSourceData,
|
||||||
position: Option<Point<i32, BufferCoords>>,
|
position: Option<Point<i32, BufferCoords>>,
|
||||||
hotspot: Point<i32, BufferCoords>,
|
hotspot: Point<i32, BufferCoords>,
|
||||||
active_frames: Vec<Frame>,
|
active_frames: Vec<FrameRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CursorSessionInner {
|
impl CursorSessionInner {
|
||||||
|
|
@ -224,13 +253,13 @@ impl CursorSessionInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsAlive for CursorSession {
|
impl IsAlive for CursorSessionRef {
|
||||||
fn alive(&self) -> bool {
|
fn alive(&self) -> bool {
|
||||||
self.obj.is_alive()
|
self.obj.is_alive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CursorSession {
|
impl CursorSessionRef {
|
||||||
pub fn update_constraints(&self, constrains: BufferConstraints) {
|
pub fn update_constraints(&self, constrains: BufferConstraints) {
|
||||||
let mut inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
|
||||||
|
|
@ -319,11 +348,29 @@ impl CursorSession {
|
||||||
pub fn user_data(&self) -> &UserDataMap {
|
pub fn user_data(&self) -> &UserDataMap {
|
||||||
&*self.user_data
|
&*self.user_data
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stop(self) {
|
#[derive(Debug)]
|
||||||
let mut inner = self.inner.lock().unwrap();
|
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<CursorSessionRef> 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,26 +380,37 @@ impl CursorSession {
|
||||||
inner.constraints.take();
|
inner.constraints.take();
|
||||||
|
|
||||||
for frame in inner.active_frames.drain(..) {
|
for frame in inner.active_frames.drain(..) {
|
||||||
frame.fail(FailureReason::Stopped);
|
frame
|
||||||
|
.inner
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.fail(&frame.obj, FailureReason::Stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
inner.stopped = true;
|
inner.stopped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl CursorSession {
|
||||||
pub struct Frame {
|
pub fn stop(self) {
|
||||||
|
let _ = self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Un-owned reference to a frame
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct FrameRef {
|
||||||
obj: ExtImageCopyCaptureFrameV1,
|
obj: ExtImageCopyCaptureFrameV1,
|
||||||
inner: Arc<Mutex<FrameInner>>,
|
inner: Arc<Mutex<FrameInner>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Frame {
|
impl PartialEq for FrameRef {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.obj == other.obj
|
self.obj == other.obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl FrameRef {
|
||||||
pub fn buffer(&self) -> WlBuffer {
|
pub fn buffer(&self) -> WlBuffer {
|
||||||
self.inner.lock().unwrap().buffer.clone().unwrap()
|
self.inner.lock().unwrap().buffer.clone().unwrap()
|
||||||
}
|
}
|
||||||
|
|
@ -364,7 +422,26 @@ impl Frame {
|
||||||
pub fn has_failed(&self) -> bool {
|
pub fn has_failed(&self) -> bool {
|
||||||
self.inner.lock().unwrap().failed.is_some()
|
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<FrameRef> for Frame {
|
||||||
|
fn eq(&self, other: &FrameRef) -> bool {
|
||||||
|
self.0 == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
pub fn success(
|
pub fn success(
|
||||||
self,
|
self,
|
||||||
transform: impl Into<Transform>,
|
transform: impl Into<Transform>,
|
||||||
|
|
@ -372,7 +449,7 @@ impl Frame {
|
||||||
presented: impl Into<Duration>,
|
presented: impl Into<Duration>,
|
||||||
) {
|
) {
|
||||||
{
|
{
|
||||||
let inner = self.inner.lock().unwrap();
|
let inner = self.0.inner.lock().unwrap();
|
||||||
if !inner.capture_requested || inner.failed.is_some() {
|
if !inner.capture_requested || inner.failed.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -390,12 +467,22 @@ impl Frame {
|
||||||
let tv_nsec = time.subsec_nanos();
|
let tv_nsec = time.subsec_nanos();
|
||||||
self.obj.presentation_time(tv_sec_hi, tv_sec_lo, tv_nsec);
|
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()
|
self.obj.ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fail(self, reason: FailureReason) {
|
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<BufferConstraints>,
|
constraints: Option<BufferConstraints>,
|
||||||
buffer: Option<WlBuffer>,
|
buffer: Option<WlBuffer>,
|
||||||
damage: Vec<Rectangle<i32, BufferCoords>>,
|
damage: Vec<Rectangle<i32, BufferCoords>>,
|
||||||
// `SessionInner` contains a `Vec<Frame>`, so use a weak reference here to
|
// `SessionInner` contains a `Vec<FrameRef>`, so use a weak reference here to
|
||||||
// avoid a cycle.
|
// avoid a cycle.
|
||||||
obj: Weak<ExtImageCopyCaptureSessionV1>,
|
obj: Weak<ExtImageCopyCaptureSessionV1>,
|
||||||
capture_requested: bool,
|
capture_requested: bool,
|
||||||
|
|
@ -451,14 +538,14 @@ pub trait ScreencopyHandler {
|
||||||
fn new_session(&mut self, session: Session);
|
fn new_session(&mut self, session: Session);
|
||||||
fn new_cursor_session(&mut self, session: CursorSession);
|
fn new_cursor_session(&mut self, session: CursorSession);
|
||||||
|
|
||||||
fn frame(&mut self, session: Session, frame: Frame);
|
fn frame(&mut self, session: SessionRef, frame: Frame);
|
||||||
fn cursor_frame(&mut self, session: CursorSession, frame: Frame);
|
fn cursor_frame(&mut self, session: CursorSessionRef, frame: Frame);
|
||||||
|
|
||||||
fn frame_aborted(&mut self, frame: Frame);
|
fn frame_aborted(&mut self, frame_handle: FrameRef);
|
||||||
fn session_destroyed(&mut self, session: Session) {
|
fn session_destroyed(&mut self, session: SessionRef) {
|
||||||
let _ = session;
|
let _ = session;
|
||||||
}
|
}
|
||||||
fn cursor_session_destroyed(&mut self, session: CursorSession) {
|
fn cursor_session_destroyed(&mut self, session: CursorSessionRef) {
|
||||||
let _ = session;
|
let _ = session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -546,7 +633,7 @@ where
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let session = Session {
|
let session = SessionRef {
|
||||||
obj,
|
obj,
|
||||||
inner: session_data,
|
inner: session_data,
|
||||||
user_data: Arc::new(UserDataMap::new()),
|
user_data: Arc::new(UserDataMap::new()),
|
||||||
|
|
@ -556,7 +643,7 @@ where
|
||||||
.screencopy_state()
|
.screencopy_state()
|
||||||
.known_sessions
|
.known_sessions
|
||||||
.push(session.clone());
|
.push(session.clone());
|
||||||
state.new_session(session);
|
state.new_session(Session(session));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -572,11 +659,11 @@ where
|
||||||
inner: session_data.clone(),
|
inner: session_data.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let session = Session {
|
let session = Session(SessionRef {
|
||||||
obj,
|
obj,
|
||||||
inner: session_data,
|
inner: session_data,
|
||||||
user_data: Arc::new(UserDataMap::new()),
|
user_data: Arc::new(UserDataMap::new()),
|
||||||
};
|
});
|
||||||
session.stop();
|
session.stop();
|
||||||
}
|
}
|
||||||
ext_image_copy_capture_manager_v1::Request::CreatePointerCursorSession {
|
ext_image_copy_capture_manager_v1::Request::CreatePointerCursorSession {
|
||||||
|
|
@ -598,7 +685,7 @@ where
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let session = CursorSession {
|
let session = CursorSessionRef {
|
||||||
obj,
|
obj,
|
||||||
inner: session_data,
|
inner: session_data,
|
||||||
user_data: Arc::new(UserDataMap::new()),
|
user_data: Arc::new(UserDataMap::new()),
|
||||||
|
|
@ -608,7 +695,7 @@ where
|
||||||
.screencopy_state()
|
.screencopy_state()
|
||||||
.known_cursor_sessions
|
.known_cursor_sessions
|
||||||
.push(session.clone());
|
.push(session.clone());
|
||||||
state.new_cursor_session(session);
|
state.new_cursor_session(CursorSession(session));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -623,11 +710,11 @@ where
|
||||||
inner: session_data.clone(),
|
inner: session_data.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let session = CursorSession {
|
let session = CursorSession(CursorSessionRef {
|
||||||
obj,
|
obj,
|
||||||
inner: session_data,
|
inner: session_data,
|
||||||
user_data: Arc::new(UserDataMap::new()),
|
user_data: Arc::new(UserDataMap::new()),
|
||||||
};
|
});
|
||||||
session.stop();
|
session.stop();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -675,7 +762,7 @@ where
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.active_frames
|
.active_frames
|
||||||
.push(Frame { obj, inner });
|
.push(FrameRef { obj, inner });
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -808,7 +895,7 @@ where
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.active_frames
|
.active_frames
|
||||||
.push(Frame { obj, inner });
|
.push(FrameRef { obj, inner });
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -877,155 +964,32 @@ where
|
||||||
.push(Rectangle::new((x, y).into(), (width, height).into()));
|
.push(Rectangle::new((x, y).into(), (width, height).into()));
|
||||||
}
|
}
|
||||||
ext_image_copy_capture_frame_v1::Request::Capture => {
|
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 {
|
if inner.capture_requested {
|
||||||
resource.post_error(
|
resource.post_error(
|
||||||
ext_image_copy_capture_frame_v1::Error::AlreadyCaptured,
|
ext_image_copy_capture_frame_v1::Error::AlreadyCaptured,
|
||||||
"Frame was captured previously",
|
"Frame was captured previously",
|
||||||
);
|
);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
if inner.buffer.is_none() {
|
|
||||||
resource.post_error(
|
if inner.buffer.is_none() {
|
||||||
ext_image_copy_capture_frame_v1::Error::NoBuffer,
|
resource.post_error(
|
||||||
"Attempting to capture frame without a buffer",
|
ext_image_copy_capture_frame_v1::Error::NoBuffer,
|
||||||
);
|
"Attempting to capture frame without a buffer",
|
||||||
}
|
);
|
||||||
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
inner.fail(&resource, FailureReason::Unknown);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = Frame {
|
let frame = Frame(FrameRef {
|
||||||
obj: resource.clone(),
|
obj: resource.clone(),
|
||||||
inner: data.inner.clone(),
|
inner: data.inner.clone(),
|
||||||
};
|
});
|
||||||
|
if let Err(reason) = capture_frame(state, frame) {
|
||||||
let scpy = state.screencopy_state();
|
data.inner.lock().unwrap().fail(resource, reason);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -1038,6 +1002,10 @@ where
|
||||||
resource: &ExtImageCopyCaptureFrameV1,
|
resource: &ExtImageCopyCaptureFrameV1,
|
||||||
data: &FrameData,
|
data: &FrameData,
|
||||||
) {
|
) {
|
||||||
|
let frame_ref = FrameRef {
|
||||||
|
obj: resource.clone(),
|
||||||
|
inner: data.inner.clone(),
|
||||||
|
};
|
||||||
{
|
{
|
||||||
let scpy = state.screencopy_state();
|
let scpy = state.screencopy_state();
|
||||||
for session in &mut scpy.known_sessions {
|
for session in &mut scpy.known_sessions {
|
||||||
|
|
@ -1046,7 +1014,7 @@ where
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.active_frames
|
.active_frames
|
||||||
.retain(|frame| frame.obj != *resource);
|
.retain(|i| *i != frame_ref);
|
||||||
}
|
}
|
||||||
for cursor_session in &mut scpy.known_cursor_sessions {
|
for cursor_session in &mut scpy.known_cursor_sessions {
|
||||||
cursor_session
|
cursor_session
|
||||||
|
|
@ -1054,14 +1022,121 @@ where
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.active_frames
|
.active_frames
|
||||||
.retain(|frame| frame.obj != *resource);
|
.retain(|i| *i != frame_ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let frame = Frame {
|
state.frame_aborted(frame_ref);
|
||||||
obj: resource.clone(),
|
}
|
||||||
inner: data.inner.clone(),
|
}
|
||||||
};
|
|
||||||
state.frame_aborted(frame);
|
fn capture_frame<D: ScreencopyHandler>(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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue