From 26a652f039a72bdc32375f52da79f3f57b36f42f Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 10 Feb 2023 14:32:56 -0800 Subject: [PATCH] Exclude "cosmic-workspace-overview" from workspace screencopy --- src/backend/kms/mod.rs | 28 ++++++-- src/backend/render/mod.rs | 3 + src/shell/workspace.rs | 13 +++- src/wayland/handlers/screencopy.rs | 109 +++++++++++++++++++++-------- 4 files changed, 113 insertions(+), 40 deletions(-) diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index cfb97422..0e430abb 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -239,10 +239,12 @@ pub fn init_backend( ); } } else { - if let Err(err) = - data.state - .device_added(dev, path.into(), &data.display.handle(), true) - { + if let Err(err) = data.state.device_added( + dev, + path.into(), + &data.display.handle(), + true, + ) { slog_scope::error!( "Failed to add drm device {}: {}", path.display(), @@ -322,10 +324,16 @@ pub fn init_backend( .device_added(dev, path.into(), dh, false) .with_context(|| format!("Failed to add drm device: {}", path.display()))?; } - + // HACK: amdgpu doesn't like us initializing vulkan too early.. // so lets do that delayed until mesa fixes that. - let devices = state.backend.kms().devices.iter().map(|(drm_node, device)| (*drm_node, device.render_node)).collect::>(); + let devices = state + .backend + .kms() + .devices + .iter() + .map(|(drm_node, device)| (*drm_node, device.render_node)) + .collect::>(); for (drm_node, render_node) in devices { state.init_vulkan(drm_node, render_node); } @@ -333,7 +341,13 @@ pub fn init_backend( } impl State { - fn device_added(&mut self, dev: dev_t, path: PathBuf, dh: &DisplayHandle, try_vulkan: bool) -> Result<()> { + fn device_added( + &mut self, + dev: dev_t, + path: PathBuf, + dh: &DisplayHandle, + try_vulkan: bool, + ) -> Result<()> { if !self.backend.kms().session.is_active() { return Ok(()); } diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 7006ce5a..f8f71afb 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -158,6 +158,7 @@ where cursor_mode, screencopy, fps, + false, ); result @@ -175,6 +176,7 @@ pub fn render_workspace<'frame, R, Target, OffTarget, Source>( mut cursor_mode: CursorMode, screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>, mut fps: Option<&mut Fps>, + exclude_workspace_overview: bool, ) -> Result<(Option>>, RenderElementStates), RenderError> where R: Renderer @@ -254,6 +256,7 @@ where output, &state.shell.override_redirect_windows, state.xwayland_state.values_mut(), + exclude_workspace_overview, ) .map_err(|_| OutputNoMode)? .into_iter() diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 3945b3d7..91e84972 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -7,7 +7,7 @@ use crate::{ state::State, utils::prelude::*, wayland::{ - handlers::screencopy::DropableSession, + handlers::screencopy::{DropableSession, WORKSPACE_OVERVIEW_NAMESPACE}, protocols::{ screencopy::{BufferParams, Session as ScreencopySession}, toplevel_info::ToplevelInfoState, @@ -434,6 +434,7 @@ impl Workspace { output: &Output, override_redirect_windows: &[X11Surface], xwm_state: impl Iterator, + exclude_workspace_overview: bool, ) -> Result>, OutputNotMapped> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, @@ -451,7 +452,11 @@ impl Workspace { layer_map .layers() .rev() - .filter(|s| s.layer() == Layer::Overlay) + .filter(|s| { + s.layer() == Layer::Overlay + && !(exclude_workspace_overview + && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) + }) .filter_map(|surface| { layer_map .layer_geometry(surface) @@ -510,6 +515,10 @@ impl Workspace { let (lower, upper): (Vec<&LayerSurface>, Vec<&LayerSurface>) = layer_map .layers() .rev() + .filter(|s| { + !(exclude_workspace_overview + && s.namespace() == "cosmic-workspace-overview") + }) .partition(|s| matches!(s.layer(), Layer::Background | Layer::Bottom)); render_elements.extend( diff --git a/src/wayland/handlers/screencopy.rs b/src/wayland/handlers/screencopy.rs index 9d42c018..be06b8db 100644 --- a/src/wayland/handlers/screencopy.rs +++ b/src/wayland/handlers/screencopy.rs @@ -5,6 +5,7 @@ use std::{ }; use anyhow::anyhow; +use calloop::LoopHandle; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::{ FailureReason, InputType, }; @@ -24,7 +25,7 @@ use smithay::{ Bind, Blit, BufferType, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, }, }, - desktop::space::SpaceElement, + desktop::{layer_map_for_output, space::SpaceElement}, output::Output, reexports::wayland_server::{ protocol::{wl_buffer::WlBuffer, wl_shm::Format as ShmFormat, wl_surface::WlSurface}, @@ -46,7 +47,7 @@ use crate::{ render_output, render_workspace, CursorMode, CLEAR_COLOR, }, shell::{CosmicMappedRenderElement, CosmicSurface}, - state::{BackendData, ClientState, Common, State}, + state::{BackendData, ClientState, Common, Data, State}, utils::prelude::OutputExt, wayland::protocols::{ screencopy::{ @@ -59,6 +60,8 @@ use crate::{ use super::data_device::get_dnd_icon; +pub const WORKSPACE_OVERVIEW_NAMESPACE: &str = "cosmic-workspace-overview"; + pub type PendingScreencopyBuffers = RefCell>; #[derive(Debug, Default)] @@ -767,6 +770,7 @@ pub fn render_workspace_to_buffer( cursor_mode, None, None, + true, ) } else { let size = buffer_dimensions(buffer).unwrap(); @@ -784,6 +788,7 @@ pub fn render_workspace_to_buffer( cursor_mode, None, None, + true, ) } } @@ -1144,8 +1149,30 @@ impl State { output: &Output, ) -> Option> { let workspace = self.common.shell.active_space_mut(output); - if !workspace.pending_buffers.is_empty() { - Some(std::mem::take(&mut workspace.pending_buffers)) + let mut pending_buffers = std::mem::take(&mut workspace.pending_buffers); + + let mut i = 0; + while i < pending_buffers.len() { + let layer_map = layer_map_for_output(&output); + if layer_map + .layers() + .any(|s| s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) + { + let (session, params) = pending_buffers.remove(i); + schedule_offscreen_workspace_session( + &self.common.event_loop_handle, + session, + params, + output.clone(), + workspace.handle.clone(), + ); + } else { + i += 1; + } + } + + if !pending_buffers.is_empty() { + Some(pending_buffers) } else { None } @@ -1174,7 +1201,12 @@ impl State { if let SessionType::Workspace(o, w) = workspace.pending_buffers[i].0.session_type() { - if active_spaces.contains(&(o.clone(), w)) { + let layer_map = layer_map_for_output(&o); + if active_spaces.contains(&(o.clone(), w)) + && !layer_map + .layers() + .any(|s| s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) + { // surface is on an active workspace/output combo, add to workspace_sessions let (session, params) = workspace.pending_buffers.remove(i); output_sessions @@ -1183,32 +1215,13 @@ impl State { } else if handle == w && output == o { // surface is visible on an offscreen workspace session, schedule a new render let (session, params) = workspace.pending_buffers.remove(i); - let output = output.clone(); - self.common.event_loop_handle.insert_idle(move |data| { - if !session.alive() { - return; - } - if !data.state.common.shell.outputs.contains(&output) { - return; - } - match render_workspace_to_buffer( - &mut data.state, - &session, - params.clone(), - &output, - &handle, - ) { - Ok(false) => { - // rendering yielded no new damage, buffer still pending - data.state.common.still_pending(session, params); - } - Ok(true) => {} - Err((reason, err)) => { - slog_scope::warn!("Screencopy session failed: {}", err); - session.failed(reason); - } - } - }); + schedule_offscreen_workspace_session( + &self.common.event_loop_handle, + session, + params, + output.clone(), + handle, + ); } else { i += 1; } @@ -1223,4 +1236,38 @@ impl State { } } +pub fn schedule_offscreen_workspace_session( + event_loop_handle: &LoopHandle<'static, Data>, + session: Session, + params: BufferParams, + output: Output, + handle: WorkspaceHandle, +) { + event_loop_handle.insert_idle(move |data| { + if !session.alive() { + return; + } + if !data.state.common.shell.outputs.contains(&output) { + return; + } + match render_workspace_to_buffer( + &mut data.state, + &session, + params.clone(), + &output, + &handle, + ) { + Ok(false) => { + // rendering yielded no new damage, buffer still pending + data.state.common.still_pending(session, params); + } + Ok(true) => {} + Err((reason, err)) => { + slog_scope::warn!("Screencopy session failed: {}", err); + session.failed(reason); + } + } + }); +} + delegate_screencopy!(State);