From cac7a5aca67e45a3d06c7b58347b037c4c2507ac Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 13 Jan 2026 18:26:26 -0800 Subject: [PATCH] image-copy: Use abstraction that's now provided by Smithay This doesn't change much, since the Smithay implementation is based on the `cosmic-comp` version, but made more generic. We provide our own implementation for our workspace capture protocol, but otherwise Smithay handles the boilerplate now. This should not cause any change in behavior. --- src/backend/kms/device.rs | 2 +- src/backend/kms/surface/mod.rs | 16 +- src/backend/render/mod.rs | 2 +- src/input/mod.rs | 6 +- src/shell/focus/target.rs | 2 +- src/shell/workspace.rs | 8 +- src/state.rs | 30 +- src/wayland/handlers/image_capture_source.rs | 61 +- .../{screencopy => image_copy_capture}/mod.rs | 135 +- .../render.rs | 38 +- .../user_data.rs | 68 +- src/wayland/handlers/mod.rs | 2 +- src/wayland/protocols/image_capture_source.rs | 276 +--- src/wayland/protocols/mod.rs | 1 - src/wayland/protocols/screencopy.rs | 1158 ----------------- src/wayland/protocols/toplevel_info.rs | 16 +- 16 files changed, 285 insertions(+), 1536 deletions(-) rename src/wayland/handlers/{screencopy => image_copy_capture}/mod.rs (78%) rename src/wayland/handlers/{screencopy => image_copy_capture}/render.rs (97%) rename src/wayland/handlers/{screencopy => image_copy_capture}/user_data.rs (79%) delete mode 100644 src/wayland/protocols/screencopy.rs diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index 926af374..3d3dfc28 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -8,7 +8,7 @@ use crate::{ config::{CompTransformDef, EdidProduct, ScreenFilter}, shell::Shell, utils::{env::dev_list_var, prelude::*}, - wayland::handlers::screencopy::PendingImageCopyData, + wayland::handlers::image_copy_capture::PendingImageCopyData, }; use anyhow::{Context, Result}; diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index 63873b64..e2d2e5b4 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -11,14 +11,9 @@ use crate::{ shell::Shell, state::SurfaceDmabufFeedback, utils::prelude::*, - wayland::{ - handlers::{ - compositor::recursive_frame_time_estimation, - screencopy::{FrameHolder, PendingImageCopyData, SessionData, submit_buffer}, - }, - protocols::screencopy::{ - FailureReason, Frame as ScreencopyFrame, SessionRef as ScreencopySessionRef, - }, + wayland::handlers::{ + compositor::recursive_frame_time_estimation, + image_copy_capture::{FrameHolder, PendingImageCopyData, SessionData, submit_buffer}, }, }; @@ -82,6 +77,9 @@ use smithay::{ utils::{Clock, Monotonic, Physical, Point, Rectangle, Transform}, wayland::{ dmabuf::{DmabufFeedbackBuilder, get_dmabuf}, + image_copy_capture::{ + CaptureFailureReason, Frame as ScreencopyFrame, SessionRef as ScreencopySessionRef, + }, presentation::Refresh, seat::WaylandFocus, shm::{shm_format_to_fourcc, with_buffer_contents}, @@ -1398,7 +1396,7 @@ impl SurfaceThreadState { .lock() .unwrap() .reset(); - frame.fail(FailureReason::Unknown); + frame.fail(CaptureFailureReason::Unknown); } return Err(err).with_context(|| "Failed to submit result for display"); } diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index c7d79967..d439e1ce 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -35,7 +35,7 @@ use crate::{ handlers::{ compositor::FRAME_TIME_FILTER, data_device::get_dnd_icon, - screencopy::{FrameHolder, SessionData, render_session}, + image_copy_capture::{FrameHolder, SessionData, render_session}, }, protocols::workspace::WorkspaceHandle, }, diff --git a/src/input/mod.rs b/src/input/mod.rs index 9b06d0d7..148f7764 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -24,9 +24,8 @@ use crate::{ zoom::ZoomState, }, utils::{prelude::*, quirks::workspace_overview_is_open}, - wayland::{ - handlers::{screencopy::SessionHolder, xwayland_keyboard_grab::XWaylandGrabSeat}, - protocols::screencopy::{BufferConstraints, CursorSessionRef}, + wayland::handlers::{ + image_copy_capture::SessionHolder, xwayland_keyboard_grab::XWaylandGrabSeat, }, }; use calloop::{ @@ -62,6 +61,7 @@ use smithay::{ }, utils::{Point, Rectangle, SERIAL_COUNTER, Serial}, wayland::{ + image_copy_capture::{BufferConstraints, CursorSessionRef}, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat, pointer_constraints::{PointerConstraint, with_pointer_constraint}, seat::WaylandFocus, diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index b5d8b8dd..63bf0a56 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -12,7 +12,7 @@ use crate::{ zoom::ZoomFocusTarget, }, utils::prelude::*, - wayland::handlers::{screencopy::SessionHolder, xdg_shell::popup::get_popup_toplevel}, + wayland::handlers::{image_copy_capture::SessionHolder, xdg_shell::popup::get_popup_toplevel}, }; use id_tree::NodeId; use smithay::{ diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 08d32d89..1c9da011 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -13,7 +13,7 @@ use crate::{ state::State, utils::{prelude::*, tween::EaseRectangle}, wayland::{ - handlers::screencopy::ScreencopySessions, + handlers::image_copy_capture::ImageCopySessions, protocols::{ toplevel_info::{toplevel_enter_output, toplevel_leave_output}, workspace::{WorkspaceHandle, WorkspaceUpdateGuard}, @@ -110,7 +110,7 @@ pub struct Workspace { pub handle: WorkspaceHandle, pub focus_stack: FocusStacks, - pub screencopy: ScreencopySessions, + pub image_copy: ImageCopySessions, output_stack: VecDeque, pub(super) backdrop_id: Id, pub dirty: AtomicBool, @@ -377,7 +377,7 @@ impl Workspace { id: None, handle, focus_stack: FocusStacks::default(), - screencopy: ScreencopySessions::default(), + image_copy: ImageCopySessions::default(), output_stack: { let mut queue = VecDeque::new(); queue.push_back(output_match); @@ -410,7 +410,7 @@ impl Workspace { id: pinned.id.clone(), handle, focus_stack: FocusStacks::default(), - screencopy: ScreencopySessions::default(), + image_copy: ImageCopySessions::default(), output_stack: { let mut queue = VecDeque::new(); queue.push_back(pinned.output.clone()); diff --git a/src/state.rs b/src/state.rs index 00ff55c1..6406cc6c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -13,16 +13,15 @@ use crate::{ shell::{CosmicSurface, SeatExt, Shell, grabs::SeatMoveGrabState}, utils::prelude::OutputExt, wayland::{ - handlers::{data_device::get_dnd_icon, screencopy::SessionHolder}, + handlers::{data_device::get_dnd_icon, image_copy_capture::SessionHolder}, protocols::{ a11y::A11yState, corner_radius::CornerRadiusState, drm::WlDrmState, - image_capture_source::ImageCaptureSourceState, + image_capture_source::CosmicImageCaptureSourceState, output_configuration::OutputConfigurationState, output_power::OutputPowerState, overlap_notify::OverlapNotifyState, - screencopy::ScreencopyState, toplevel_info::ToplevelInfoState, toplevel_management::{ManagementCapabilities, ToplevelManagementState}, workspace::{WorkspaceState, WorkspaceUpdateGuard}, @@ -80,6 +79,8 @@ use smithay::{ fractional_scale::{FractionalScaleManagerState, with_fractional_scale}, idle_inhibit::IdleInhibitManagerState, idle_notify::IdleNotifierState, + image_capture_source::{OutputCaptureSourceState, ToplevelCaptureSourceState}, + image_copy_capture::ImageCopyCaptureState, input_method::InputMethodManagerState, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, output::OutputManagerState, @@ -260,8 +261,10 @@ pub struct Common { pub primary_selection_state: PrimarySelectionState, pub ext_data_control_state: ExtDataControlState, pub wlr_data_control_state: WlrDataControlState, - pub image_capture_source_state: ImageCaptureSourceState, - pub screencopy_state: ScreencopyState, + pub cosmic_image_capture_source_state: CosmicImageCaptureSourceState, + pub output_capture_source_state: OutputCaptureSourceState, + pub toplevel_capture_source_state: ToplevelCaptureSourceState, + pub image_copy_capture_state: ImageCopyCaptureState, pub seat_state: SeatState, pub session_lock_manager_state: SessionLockManagerState, pub idle_notifier_state: IdleNotifierState, @@ -645,9 +648,14 @@ impl State { OverlapNotifyState::new::(dh, client_has_no_security_context); let presentation_state = PresentationState::new::(dh, clock.id() as u32); let primary_selection_state = PrimarySelectionState::new::(dh); - let image_capture_source_state = - ImageCaptureSourceState::new::(dh, client_not_sandboxed); - let screencopy_state = ScreencopyState::new::(dh, client_not_sandboxed); + let cosmic_image_capture_source_state = + CosmicImageCaptureSourceState::new::(dh, client_not_sandboxed); + let output_capture_source_state = + OutputCaptureSourceState::new_with_filter::(&dh, client_not_sandboxed); + let toplevel_capture_source_state = + ToplevelCaptureSourceState::new_with_filter::(&dh, client_not_sandboxed); + let image_copy_capture_state = + ImageCopyCaptureState::new_with_filter::(dh, client_not_sandboxed); let shm_state = ShmState::new::(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]); let cursor_shape_manager_state = CursorShapeManagerState::new::(dh); @@ -754,8 +762,10 @@ impl State { idle_notifier_state, idle_inhibit_manager_state, idle_inhibiting_surfaces, - image_capture_source_state, - screencopy_state, + cosmic_image_capture_source_state, + output_capture_source_state, + toplevel_capture_source_state, + image_copy_capture_state, shm_state, cursor_shape_manager_state, seat_state, diff --git a/src/wayland/handlers/image_capture_source.rs b/src/wayland/handlers/image_capture_source.rs index 686b2aaa..7e2e347a 100644 --- a/src/wayland/handlers/image_capture_source.rs +++ b/src/wayland/handlers/image_capture_source.rs @@ -1,4 +1,59 @@ -use crate::state::State; -use crate::wayland::protocols::image_capture_source::delegate_image_capture_source; +// SPDX-License-Identifier: GPL-3.0-only -delegate_image_capture_source!(State); +use crate::{ + state::State, + wayland::protocols::{ + image_capture_source::{ImageCaptureSourceKind, delegate_cosmic_image_capture_source}, + toplevel_info::window_from_ext, + }, +}; +use smithay::{ + output::Output, + wayland::{ + foreign_toplevel_list::ForeignToplevelHandle, + image_capture_source::{ + ImageCaptureSource, ImageCaptureSourceHandler, OutputCaptureSourceHandler, + OutputCaptureSourceState, ToplevelCaptureSourceHandler, ToplevelCaptureSourceState, + }, + }, +}; + +impl ImageCaptureSourceHandler for State { + fn source_destroyed(&mut self, _source: ImageCaptureSource) {} +} + +impl OutputCaptureSourceHandler for State { + fn output_capture_source_state(&mut self) -> &mut OutputCaptureSourceState { + &mut self.common.output_capture_source_state + } + + fn output_source_created(&mut self, source: ImageCaptureSource, output: &Output) { + source + .user_data() + .insert_if_missing(|| ImageCaptureSourceKind::Output(output.downgrade())); + } +} + +impl ToplevelCaptureSourceHandler for State { + fn toplevel_capture_source_state(&mut self) -> &mut ToplevelCaptureSourceState { + &mut self.common.toplevel_capture_source_state + } + + fn toplevel_source_created( + &mut self, + source: ImageCaptureSource, + toplevel: &ForeignToplevelHandle, + ) { + let data = match window_from_ext(self, toplevel) { + Some(toplevel) => ImageCaptureSourceKind::Toplevel(toplevel.clone()), + None => ImageCaptureSourceKind::Destroyed, + }; + source.user_data().insert_if_missing(|| data); + } +} + +smithay::delegate_image_capture_source!(State); +smithay::delegate_output_capture_source!(State); +smithay::delegate_toplevel_capture_source!(State); + +delegate_cosmic_image_capture_source!(State); diff --git a/src/wayland/handlers/screencopy/mod.rs b/src/wayland/handlers/image_copy_capture/mod.rs similarity index 78% rename from src/wayland/handlers/screencopy/mod.rs rename to src/wayland/handlers/image_copy_capture/mod.rs index 379b04ad..a63365c2 100644 --- a/src/wayland/handlers/screencopy/mod.rs +++ b/src/wayland/handlers/image_copy_capture/mod.rs @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-only + use std::{borrow::Borrow, collections::HashMap, sync::Mutex}; use smithay::{ @@ -15,7 +17,15 @@ use smithay::{ output::Output, reexports::wayland_server::protocol::wl_shm::Format as ShmFormat, utils::{Buffer as BufferCoords, Point, Size, Transform}, - wayland::{dmabuf::get_dmabuf, seat::WaylandFocus}, + wayland::{ + dmabuf::get_dmabuf, + image_capture_source::ImageCaptureSource, + image_copy_capture::{ + BufferConstraints, CursorSession, CursorSessionRef, DmabufConstraints, Frame, FrameRef, + ImageCopyCaptureHandler, ImageCopyCaptureState, Session, SessionRef, + }, + seat::WaylandFocus, + }, }; use crate::{ @@ -24,45 +34,41 @@ use crate::{ utils::prelude::{ OutputExt, PointExt, PointGlobalExt, PointLocalExt, RectExt, RectLocalExt, SeatExt, }, - wayland::protocols::{ - image_capture_source::ImageCaptureSourceData, - screencopy::{ - BufferConstraints, CursorSession, CursorSessionRef, DmabufConstraints, Frame, FrameRef, - ScreencopyHandler, ScreencopyState, Session, SessionRef, delegate_screencopy, - }, - }, + wayland::protocols::image_capture_source::ImageCaptureSourceKind, }; mod render; mod user_data; pub use self::render::*; use self::user_data::*; -pub use self::user_data::{FrameHolder, ScreencopySessions, SessionData, SessionHolder}; +pub use self::user_data::{FrameHolder, ImageCopySessions, SessionData, SessionHolder}; -impl ScreencopyHandler for State { - fn screencopy_state(&mut self) -> &mut ScreencopyState { - &mut self.common.screencopy_state +impl ImageCopyCaptureHandler for State { + fn image_copy_capture_state(&mut self) -> &mut ImageCopyCaptureState { + &mut self.common.image_copy_capture_state } - fn capture_source(&mut self, source: &ImageCaptureSourceData) -> Option { - match source { - ImageCaptureSourceData::Output(weak) => weak + fn capture_constraints(&mut self, source: &ImageCaptureSource) -> Option { + let kind = source.user_data().get::().unwrap(); + match kind { + ImageCaptureSourceKind::Output(weak) => weak .upgrade() .and_then(|output| constraints_for_output(&output, &mut self.backend)), - ImageCaptureSourceData::Workspace(handle) => { + ImageCaptureSourceKind::Workspace(handle) => { let shell = self.common.shell.read(); let output = shell.workspaces.space_for_handle(handle)?.output(); constraints_for_output(output, &mut self.backend) } - ImageCaptureSourceData::Toplevel(window) => { + ImageCaptureSourceKind::Toplevel(window) => { constraints_for_toplevel(window, &mut self.backend) } _ => None, } } - fn capture_cursor_source( + + fn cursor_capture_constraints( &mut self, - _source: &ImageCaptureSourceData, + _source: &ImageCaptureSource, ) -> Option { let size = if let Some((geometry, _)) = self .common @@ -85,8 +91,14 @@ impl ScreencopyHandler for State { } fn new_session(&mut self, session: Session) { - match session.source() { - ImageCaptureSourceData::Output(weak) => { + let kind = session + .source() + .user_data() + .get::() + .unwrap() + .clone(); + match kind { + ImageCaptureSourceKind::Output(weak) => { let Some(mut output) = weak.upgrade() else { session.stop(); return; @@ -100,7 +112,7 @@ impl ScreencopyHandler for State { output.add_session(session); } - ImageCaptureSourceData::Workspace(handle) => { + ImageCaptureSourceKind::Workspace(handle) => { let mut shell = self.common.shell.write(); let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else { session.stop(); @@ -114,7 +126,7 @@ impl ScreencopyHandler for State { }); workspace.add_session(session); } - ImageCaptureSourceData::Toplevel(mut toplevel) => { + ImageCaptureSourceKind::Toplevel(mut toplevel) => { let size = toplevel.geometry().size.to_physical(1); session.user_data().insert_if_missing_threadsafe(|| { Mutex::new(SessionUserData::new(OutputDamageTracker::new( @@ -125,9 +137,10 @@ impl ScreencopyHandler for State { }); toplevel.add_session(session); } - ImageCaptureSourceData::Destroyed => unreachable!(), + ImageCaptureSourceKind::Destroyed => unreachable!(), } } + fn new_cursor_session(&mut self, session: CursorSession) { let (pointer_loc, pointer_size, hotspot) = { let seat = self.common.shell.read().seats.last_active().clone(); @@ -154,8 +167,14 @@ impl ScreencopyHandler for State { ))) }); - match session.source() { - ImageCaptureSourceData::Output(weak) => { + let kind = session + .source() + .user_data() + .get::() + .unwrap() + .clone(); + match kind { + ImageCaptureSourceKind::Output(weak) => { let Some(mut output) = weak.upgrade() else { return; }; @@ -184,7 +203,7 @@ impl ScreencopyHandler for State { output.add_cursor_session(session); } - ImageCaptureSourceData::Workspace(handle) => { + ImageCaptureSourceKind::Workspace(handle) => { let mut shell = self.common.shell.write(); let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else { return; @@ -215,7 +234,7 @@ impl ScreencopyHandler for State { workspace.add_cursor_session(session); } - ImageCaptureSourceData::Toplevel(mut toplevel) => { + ImageCaptureSourceKind::Toplevel(mut toplevel) => { let shell = self.common.shell.read(); if let Some(element) = shell.element_for_surface(&toplevel) { if element.has_active_window(&toplevel) { @@ -238,38 +257,44 @@ impl ScreencopyHandler for State { toplevel.add_cursor_session(session); } - ImageCaptureSourceData::Destroyed => unreachable!(), + ImageCaptureSourceKind::Destroyed => unreachable!(), } } - fn frame(&mut self, session: SessionRef, frame: Frame) { - match session.source() { - ImageCaptureSourceData::Output(weak) => { + fn frame(&mut self, session: &SessionRef, frame: Frame) { + let kind = session + .source() + .user_data() + .get::() + .unwrap() + .clone(); + match kind { + ImageCaptureSourceKind::Output(weak) => { let Some(mut output) = weak.upgrade() else { return; }; - output.add_frame(session, frame); + output.add_frame(session.clone(), frame); self.backend.schedule_render(&output); } - ImageCaptureSourceData::Workspace(handle) => { + ImageCaptureSourceKind::Workspace(handle) => { render_workspace_to_buffer(self, session, frame, handle) } - ImageCaptureSourceData::Toplevel(toplevel) => { + ImageCaptureSourceKind::Toplevel(toplevel) => { render_window_to_buffer(self, session, frame, &toplevel) } - ImageCaptureSourceData::Destroyed => unreachable!(), + ImageCaptureSourceKind::Destroyed => unreachable!(), } } - fn cursor_frame(&mut self, session: CursorSessionRef, frame: Frame) { + fn cursor_frame(&mut self, session: &CursorSessionRef, frame: Frame) { if !session.has_cursor() { frame.success(Transform::Normal, Vec::new(), self.common.clock.now()); return; } let seat = self.common.shell.read().seats.last_active().clone(); - render_cursor_to_buffer(self, &session, frame, &seat); + render_cursor_to_buffer(self, session, frame, &seat); } fn frame_aborted(&mut self, frame: FrameRef) { @@ -280,13 +305,19 @@ impl ScreencopyHandler for State { } fn session_destroyed(&mut self, session: SessionRef) { - match session.source() { - ImageCaptureSourceData::Output(weak) => { + let kind = session + .source() + .user_data() + .get::() + .unwrap() + .clone(); + match kind { + ImageCaptureSourceKind::Output(weak) => { if let Some(mut output) = weak.upgrade() { output.remove_session(&session); } } - ImageCaptureSourceData::Workspace(handle) => { + ImageCaptureSourceKind::Workspace(handle) => { if let Some(workspace) = self .common .shell @@ -297,19 +328,25 @@ impl ScreencopyHandler for State { workspace.remove_session(&session) } } - ImageCaptureSourceData::Toplevel(mut toplevel) => toplevel.remove_session(&session), - ImageCaptureSourceData::Destroyed => unreachable!(), + ImageCaptureSourceKind::Toplevel(mut toplevel) => toplevel.remove_session(&session), + ImageCaptureSourceKind::Destroyed => unreachable!(), } } fn cursor_session_destroyed(&mut self, session: CursorSessionRef) { - match session.source() { - ImageCaptureSourceData::Output(weak) => { + let kind = session + .source() + .user_data() + .get::() + .unwrap() + .clone(); + match kind { + ImageCaptureSourceKind::Output(weak) => { if let Some(mut output) = weak.upgrade() { output.remove_cursor_session(&session); } } - ImageCaptureSourceData::Workspace(handle) => { + ImageCaptureSourceKind::Workspace(handle) => { if let Some(workspace) = self .common .shell @@ -320,10 +357,10 @@ impl ScreencopyHandler for State { workspace.remove_cursor_session(&session) } } - ImageCaptureSourceData::Toplevel(mut toplevel) => { + ImageCaptureSourceKind::Toplevel(mut toplevel) => { toplevel.remove_cursor_session(&session) } - ImageCaptureSourceData::Destroyed => unreachable!(), + ImageCaptureSourceKind::Destroyed => unreachable!(), } } } @@ -413,4 +450,4 @@ fn constraints_for_renderer( constraints } -delegate_screencopy!(State); +smithay::delegate_image_copy_capture!(State); diff --git a/src/wayland/handlers/screencopy/render.rs b/src/wayland/handlers/image_copy_capture/render.rs similarity index 97% rename from src/wayland/handlers/screencopy/render.rs rename to src/wayland/handlers/image_copy_capture/render.rs index 0013e099..346534ed 100644 --- a/src/wayland/handlers/screencopy/render.rs +++ b/src/wayland/handlers/image_copy_capture/render.rs @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-only + use calloop::LoopHandle; use smithay::{ backend::{ @@ -26,6 +28,9 @@ use smithay::{ }, wayland::{ dmabuf::get_dmabuf, + image_copy_capture::{ + BufferConstraints, CaptureFailureReason, CursorSessionRef, Frame, SessionRef, + }, seat::WaylandFocus, shm::{shm_format_to_fourcc, with_buffer_contents, with_buffer_contents_mut}, }, @@ -43,13 +48,10 @@ use crate::{ state::{Common, KmsNodes, State}, utils::prelude::{PointExt, PointGlobalExt, RectExt, RectLocalExt, SeatExt}, wayland::{ - handlers::screencopy::{ + handlers::image_copy_capture::{ SessionData, SessionUserData, constraints_for_output, constraints_for_toplevel, }, - protocols::{ - screencopy::{BufferConstraints, CursorSessionRef, FailureReason, Frame, SessionRef}, - workspace::WorkspaceHandle, - }, + protocols::workspace::WorkspaceHandle, }, }; @@ -165,7 +167,7 @@ where .map_err(|err| R::Error::from_gles_error(GlesError::BufferAccessError(err))) .and_then(|x| x) { - frame.fail(FailureReason::Unknown); + frame.fail(CaptureFailureReason::Unknown); return Err(err); } } @@ -249,7 +251,7 @@ where ) .map_err(DTError::Rendering), Err(err) => { - frame.fail(FailureReason::Unknown); + frame.fail(CaptureFailureReason::Unknown); Err(err) } } @@ -257,7 +259,7 @@ where pub fn render_workspace_to_buffer( state: &mut State, - session: SessionRef, + session: &SessionRef, frame: Frame, handle: WorkspaceHandle, ) { @@ -278,14 +280,14 @@ pub fn render_workspace_to_buffer( let buffer_size = buffer_dimensions(&buffer).unwrap(); if mode != Some(buffer_size) { let Some(constraints) = constraints_for_output(&output, &mut state.backend) else { - output.remove_session(&session); + output.remove_session(session); return; }; session.update_constraints(constraints); if let Some(data) = session.user_data().get::() { *data.lock().unwrap() = SessionUserData::new(OutputDamageTracker::from_output(&output)); } - frame.fail(FailureReason::BufferConstraints); + frame.fail(CaptureFailureReason::BufferConstraints); return; } @@ -414,7 +416,7 @@ pub fn render_workspace_to_buffer( Ok(renderer) => renderer, Err(err) => { warn!(?err, "Couldn't use node for screencopy"); - frame.fail(FailureReason::Unknown); + frame.fail(CaptureFailureReason::Unknown); return; } }; @@ -495,12 +497,12 @@ smithay::render_elements! { pub fn render_window_to_buffer( state: &mut State, - session: SessionRef, + session: &SessionRef, frame: Frame, toplevel: &CosmicSurface, ) { if !toplevel.alive() { - toplevel.clone().remove_session(&session); + toplevel.clone().remove_session(session); return; } @@ -509,7 +511,7 @@ pub fn render_window_to_buffer( let buffer_size = buffer_dimensions(&buffer).unwrap(); if buffer_size != geometry.size.to_buffer(1, Transform::Normal) { let Some(constraints) = constraints_for_toplevel(toplevel, &mut state.backend) else { - toplevel.clone().remove_session(&session); + toplevel.clone().remove_session(session); return; }; session.update_constraints(constraints); @@ -518,7 +520,7 @@ pub fn render_window_to_buffer( *data.lock().unwrap() = SessionUserData::new(OutputDamageTracker::new(size, 1.0, Transform::Normal)); } - frame.fail(FailureReason::BufferConstraints); + frame.fail(CaptureFailureReason::BufferConstraints); return; } @@ -666,7 +668,7 @@ pub fn render_window_to_buffer( Ok(renderer) => renderer, Err(err) => { warn!(?err, "Couldn't use node for screencopy"); - frame.fail(FailureReason::Unknown); + frame.fail(CaptureFailureReason::Unknown); return; } }; @@ -760,7 +762,7 @@ pub fn render_cursor_to_buffer( Transform::Normal, )); } - frame.fail(FailureReason::BufferConstraints); + frame.fail(CaptureFailureReason::BufferConstraints); return; } @@ -826,7 +828,7 @@ pub fn render_cursor_to_buffer( Ok(renderer) => renderer, Err(err) => { warn!(?err, "Couldn't use node for screencopy"); - frame.fail(FailureReason::Unknown); + frame.fail(CaptureFailureReason::Unknown); return; } }; diff --git a/src/wayland/handlers/screencopy/user_data.rs b/src/wayland/handlers/image_copy_capture/user_data.rs similarity index 79% rename from src/wayland/handlers/screencopy/user_data.rs rename to src/wayland/handlers/image_copy_capture/user_data.rs index 0a499504..3188cb39 100644 --- a/src/wayland/handlers/screencopy/user_data.rs +++ b/src/wayland/handlers/image_copy_capture/user_data.rs @@ -1,20 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-only + use std::{cell::RefCell, collections::HashMap, sync::Mutex}; use smithay::{ backend::renderer::{damage::OutputDamageTracker, utils::CommitCounter}, output::Output, reexports::wayland_server::{Resource, Weak, protocol::wl_buffer::WlBuffer}, -}; - -use crate::{ - shell::{CosmicSurface, Workspace}, - wayland::protocols::screencopy::{ + wayland::image_copy_capture::{ CursorSession, CursorSessionRef, Frame, FrameRef, Session, SessionRef, }, }; -type ScreencopySessionsData = RefCell; -type PendingScreencopyBuffers = Mutex>; +use crate::shell::{CosmicSurface, Workspace}; + +type ImageCopySessionsData = RefCell; +type PendingImageCopyBuffers = Mutex>; pub type SessionData = Mutex; @@ -54,7 +54,7 @@ impl SessionUserData { } #[derive(Debug, Default)] -pub struct ScreencopySessions { +pub struct ImageCopySessions { sessions: Vec, cursor_sessions: Vec, } @@ -78,9 +78,9 @@ pub trait FrameHolder { impl SessionHolder for Output { fn add_session(&mut self, session: Session) { self.user_data() - .insert_if_missing(ScreencopySessionsData::default); + .insert_if_missing(ImageCopySessionsData::default); self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .sessions @@ -89,7 +89,7 @@ impl SessionHolder for Output { fn remove_session(&mut self, session: &SessionRef) { self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .sessions @@ -98,7 +98,7 @@ impl SessionHolder for Output { fn sessions(&self) -> Vec { self.user_data() - .get::() + .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() @@ -111,9 +111,9 @@ impl SessionHolder for Output { fn add_cursor_session(&mut self, session: CursorSession) { self.user_data() - .insert_if_missing(ScreencopySessionsData::default); + .insert_if_missing(ImageCopySessionsData::default); self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .cursor_sessions @@ -122,7 +122,7 @@ impl SessionHolder for Output { fn remove_cursor_session(&mut self, session: &CursorSessionRef) { self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .cursor_sessions @@ -131,7 +131,7 @@ impl SessionHolder for Output { fn cursor_sessions(&self) -> Vec { self.user_data() - .get::() + .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() @@ -146,22 +146,22 @@ impl SessionHolder for Output { impl FrameHolder for Output { fn add_frame(&mut self, session: SessionRef, frame: Frame) { self.user_data() - .insert_if_missing_threadsafe(PendingScreencopyBuffers::default); + .insert_if_missing_threadsafe(PendingImageCopyBuffers::default); self.user_data() - .get::() + .get::() .unwrap() .lock() .unwrap() .push((session, frame)); } fn remove_frame(&mut self, frame: &FrameRef) { - if let Some(pending) = self.user_data().get::() { + 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::() + .get::() .map(|pending| std::mem::take(&mut *pending.lock().unwrap())) .unwrap_or_default() } @@ -169,14 +169,14 @@ impl FrameHolder for Output { impl SessionHolder for Workspace { fn add_session(&mut self, session: Session) { - self.screencopy.sessions.push(session); + self.image_copy.sessions.push(session); } fn remove_session(&mut self, session: &SessionRef) { - self.screencopy.sessions.retain(|s| s != session); + self.image_copy.sessions.retain(|s| s != session); } fn sessions(&self) -> Vec { - self.screencopy + self.image_copy .sessions .iter() .map(|s| (*s).clone()) @@ -184,14 +184,14 @@ impl SessionHolder for Workspace { } fn add_cursor_session(&mut self, session: CursorSession) { - self.screencopy.cursor_sessions.push(session); + self.image_copy.cursor_sessions.push(session); } fn remove_cursor_session(&mut self, session: &CursorSessionRef) { - self.screencopy.cursor_sessions.retain(|s| s != session); + self.image_copy.cursor_sessions.retain(|s| s != session); } fn cursor_sessions(&self) -> Vec { - self.screencopy + self.image_copy .cursor_sessions .iter() .map(|s| (*s).clone()) @@ -202,9 +202,9 @@ impl SessionHolder for Workspace { impl SessionHolder for CosmicSurface { fn add_session(&mut self, session: Session) { self.user_data() - .insert_if_missing(ScreencopySessionsData::default); + .insert_if_missing(ImageCopySessionsData::default); self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .sessions @@ -213,7 +213,7 @@ impl SessionHolder for CosmicSurface { fn remove_session(&mut self, session: &SessionRef) { self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .sessions @@ -221,7 +221,7 @@ impl SessionHolder for CosmicSurface { } fn sessions(&self) -> Vec { self.user_data() - .get::() + .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() @@ -234,9 +234,9 @@ impl SessionHolder for CosmicSurface { fn add_cursor_session(&mut self, session: CursorSession) { self.user_data() - .insert_if_missing(ScreencopySessionsData::default); + .insert_if_missing(ImageCopySessionsData::default); self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .cursor_sessions @@ -245,7 +245,7 @@ impl SessionHolder for CosmicSurface { fn remove_cursor_session(&mut self, session: &CursorSessionRef) { self.user_data() - .get::() + .get::() .unwrap() .borrow_mut() .cursor_sessions @@ -254,7 +254,7 @@ impl SessionHolder for CosmicSurface { fn cursor_sessions(&self) -> Vec { self.user_data() - .get::() + .get::() .map_or(Vec::new(), |sessions| { sessions .borrow() diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index b057c8c2..06fd816f 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -17,6 +17,7 @@ pub mod fractional_scale; pub mod idle_inhibit; pub mod idle_notify; pub mod image_capture_source; +pub mod image_copy_capture; pub mod input_method; pub mod keyboard_shortcuts_inhibit; pub mod layer_shell; @@ -29,7 +30,6 @@ pub mod pointer_gestures; pub mod presentation; pub mod primary_selection; pub mod relative_pointer; -pub mod screencopy; pub mod seat; pub mod security_context; pub mod selection; diff --git a/src/wayland/protocols/image_capture_source.rs b/src/wayland/protocols/image_capture_source.rs index f71eaca9..1214cbe0 100644 --- a/src/wayland/protocols/image_capture_source.rs +++ b/src/wayland/protocols/image_capture_source.rs @@ -1,10 +1,8 @@ use super::{ - toplevel_info::window_from_ext_handle, workspace::{WorkspaceHandle, WorkspaceHandler}, }; use crate::{ shell::CosmicSurface, - wayland::protocols::toplevel_info::ToplevelInfoHandler, }; use cosmic_protocols::image_capture_source::v1::server::{ zcosmic_workspace_image_capture_source_manager_v1::{ @@ -12,75 +10,54 @@ use cosmic_protocols::image_capture_source::v1::server::{ }, }; use smithay::reexports::wayland_protocols::ext::image_capture_source::v1::server::{ - ext_foreign_toplevel_image_capture_source_manager_v1::{ - Request as ToplevelSourceRequest, ExtForeignToplevelImageCaptureSourceManagerV1, - }, ext_image_capture_source_v1::ExtImageCaptureSourceV1, - ext_output_image_capture_source_manager_v1::{ - Request as OutputSourceRequest, ExtOutputImageCaptureSourceManagerV1, - }, }; use smithay::{ - output::{Output, WeakOutput}, + output::WeakOutput, reexports::wayland_server::{ Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, }, + wayland::image_capture_source::{ImageCaptureSource, ImageCaptureSourceData}, }; use wayland_backend::server::GlobalId; #[derive(Debug)] -pub struct ImageCaptureSourceState { - output_source_global: GlobalId, +pub struct CosmicImageCaptureSourceState { workspace_source_global: GlobalId, - toplevel_source_global: GlobalId, } -pub struct OutputImageCaptureSourceManagerGlobalData { - filter: Box Fn(&'a Client) -> bool + Send + Sync>, -} pub struct WorkspaceImageCaptureSourceManagerGlobalData { filter: Box Fn(&'a Client) -> bool + Send + Sync>, } -pub struct ToplevelImageCaptureSourceManagerGlobalData { - filter: Box Fn(&'a Client) -> bool + Send + Sync>, -} #[derive(Debug, Clone, PartialEq)] -pub enum ImageCaptureSourceData { +pub enum ImageCaptureSourceKind { Output(WeakOutput), Workspace(WorkspaceHandle), Toplevel(CosmicSurface), Destroyed, } -impl ImageCaptureSourceState { - pub fn new(display: &DisplayHandle, client_filter: F) -> ImageCaptureSourceState +impl ImageCaptureSourceKind { + pub fn from_resource(resource: &ExtImageCaptureSourceV1) -> Option { + let source = ImageCaptureSource::from_resource(resource)?; + source.user_data().get::().cloned() + } +} + +impl CosmicImageCaptureSourceState { + pub fn new(display: &DisplayHandle, client_filter: F) -> CosmicImageCaptureSourceState where D: GlobalDispatch< - ExtOutputImageCaptureSourceManagerV1, - OutputImageCaptureSourceManagerGlobalData, - > + Dispatch - + GlobalDispatch< ZcosmicWorkspaceImageCaptureSourceManagerV1, WorkspaceImageCaptureSourceManagerGlobalData, > + Dispatch - + GlobalDispatch< - ExtForeignToplevelImageCaptureSourceManagerV1, - ToplevelImageCaptureSourceManagerGlobalData, - > + Dispatch + Dispatch + WorkspaceHandler + 'static, F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static, { - ImageCaptureSourceState { - output_source_global: display - .create_global::( - 1, - OutputImageCaptureSourceManagerGlobalData { - filter: Box::new(client_filter.clone()), - }, - ), + CosmicImageCaptureSourceState { workspace_source_global: display .create_global::( 1, @@ -88,57 +65,12 @@ impl ImageCaptureSourceState { filter: Box::new(client_filter.clone()), }, ), - toplevel_source_global: display - .create_global::( - 1, - ToplevelImageCaptureSourceManagerGlobalData { - filter: Box::new(client_filter), - }, - ), } } - pub fn output_source_id(&self) -> &GlobalId { - &self.output_source_global - } - pub fn workspace_source_id(&self) -> &GlobalId { &self.workspace_source_global } - - pub fn toplevel_source_id(&self) -> &GlobalId { - &self.toplevel_source_global - } -} - -impl - GlobalDispatch< - ExtOutputImageCaptureSourceManagerV1, - OutputImageCaptureSourceManagerGlobalData, - D, - > for ImageCaptureSourceState -where - D: GlobalDispatch< - ExtOutputImageCaptureSourceManagerV1, - OutputImageCaptureSourceManagerGlobalData, - > + Dispatch - + Dispatch - + 'static, -{ - fn bind( - _state: &mut D, - _handle: &DisplayHandle, - _client: &Client, - resource: New, - _global_data: &OutputImageCaptureSourceManagerGlobalData, - data_init: &mut DataInit<'_, D>, - ) { - data_init.init(resource, ()); - } - - fn can_view(client: Client, global_data: &OutputImageCaptureSourceManagerGlobalData) -> bool { - (global_data.filter)(&client) - } } impl @@ -146,7 +78,7 @@ impl ZcosmicWorkspaceImageCaptureSourceManagerV1, WorkspaceImageCaptureSourceManagerGlobalData, D, - > for ImageCaptureSourceState + > for CosmicImageCaptureSourceState where D: GlobalDispatch< ZcosmicWorkspaceImageCaptureSourceManagerV1, @@ -174,70 +106,8 @@ where } } -impl - GlobalDispatch< - ExtForeignToplevelImageCaptureSourceManagerV1, - ToplevelImageCaptureSourceManagerGlobalData, - D, - > for ImageCaptureSourceState -where - D: GlobalDispatch< - ExtForeignToplevelImageCaptureSourceManagerV1, - ToplevelImageCaptureSourceManagerGlobalData, - > + Dispatch - + Dispatch - + 'static, -{ - fn bind( - _state: &mut D, - _handle: &DisplayHandle, - _client: &Client, - resource: New, - _global_data: &ToplevelImageCaptureSourceManagerGlobalData, - data_init: &mut DataInit<'_, D>, - ) { - data_init.init(resource, ()); - } - - fn can_view(client: Client, global_data: &ToplevelImageCaptureSourceManagerGlobalData) -> bool { - (global_data.filter)(&client) - } -} - -impl Dispatch for ImageCaptureSourceState -where - D: Dispatch - + Dispatch - + 'static, -{ - fn request( - _state: &mut D, - _client: &Client, - _resource: &ExtOutputImageCaptureSourceManagerV1, - request: ::Request, - _data: &(), - _dhandle: &DisplayHandle, - data_init: &mut DataInit<'_, D>, - ) { - if let OutputSourceRequest::CreateSource { source, output } = request { - let data = match Output::from_resource(&output) { - Some(output) => ImageCaptureSourceData::Output(output.downgrade()), - None => ImageCaptureSourceData::Destroyed, - }; - data_init.init(source, data); - } - } - - fn destroyed( - _state: &mut D, - _client: wayland_backend::server::ClientId, - _resource: &ExtOutputImageCaptureSourceManagerV1, - _data: &(), - ) { - } -} - -impl Dispatch for ImageCaptureSourceState +impl Dispatch + for CosmicImageCaptureSourceState where D: Dispatch + Dispatch @@ -253,110 +123,36 @@ where _dhandle: &DisplayHandle, data_init: &mut DataInit<'_, D>, ) { - if let CosmicWorkspaceSourceRequest::CreateSource { source, output } = request { - let data = match state.workspace_state().get_ext_workspace_handle(&output) { - Some(workspace) => ImageCaptureSourceData::Workspace(workspace), - None => ImageCaptureSourceData::Destroyed, - }; - data_init.init(source, data); - } - } - - fn destroyed( - _state: &mut D, - _client: wayland_backend::server::ClientId, - _resource: &ZcosmicWorkspaceImageCaptureSourceManagerV1, - _data: &(), - ) { - } -} - -impl Dispatch for ImageCaptureSourceState -where - D: Dispatch - + Dispatch - + ToplevelInfoHandler - + 'static, -{ - fn request( - state: &mut D, - _client: &Client, - _resource: &ExtForeignToplevelImageCaptureSourceManagerV1, - request: ::Request, - _data: &(), - _dhandle: &DisplayHandle, - data_init: &mut DataInit<'_, D>, - ) { - if let ToplevelSourceRequest::CreateSource { - source, - toplevel_handle, + if let CosmicWorkspaceSourceRequest::CreateSource { + source: source_handle, + output, } = request { - let data = match window_from_ext_handle(state, &toplevel_handle) { - Some(toplevel) => ImageCaptureSourceData::Toplevel(toplevel.clone()), - None => ImageCaptureSourceData::Destroyed, + let data = match state.workspace_state().get_ext_workspace_handle(&output) { + Some(workspace) => ImageCaptureSourceKind::Workspace(workspace), + None => ImageCaptureSourceKind::Destroyed, }; - data_init.init(source, data); + let source = ImageCaptureSource::new(); + source.user_data().insert_if_missing(|| data); + let instance = data_init.init( + source_handle, + ImageCaptureSourceData { + source: source.clone(), + }, + ); + source.add_instance(&instance); } } - - fn destroyed( - _state: &mut D, - _client: wayland_backend::server::ClientId, - _resource: &ExtForeignToplevelImageCaptureSourceManagerV1, - _data: &(), - ) { - } } -impl Dispatch for ImageCaptureSourceState -where - D: Dispatch + 'static, -{ - fn request( - _state: &mut D, - _client: &Client, - _resource: &ExtImageCaptureSourceV1, - _request: ::Request, - _data: &ImageCaptureSourceData, - _dhandle: &DisplayHandle, - _data_init: &mut DataInit<'_, D>, - ) { - {} - } - - fn destroyed( - _state: &mut D, - _client: wayland_backend::server::ClientId, - _resource: &ExtImageCaptureSourceV1, - _data: &ImageCaptureSourceData, - ) { - } -} - -macro_rules! delegate_image_capture_source { +macro_rules! delegate_cosmic_image_capture_source { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_capture_source::v1::server::ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1: $crate::wayland::protocols::image_capture_source::OutputImageCaptureSourceManagerGlobalData - ] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_capture_source::v1::server::ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1: () - ] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ cosmic_protocols::image_capture_source::v1::server::zcosmic_workspace_image_capture_source_manager_v1::ZcosmicWorkspaceImageCaptureSourceManagerV1: $crate::wayland::protocols::image_capture_source::WorkspaceImageCaptureSourceManagerGlobalData - ] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); + ] => $crate::wayland::protocols::image_capture_source::CosmicImageCaptureSourceState); smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ cosmic_protocols::image_capture_source::v1::server::zcosmic_workspace_image_capture_source_manager_v1::ZcosmicWorkspaceImageCaptureSourceManagerV1: () - ] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); - smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_capture_source::v1::server::ext_foreign_toplevel_image_capture_source_manager_v1::ExtForeignToplevelImageCaptureSourceManagerV1: $crate::wayland::protocols::image_capture_source::ToplevelImageCaptureSourceManagerGlobalData - ] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_capture_source::v1::server::ext_foreign_toplevel_image_capture_source_manager_v1::ExtForeignToplevelImageCaptureSourceManagerV1: () - ] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_capture_source::v1::server::ext_image_capture_source_v1::ExtImageCaptureSourceV1: $crate::wayland::protocols::image_capture_source::ImageCaptureSourceData - ] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); + ] => $crate::wayland::protocols::image_capture_source::CosmicImageCaptureSourceState); }; } -pub(crate) use delegate_image_capture_source; +pub(crate) use delegate_cosmic_image_capture_source; diff --git a/src/wayland/protocols/mod.rs b/src/wayland/protocols/mod.rs index 99e39592..57e05b8a 100644 --- a/src/wayland/protocols/mod.rs +++ b/src/wayland/protocols/mod.rs @@ -7,7 +7,6 @@ pub mod image_capture_source; pub mod output_configuration; pub mod output_power; pub mod overlap_notify; -pub mod screencopy; pub mod toplevel_info; pub mod toplevel_management; pub mod workspace; diff --git a/src/wayland/protocols/screencopy.rs b/src/wayland/protocols/screencopy.rs deleted file mode 100644 index ca756d92..00000000 --- a/src/wayland/protocols/screencopy.rs +++ /dev/null @@ -1,1158 +0,0 @@ -use std::{ - ops, - sync::{Arc, Mutex}, - time::Duration, -}; - -pub use smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::{ - ext_image_copy_capture_frame_v1::FailureReason, -}; -use smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::{ - ext_image_copy_capture_cursor_session_v1::{self, ExtImageCopyCaptureCursorSessionV1}, - ext_image_copy_capture_frame_v1::{self, ExtImageCopyCaptureFrameV1}, - ext_image_copy_capture_manager_v1::{self, ExtImageCopyCaptureManagerV1}, - ext_image_copy_capture_session_v1::{self, ExtImageCopyCaptureSessionV1}, -}; -use smithay::{ - backend::{ - allocator::{Buffer, Fourcc, Modifier}, - drm::DrmNode, - renderer::{buffer_type, BufferType}, - }, - utils::{user_data::UserDataMap, Buffer as BufferCoords, IsAlive, Size, Transform}, - wayland::{dmabuf::get_dmabuf, shm::with_buffer_contents}, -}; -use smithay::{reexports::wayland_server::protocol::wl_buffer::WlBuffer, utils::Point}; -use smithay::{ - reexports::wayland_server::{ - protocol::wl_shm, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, - Weak, - }, - utils::Rectangle, -}; -use tracing::debug; -use wayland_backend::server::GlobalId; - -use super::image_capture_source::ImageCaptureSourceData; - -#[derive(Debug)] -pub struct ScreencopyState { - global: GlobalId, - known_sessions: Vec, - known_cursor_sessions: Vec, -} - -impl ScreencopyState { - pub fn new(display: &DisplayHandle, client_filter: F) -> ScreencopyState - where - D: GlobalDispatch - + Dispatch - + Dispatch - + Dispatch - + Dispatch - + Dispatch - + ScreencopyHandler - + 'static, - F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static, - { - ScreencopyState { - global: display.create_global::( - 1, - ScreencopyGlobalData { - filter: Box::new(client_filter), - }, - ), - known_sessions: Vec::new(), - known_cursor_sessions: Vec::new(), - } - } - - pub fn global_id(&self) -> &GlobalId { - &self.global - } -} - -#[derive(Debug, Clone)] -pub struct BufferConstraints { - pub size: Size, - pub shm: Vec, - pub dma: Option, -} - -#[derive(Debug, Clone)] -pub struct DmabufConstraints { - pub node: DrmNode, - pub formats: Vec<(Fourcc, Vec)>, -} - -#[derive(Debug, Clone)] -pub struct SessionRef { - obj: ExtImageCopyCaptureSessionV1, - inner: Arc>, - user_data: Arc, -} - -impl PartialEq for SessionRef { - fn eq(&self, other: &Self) -> bool { - self.obj == other.obj - } -} - -#[derive(Debug)] -struct SessionInner { - stopped: bool, - constraints: Option, - draw_cursors: bool, - source: ImageCaptureSourceData, - active_frames: Vec, -} - -impl SessionInner { - fn new(source: ImageCaptureSourceData, draw_cursors: bool) -> SessionInner { - SessionInner { - stopped: false, - constraints: None, - draw_cursors, - source, - active_frames: Vec::new(), - } - } -} - -impl IsAlive for SessionRef { - fn alive(&self) -> bool { - self.obj.is_alive() - } -} - -impl SessionRef { - pub fn update_constraints(&self, constraints: BufferConstraints) { - let mut inner = self.inner.lock().unwrap(); - - if !self.obj.is_alive() || inner.stopped { - return; - } - - self.obj - .buffer_size(constraints.size.w as u32, constraints.size.h as u32); - for fmt in &constraints.shm { - self.obj.shm_format(*fmt); - } - if let Some(dma) = constraints.dma.as_ref() { - let node = Vec::from(dma.node.dev_id().to_ne_bytes()); - self.obj.dmabuf_device(node); - for (fmt, modifiers) in &dma.formats { - let modifiers = modifiers - .iter() - .flat_map(|modifier| u64::from(*modifier).to_ne_bytes()) - .collect::>(); - self.obj.dmabuf_format(*fmt as u32, modifiers); - } - } - self.obj.done(); - - inner.constraints = Some(constraints); - } - - pub fn current_constraints(&self) -> Option { - self.inner.lock().unwrap().constraints.clone() - } - - pub fn source(&self) -> ImageCaptureSourceData { - self.inner.lock().unwrap().source.clone() - } - - pub fn draw_cursor(&self) -> bool { - self.inner.lock().unwrap().draw_cursors - } - - pub fn user_data(&self) -> &UserDataMap { - &self.user_data - } -} - -#[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 - .inner - .lock() - .unwrap() - .fail(&frame.obj, FailureReason::Stopped); - } - - self.obj.stopped(); - inner.constraints.take(); - inner.stopped = true; - } -} - -impl Session { - pub fn stop(self) { - let _ = self; - } -} - -#[derive(Debug, Clone)] -pub struct CursorSessionRef { - obj: ExtImageCopyCaptureCursorSessionV1, - inner: Arc>, - user_data: Arc, -} - -impl PartialEq for CursorSessionRef { - fn eq(&self, other: &Self) -> bool { - self.obj == other.obj - } -} - -#[derive(Debug)] -struct CursorSessionInner { - session: Option, - stopped: bool, - constraints: Option, - source: ImageCaptureSourceData, - position: Option>, - hotspot: Point, - active_frames: Vec, -} - -impl CursorSessionInner { - fn new(source: ImageCaptureSourceData) -> CursorSessionInner { - CursorSessionInner { - session: None, - stopped: false, - constraints: None, - source, - position: None, - hotspot: Point::from((0, 0)), - active_frames: Vec::new(), - } - } -} - -impl IsAlive for CursorSessionRef { - fn alive(&self) -> bool { - self.obj.is_alive() - } -} - -impl CursorSessionRef { - pub fn update_constraints(&self, constrains: BufferConstraints) { - let mut inner = self.inner.lock().unwrap(); - - if !self.obj.is_alive() || inner.stopped { - return; - } - - if let Some(session_obj) = inner.session.as_ref() { - session_obj.buffer_size(constrains.size.w as u32, constrains.size.h as u32); - for fmt in &constrains.shm { - session_obj.shm_format(*fmt); - } - if let Some(dma) = constrains.dma.as_ref() { - let node = Vec::from(dma.node.dev_id().to_ne_bytes()); - session_obj.dmabuf_device(node); - for (fmt, modifiers) in &dma.formats { - let modifiers = modifiers - .iter() - .flat_map(|modifier| u64::from(*modifier).to_ne_bytes()) - .collect::>(); - session_obj.dmabuf_format(*fmt as u32, modifiers); - } - } - session_obj.done(); - } - - inner.constraints = Some(constrains); - } - - pub fn current_constraints(&self) -> Option { - self.inner.lock().unwrap().constraints.clone() - } - - pub fn source(&self) -> ImageCaptureSourceData { - self.inner.lock().unwrap().source.clone() - } - - pub fn has_cursor(&self) -> bool { - self.inner.lock().unwrap().position.is_some() - } - - pub fn set_cursor_pos(&self, position: Option>) { - if !self.obj.is_alive() { - return; - } - - let mut inner = self.inner.lock().unwrap(); - - if inner.position == position { - return; - } - - if inner.position.is_none() { - self.obj.enter(); - self.obj.hotspot(inner.hotspot.x, inner.hotspot.y) - } - - if let Some(new_pos) = position { - self.obj.position(new_pos.x, new_pos.y); - } else { - self.obj.leave() - } - - inner.position = position; - } - - pub fn set_cursor_hotspot(&self, hotspot: impl Into>) { - if !self.obj.is_alive() { - return; - } - - let hotspot = hotspot.into(); - - let mut inner = self.inner.lock().unwrap(); - - if inner.hotspot == hotspot { - return; - } - - inner.hotspot = hotspot; - if inner.position.is_some() { - self.obj.hotspot(hotspot.x, hotspot.y); - } - } - - pub fn user_data(&self) -> &UserDataMap { - &self.user_data - } -} - -#[derive(Debug)] -pub struct CursorSession(CursorSessionRef); - -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; - } - - if let Some(session_obj) = inner.session.as_ref() { - session_obj.stopped(); - } - inner.constraints.take(); - - for frame in inner.active_frames.drain(..) { - frame - .inner - .lock() - .unwrap() - .fail(&frame.obj, FailureReason::Stopped); - } - - inner.stopped = true; - } -} - -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 FrameRef { - fn eq(&self, other: &Self) -> bool { - self.obj == other.obj - } -} - -impl FrameRef { - pub fn buffer(&self) -> WlBuffer { - self.inner.lock().unwrap().buffer.clone().unwrap() - } - - pub fn damage(&self) -> Vec> { - self.inner.lock().unwrap().damage.clone() - } - - 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, - damage: impl Into>>>, - presented: impl Into, - ) { - { - let inner = self.0.inner.lock().unwrap(); - if !inner.capture_requested || inner.failed.is_some() { - return; - } - } - - self.obj.transform(transform.into().into()); - for damage in damage.into().into_iter().flatten() { - self.obj - .damage(damage.loc.x, damage.loc.y, damage.size.w, damage.size.h); - } - - let time = presented.into(); - let tv_sec_hi = (time.as_secs() >> 32) as u32; - let tv_sec_lo = (time.as_secs() & 0xFFFFFFFF) as u32; - let tv_nsec = time.subsec_nanos(); - self.obj.presentation_time(tv_sec_hi, tv_sec_lo, tv_nsec); - - self.0.inner.lock().unwrap().ready = true; - self.obj.ready() - } - - pub fn fail(self, reason: FailureReason) { - 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); - } -} - -#[derive(Debug)] -struct FrameInner { - constraints: Option, - buffer: Option, - damage: Vec>, - // `SessionInner` contains a `Vec`, so use a weak reference here to - // avoid a cycle. - obj: Weak, - capture_requested: bool, - failed: Option, - ready: bool, -} - -impl FrameInner { - fn new( - obj: ExtImageCopyCaptureSessionV1, - constraints: impl Into>, - ) -> Self { - FrameInner { - constraints: constraints.into(), - buffer: None, - damage: Vec::new(), - obj: obj.downgrade(), - capture_requested: false, - failed: None, - ready: false, - } - } - - fn fail(&mut self, frame: &ExtImageCopyCaptureFrameV1, reason: FailureReason) { - if self.ready || self.failed.is_some() { - return; - } - self.failed = Some(reason); - if self.capture_requested { - frame.failed(reason); - } - } -} - -pub trait ScreencopyHandler { - fn screencopy_state(&mut self) -> &mut ScreencopyState; - - fn capture_source(&mut self, source: &ImageCaptureSourceData) -> Option; - fn capture_cursor_source( - &mut self, - source: &ImageCaptureSourceData, - ) -> Option; - - fn new_session(&mut self, session: Session); - fn new_cursor_session(&mut self, session: CursorSession); - - fn frame(&mut self, session: SessionRef, frame: Frame); - fn cursor_frame(&mut self, session: CursorSessionRef, frame: Frame); - - fn frame_aborted(&mut self, frame_handle: FrameRef); - fn session_destroyed(&mut self, session: SessionRef) { - let _ = session; - } - fn cursor_session_destroyed(&mut self, session: CursorSessionRef) { - let _ = session; - } -} - -pub struct ScreencopyGlobalData { - filter: Box Fn(&'a Client) -> bool + Send + Sync>, -} - -pub struct ScreencopyData; - -pub struct SessionData { - inner: Arc>, -} - -pub struct CursorSessionData { - inner: Arc>, -} -pub struct FrameData { - inner: Arc>, -} - -impl GlobalDispatch for ScreencopyState -where - D: GlobalDispatch - + Dispatch - + Dispatch - + Dispatch - + Dispatch - + Dispatch - + ScreencopyHandler - + 'static, -{ - fn bind( - _state: &mut D, - _handle: &DisplayHandle, - _client: &Client, - resource: New, - _global_data: &ScreencopyGlobalData, - data_init: &mut DataInit<'_, D>, - ) { - data_init.init(resource, ScreencopyData); - } - - fn can_view(client: Client, global_data: &ScreencopyGlobalData) -> bool { - (global_data.filter)(&client) - } -} - -impl Dispatch for ScreencopyState -where - D: Dispatch - + Dispatch - + Dispatch - + Dispatch - + Dispatch - + ScreencopyHandler - + 'static, -{ - fn request( - state: &mut D, - _client: &Client, - _resource: &ExtImageCopyCaptureManagerV1, - request: ::Request, - _data: &ScreencopyData, - _dhandle: &DisplayHandle, - data_init: &mut DataInit<'_, D>, - ) { - match request { - ext_image_copy_capture_manager_v1::Request::CreateSession { - session, - source, - options, - } => { - if let Some(src) = source.data::() { - if *src != ImageCaptureSourceData::Destroyed { - if let Some(buffer_constraints) = state.capture_source(src) { - let session_data = Arc::new(Mutex::new(SessionInner::new( - src.clone(), - Into::::into(options) == 1, - ))); - let obj = data_init.init( - session, - SessionData { - inner: session_data.clone(), - }, - ); - - let session = SessionRef { - obj, - inner: session_data, - user_data: Arc::new(UserDataMap::new()), - }; - session.update_constraints(buffer_constraints); - state - .screencopy_state() - .known_sessions - .push(session.clone()); - state.new_session(Session(session)); - return; - } - } - } - - let session_data = Arc::new(Mutex::new(SessionInner::new( - ImageCaptureSourceData::Destroyed, - false, - ))); - let obj = data_init.init( - session, - SessionData { - inner: session_data.clone(), - }, - ); - let session = Session(SessionRef { - obj, - inner: session_data, - user_data: Arc::new(UserDataMap::new()), - }); - session.stop(); - } - ext_image_copy_capture_manager_v1::Request::CreatePointerCursorSession { - session, - source, - pointer: _, - } => { - // TODO: use pointer, but we need new smithay api for that. - - if let Some(src) = source.data::() { - if *src != ImageCaptureSourceData::Destroyed { - if let Some(buffer_constraints) = state.capture_cursor_source(src) { - let session_data = - Arc::new(Mutex::new(CursorSessionInner::new(src.clone()))); - let obj = data_init.init( - session, - CursorSessionData { - inner: session_data.clone(), - }, - ); - - let session = CursorSessionRef { - obj, - inner: session_data, - user_data: Arc::new(UserDataMap::new()), - }; - session.update_constraints(buffer_constraints); - state - .screencopy_state() - .known_cursor_sessions - .push(session.clone()); - state.new_cursor_session(CursorSession(session)); - return; - } - } - } - - let session_data = Arc::new(Mutex::new(CursorSessionInner::new( - ImageCaptureSourceData::Destroyed, - ))); - let obj = data_init.init( - session, - CursorSessionData { - inner: session_data.clone(), - }, - ); - let session = CursorSession(CursorSessionRef { - obj, - inner: session_data, - user_data: Arc::new(UserDataMap::new()), - }); - session.stop(); - } - _ => {} - } - } - - fn destroyed( - _state: &mut D, - _client: wayland_backend::server::ClientId, - _resource: &ExtImageCopyCaptureManagerV1, - _data: &ScreencopyData, - ) { - } -} - -impl Dispatch for ScreencopyState -where - D: Dispatch - + Dispatch - + ScreencopyHandler - + 'static, -{ - fn request( - _state: &mut D, - _client: &Client, - resource: &ExtImageCopyCaptureSessionV1, - request: ::Request, - data: &SessionData, - _dhandle: &DisplayHandle, - data_init: &mut DataInit<'_, D>, - ) { - if let ext_image_copy_capture_session_v1::Request::CreateFrame { frame } = request { - let inner = Arc::new(Mutex::new(FrameInner::new( - resource.clone(), - data.inner.lock().unwrap().constraints.clone(), - ))); - let obj = data_init.init( - frame, - FrameData { - inner: inner.clone(), - }, - ); - data.inner - .lock() - .unwrap() - .active_frames - .push(FrameRef { obj, inner }); - } - } - - fn destroyed( - state: &mut D, - _client: wayland_backend::server::ClientId, - resource: &ExtImageCopyCaptureSessionV1, - _data: &SessionData, - ) { - let scpy = state.screencopy_state(); - if let Some(pos) = scpy - .known_sessions - .iter() - .position(|session| session.obj == *resource) - { - let session = scpy.known_sessions.remove(pos); - state.session_destroyed(session); - } - } -} - -impl Dispatch for ScreencopyState -where - D: Dispatch - + Dispatch - + Dispatch - + ScreencopyHandler - + 'static, -{ - fn request( - _state: &mut D, - _client: &Client, - resource: &ExtImageCopyCaptureCursorSessionV1, - request: ::Request, - data: &CursorSessionData, - _dhandle: &DisplayHandle, - data_init: &mut DataInit<'_, D>, - ) { - if let ext_image_copy_capture_cursor_session_v1::Request::GetCaptureSession { session } = - request - { - let new_data = CursorSessionData { - inner: data.inner.clone(), - }; - let session = data_init.init(session, new_data); - - let mut inner = data.inner.lock().unwrap(); - if inner.session.is_some() { - resource.post_error( - ext_image_copy_capture_cursor_session_v1::Error::DuplicateSession, - "Duplicate session", - ); - return; - } - - if inner.stopped { - session.stopped(); - } else if let Some(constraints) = inner.constraints.as_ref() { - session.buffer_size(constraints.size.w as u32, constraints.size.h as u32); - for fmt in &constraints.shm { - session.shm_format(*fmt); - } - if let Some(dma) = constraints.dma.as_ref() { - let node = Vec::from(dma.node.dev_id().to_ne_bytes()); - session.dmabuf_device(node); - for (fmt, modifiers) in &dma.formats { - let modifiers = modifiers - .iter() - .flat_map(|modifier| u64::from(*modifier).to_ne_bytes()) - .collect::>(); - session.dmabuf_format(*fmt as u32, modifiers); - } - } - session.done(); - } - inner.session = Some(session); - } - } - - fn destroyed( - state: &mut D, - _client: wayland_backend::server::ClientId, - resource: &ExtImageCopyCaptureCursorSessionV1, - _data: &CursorSessionData, - ) { - let scpy = state.screencopy_state(); - if let Some(pos) = scpy - .known_cursor_sessions - .iter() - .position(|session| session.obj == *resource) - { - let session = scpy.known_cursor_sessions.remove(pos); - state.cursor_session_destroyed(session); - } - } -} - -impl Dispatch for ScreencopyState -where - D: Dispatch - + Dispatch - + ScreencopyHandler - + 'static, -{ - fn request( - _state: &mut D, - _client: &Client, - resource: &ExtImageCopyCaptureSessionV1, - request: ::Request, - data: &CursorSessionData, - _dhandle: &DisplayHandle, - data_init: &mut DataInit<'_, D>, - ) { - if let ext_image_copy_capture_session_v1::Request::CreateFrame { frame } = request { - let inner = Arc::new(Mutex::new(FrameInner::new( - resource.clone(), - data.inner.lock().unwrap().constraints.clone(), - ))); - let obj = data_init.init( - frame, - FrameData { - inner: inner.clone(), - }, - ); - data.inner - .lock() - .unwrap() - .active_frames - .push(FrameRef { obj, inner }); - } - } - - fn destroyed( - _state: &mut D, - _client: wayland_backend::server::ClientId, - _resource: &ExtImageCopyCaptureSessionV1, - _data: &CursorSessionData, - ) { - } -} - -impl Dispatch for ScreencopyState -where - D: Dispatch + ScreencopyHandler + 'static, -{ - fn request( - state: &mut D, - _client: &Client, - resource: &ExtImageCopyCaptureFrameV1, - request: ::Request, - data: &FrameData, - _dhandle: &DisplayHandle, - _data_init: &mut DataInit<'_, D>, - ) { - match request { - ext_image_copy_capture_frame_v1::Request::AttachBuffer { buffer } => { - let mut inner = data.inner.lock().unwrap(); - - if inner.capture_requested { - resource.post_error( - ext_image_copy_capture_frame_v1::Error::AlreadyCaptured, - "Frame was captured previously", - ); - } - - inner.buffer = Some(buffer); - } - ext_image_copy_capture_frame_v1::Request::DamageBuffer { - x, - y, - width, - height, - } => { - let mut 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 x < 0 || y < 0 || width <= 0 || height <= 0 { - resource.post_error( - ext_image_copy_capture_frame_v1::Error::InvalidBufferDamage, - "Coordinates negative or size equal to zero", - ); - return; - } - - inner - .damage - .push(Rectangle::new((x, y).into(), (width, height).into())); - } - ext_image_copy_capture_frame_v1::Request::Capture => { - { - 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", - ); - 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; - } - } - - let frame = Frame(FrameRef { - obj: resource.clone(), - inner: data.inner.clone(), - }); - if let Err(reason) = capture_frame(state, frame) { - data.inner.lock().unwrap().fail(resource, reason); - } - } - _ => {} - } - } - - fn destroyed( - state: &mut D, - _client: wayland_backend::server::ClientId, - 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 { - session - .inner - .lock() - .unwrap() - .active_frames - .retain(|i| *i != frame_ref); - } - for cursor_session in &mut scpy.known_cursor_sessions { - cursor_session - .inner - .lock() - .unwrap() - .active_frames - .retain(|i| *i != frame_ref); - } - } - 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) - } -} - -macro_rules! delegate_screencopy { - ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::ext_image_copy_capture_manager_v1::ExtImageCopyCaptureManagerV1: $crate::wayland::protocols::screencopy::ScreencopyGlobalData - ] => $crate::wayland::protocols::screencopy::ScreencopyState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::ext_image_copy_capture_manager_v1::ExtImageCopyCaptureManagerV1: $crate::wayland::protocols::screencopy::ScreencopyData - ] => $crate::wayland::protocols::screencopy::ScreencopyState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::ext_image_copy_capture_session_v1::ExtImageCopyCaptureSessionV1: $crate::wayland::protocols::screencopy::SessionData - ] => $crate::wayland::protocols::screencopy::ScreencopyState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::ext_image_copy_capture_cursor_session_v1::ExtImageCopyCaptureCursorSessionV1: $crate::wayland::protocols::screencopy::CursorSessionData - ] => $crate::wayland::protocols::screencopy::ScreencopyState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::ext_image_copy_capture_session_v1::ExtImageCopyCaptureSessionV1: $crate::wayland::protocols::screencopy::CursorSessionData - ] => $crate::wayland::protocols::screencopy::ScreencopyState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - smithay::reexports::wayland_protocols::ext::image_copy_capture::v1::server::ext_image_copy_capture_frame_v1::ExtImageCopyCaptureFrameV1: $crate::wayland::protocols::screencopy::FrameData - ] => $crate::wayland::protocols::screencopy::ScreencopyState); - }; -} -pub(crate) use delegate_screencopy; diff --git a/src/wayland/protocols/toplevel_info.rs b/src/wayland/protocols/toplevel_info.rs index a64f8e9e..4d30e73f 100644 --- a/src/wayland/protocols/toplevel_info.rs +++ b/src/wayland/protocols/toplevel_info.rs @@ -635,14 +635,13 @@ pub fn window_from_handle(handle: ZcosmicToplevelHandleV1) .and_then(|state| state.lock().unwrap().window.clone()) } -pub fn window_from_ext_handle<'a, W: Window + 'static, D>( +pub fn window_from_ext<'a, W: Window + 'static, D>( state: &'a D, - foreign_toplevel: &ExtForeignToplevelHandleV1, + handle: &ForeignToplevelHandle, ) -> Option<&'a W> where D: ToplevelInfoHandler, { - let handle = ForeignToplevelHandle::from_resource(foreign_toplevel)?; state.toplevel_info_state().toplevels.iter().find(|w| { w.user_data().get::().and_then(|inner| { inner @@ -655,6 +654,17 @@ where }) } +pub fn window_from_ext_handle<'a, W: Window + 'static, D>( + state: &'a D, + foreign_toplevel: &ExtForeignToplevelHandleV1, +) -> Option<&'a W> +where + D: ToplevelInfoHandler, +{ + let handle = ForeignToplevelHandle::from_resource(foreign_toplevel)?; + window_from_ext(state, &handle) +} + macro_rules! delegate_toplevel_info { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, $window: ty) => { smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [