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

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

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

View file

@ -8,7 +8,7 @@ use crate::{
config::{CompTransformDef, EdidProduct, ScreenFilter}, config::{CompTransformDef, EdidProduct, ScreenFilter},
shell::Shell, shell::Shell,
utils::{env::dev_list_var, prelude::*}, utils::{env::dev_list_var, prelude::*},
wayland::handlers::screencopy::PendingImageCopyData, wayland::handlers::image_copy_capture::PendingImageCopyData,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};

View file

@ -11,14 +11,9 @@ use crate::{
shell::Shell, shell::Shell,
state::SurfaceDmabufFeedback, state::SurfaceDmabufFeedback,
utils::prelude::*, utils::prelude::*,
wayland::{ wayland::handlers::{
handlers::{ compositor::recursive_frame_time_estimation,
compositor::recursive_frame_time_estimation, image_copy_capture::{FrameHolder, PendingImageCopyData, SessionData, submit_buffer},
screencopy::{FrameHolder, PendingImageCopyData, SessionData, submit_buffer},
},
protocols::screencopy::{
FailureReason, Frame as ScreencopyFrame, SessionRef as ScreencopySessionRef,
},
}, },
}; };
@ -82,6 +77,9 @@ use smithay::{
utils::{Clock, Monotonic, Physical, Point, Rectangle, Transform}, utils::{Clock, Monotonic, Physical, Point, Rectangle, Transform},
wayland::{ wayland::{
dmabuf::{DmabufFeedbackBuilder, get_dmabuf}, dmabuf::{DmabufFeedbackBuilder, get_dmabuf},
image_copy_capture::{
CaptureFailureReason, Frame as ScreencopyFrame, SessionRef as ScreencopySessionRef,
},
presentation::Refresh, presentation::Refresh,
seat::WaylandFocus, seat::WaylandFocus,
shm::{shm_format_to_fourcc, with_buffer_contents}, shm::{shm_format_to_fourcc, with_buffer_contents},
@ -1398,7 +1396,7 @@ impl SurfaceThreadState {
.lock() .lock()
.unwrap() .unwrap()
.reset(); .reset();
frame.fail(FailureReason::Unknown); frame.fail(CaptureFailureReason::Unknown);
} }
return Err(err).with_context(|| "Failed to submit result for display"); return Err(err).with_context(|| "Failed to submit result for display");
} }

View file

@ -35,7 +35,7 @@ use crate::{
handlers::{ handlers::{
compositor::FRAME_TIME_FILTER, compositor::FRAME_TIME_FILTER,
data_device::get_dnd_icon, data_device::get_dnd_icon,
screencopy::{FrameHolder, SessionData, render_session}, image_copy_capture::{FrameHolder, SessionData, render_session},
}, },
protocols::workspace::WorkspaceHandle, protocols::workspace::WorkspaceHandle,
}, },

View file

@ -24,9 +24,8 @@ use crate::{
zoom::ZoomState, zoom::ZoomState,
}, },
utils::{prelude::*, quirks::workspace_overview_is_open}, utils::{prelude::*, quirks::workspace_overview_is_open},
wayland::{ wayland::handlers::{
handlers::{screencopy::SessionHolder, xwayland_keyboard_grab::XWaylandGrabSeat}, image_copy_capture::SessionHolder, xwayland_keyboard_grab::XWaylandGrabSeat,
protocols::screencopy::{BufferConstraints, CursorSessionRef},
}, },
}; };
use calloop::{ use calloop::{
@ -62,6 +61,7 @@ use smithay::{
}, },
utils::{Point, Rectangle, SERIAL_COUNTER, Serial}, utils::{Point, Rectangle, SERIAL_COUNTER, Serial},
wayland::{ wayland::{
image_copy_capture::{BufferConstraints, CursorSessionRef},
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat,
pointer_constraints::{PointerConstraint, with_pointer_constraint}, pointer_constraints::{PointerConstraint, with_pointer_constraint},
seat::WaylandFocus, seat::WaylandFocus,

View file

@ -12,7 +12,7 @@ use crate::{
zoom::ZoomFocusTarget, zoom::ZoomFocusTarget,
}, },
utils::prelude::*, 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 id_tree::NodeId;
use smithay::{ use smithay::{

View file

@ -13,7 +13,7 @@ use crate::{
state::State, state::State,
utils::{prelude::*, tween::EaseRectangle}, utils::{prelude::*, tween::EaseRectangle},
wayland::{ wayland::{
handlers::screencopy::ScreencopySessions, handlers::image_copy_capture::ImageCopySessions,
protocols::{ protocols::{
toplevel_info::{toplevel_enter_output, toplevel_leave_output}, toplevel_info::{toplevel_enter_output, toplevel_leave_output},
workspace::{WorkspaceHandle, WorkspaceUpdateGuard}, workspace::{WorkspaceHandle, WorkspaceUpdateGuard},
@ -110,7 +110,7 @@ pub struct Workspace {
pub handle: WorkspaceHandle, pub handle: WorkspaceHandle,
pub focus_stack: FocusStacks, pub focus_stack: FocusStacks,
pub screencopy: ScreencopySessions, pub image_copy: ImageCopySessions,
output_stack: VecDeque<OutputMatch>, output_stack: VecDeque<OutputMatch>,
pub(super) backdrop_id: Id, pub(super) backdrop_id: Id,
pub dirty: AtomicBool, pub dirty: AtomicBool,
@ -377,7 +377,7 @@ impl Workspace {
id: None, id: None,
handle, handle,
focus_stack: FocusStacks::default(), focus_stack: FocusStacks::default(),
screencopy: ScreencopySessions::default(), image_copy: ImageCopySessions::default(),
output_stack: { output_stack: {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
queue.push_back(output_match); queue.push_back(output_match);
@ -410,7 +410,7 @@ impl Workspace {
id: pinned.id.clone(), id: pinned.id.clone(),
handle, handle,
focus_stack: FocusStacks::default(), focus_stack: FocusStacks::default(),
screencopy: ScreencopySessions::default(), image_copy: ImageCopySessions::default(),
output_stack: { output_stack: {
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
queue.push_back(pinned.output.clone()); queue.push_back(pinned.output.clone());

View file

@ -13,16 +13,15 @@ use crate::{
shell::{CosmicSurface, SeatExt, Shell, grabs::SeatMoveGrabState}, shell::{CosmicSurface, SeatExt, Shell, grabs::SeatMoveGrabState},
utils::prelude::OutputExt, utils::prelude::OutputExt,
wayland::{ wayland::{
handlers::{data_device::get_dnd_icon, screencopy::SessionHolder}, handlers::{data_device::get_dnd_icon, image_copy_capture::SessionHolder},
protocols::{ protocols::{
a11y::A11yState, a11y::A11yState,
corner_radius::CornerRadiusState, corner_radius::CornerRadiusState,
drm::WlDrmState, drm::WlDrmState,
image_capture_source::ImageCaptureSourceState, image_capture_source::CosmicImageCaptureSourceState,
output_configuration::OutputConfigurationState, output_configuration::OutputConfigurationState,
output_power::OutputPowerState, output_power::OutputPowerState,
overlap_notify::OverlapNotifyState, overlap_notify::OverlapNotifyState,
screencopy::ScreencopyState,
toplevel_info::ToplevelInfoState, toplevel_info::ToplevelInfoState,
toplevel_management::{ManagementCapabilities, ToplevelManagementState}, toplevel_management::{ManagementCapabilities, ToplevelManagementState},
workspace::{WorkspaceState, WorkspaceUpdateGuard}, workspace::{WorkspaceState, WorkspaceUpdateGuard},
@ -80,6 +79,8 @@ use smithay::{
fractional_scale::{FractionalScaleManagerState, with_fractional_scale}, fractional_scale::{FractionalScaleManagerState, with_fractional_scale},
idle_inhibit::IdleInhibitManagerState, idle_inhibit::IdleInhibitManagerState,
idle_notify::IdleNotifierState, idle_notify::IdleNotifierState,
image_capture_source::{OutputCaptureSourceState, ToplevelCaptureSourceState},
image_copy_capture::ImageCopyCaptureState,
input_method::InputMethodManagerState, input_method::InputMethodManagerState,
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
output::OutputManagerState, output::OutputManagerState,
@ -260,8 +261,10 @@ pub struct Common {
pub primary_selection_state: PrimarySelectionState, pub primary_selection_state: PrimarySelectionState,
pub ext_data_control_state: ExtDataControlState, pub ext_data_control_state: ExtDataControlState,
pub wlr_data_control_state: WlrDataControlState, pub wlr_data_control_state: WlrDataControlState,
pub image_capture_source_state: ImageCaptureSourceState, pub cosmic_image_capture_source_state: CosmicImageCaptureSourceState,
pub screencopy_state: ScreencopyState, pub output_capture_source_state: OutputCaptureSourceState,
pub toplevel_capture_source_state: ToplevelCaptureSourceState,
pub image_copy_capture_state: ImageCopyCaptureState,
pub seat_state: SeatState<State>, pub seat_state: SeatState<State>,
pub session_lock_manager_state: SessionLockManagerState, pub session_lock_manager_state: SessionLockManagerState,
pub idle_notifier_state: IdleNotifierState<State>, pub idle_notifier_state: IdleNotifierState<State>,
@ -645,9 +648,14 @@ impl State {
OverlapNotifyState::new::<Self, _>(dh, client_has_no_security_context); OverlapNotifyState::new::<Self, _>(dh, client_has_no_security_context);
let presentation_state = PresentationState::new::<Self>(dh, clock.id() as u32); let presentation_state = PresentationState::new::<Self>(dh, clock.id() as u32);
let primary_selection_state = PrimarySelectionState::new::<Self>(dh); let primary_selection_state = PrimarySelectionState::new::<Self>(dh);
let image_capture_source_state = let cosmic_image_capture_source_state =
ImageCaptureSourceState::new::<Self, _>(dh, client_not_sandboxed); CosmicImageCaptureSourceState::new::<Self, _>(dh, client_not_sandboxed);
let screencopy_state = ScreencopyState::new::<Self, _>(dh, client_not_sandboxed); let output_capture_source_state =
OutputCaptureSourceState::new_with_filter::<State, _>(&dh, client_not_sandboxed);
let toplevel_capture_source_state =
ToplevelCaptureSourceState::new_with_filter::<State, _>(&dh, client_not_sandboxed);
let image_copy_capture_state =
ImageCopyCaptureState::new_with_filter::<Self, _>(dh, client_not_sandboxed);
let shm_state = let shm_state =
ShmState::new::<Self>(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]); ShmState::new::<Self>(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]);
let cursor_shape_manager_state = CursorShapeManagerState::new::<State>(dh); let cursor_shape_manager_state = CursorShapeManagerState::new::<State>(dh);
@ -754,8 +762,10 @@ impl State {
idle_notifier_state, idle_notifier_state,
idle_inhibit_manager_state, idle_inhibit_manager_state,
idle_inhibiting_surfaces, idle_inhibiting_surfaces,
image_capture_source_state, cosmic_image_capture_source_state,
screencopy_state, output_capture_source_state,
toplevel_capture_source_state,
image_copy_capture_state,
shm_state, shm_state,
cursor_shape_manager_state, cursor_shape_manager_state,
seat_state, seat_state,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,10 +1,8 @@
use super::{ use super::{
toplevel_info::window_from_ext_handle,
workspace::{WorkspaceHandle, WorkspaceHandler}, workspace::{WorkspaceHandle, WorkspaceHandler},
}; };
use crate::{ use crate::{
shell::CosmicSurface, shell::CosmicSurface,
wayland::protocols::toplevel_info::ToplevelInfoHandler,
}; };
use cosmic_protocols::image_capture_source::v1::server::{ use cosmic_protocols::image_capture_source::v1::server::{
zcosmic_workspace_image_capture_source_manager_v1::{ 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::{ 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_image_capture_source_v1::ExtImageCaptureSourceV1,
ext_output_image_capture_source_manager_v1::{
Request as OutputSourceRequest, ExtOutputImageCaptureSourceManagerV1,
},
}; };
use smithay::{ use smithay::{
output::{Output, WeakOutput}, output::WeakOutput,
reexports::wayland_server::{ reexports::wayland_server::{
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
}, },
wayland::image_capture_source::{ImageCaptureSource, ImageCaptureSourceData},
}; };
use wayland_backend::server::GlobalId; use wayland_backend::server::GlobalId;
#[derive(Debug)] #[derive(Debug)]
pub struct ImageCaptureSourceState { pub struct CosmicImageCaptureSourceState {
output_source_global: GlobalId,
workspace_source_global: GlobalId, workspace_source_global: GlobalId,
toplevel_source_global: GlobalId,
} }
pub struct OutputImageCaptureSourceManagerGlobalData {
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
}
pub struct WorkspaceImageCaptureSourceManagerGlobalData { pub struct WorkspaceImageCaptureSourceManagerGlobalData {
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>, filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
} }
pub struct ToplevelImageCaptureSourceManagerGlobalData {
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum ImageCaptureSourceData { pub enum ImageCaptureSourceKind {
Output(WeakOutput), Output(WeakOutput),
Workspace(WorkspaceHandle), Workspace(WorkspaceHandle),
Toplevel(CosmicSurface), Toplevel(CosmicSurface),
Destroyed, Destroyed,
} }
impl ImageCaptureSourceState { impl ImageCaptureSourceKind {
pub fn new<D, F>(display: &DisplayHandle, client_filter: F) -> ImageCaptureSourceState pub fn from_resource(resource: &ExtImageCaptureSourceV1) -> Option<Self> {
let source = ImageCaptureSource::from_resource(resource)?;
source.user_data().get::<ImageCaptureSourceKind>().cloned()
}
}
impl CosmicImageCaptureSourceState {
pub fn new<D, F>(display: &DisplayHandle, client_filter: F) -> CosmicImageCaptureSourceState
where where
D: GlobalDispatch< D: GlobalDispatch<
ExtOutputImageCaptureSourceManagerV1,
OutputImageCaptureSourceManagerGlobalData,
> + Dispatch<ExtOutputImageCaptureSourceManagerV1, ()>
+ GlobalDispatch<
ZcosmicWorkspaceImageCaptureSourceManagerV1, ZcosmicWorkspaceImageCaptureSourceManagerV1,
WorkspaceImageCaptureSourceManagerGlobalData, WorkspaceImageCaptureSourceManagerGlobalData,
> + Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, ()> > + Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, ()>
+ GlobalDispatch<
ExtForeignToplevelImageCaptureSourceManagerV1,
ToplevelImageCaptureSourceManagerGlobalData,
> + Dispatch<ExtForeignToplevelImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData> + Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
+ WorkspaceHandler + WorkspaceHandler
+ 'static, + 'static,
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static, F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static,
{ {
ImageCaptureSourceState { CosmicImageCaptureSourceState {
output_source_global: display
.create_global::<D, ExtOutputImageCaptureSourceManagerV1, _>(
1,
OutputImageCaptureSourceManagerGlobalData {
filter: Box::new(client_filter.clone()),
},
),
workspace_source_global: display workspace_source_global: display
.create_global::<D, ZcosmicWorkspaceImageCaptureSourceManagerV1, _>( .create_global::<D, ZcosmicWorkspaceImageCaptureSourceManagerV1, _>(
1, 1,
@ -88,57 +65,12 @@ impl ImageCaptureSourceState {
filter: Box::new(client_filter.clone()), filter: Box::new(client_filter.clone()),
}, },
), ),
toplevel_source_global: display
.create_global::<D, ExtForeignToplevelImageCaptureSourceManagerV1, _>(
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 { pub fn workspace_source_id(&self) -> &GlobalId {
&self.workspace_source_global &self.workspace_source_global
} }
pub fn toplevel_source_id(&self) -> &GlobalId {
&self.toplevel_source_global
}
}
impl<D>
GlobalDispatch<
ExtOutputImageCaptureSourceManagerV1,
OutputImageCaptureSourceManagerGlobalData,
D,
> for ImageCaptureSourceState
where
D: GlobalDispatch<
ExtOutputImageCaptureSourceManagerV1,
OutputImageCaptureSourceManagerGlobalData,
> + Dispatch<ExtOutputImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
+ 'static,
{
fn bind(
_state: &mut D,
_handle: &DisplayHandle,
_client: &Client,
resource: New<ExtOutputImageCaptureSourceManagerV1>,
_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<D> impl<D>
@ -146,7 +78,7 @@ impl<D>
ZcosmicWorkspaceImageCaptureSourceManagerV1, ZcosmicWorkspaceImageCaptureSourceManagerV1,
WorkspaceImageCaptureSourceManagerGlobalData, WorkspaceImageCaptureSourceManagerGlobalData,
D, D,
> for ImageCaptureSourceState > for CosmicImageCaptureSourceState
where where
D: GlobalDispatch< D: GlobalDispatch<
ZcosmicWorkspaceImageCaptureSourceManagerV1, ZcosmicWorkspaceImageCaptureSourceManagerV1,
@ -174,70 +106,8 @@ where
} }
} }
impl<D> impl<D> Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, (), D>
GlobalDispatch< for CosmicImageCaptureSourceState
ExtForeignToplevelImageCaptureSourceManagerV1,
ToplevelImageCaptureSourceManagerGlobalData,
D,
> for ImageCaptureSourceState
where
D: GlobalDispatch<
ExtForeignToplevelImageCaptureSourceManagerV1,
ToplevelImageCaptureSourceManagerGlobalData,
> + Dispatch<ExtForeignToplevelImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
+ 'static,
{
fn bind(
_state: &mut D,
_handle: &DisplayHandle,
_client: &Client,
resource: New<ExtForeignToplevelImageCaptureSourceManagerV1>,
_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<D> Dispatch<ExtOutputImageCaptureSourceManagerV1, (), D> for ImageCaptureSourceState
where
D: Dispatch<ExtOutputImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
+ 'static,
{
fn request(
_state: &mut D,
_client: &Client,
_resource: &ExtOutputImageCaptureSourceManagerV1,
request: <ExtOutputImageCaptureSourceManagerV1 as Resource>::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<D> Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, (), D> for ImageCaptureSourceState
where where
D: Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, ()> D: Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData> + Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
@ -253,110 +123,36 @@ where
_dhandle: &DisplayHandle, _dhandle: &DisplayHandle,
data_init: &mut DataInit<'_, D>, data_init: &mut DataInit<'_, D>,
) { ) {
if let CosmicWorkspaceSourceRequest::CreateSource { source, output } = request { if let CosmicWorkspaceSourceRequest::CreateSource {
let data = match state.workspace_state().get_ext_workspace_handle(&output) { source: source_handle,
Some(workspace) => ImageCaptureSourceData::Workspace(workspace), output,
None => ImageCaptureSourceData::Destroyed,
};
data_init.init(source, data);
}
}
fn destroyed(
_state: &mut D,
_client: wayland_backend::server::ClientId,
_resource: &ZcosmicWorkspaceImageCaptureSourceManagerV1,
_data: &(),
) {
}
}
impl<D> Dispatch<ExtForeignToplevelImageCaptureSourceManagerV1, (), D> for ImageCaptureSourceState
where
D: Dispatch<ExtForeignToplevelImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
+ ToplevelInfoHandler<Window = CosmicSurface>
+ 'static,
{
fn request(
state: &mut D,
_client: &Client,
_resource: &ExtForeignToplevelImageCaptureSourceManagerV1,
request: <ExtForeignToplevelImageCaptureSourceManagerV1 as Resource>::Request,
_data: &(),
_dhandle: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
if let ToplevelSourceRequest::CreateSource {
source,
toplevel_handle,
} = request } = request
{ {
let data = match window_from_ext_handle(state, &toplevel_handle) { let data = match state.workspace_state().get_ext_workspace_handle(&output) {
Some(toplevel) => ImageCaptureSourceData::Toplevel(toplevel.clone()), Some(workspace) => ImageCaptureSourceKind::Workspace(workspace),
None => ImageCaptureSourceData::Destroyed, 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<D> Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData, D> for ImageCaptureSourceState macro_rules! delegate_cosmic_image_capture_source {
where
D: Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData> + 'static,
{
fn request(
_state: &mut D,
_client: &Client,
_resource: &ExtImageCaptureSourceV1,
_request: <ExtImageCaptureSourceV1 as Resource>::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 {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { ($(@<$( $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: [ 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 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: [ 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: () cosmic_protocols::image_capture_source::v1::server::zcosmic_workspace_image_capture_source_manager_v1::ZcosmicWorkspaceImageCaptureSourceManagerV1: ()
] => $crate::wayland::protocols::image_capture_source::ImageCaptureSourceState); ] => $crate::wayland::protocols::image_capture_source::CosmicImageCaptureSourceState);
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);
}; };
} }
pub(crate) use delegate_image_capture_source; pub(crate) use delegate_cosmic_image_capture_source;

View file

@ -7,7 +7,6 @@ pub mod image_capture_source;
pub mod output_configuration; pub mod output_configuration;
pub mod output_power; pub mod output_power;
pub mod overlap_notify; pub mod overlap_notify;
pub mod screencopy;
pub mod toplevel_info; pub mod toplevel_info;
pub mod toplevel_management; pub mod toplevel_management;
pub mod workspace; pub mod workspace;

File diff suppressed because it is too large Load diff

View file

@ -635,14 +635,13 @@ pub fn window_from_handle<W: Window + 'static>(handle: ZcosmicToplevelHandleV1)
.and_then(|state| state.lock().unwrap().window.clone()) .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, state: &'a D,
foreign_toplevel: &ExtForeignToplevelHandleV1, handle: &ForeignToplevelHandle,
) -> Option<&'a W> ) -> Option<&'a W>
where where
D: ToplevelInfoHandler<Window = W>, D: ToplevelInfoHandler<Window = W>,
{ {
let handle = ForeignToplevelHandle::from_resource(foreign_toplevel)?;
state.toplevel_info_state().toplevels.iter().find(|w| { state.toplevel_info_state().toplevels.iter().find(|w| {
w.user_data().get::<ToplevelState>().and_then(|inner| { w.user_data().get::<ToplevelState>().and_then(|inner| {
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<Window = W>,
{
let handle = ForeignToplevelHandle::from_resource(foreign_toplevel)?;
window_from_ext(state, &handle)
}
macro_rules! delegate_toplevel_info { macro_rules! delegate_toplevel_info {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, $window: ty) => { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, $window: ty) => {
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [