Merge branch 'master' into fullscreen_panic_fix

This commit is contained in:
Levi Portenier 2026-02-13 13:42:17 -07:00 committed by GitHub
commit 00bf8fe215
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 632 additions and 1790 deletions

View file

@ -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};
@ -95,6 +95,7 @@ pub struct Device {
pub drm: GbmDrmOutputManager,
supports_atomic: bool,
pub texture_formats: FormatSet,
event_token: Option<RegistrationToken>,
pub socket: Option<Socket>,
}
@ -285,7 +286,7 @@ impl State {
.with_context(|| format!("Failed to add drm device to event loop: {}", dev))?;
let socket = match (!is_software)
.then(|| self.create_socket(dh, render_node, texture_formats))
.then(|| self.create_socket(dh, render_node, texture_formats.clone()))
.transpose()
{
Ok(socket) => socket,
@ -349,6 +350,7 @@ impl State {
},
supports_atomic,
texture_formats,
event_token: Some(token),
socket,
};

View file

@ -14,7 +14,7 @@ use indexmap::IndexMap;
use render::gles::GbmGlowBackend;
use smithay::{
backend::{
allocator::{dmabuf::Dmabuf, format::FormatSet},
allocator::{Buffer, dmabuf::Dmabuf, format::FormatSet},
drm::{DrmDeviceFd, DrmNode, NodeType, VrrSupport, output::DrmOutputRenderElements},
egl::{EGLContext, EGLDevice, EGLDisplay},
input::InputEvent,
@ -491,7 +491,7 @@ impl KmsState {
global: &DmabufGlobal,
dmabuf: Dmabuf,
) -> Result<DrmNode> {
let device = self
let mut device = self
.drm_devices
.values_mut()
.find(|device| {
@ -503,6 +503,21 @@ impl KmsState {
})
.context("Couldn't find gpu for dmabuf global")?;
// If device advertised to client doesn't support format/modifier, select
// first device that does. This is needed for image-copy from
// output/toplevel on a different node.
//
// TODO: After
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/268,
// only try the device specified explicitly by the client, if set.
if !device.texture_formats.contains(&dmabuf.format()) {
device = self
.drm_devices
.values_mut()
.find(|device| device.texture_formats.contains(&dmabuf.format()))
.context("Dmabuf cannot be imported on any gpu")?;
}
let new_client = if let Some(client) = client {
let new = device.inner.active_clients.insert(client.id());
device.inner.update_egl(

View file

@ -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},
@ -1082,7 +1080,7 @@ impl SurfaceThreadState {
let frames = self
.mirroring
.is_none()
.then(|| take_screencopy_frames(&self.output, &mut elements, &mut has_cursor_mode_none))
.then(|| take_screencopy_frames(&self.output, &elements, &mut has_cursor_mode_none))
.unwrap_or_default();
// actual rendering
@ -1355,13 +1353,6 @@ impl SurfaceThreadState {
(&session, frame, res),
now.into(),
) {
session
.user_data()
.get::<SessionData>()
.unwrap()
.lock()
.unwrap()
.reset();
tracing::warn!(?err, "Failed to screencopy");
}
}
@ -1390,15 +1381,8 @@ impl SurfaceThreadState {
}
}
Err(err) => {
for (session, frame, _) in frames {
session
.user_data()
.get::<SessionData>()
.unwrap()
.lock()
.unwrap()
.reset();
frame.fail(FailureReason::Unknown);
for (_session, frame, _) in frames {
frame.fail(CaptureFailureReason::Unknown);
}
return Err(err).with_context(|| "Failed to submit result for display");
}
@ -1608,10 +1592,9 @@ fn get_surface_dmabuf_feedback(
}
}
// TODO: Don't mutate `elements`
fn take_screencopy_frames(
output: &Output,
elements: &mut Vec<CosmicElement<GlMultiRenderer>>,
elements: &[CosmicElement<GlMultiRenderer>],
has_cursor_mode_none: &mut bool,
) -> Vec<(
ScreencopySessionRef,
@ -1626,7 +1609,15 @@ fn take_screencopy_frames(
let session_data = session.user_data().get::<SessionData>().unwrap();
let mut damage_tracking = session_data.lock().unwrap();
let old_len = if !additional_damage.is_empty() {
let buffer = frame.buffer();
let age = if matches!(buffer_type(&buffer), Some(BufferType::Shm)) {
// TODO re-use offscreen buffer to damage track screencopy to shm
0
} else {
1
};
if !additional_damage.is_empty() {
let area = output
.current_mode()
.unwrap()
@ -1636,41 +1627,26 @@ fn take_screencopy_frames(
.to_buffer(1, Transform::Normal)
.to_f64();
let old_len = elements.len();
elements.extend(
additional_damage
.into_iter()
.map(|rect| {
rect.to_f64()
.to_logical(
output.current_scale().fractional_scale(),
output.current_transform(),
&area,
)
.to_i32_round()
})
.map(DamageElement::new)
.map(Into::into),
);
Some(old_len)
} else {
None
let additional_damage_elements: Vec<_> = additional_damage
.into_iter()
.map(|rect| {
rect.to_f64()
.to_logical(
output.current_scale().fractional_scale(),
output.current_transform(),
&area,
)
.to_i32_round()
})
.map(DamageElement::new)
.collect();
let _ = damage_tracking
.dt
.damage_output(age, &additional_damage_elements);
};
let buffer = frame.buffer();
let age = if matches!(buffer_type(&frame.buffer()), Some(BufferType::Shm)) {
// TODO re-use offscreen buffer to damage track screencopy to shm
0
} else {
damage_tracking.age_for_buffer(&buffer)
};
let res = damage_tracking.dt.damage_output(age, elements);
if let Some(old_len) = old_len {
elements.truncate(old_len);
}
if !session.draw_cursor() {
*has_cursor_mode_none = true;
}

View file

@ -32,7 +32,6 @@ where
Cursor(RescaleRenderElement<RelocateRenderElement<CursorRenderElement<R>>>),
Dnd(WaylandSurfaceRenderElement<R>),
MoveGrab(RescaleRenderElement<CosmicMappedRenderElement<R>>),
AdditionalDamage(DamageElement),
Postprocess(
CropRenderElement<RelocateRenderElement<RescaleRenderElement<TextureShaderElement>>>,
),
@ -53,7 +52,6 @@ where
CosmicElement::Cursor(elem) => elem.id(),
CosmicElement::Dnd(elem) => elem.id(),
CosmicElement::MoveGrab(elem) => elem.id(),
CosmicElement::AdditionalDamage(elem) => elem.id(),
CosmicElement::Postprocess(elem) => elem.id(),
CosmicElement::Zoom(elem) => elem.id(),
#[cfg(feature = "debug")]
@ -67,7 +65,6 @@ where
CosmicElement::Cursor(elem) => elem.current_commit(),
CosmicElement::Dnd(elem) => elem.current_commit(),
CosmicElement::MoveGrab(elem) => elem.current_commit(),
CosmicElement::AdditionalDamage(elem) => elem.current_commit(),
CosmicElement::Postprocess(elem) => elem.current_commit(),
CosmicElement::Zoom(elem) => elem.current_commit(),
#[cfg(feature = "debug")]
@ -81,7 +78,6 @@ where
CosmicElement::Cursor(elem) => elem.src(),
CosmicElement::Dnd(elem) => elem.src(),
CosmicElement::MoveGrab(elem) => elem.src(),
CosmicElement::AdditionalDamage(elem) => elem.src(),
CosmicElement::Postprocess(elem) => elem.src(),
CosmicElement::Zoom(elem) => elem.src(),
#[cfg(feature = "debug")]
@ -95,7 +91,6 @@ where
CosmicElement::Cursor(elem) => elem.geometry(scale),
CosmicElement::Dnd(elem) => elem.geometry(scale),
CosmicElement::MoveGrab(elem) => elem.geometry(scale),
CosmicElement::AdditionalDamage(elem) => elem.geometry(scale),
CosmicElement::Postprocess(elem) => elem.geometry(scale),
CosmicElement::Zoom(elem) => elem.geometry(scale),
#[cfg(feature = "debug")]
@ -109,7 +104,6 @@ where
CosmicElement::Cursor(elem) => elem.location(scale),
CosmicElement::Dnd(elem) => elem.location(scale),
CosmicElement::MoveGrab(elem) => elem.location(scale),
CosmicElement::AdditionalDamage(elem) => elem.location(scale),
CosmicElement::Postprocess(elem) => elem.location(scale),
CosmicElement::Zoom(elem) => elem.location(scale),
#[cfg(feature = "debug")]
@ -123,7 +117,6 @@ where
CosmicElement::Cursor(elem) => elem.transform(),
CosmicElement::Dnd(elem) => elem.transform(),
CosmicElement::MoveGrab(elem) => elem.transform(),
CosmicElement::AdditionalDamage(elem) => elem.transform(),
CosmicElement::Postprocess(elem) => elem.transform(),
CosmicElement::Zoom(elem) => elem.transform(),
#[cfg(feature = "debug")]
@ -141,7 +134,6 @@ where
CosmicElement::Cursor(elem) => elem.damage_since(scale, commit),
CosmicElement::Dnd(elem) => elem.damage_since(scale, commit),
CosmicElement::MoveGrab(elem) => elem.damage_since(scale, commit),
CosmicElement::AdditionalDamage(elem) => elem.damage_since(scale, commit),
CosmicElement::Postprocess(elem) => elem.damage_since(scale, commit),
CosmicElement::Zoom(elem) => elem.damage_since(scale, commit),
#[cfg(feature = "debug")]
@ -155,7 +147,6 @@ where
CosmicElement::Cursor(elem) => elem.opaque_regions(scale),
CosmicElement::Dnd(elem) => elem.opaque_regions(scale),
CosmicElement::MoveGrab(elem) => elem.opaque_regions(scale),
CosmicElement::AdditionalDamage(elem) => elem.opaque_regions(scale),
CosmicElement::Postprocess(elem) => elem.opaque_regions(scale),
CosmicElement::Zoom(elem) => elem.opaque_regions(scale),
#[cfg(feature = "debug")]
@ -169,7 +160,6 @@ where
CosmicElement::Cursor(elem) => elem.alpha(),
CosmicElement::Dnd(elem) => elem.alpha(),
CosmicElement::MoveGrab(elem) => elem.alpha(),
CosmicElement::AdditionalDamage(elem) => elem.alpha(),
CosmicElement::Postprocess(elem) => elem.alpha(),
CosmicElement::Zoom(elem) => elem.alpha(),
#[cfg(feature = "debug")]
@ -183,7 +173,6 @@ where
CosmicElement::Cursor(elem) => elem.kind(),
CosmicElement::Dnd(elem) => elem.kind(),
CosmicElement::MoveGrab(elem) => elem.kind(),
CosmicElement::AdditionalDamage(elem) => elem.kind(),
CosmicElement::Postprocess(elem) => elem.kind(),
CosmicElement::Zoom(elem) => elem.kind(),
#[cfg(feature = "debug")]
@ -212,9 +201,6 @@ where
CosmicElement::Cursor(elem) => elem.draw(frame, src, dst, damage, opaque_regions),
CosmicElement::Dnd(elem) => elem.draw(frame, src, dst, damage, opaque_regions),
CosmicElement::MoveGrab(elem) => elem.draw(frame, src, dst, damage, opaque_regions),
CosmicElement::AdditionalDamage(elem) => {
RenderElement::<R>::draw(elem, frame, src, dst, damage, opaque_regions)
}
CosmicElement::Postprocess(elem) => {
let glow_frame = R::glow_frame_mut(frame);
RenderElement::<GlowRenderer>::draw(
@ -250,7 +236,6 @@ where
CosmicElement::Cursor(elem) => elem.underlying_storage(renderer),
CosmicElement::Dnd(elem) => elem.underlying_storage(renderer),
CosmicElement::MoveGrab(elem) => elem.underlying_storage(renderer),
CosmicElement::AdditionalDamage(elem) => elem.underlying_storage(renderer),
CosmicElement::Postprocess(elem) => {
let glow_renderer = renderer.glow_renderer_mut();
elem.underlying_storage(glow_renderer)
@ -281,17 +266,6 @@ where
}
}
impl<R> From<DamageElement> for CosmicElement<R>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
R::TextureId: 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
fn from(elem: DamageElement) -> Self {
Self::AdditionalDamage(elem)
}
}
impl<R> From<MemoryRenderBufferRenderElement<R>> for CosmicElement<R>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,

View file

@ -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,
},
@ -1393,21 +1393,20 @@ where
)?;
let old_len = elements.len();
elements.extend(
additional_damage
.into_iter()
.map(|rect| {
rect.to_f64()
.to_logical(
output.current_scale().fractional_scale(),
output.current_transform(),
&area,
)
.to_i32_round()
})
.map(DamageElement::new)
.map(Into::into),
);
let additional_damage_elements: Vec<_> = additional_damage
.into_iter()
.map(|rect| {
rect.to_f64()
.to_logical(
output.current_scale().fractional_scale(),
output.current_transform(),
&area,
)
.to_i32_round()
})
.map(DamageElement::new)
.collect();
dt.damage_output(age, &additional_damage_elements)?;
Some(old_len)
} else {
@ -1513,7 +1512,7 @@ where
CosmicMappedRenderElement<R>: RenderElement<R>,
WorkspaceRenderElement<R>: RenderElement<R>,
{
let mut elements: Vec<CosmicElement<R>> = workspace_elements(
let elements: Vec<CosmicElement<R>> = workspace_elements(
gpu,
renderer,
shell,
@ -1528,13 +1527,12 @@ where
if let Some(additional_damage) = additional_damage {
let output_geo = output.geometry().to_local(output).as_logical();
elements.extend(
additional_damage
.into_iter()
.filter_map(|rect| rect.intersection(output_geo))
.map(DamageElement::new)
.map(Into::<CosmicElement<R>>::into),
);
let additional_damage_elements: Vec<_> = additional_damage
.into_iter()
.filter_map(|rect| rect.intersection(output_geo))
.map(DamageElement::new)
.collect();
damage_tracker.damage_output(age, &additional_damage_elements)?;
}
let res = damage_tracker.render_output(

View file

@ -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,

View file

@ -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::{

View file

@ -906,20 +906,22 @@ impl Drop for MoveGrab {
}
}
} else {
let mut shell = state.common.shell.write();
shell
.workspaces
.active_mut(&cursor_output)
.unwrap()
.tiling_layer
.cleanup_drag();
shell.set_overview_mode(None, state.common.event_loop_handle.clone());
None
}
} else {
None
};
let mut shell = state.common.shell.write();
shell
.workspaces
.active_mut(&cursor_output)
.unwrap()
.tiling_layer
.cleanup_drag();
shell.set_overview_mode(None, state.common.event_loop_handle.clone());
drop(shell);
{
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
cursor_state.lock().unwrap().unset_shape();

View file

@ -1384,6 +1384,13 @@ impl TilingLayout {
) -> Option<NodeId> {
let node_id = window.tiling_node_id.lock().unwrap().take()?;
// Initialize last_overview_hover to the placeholder position so that
// dropping without mouse movement restores the window to its original position
if matches!(type_, PlaceholderType::GrabbedWindow) {
self.last_overview_hover =
Some((None, TargetZone::InitialPlaceholder(node_id.clone())));
}
let data = self
.queue
.trees
@ -2630,28 +2637,36 @@ impl TilingLayout {
}
pub fn cleanup_drag(&mut self) {
let gaps = self.gaps();
let old_tree = &self.queue.trees.back().unwrap().0;
let mut new_tree = None;
let mut tree = self.queue.trees.back().unwrap().0.copy_clone();
if let Some(root) = tree.root_node_id() {
for id in tree
.traverse_pre_order_ids(root)
.unwrap()
.collect::<Vec<_>>()
.into_iter()
{
match tree.get_mut(&id).map(|node| node.data_mut()) {
Ok(Data::Placeholder { .. }) => TilingLayout::unmap_internal(&mut tree, &id),
if let Some(root) = old_tree.root_node_id() {
for id in old_tree.traverse_pre_order_ids(root).unwrap() {
match old_tree.get(&id).map(|node| node.data()) {
Ok(Data::Placeholder { .. }) => {
// Copy a tree on write
let new_tree = new_tree.get_or_insert_with(|| old_tree.copy_clone());
TilingLayout::unmap_internal(new_tree, &id)
}
Ok(Data::Group { pill_indicator, .. }) if pill_indicator.is_some() => {
pill_indicator.take();
let new_tree = new_tree.get_or_insert_with(|| old_tree.copy_clone());
match new_tree.get_mut(&id).unwrap().data_mut() {
Data::Group { pill_indicator, .. } => {
*pill_indicator = None;
}
_ => unreachable!(),
}
}
_ => {}
}
}
let blocker = TilingLayout::update_positions(&self.output, &mut tree, gaps);
self.queue.push_tree(tree, ANIMATION_DURATION, blocker);
// If anything was changed, push updated tree
if let Some(mut new_tree) = new_tree {
let blocker =
TilingLayout::update_positions(&self.output, &mut new_tree, self.gaps());
self.queue.push_tree(new_tree, ANIMATION_DURATION, blocker);
}
}
}
@ -2666,7 +2681,7 @@ impl TilingLayout {
window.set_bounds(layer_map.non_exclusive_zone().size);
}
let mapped = match self.last_overview_hover.as_ref().map(|x| &x.1) {
let mapped = match self.last_overview_hover.as_ref().map(|(_, zone)| zone) {
Some(TargetZone::GroupEdge(group_id, direction)) if tree.get(group_id).is_ok() => {
let new_id = tree
.insert(
@ -4039,7 +4054,7 @@ impl TilingLayout {
let is_overview = !matches!(overview.0, OverviewMode::None);
let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_))))
.then(|| self.last_overview_hover.as_ref().map(|x| &x.1));
.then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone));
let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() {
Some(desc.clone())
} else {
@ -4190,7 +4205,7 @@ impl TilingLayout {
let mut elements = Vec::default();
let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_))))
.then(|| self.last_overview_hover.as_ref().map(|x| &x.1));
.then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone));
let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() {
Some(desc.clone())
} else {
@ -5563,11 +5578,18 @@ where
let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale);
let scale = geo.size.to_f64() / original_geo.size.to_f64();
// In overview mode, don't pass max_size to avoid pre-clipping.
// Let constrain_render_elements handle scaling instead.
let max_size = if is_overview {
None
} else {
Some(geo.size.as_logical())
};
let shadow_element = mapped.shadow_render_element(
renderer,
geo.loc.as_logical().to_physical_precise_round(output_scale)
- elem_geometry.loc,
Some(geo.size.as_logical()),
max_size,
Scale::from(output_scale),
scale.x.min(scale.y),
alpha,
@ -5577,7 +5599,7 @@ where
//original_location,
geo.loc.as_logical().to_physical_precise_round(output_scale)
- elem_geometry.loc,
Some(geo.size.as_logical()),
max_size,
Scale::from(output_scale),
alpha,
None,

View file

@ -3135,8 +3135,8 @@ impl Shell {
toplevel_enter_workspace(window, to);
// we can't restore to a given position
if let WorkspaceRestoreData::Tiling(state) = &mut window_state {
state.take();
if let WorkspaceRestoreData::Tiling(Some(state)) = &mut window_state {
state.state.take();
}
// update fullscreen state to restore to the new workspace
if let WorkspaceRestoreData::Fullscreen(Some(FullscreenRestoreData {

View file

@ -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<OutputMatch>,
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());

View file

@ -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},
@ -77,9 +76,12 @@ use smithay::{
compositor::{CompositorClientState, CompositorState, SurfaceData},
cursor_shape::CursorShapeManagerState,
dmabuf::{DmabufFeedback, DmabufGlobal, DmabufState},
fixes::FixesState,
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 +262,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<State>,
pub session_lock_manager_state: SessionLockManagerState,
pub idle_notifier_state: IdleNotifierState<State>,
@ -645,9 +649,14 @@ impl State {
OverlapNotifyState::new::<Self, _>(dh, client_has_no_security_context);
let presentation_state = PresentationState::new::<Self>(dh, clock.id() as u32);
let primary_selection_state = PrimarySelectionState::new::<Self>(dh);
let image_capture_source_state =
ImageCaptureSourceState::new::<Self, _>(dh, client_not_sandboxed);
let screencopy_state = ScreencopyState::new::<Self, _>(dh, client_not_sandboxed);
let cosmic_image_capture_source_state =
CosmicImageCaptureSourceState::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 =
ShmState::new::<Self>(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]);
let cursor_shape_manager_state = CursorShapeManagerState::new::<State>(dh);
@ -669,6 +678,7 @@ impl State {
VirtualKeyboardManagerState::new::<State, _>(dh, client_not_sandboxed);
AlphaModifierState::new::<Self>(dh);
SinglePixelBufferState::new::<Self>(dh);
FixesState::new::<Self>(&dh);
let idle_notifier_state = IdleNotifierState::<Self>::new(dh, handle.clone());
let idle_inhibit_manager_state = IdleInhibitManagerState::new::<State>(dh);
@ -754,8 +764,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,

View file

@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::state::State;
use smithay::delegate_fixes;
delegate_fixes!(State);

View file

@ -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);

View file

@ -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<BufferConstraints> {
match source {
ImageCaptureSourceData::Output(weak) => weak
fn capture_constraints(&mut self, source: &ImageCaptureSource) -> Option<BufferConstraints> {
let kind = source.user_data().get::<ImageCaptureSourceKind>().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<BufferConstraints> {
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::<ImageCaptureSourceKind>()
.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::<ImageCaptureSourceKind>()
.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::<ImageCaptureSourceKind>()
.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::<ImageCaptureSourceKind>()
.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::<ImageCaptureSourceKind>()
.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);

View file

@ -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);
}
}
@ -223,7 +225,7 @@ where
// TODO re-use offscreen buffer to damage track screencopy to shm
0
} else {
session_damage_tracking.age_for_buffer(&buffer)
1
};
let mut fb = offscreen
.as_mut()
@ -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::<SessionData>() {
*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;
}
};
@ -490,17 +492,16 @@ smithay::render_elements! {
pub WindowCaptureElement<R> where R: ImportAll + ImportMem;
WaylandElement=WaylandSurfaceRenderElement<R>,
CursorElement=RelocateRenderElement<cursor::CursorRenderElement<R>>,
AdditionalDamage=DamageElement,
}
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 +510,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 +519,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;
}
@ -541,22 +542,19 @@ pub fn render_window_to_buffer(
CosmicElement<R>: RenderElement<R>,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
let mut elements = Vec::new();
elements.extend(
additional_damage
.into_iter()
.filter_map(|rect| {
let logical_rect = rect.to_logical(
1,
Transform::Normal,
&geometry.size.to_buffer(1, Transform::Normal),
);
logical_rect.intersection(Rectangle::from_size(geometry.size))
})
.map(DamageElement::new)
.map(Into::<WindowCaptureElement<R>>::into),
);
let additional_damage_elements: Vec<_> = additional_damage
.into_iter()
.filter_map(|rect| {
let logical_rect = rect.to_logical(
1,
Transform::Normal,
&geometry.size.to_buffer(1, Transform::Normal),
);
logical_rect.intersection(Rectangle::from_size(geometry.size))
})
.map(DamageElement::new)
.collect();
dt.damage_output(age, &additional_damage_elements)?;
let shell = common.shell.read();
let seat = shell.seats.last_active().clone();
@ -579,6 +577,8 @@ pub fn render_window_to_buffer(
};
std::mem::drop(shell);
let mut elements = Vec::new();
if let Some(location) = location {
if draw_cursor {
elements.extend(
@ -666,7 +666,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 +760,7 @@ pub fn render_cursor_to_buffer(
Transform::Normal,
));
}
frame.fail(FailureReason::BufferConstraints);
frame.fail(CaptureFailureReason::BufferConstraints);
return;
}
@ -781,7 +781,17 @@ pub fn render_cursor_to_buffer(
CosmicElement<R>: RenderElement<R>,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
let mut elements = cursor::draw_cursor(
let additional_damage_elements: Vec<_> = additional_damage
.into_iter()
.filter_map(|rect| {
let logical_rect = rect.to_logical(1, Transform::Normal, &Size::from((64, 64)));
logical_rect.intersection(Rectangle::from_size((64, 64).into()))
})
.map(DamageElement::new)
.collect();
dt.damage_output(age, &additional_damage_elements)?;
let elements = cursor::draw_cursor(
renderer,
seat,
Point::from((0.0, 0.0)),
@ -795,17 +805,6 @@ pub fn render_cursor_to_buffer(
.map(WindowCaptureElement::from)
.collect::<Vec<_>>();
elements.extend(
additional_damage
.into_iter()
.filter_map(|rect| {
let logical_rect = rect.to_logical(1, Transform::Normal, &Size::from((64, 64)));
logical_rect.intersection(Rectangle::from_size((64, 64).into()))
})
.map(DamageElement::new)
.map(Into::<WindowCaptureElement<R>>::into),
);
if let Ok(dmabuf) = get_dmabuf(buffer) {
let mut dmabuf_clone = dmabuf.clone();
let mut fb = renderer
@ -826,7 +825,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;
}
};

View file

@ -1,60 +1,34 @@
use std::{cell::RefCell, collections::HashMap, sync::Mutex};
// SPDX-License-Identifier: GPL-3.0-only
use std::{cell::RefCell, sync::Mutex};
use smithay::{
backend::renderer::{damage::OutputDamageTracker, utils::CommitCounter},
backend::renderer::damage::OutputDamageTracker,
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<ScreencopySessions>;
type PendingScreencopyBuffers = Mutex<Vec<(SessionRef, Frame)>>;
use crate::shell::{CosmicSurface, Workspace};
type ImageCopySessionsData = RefCell<ImageCopySessions>;
type PendingImageCopyBuffers = Mutex<Vec<(SessionRef, Frame)>>;
pub type SessionData = Mutex<SessionUserData>;
pub struct SessionUserData {
pub dt: OutputDamageTracker,
commit_counter: CommitCounter,
buffer_age: HashMap<Weak<WlBuffer>, CommitCounter>,
}
impl SessionUserData {
pub fn new(tracker: OutputDamageTracker) -> SessionUserData {
SessionUserData {
dt: tracker,
commit_counter: CommitCounter::default(),
buffer_age: HashMap::new(),
}
}
pub fn age_for_buffer(&mut self, buffer: &WlBuffer) -> usize {
self.buffer_age.retain(|k, _| k.upgrade().is_ok());
let weak = buffer.downgrade();
let age = self
.commit_counter
.distance(self.buffer_age.get(&weak).copied())
.unwrap_or(0);
self.buffer_age.insert(weak, self.commit_counter);
self.commit_counter.increment();
age
}
pub fn reset(&mut self) {
self.commit_counter = CommitCounter::default();
self.buffer_age.clear();
SessionUserData { dt: tracker }
}
}
#[derive(Debug, Default)]
pub struct ScreencopySessions {
pub struct ImageCopySessions {
sessions: Vec<Session>,
cursor_sessions: Vec<CursorSession>,
}
@ -78,9 +52,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::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -89,7 +63,7 @@ impl SessionHolder for Output {
fn remove_session(&mut self, session: &SessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -98,7 +72,7 @@ impl SessionHolder for Output {
fn sessions(&self) -> Vec<SessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()
@ -111,9 +85,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::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -122,7 +96,7 @@ impl SessionHolder for Output {
fn remove_cursor_session(&mut self, session: &CursorSessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -131,7 +105,7 @@ impl SessionHolder for Output {
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()
@ -146,22 +120,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::<PendingScreencopyBuffers>()
.get::<PendingImageCopyBuffers>()
.unwrap()
.lock()
.unwrap()
.push((session, frame));
}
fn remove_frame(&mut self, frame: &FrameRef) {
if let Some(pending) = self.user_data().get::<PendingScreencopyBuffers>() {
if let Some(pending) = self.user_data().get::<PendingImageCopyBuffers>() {
pending.lock().unwrap().retain(|(_, f)| f != frame);
}
}
fn take_pending_frames(&self) -> Vec<(SessionRef, Frame)> {
self.user_data()
.get::<PendingScreencopyBuffers>()
.get::<PendingImageCopyBuffers>()
.map(|pending| std::mem::take(&mut *pending.lock().unwrap()))
.unwrap_or_default()
}
@ -169,14 +143,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<SessionRef> {
self.screencopy
self.image_copy
.sessions
.iter()
.map(|s| (*s).clone())
@ -184,14 +158,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<CursorSessionRef> {
self.screencopy
self.image_copy
.cursor_sessions
.iter()
.map(|s| (*s).clone())
@ -202,9 +176,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::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -213,7 +187,7 @@ impl SessionHolder for CosmicSurface {
fn remove_session(&mut self, session: &SessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.sessions
@ -221,7 +195,7 @@ impl SessionHolder for CosmicSurface {
}
fn sessions(&self) -> Vec<SessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()
@ -234,9 +208,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::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -245,7 +219,7 @@ impl SessionHolder for CosmicSurface {
fn remove_cursor_session(&mut self, session: &CursorSessionRef) {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.unwrap()
.borrow_mut()
.cursor_sessions
@ -254,7 +228,7 @@ impl SessionHolder for CosmicSurface {
fn cursor_sessions(&self) -> Vec<CursorSessionRef> {
self.user_data()
.get::<ScreencopySessionsData>()
.get::<ImageCopySessionsData>()
.map_or(Vec::new(), |sessions| {
sessions
.borrow()

View file

@ -12,11 +12,13 @@ pub mod dmabuf;
pub mod drm;
pub mod drm_lease;
pub mod drm_syncobj;
pub mod fixes;
pub mod foreign_toplevel_list;
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 +31,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;

View file

@ -110,7 +110,10 @@ impl ToplevelManagementHandler for State {
std::mem::drop(shell);
if seat.active_output() != *output {
// move pointer to window if its on a different monitor/output
if seat.active_output() != *output
&& self.common.config.cosmic_conf.cursor_follows_focus
{
if let Some(new_pos) = new_pos {
seat.set_active_output(output);
if let Some(ptr) = seat.get_pointer() {

View file

@ -1,6 +1,35 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::state::State;
use smithay::delegate_virtual_keyboard_manager;
use smithay::{
backend::input::KeyState,
delegate_virtual_keyboard_manager,
input::keyboard::{FilterResult, KeyboardHandle, Keycode, xkb::ModMask},
utils::SERIAL_COUNTER,
wayland::virtual_keyboard::VirtualKeyboardHandler,
};
impl VirtualKeyboardHandler for State {
fn on_keyboard_event(
&mut self,
keycode: Keycode,
state: KeyState,
time: u32,
keyboard: KeyboardHandle<Self>,
) {
let serial = SERIAL_COUNTER.next_serial();
keyboard.input(self, keycode, state, serial, time, |_, _, _| {
FilterResult::Forward::<bool>
});
}
fn on_keyboard_modifiers(
&mut self,
_depressed_mods: ModMask,
_latched_mods: ModMask,
_locked_mods: ModMask,
_keyboard: KeyboardHandle<Self>,
) {
}
}
delegate_virtual_keyboard_manager!(State);

View file

@ -172,12 +172,6 @@ impl XdgShellHandler for State {
self.common.shell.read().unconstrain_popup(&surface);
surface.send_repositioned(token);
if let Err(err) = surface.send_configure() {
warn!(
?err,
"Client bug: Unable to re-configure repositioned popup.",
);
}
}
fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) {

View file

@ -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<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
}
pub struct WorkspaceImageCaptureSourceManagerGlobalData {
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)]
pub enum ImageCaptureSourceData {
pub enum ImageCaptureSourceKind {
Output(WeakOutput),
Workspace(WorkspaceHandle),
Toplevel(CosmicSurface),
Destroyed,
}
impl ImageCaptureSourceState {
pub fn new<D, F>(display: &DisplayHandle, client_filter: F) -> ImageCaptureSourceState
impl ImageCaptureSourceKind {
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
D: GlobalDispatch<
ExtOutputImageCaptureSourceManagerV1,
OutputImageCaptureSourceManagerGlobalData,
> + Dispatch<ExtOutputImageCaptureSourceManagerV1, ()>
+ GlobalDispatch<
ZcosmicWorkspaceImageCaptureSourceManagerV1,
WorkspaceImageCaptureSourceManagerGlobalData,
> + Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, ()>
+ GlobalDispatch<
ExtForeignToplevelImageCaptureSourceManagerV1,
ToplevelImageCaptureSourceManagerGlobalData,
> + Dispatch<ExtForeignToplevelImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
+ WorkspaceHandler
+ 'static,
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static,
{
ImageCaptureSourceState {
output_source_global: display
.create_global::<D, ExtOutputImageCaptureSourceManagerV1, _>(
1,
OutputImageCaptureSourceManagerGlobalData {
filter: Box::new(client_filter.clone()),
},
),
CosmicImageCaptureSourceState {
workspace_source_global: display
.create_global::<D, ZcosmicWorkspaceImageCaptureSourceManagerV1, _>(
1,
@ -88,57 +65,12 @@ impl ImageCaptureSourceState {
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 {
&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>
@ -146,7 +78,7 @@ impl<D>
ZcosmicWorkspaceImageCaptureSourceManagerV1,
WorkspaceImageCaptureSourceManagerGlobalData,
D,
> for ImageCaptureSourceState
> for CosmicImageCaptureSourceState
where
D: GlobalDispatch<
ZcosmicWorkspaceImageCaptureSourceManagerV1,
@ -174,70 +106,8 @@ where
}
}
impl<D>
GlobalDispatch<
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
impl<D> Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, (), D>
for CosmicImageCaptureSourceState
where
D: Dispatch<ZcosmicWorkspaceImageCaptureSourceManagerV1, ()>
+ Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData>
@ -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<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,
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<D> Dispatch<ExtImageCaptureSourceV1, ImageCaptureSourceData, D> for ImageCaptureSourceState
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 {
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;

View file

@ -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;

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())
}
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<Window = W>,
{
let handle = ForeignToplevelHandle::from_resource(foreign_toplevel)?;
state.toplevel_info_state().toplevels.iter().find(|w| {
w.user_data().get::<ToplevelState>().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<Window = W>,
{
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: [