From a1e5ce0502027b9c04fa42dbf6fa0eeed20cef5b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 9 Jul 2024 15:21:16 -0700 Subject: [PATCH 1/6] Add a `SplitRenderElements` type, with useful methods `(w_elements, p_elements)` tuples are used in a bunch of places. A struct with named fields is generally an improvement just due to the fact the order is non-obvious. But we can also add methods. In particular, `extend_from_workspace_elements` abstracts out some of the more redundant code in `workspace_elements`. It would be nice to avoid allocation everywhere, but iterators would complicate lifetimes, run into issues with needing multiple mutable borrows to things like the `Renderer`, and be awkward in certain functions without generator syntax. In any case, cosmic-comp already relies on allocating vectors here. If this abstraction is commonly useful in compositors, perhaps it could be moved to Smithay. --- src/backend/render/mod.rs | 333 +++++++++++++++---------------- src/shell/element/mod.rs | 43 ++-- src/shell/element/stack.rs | 41 ++-- src/shell/element/surface.rs | 20 +- src/shell/element/window.rs | 39 ++-- src/shell/grabs/moving.rs | 11 +- src/shell/layout/floating/mod.rs | 25 ++- src/shell/layout/tiling/mod.rs | 175 ++++++++-------- src/shell/workspace.rs | 70 +++---- 9 files changed, 376 insertions(+), 381 deletions(-) diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 2674a938..e72ff4c3 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -58,7 +58,7 @@ use smithay::{ desktop::{layer_map_for_output, PopupManager}, input::Seat, output::{Output, OutputNoMode}, - utils::{IsAlive, Logical, Monotonic, Point, Rectangle, Scale, Time, Transform}, + utils::{IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Time, Transform}, wayland::{ dmabuf::get_dmabuf, shell::wlr_layer::Layer, @@ -464,6 +464,60 @@ where #[cfg(not(feature = "debug"))] pub type EguiState = (); +#[derive(Clone, Debug)] +pub struct SplitRenderElements { + pub w_elements: Vec, + pub p_elements: Vec, +} + +impl Default for SplitRenderElements { + fn default() -> Self { + Self { + w_elements: Vec::new(), + p_elements: Vec::new(), + } + } +} + +impl SplitRenderElements { + pub fn extend(&mut self, other: Self) { + self.w_elements.extend(other.w_elements); + self.p_elements.extend(other.p_elements); + } + + pub fn extend_map E>(&mut self, other: SplitRenderElements, mut f: F) { + self.w_elements + .extend(other.w_elements.into_iter().map(&mut f)); + self.p_elements + .extend(other.p_elements.into_iter().map(&mut f)); + } + + pub fn join(mut self) -> Vec { + self.p_elements.extend(self.w_elements); + self.p_elements + } +} + +impl SplitRenderElements> +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + CosmicMappedRenderElement: RenderElement, +{ + fn extend_from_workspace_elements>>( + &mut self, + other: SplitRenderElements, + offset: Point, + ) { + self.extend_map(other, |element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + element.into(), + offset, + Relocate::Relative, + )) + }) + } +} + #[profiling::function] pub fn workspace_elements( _gpu: Option<&DrmNode>, @@ -484,6 +538,8 @@ where CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { + let mut elements = SplitRenderElements::default(); + let theme = shell.read().unwrap().theme().clone(); let seats = shell .read() @@ -493,7 +549,7 @@ where .cloned() .collect::>(); - let mut elements = cursor_elements( + elements.p_elements.extend(cursor_elements( renderer, seats.iter(), &theme, @@ -501,7 +557,7 @@ where output, cursor_mode, exclude_workspace_overview, - ); + )); #[cfg(feature = "debug")] { @@ -525,7 +581,7 @@ where ) .map_err(FromGlesError::from_gles_error) .map_err(RenderError::Rendering)?; - elements.push(fps_overlay.into()); + elements.p_elements.push(fps_overlay.into()); } } @@ -533,12 +589,12 @@ where // If session locked, only show session lock surfaces if let Some(session_lock) = &shell.session_lock { - elements.extend( + elements.p_elements.extend( session_lock_elements(renderer, output, session_lock) .into_iter() .map(|x| WorkspaceRenderElement::from(x).into()), ); - return Ok(elements); + return Ok(elements.join()); } let theme = theme.cosmic(); @@ -586,20 +642,22 @@ where .as_ref() .filter(|f| !f.is_animating()) .is_some(); - let (overlay_elements, overlay_popups) = + let overlay_elements = split_layer_elements(renderer, output, Layer::Overlay, exclude_workspace_overview); // overlay is above everything - elements.extend(overlay_popups.into_iter().map(Into::into)); - elements.extend(overlay_elements.into_iter().map(Into::into)); - - let mut window_elements = if !has_fullscreen { - let (top_elements, top_popups) = - split_layer_elements(renderer, output, Layer::Top, exclude_workspace_overview); - elements.extend(top_popups.into_iter().map(Into::into)); - top_elements.into_iter().map(Into::into).collect() - } else { - Vec::new() + elements + .p_elements + .extend(overlay_elements.p_elements.into_iter().map(Into::into)); + elements + .p_elements + .extend(overlay_elements.w_elements.into_iter().map(Into::into)); + + if !has_fullscreen { + elements.extend_from_workspace_elements( + split_layer_elements(renderer, output, Layer::Top, exclude_workspace_overview), + (0, 0).into(), + ); }; let active_hint = if shell.active_hint { @@ -611,7 +669,7 @@ where // overlay redirect windows // they need to be over sticky windows, because they could be popups of sticky windows, // and we can't differenciate that. - elements.extend( + elements.p_elements.extend( shell .override_redirect_windows .iter() @@ -632,13 +690,7 @@ where 1.0, ) }) - .map(|p_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - p_element, - (0, 0), - Relocate::Relative, - )) - }), + .map(|p_element| p_element.into()), ); // sticky windows @@ -664,29 +716,17 @@ where .then_some(last_active_seat) .map(|seat| workspace.focus_stack.get(seat)); - let (w_elements, p_elements) = set.sticky_layer.render( - renderer, - current_focus.as_ref().and_then(|stack| stack.last()), - resize_indicator.clone(), - active_hint, - alpha, - theme, + elements.extend_from_workspace_elements( + set.sticky_layer.render( + renderer, + current_focus.as_ref().and_then(|stack| stack.last()), + resize_indicator.clone(), + active_hint, + alpha, + theme, + ), + (0, 0).into(), ); - - elements.extend(p_elements.into_iter().map(|p_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - WorkspaceRenderElement::Window(p_element), - (0, 0), - Relocate::Relative, - )) - })); - window_elements.extend(w_elements.into_iter().map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - WorkspaceRenderElement::Window(w_element), - (0, 0), - Relocate::Relative, - )) - })); } let offset = match previous.as_ref() { @@ -728,48 +768,25 @@ where } }); - let (w_elements, p_elements) = workspace - .render::( - renderer, - (!move_active && is_active_space).then_some(last_active_seat), - overview.clone(), - resize_indicator.clone(), - active_hint, - theme, - ) - .map_err(|_| OutputNoMode)?; - elements.extend(p_elements.into_iter().map(|p_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - p_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); - window_elements.extend(w_elements.into_iter().map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); + elements.extend_from_workspace_elements( + workspace + .render::( + renderer, + (!move_active && is_active_space).then_some(last_active_seat), + overview.clone(), + resize_indicator.clone(), + active_hint, + theme, + ) + .map_err(|_| OutputNoMode)?, + offset.to_physical_precise_round(output_scale), + ); if !has_fullscreen { - let (w_elements, p_elements) = - background_layer_elements(renderer, output, exclude_workspace_overview); - elements.extend(p_elements.into_iter().map(|p_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - p_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); - window_elements.extend(w_elements.into_iter().map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); + elements.extend_from_workspace_elements( + background_layer_elements(renderer, output, exclude_workspace_overview), + offset.to_physical_precise_round(output_scale), + ); } Point::::from(match (layout, *previous_idx < current.1) { @@ -782,55 +799,28 @@ where None => (0, 0).into(), }; - let (w_elements, p_elements) = workspace - .render::( - renderer, - (!move_active && is_active_space).then_some(&last_active_seat), - overview, - resize_indicator, - active_hint, - theme, - ) - .map_err(|_| OutputNoMode)?; - elements.extend(p_elements.into_iter().map(|p_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - p_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); - window_elements.extend(w_elements.into_iter().map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); + elements.extend_from_workspace_elements( + workspace + .render::( + renderer, + (!move_active && is_active_space).then_some(&last_active_seat), + overview, + resize_indicator, + active_hint, + theme, + ) + .map_err(|_| OutputNoMode)?, + offset.to_physical_precise_round(output_scale), + ); if !has_fullscreen { - let (w_elements, p_elements) = - background_layer_elements(renderer, output, exclude_workspace_overview); - - elements.extend(p_elements.into_iter().map(|p_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - p_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); - - window_elements.extend(w_elements.into_iter().map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - })); + elements.extend_from_workspace_elements( + background_layer_elements(renderer, output, exclude_workspace_overview), + offset.to_physical_precise_round(output_scale), + ); } - elements.extend(window_elements); - - Ok(elements) + Ok(elements.join()) } pub fn split_layer_elements( @@ -838,10 +828,7 @@ pub fn split_layer_elements( output: &Output, layer: Layer, exclude_workspace_overview: bool, -) -> ( - Vec>, - Vec>, -) +) -> SplitRenderElements> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Clone + 'static, @@ -852,8 +839,7 @@ where let layer_map = layer_map_for_output(output); let output_scale = output.current_scale().fractional_scale(); - let mut popup_elements = Vec::new(); - let mut layer_elements = Vec::new(); + let mut elements = SplitRenderElements::default(); layer_map .layers_on(layer) @@ -869,35 +855,39 @@ where let surface = surface.wl_surface(); let scale = Scale::from(output_scale); - popup_elements.extend(PopupManager::popups_for_surface(surface).flat_map( - |(popup, popup_offset)| { - let offset = (popup_offset - popup.geometry().loc) - .to_f64() - .to_physical(scale) - .to_i32_round(); - - render_elements_from_surface_tree( - renderer, - popup.wl_surface(), - location + offset, - scale, - 1.0, - Kind::Unspecified, - ) - }, - )); + elements + .p_elements + .extend(PopupManager::popups_for_surface(surface).flat_map( + |(popup, popup_offset)| { + let offset = (popup_offset - popup.geometry().loc) + .to_f64() + .to_physical(scale) + .to_i32_round(); + + render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + location + offset, + scale, + 1.0, + Kind::Unspecified, + ) + }, + )); - layer_elements.extend(render_elements_from_surface_tree( - renderer, - surface, - location, - scale, - 1.0, - Kind::Unspecified, - )); + elements + .w_elements + .extend(render_elements_from_surface_tree( + renderer, + surface, + location, + scale, + 1.0, + Kind::Unspecified, + )); }); - (layer_elements, popup_elements) + elements } // bottom and background layer surfaces @@ -905,10 +895,7 @@ pub fn background_layer_elements( renderer: &mut R, output: &Output, exclude_workspace_overview: bool, -) -> ( - Vec>, - Vec>, -) +) -> SplitRenderElements> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Clone + 'static, @@ -916,17 +903,15 @@ where CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let (mut layer_elements, mut popup_elements) = + let mut elements = split_layer_elements(renderer, output, Layer::Bottom, exclude_workspace_overview); - let more = split_layer_elements( + elements.extend(split_layer_elements( renderer, output, Layer::Background, exclude_workspace_overview, - ); - layer_elements.extend(more.0); - popup_elements.extend(more.1); - (layer_elements, popup_elements) + )); + elements } fn session_lock_elements( diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 231f633a..94cb702e 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -1,7 +1,7 @@ use crate::{ backend::render::{ element::{AsGlowFrame, AsGlowRenderer}, - GlMultiError, GlMultiFrame, GlMultiRenderer, + GlMultiError, GlMultiFrame, GlMultiRenderer, SplitRenderElements, }, state::State, utils::{iced::IcedElementInternal, prelude::*}, @@ -663,7 +663,7 @@ impl CosmicMapped { location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, - ) -> (Vec, Vec) + ) -> SplitRenderElements where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -842,27 +842,28 @@ impl CosmicMapped { #[cfg(not(feature = "debug"))] let debug_elements = Vec::new(); - #[cfg_attr(not(feature = "debug"), allow(unused_mut))] - let (window_elements, popup_elements) = match &self.element { - CosmicMappedInternal::Stack(s) => s - .split_render_elements::>( - renderer, location, scale, alpha, - ), - CosmicMappedInternal::Window(w) => w - .split_render_elements::>( - renderer, location, scale, alpha, - ), - _ => unreachable!(), + let mut elements = SplitRenderElements { + w_elements: debug_elements, + p_elements: Vec::new(), }; - ( - debug_elements - .into_iter() - .map(C::from) - .chain(window_elements.into_iter().map(C::from)) - .collect(), - popup_elements.into_iter().map(C::from).collect(), - ) + #[cfg_attr(not(feature = "debug"), allow(unused_mut))] + elements.extend_map( + match &self.element { + CosmicMappedInternal::Stack(s) => s + .split_render_elements::>( + renderer, location, scale, alpha, + ), + CosmicMappedInternal::Window(w) => w + .split_render_elements::>( + renderer, location, scale, alpha, + ), + _ => unreachable!(), + }, + C::from, + ); + + elements } pub(crate) fn update_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 107179a3..8489365b 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -1,6 +1,9 @@ use super::{surface::RESIZE_BORDER, window::Focus, CosmicSurface}; use crate::{ - backend::render::cursor::{CursorShape, CursorState}, + backend::render::{ + cursor::{CursorShape, CursorState}, + SplitRenderElements, + }, shell::{ focus::target::PointerFocusTarget, grabs::{ReleaseMode, ResizeEdge}, @@ -547,7 +550,7 @@ impl CosmicStack { location: Point, scale: Scale, alpha: f32, - ) -> (Vec, Vec) + ) -> SplitRenderElements where R: Renderer + ImportAll + ImportMem, ::TextureId: Send + Clone + 'static, @@ -564,30 +567,28 @@ impl CosmicStack { let stack_loc = location + offset; let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); - let elements = AsRenderElements::::render_elements::>( + let w_elements = AsRenderElements::::render_elements::>( &self.0, renderer, stack_loc, scale, alpha, ); - let (window_elements, popup_elements) = self.0.with_program(|p| { - let windows = p.windows.lock().unwrap(); - let active = p.active.load(Ordering::SeqCst); + let mut elements = SplitRenderElements { + w_elements: w_elements.into_iter().map(C::from).collect(), + p_elements: Vec::new(), + }; - let (window_elements, popup_elements) = windows[active] - .split_render_elements::>( - renderer, window_loc, scale, alpha, - ); + elements.extend_map( + self.0.with_program(|p| { + let windows = p.windows.lock().unwrap(); + let active = p.active.load(Ordering::SeqCst); - (window_elements, popup_elements) - }); + windows[active].split_render_elements::>( + renderer, window_loc, scale, alpha, + ) + }), + C::from, + ); - ( - elements - .into_iter() - .map(C::from) - .chain(window_elements.into_iter().map(C::from)) - .collect(), - popup_elements.into_iter().map(C::from).collect(), - ) + elements } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 5c18870a..a870d8e4 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -42,6 +42,7 @@ use smithay::{ }; use crate::{ + backend::render::SplitRenderElements, state::{State, SurfaceDmabufFeedback}, utils::prelude::*, wayland::handlers::decoration::PreferredDecorationMode, @@ -563,7 +564,7 @@ impl CosmicSurface { location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, - ) -> (Vec, Vec) + ) -> SplitRenderElements where R: Renderer + ImportAll, ::TextureId: Clone + 'static, @@ -573,7 +574,7 @@ impl CosmicSurface { WindowSurface::Wayland(toplevel) => { let surface = toplevel.wl_surface(); - let popup_render_elements = PopupManager::popups_for_surface(surface) + let p_elements = PopupManager::popups_for_surface(surface) .flat_map(|(popup, popup_offset)| { let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc) .to_physical_precise_round(scale); @@ -589,7 +590,7 @@ impl CosmicSurface { }) .collect(); - let window_render_elements = render_elements_from_surface_tree( + let w_elements = render_elements_from_surface_tree( renderer, surface, location, @@ -598,12 +599,15 @@ impl CosmicSurface { element::Kind::Unspecified, ); - (window_render_elements, popup_render_elements) + SplitRenderElements { + w_elements, + p_elements, + } } - WindowSurface::X11(surface) => ( - surface.render_elements(renderer, location, scale, alpha), - Vec::new(), - ), + WindowSurface::X11(surface) => SplitRenderElements { + w_elements: surface.render_elements(renderer, location, scale, alpha), + p_elements: Vec::new(), + }, } } diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 5917a78d..706784fd 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -1,5 +1,8 @@ use crate::{ - backend::render::cursor::{CursorShape, CursorState}, + backend::render::{ + cursor::{CursorShape, CursorState}, + SplitRenderElements, + }, shell::{ focus::target::PointerFocusTarget, grabs::{ReleaseMode, ResizeEdge}, @@ -317,7 +320,7 @@ impl CosmicWindow { location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, - ) -> (Vec, Vec) + ) -> SplitRenderElements where R: Renderer + ImportAll + ImportMem, ::TextureId: Send + Clone + 'static, @@ -331,12 +334,17 @@ impl CosmicWindow { location }; - let (mut window_elements, popup_elements) = self.0.with_program(|p| { - p.window - .split_render_elements::>( - renderer, window_loc, scale, alpha, - ) - }); + let mut elements = SplitRenderElements::default(); + + elements.extend_map( + self.0.with_program(|p| { + p.window + .split_render_elements::>( + renderer, window_loc, scale, alpha, + ) + }), + C::from, + ); if has_ssd { let ssd_loc = location @@ -344,15 +352,16 @@ impl CosmicWindow { .0 .with_program(|p| p.window.geometry().loc) .to_physical_precise_round(scale); - window_elements.extend(AsRenderElements::::render_elements::< - CosmicWindowRenderElement, - >(&self.0, renderer, ssd_loc, scale, alpha)) + elements.w_elements.extend( + AsRenderElements::::render_elements::>( + &self.0, renderer, ssd_loc, scale, alpha, + ) + .into_iter() + .map(C::from), + ) } - ( - window_elements.into_iter().map(C::from).collect(), - popup_elements.into_iter().map(C::from).collect(), - ) + elements } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 0cbe400f..b4a0bac0 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -4,7 +4,7 @@ use crate::{ backend::render::{ cursor::{CursorShape, CursorState}, element::AsGlowRenderer, - BackdropShader, IndicatorShader, Key, Usage, + BackdropShader, IndicatorShader, Key, SplitRenderElements, Usage, }, shell::{ element::{ @@ -182,7 +182,10 @@ impl MoveGrabState { _ => vec![], }; - let (window_elements, popup_elements) = self + let SplitRenderElements { + w_elements, + p_elements, + } = self .window .split_render_elements::>( renderer, @@ -202,9 +205,9 @@ impl MoveGrabState { 1.0, ) }) - .chain(popup_elements) + .chain(p_elements) .chain(focus_element) - .chain(window_elements.into_iter().map(|elem| match elem { + .chain(w_elements.into_iter().map(|elem| match elem { CosmicMappedRenderElement::Stack(stack) => { CosmicMappedRenderElement::GrabbedStack( RescaleRenderElement::from_element( diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 1c184a30..c0ff2ad2 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -24,7 +24,7 @@ use smithay::{ }; use crate::{ - backend::render::{element::AsGlowRenderer, IndicatorShader, Key, Usage}, + backend::render::{element::AsGlowRenderer, IndicatorShader, Key, SplitRenderElements, Usage}, shell::{ element::{ resize_indicator::ResizeIndicator, @@ -1270,10 +1270,7 @@ impl FloatingLayout { indicator_thickness: u8, alpha: f32, theme: &cosmic::theme::CosmicTheme, - ) -> ( - Vec>, - Vec>, - ) + ) -> SplitRenderElements> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -1288,8 +1285,7 @@ impl FloatingLayout { }; let output_scale = output.current_scale().fractional_scale(); - let mut window_elements = Vec::new(); - let mut popup_elements = Vec::new(); + let mut elements = SplitRenderElements::default(); for elem in self .animations @@ -1305,7 +1301,10 @@ impl FloatingLayout { .unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha)); let render_location = geometry.loc - elem.geometry().loc.as_local(); - let (mut w_elements, p_elements) = elem.split_render_elements( + let SplitRenderElements { + mut w_elements, + p_elements, + } = elem.split_render_elements( renderer, render_location .as_logical() @@ -1388,7 +1387,7 @@ impl FloatingLayout { resize.resize(resize_geometry.size.as_logical()); resize.output_enter(output, Rectangle::default() /* unused */); - window_elements.extend( + elements.w_elements.extend( resize .render_elements::>( renderer, @@ -1420,15 +1419,15 @@ impl FloatingLayout { active_window_hint.blue, ], ); - window_elements.push(element.into()); + elements.w_elements.push(element.into()); } } - window_elements.extend(w_elements); - popup_elements.extend(p_elements); + elements.w_elements.extend(w_elements); + elements.p_elements.extend(p_elements); } - (window_elements, popup_elements) + elements } fn gaps(&self) -> (i32, i32) { diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 83084b3f..3a16ef14 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -2,8 +2,8 @@ use crate::{ backend::render::{ - element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage, ACTIVE_GROUP_COLOR, - GROUP_COLOR, + element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, SplitRenderElements, Usage, + ACTIVE_GROUP_COLOR, GROUP_COLOR, }, shell::{ element::{ @@ -3846,13 +3846,7 @@ impl TilingLayout { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &cosmic::theme::CosmicTheme, - ) -> Result< - ( - Vec>, - Vec>, - ), - OutputNotMapped, - > + ) -> Result>, OutputNotMapped> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -3885,8 +3879,7 @@ impl TilingLayout { }; let draw_groups = overview.0.alpha(); - let mut window_elements = Vec::new(); - let mut popup_elements = Vec::new(); + let mut elements = SplitRenderElements::default(); let is_overview = !matches!(overview.0, OverviewMode::None); let is_mouse_tiling = (matches!(overview.0, OverviewMode::Started(Trigger::Pointer(_), _))) @@ -3921,7 +3914,7 @@ impl TilingLayout { .unzip(); // all old windows we want to fade out - let (w_elements, p_elements) = render_old_tree( + elements.extend(render_old_tree( reference_tree, target_tree, renderer, @@ -3931,9 +3924,7 @@ impl TilingLayout { indicator_thickness, swap_desc.is_some(), theme, - ); - window_elements.extend(w_elements); - popup_elements.extend(p_elements); + )); geometries } else { @@ -3961,7 +3952,7 @@ impl TilingLayout { .unzip(); // all alive windows - let (w_elements, p_elements) = render_new_tree( + elements.extend(render_new_tree( target_tree, reference_tree, renderer, @@ -3989,16 +3980,14 @@ impl TilingLayout { &self.swapping_stack_surface_id, &self.placeholder_id, theme, - ); - window_elements.extend(w_elements); - popup_elements.extend(p_elements); + )); // tiling hints if let Some(group_elements) = group_elements { - window_elements.extend(group_elements); + elements.w_elements.extend(group_elements); } - Ok((window_elements, popup_elements)) + Ok(elements) } fn gaps(&self) -> (i32, i32) { @@ -4694,10 +4683,7 @@ fn render_old_tree( indicator_thickness: u8, is_swap_mode: bool, theme: &cosmic::theme::CosmicTheme, -) -> ( - Vec>, - Vec>, -) +) -> SplitRenderElements> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -4706,8 +4692,7 @@ where CosmicStackRenderElement: RenderElement, { let window_hint = crate::theme::active_window_hint(theme); - let mut window_elements = Vec::new(); - let mut popup_elements = Vec::new(); + let mut elements = SplitRenderElements::default(); if let Some(root) = reference_tree.root_node_id() { let geometries = geometries.unwrap_or_default(); @@ -4777,62 +4762,68 @@ where }; let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); - let (w_elements, p_elements) = mapped - .split_render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - Scale::from(output_scale), - alpha, - ); + let SplitRenderElements { + w_elements, + p_elements, + } = mapped.split_render_elements::>( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + Scale::from(output_scale), + alpha, + ); - window_elements.extend(w_elements.into_iter().flat_map(|element| { - match element { - CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( - std::iter::once(elem), - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - geo.as_logical().to_physical_precise_round(output_scale), - elem_geometry, - ConstrainScaleBehavior::Stretch, - ConstrainAlign::CENTER, - output_scale, - ) - .next() - .map(CosmicMappedRenderElement::TiledStack), - CosmicMappedRenderElement::Window(elem) => constrain_render_elements( - std::iter::once(elem), - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - geo.as_logical().to_physical_precise_round(output_scale), - elem_geometry, - ConstrainScaleBehavior::Stretch, - ConstrainAlign::CENTER, - output_scale, - ) - .next() - .map(CosmicMappedRenderElement::TiledWindow), - x => Some(x), - } - })); + elements + .w_elements + .extend(w_elements.into_iter().flat_map(|element| { + match element { + CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( + std::iter::once(elem), + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + geo.as_logical().to_physical_precise_round(output_scale), + elem_geometry, + ConstrainScaleBehavior::Stretch, + ConstrainAlign::CENTER, + output_scale, + ) + .next() + .map(CosmicMappedRenderElement::TiledStack), + CosmicMappedRenderElement::Window(elem) => constrain_render_elements( + std::iter::once(elem), + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + geo.as_logical().to_physical_precise_round(output_scale), + elem_geometry, + ConstrainScaleBehavior::Stretch, + ConstrainAlign::CENTER, + output_scale, + ) + .next() + .map(CosmicMappedRenderElement::TiledWindow), + x => Some(x), + } + })); if minimize_geo.is_some() && indicator_thickness > 0 { - window_elements.push(CosmicMappedRenderElement::FocusIndicator( - IndicatorShader::focus_element( - renderer, - Key::Window(Usage::FocusIndicator, mapped.clone().key()), - geo, - indicator_thickness, - output_scale, - alpha, - [window_hint.red, window_hint.green, window_hint.blue], - ), - )); + elements + .w_elements + .push(CosmicMappedRenderElement::FocusIndicator( + IndicatorShader::focus_element( + renderer, + Key::Window(Usage::FocusIndicator, mapped.clone().key()), + geo, + indicator_thickness, + output_scale, + alpha, + [window_hint.red, window_hint.green, window_hint.blue], + ), + )); } - popup_elements.extend(p_elements); + elements.p_elements.extend(p_elements); }); } - (window_elements, popup_elements) + elements } fn render_new_tree( @@ -4854,10 +4845,7 @@ fn render_new_tree( swapping_stack_surface_id: &Id, placeholder_id: &Id, theme: &cosmic::theme::CosmicTheme, -) -> ( - Vec>, - Vec>, -) +) -> SplitRenderElements> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -5246,15 +5234,17 @@ where if let Data::Mapped { mapped, .. } = data { let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); - let (mut w_elements, p_elements) = mapped - .split_render_elements::>( - renderer, - //original_location, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - Scale::from(output_scale), - alpha, - ); + let SplitRenderElements { + mut w_elements, + p_elements, + } = mapped.split_render_elements::>( + renderer, + //original_location, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + Scale::from(output_scale), + alpha, + ); if swap_desc .as_ref() .filter(|swap_desc| swap_desc.node == node_id) @@ -5373,7 +5363,10 @@ where .chain(group_backdrop.into_iter().map(Into::into)) .collect(); - (window_elements, popup_elements) + SplitRenderElements { + w_elements: window_elements, + p_elements: popup_elements, + } } fn scale_to_center( diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index c161886d..94ba2d60 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -1,7 +1,7 @@ use crate::{ backend::render::{ element::{AsGlowFrame, AsGlowRenderer}, - BackdropShader, GlMultiError, GlMultiFrame, GlMultiRenderer, + BackdropShader, GlMultiError, GlMultiFrame, GlMultiRenderer, SplitRenderElements, }, shell::{ layout::{floating::FloatingLayout, tiling::TilingLayout}, @@ -1005,13 +1005,7 @@ impl Workspace { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &CosmicTheme, - ) -> Result< - ( - Vec>, - Vec>, - ), - OutputNotMapped, - > + ) -> Result>, OutputNotMapped> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -1020,8 +1014,7 @@ impl Workspace { CosmicStackRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut window_elements = Vec::new(); - let mut popup_elements = Vec::new(); + let mut elements = SplitRenderElements::default(); let output_scale = self.output.current_scale().fractional_scale(); let zone = { @@ -1104,7 +1097,10 @@ impl Workspace { y: target_geo.size.h as f64 / bbox.size.h as f64, }; - let (w_elements, p_elements) = fullscreen + let SplitRenderElements { + w_elements, + p_elements, + } = fullscreen .surface .split_render_elements::>( renderer, @@ -1112,13 +1108,15 @@ impl Workspace { output_scale.into(), alpha, ); - window_elements.extend( + elements.w_elements.extend( w_elements .into_iter() .map(|elem| RescaleRenderElement::from_element(elem, render_loc, scale)) .map(Into::into), ); - popup_elements.extend(p_elements.into_iter().map(Into::into)); + elements + .p_elements + .extend(p_elements.into_iter().map(Into::into)) } if self @@ -1149,16 +1147,17 @@ impl Workspace { OverviewMode::None => 1.0, }; - let (w_elements, p_elements) = self.floating_layer.render::( - renderer, - focused.as_ref(), - resize_indicator.clone(), - indicator_thickness, - alpha, - theme, + elements.extend_map( + self.floating_layer.render::( + renderer, + focused.as_ref(), + resize_indicator.clone(), + indicator_thickness, + alpha, + theme, + ), + WorkspaceRenderElement::from, ); - popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); - window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); let alpha = match &overview.0 { OverviewMode::Started(_, start) => Some( @@ -1173,20 +1172,21 @@ impl Workspace { }; //tiling surfaces - let (w_elements, p_elements) = self.tiling_layer.render::( - renderer, - draw_focus_indicator, - zone, - overview, - resize_indicator, - indicator_thickness, - theme, - )?; - popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); - window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); + elements.extend_map( + self.tiling_layer.render::( + renderer, + draw_focus_indicator, + zone, + overview, + resize_indicator, + indicator_thickness, + theme, + )?, + WorkspaceRenderElement::from, + ); if let Some(alpha) = alpha { - window_elements.push( + elements.w_elements.push( Into::>::into(BackdropShader::element( renderer, self.backdrop_id.clone(), @@ -1203,7 +1203,7 @@ impl Workspace { } } - Ok((window_elements, popup_elements)) + Ok(elements) } } From 63a0bf27c46bbc40b7a7f5706f964a999a697a1c Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 3 May 2024 17:00:45 -0700 Subject: [PATCH 2/6] Inhibit workspace animations when workspaces view is open Fixes https://github.com/pop-os/cosmic-workspaces-epoch/issues/27. We want this to apply to changes to workspace either through keybindings or the cosmic-workspaces UI, so it adding a check here seems reasonable. In principle it could be good to have some kind of privileged protocol for setting things like this. We may also want a configuration option to disable animations at some point. --- src/shell/mod.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 2e81c6a9..92f1f201 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -55,8 +55,8 @@ use crate::{ utils::prelude::*, wayland::{ handlers::{ - toplevel_management::minimize_rectangle, xdg_activation::ActivationContext, - xdg_shell::popup::get_popup_toplevel, + screencopy::WORKSPACE_OVERVIEW_NAMESPACE, toplevel_management::minimize_rectangle, + xdg_activation::ActivationContext, xdg_shell::popup::get_popup_toplevel, }, protocols::{ toplevel_info::{ @@ -416,13 +416,23 @@ impl WorkspaceSet { return Err(InvalidWorkspaceIndex); } + // Animate if workspaces overview isn't open + let layer_map = layer_map_for_output(&self.output); + let animate = !layer_map + .layers() + .any(|l| l.namespace() == WORKSPACE_OVERVIEW_NAMESPACE); + if self.active != idx { let old_active = self.active; state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Active); state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Urgent); state.remove_workspace_state(&self.workspaces[idx].handle, WState::Urgent); state.add_workspace_state(&self.workspaces[idx].handle, WState::Active); - self.previously_active = Some((old_active, workspace_delta)); + self.previously_active = if animate { + Some((old_active, workspace_delta)) + } else { + None + }; self.active = idx; Ok(true) } else { From ebb17204f02fd7cdf049cc0df00cfa76e04e9909 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 9 Jul 2024 20:46:41 -0700 Subject: [PATCH 3/6] When `cosmic-workspaces` is shown, render only layer-shell surfaces This allows `cosmic-workspaces` to rely on cosmic-comp for rendering the background, and just have transparency. This should be a more reliable and performant way of doing things, at least for now. Instead of adding another opaque bool argument, this defines an `ElementFilter` enum, which makes calls more readable. Window surfaces are still included in screencopy, as needed for the workspace previews. --- src/backend/kms/surface/mod.rs | 19 +++- src/backend/render/mod.rs | 118 ++++++++++++---------- src/wayland/handlers/screencopy/render.rs | 6 +- 3 files changed, 83 insertions(+), 60 deletions(-) diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index 1a51816e..18114192 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -3,13 +3,15 @@ use crate::{ backend::render::{ element::{CosmicElement, DamageElement}, - init_shaders, workspace_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR, + init_shaders, workspace_elements, CursorMode, ElementFilter, GlMultiRenderer, CLEAR_COLOR, }, shell::Shell, state::SurfaceDmabufFeedback, utils::prelude::*, wayland::{ - handlers::screencopy::{submit_buffer, FrameHolder, SessionData}, + handlers::screencopy::{ + submit_buffer, FrameHolder, SessionData, WORKSPACE_OVERVIEW_NAMESPACE, + }, protocols::screencopy::{ FailureReason, Frame as ScreencopyFrame, Session as ScreencopySession, }, @@ -46,7 +48,7 @@ use smithay::{ Bind, ImportDma, Offscreen, Renderer, Texture, }, }, - desktop::utils::OutputPresentationFeedback, + desktop::{layer_map_for_output, utils::OutputPresentationFeedback}, output::{Output, OutputNoMode}, reexports::{ calloop::{ @@ -869,6 +871,15 @@ impl SurfaceThreadState { std::mem::drop(shell); + let element_filter = if layer_map_for_output(output) + .layers() + .any(|s| s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) + { + ElementFilter::LayerShellOnly + } else { + ElementFilter::All + }; + workspace_elements( Some(&render_node), &mut renderer, @@ -878,7 +889,7 @@ impl SurfaceThreadState { previous_workspace, workspace, CursorMode::All, - false, + element_filter, #[cfg(not(feature = "debug"))] None, #[cfg(feature = "debug")] diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index e72ff4c3..bf322d1c 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -464,6 +464,13 @@ where #[cfg(not(feature = "debug"))] pub type EguiState = (); +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ElementFilter { + All, + ExcludeWorkspaceOverview, + LayerShellOnly, +} + #[derive(Clone, Debug)] pub struct SplitRenderElements { pub w_elements: Vec, @@ -528,7 +535,7 @@ pub fn workspace_elements( previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>, current: (WorkspaceHandle, usize), cursor_mode: CursorMode, - exclude_workspace_overview: bool, + element_filter: ElementFilter, _fps: Option<(&EguiState, &Timings)>, ) -> Result>, RenderError> where @@ -556,7 +563,7 @@ where now, output, cursor_mode, - exclude_workspace_overview, + element_filter == ElementFilter::ExcludeWorkspaceOverview, )); #[cfg(feature = "debug")] @@ -642,8 +649,7 @@ where .as_ref() .filter(|f| !f.is_animating()) .is_some(); - let overlay_elements = - split_layer_elements(renderer, output, Layer::Overlay, exclude_workspace_overview); + let overlay_elements = split_layer_elements(renderer, output, Layer::Overlay, element_filter); // overlay is above everything elements @@ -655,7 +661,7 @@ where if !has_fullscreen { elements.extend_from_workspace_elements( - split_layer_elements(renderer, output, Layer::Top, exclude_workspace_overview), + split_layer_elements(renderer, output, Layer::Top, element_filter), (0, 0).into(), ); }; @@ -669,32 +675,34 @@ where // overlay redirect windows // they need to be over sticky windows, because they could be popups of sticky windows, // and we can't differenciate that. - elements.p_elements.extend( - shell - .override_redirect_windows - .iter() - .filter(|or| { - (*or) - .geometry() - .as_global() - .intersection(workspace.output.geometry()) - .is_some() - }) - .flat_map(|or| { - AsRenderElements::::render_elements::>( - or, - renderer, - (or.geometry().loc - workspace.output.geometry().loc.as_logical()) - .to_physical_precise_round(output_scale), - Scale::from(output_scale), - 1.0, - ) - }) - .map(|p_element| p_element.into()), - ); + if element_filter != ElementFilter::LayerShellOnly { + elements.p_elements.extend( + shell + .override_redirect_windows + .iter() + .filter(|or| { + (*or) + .geometry() + .as_global() + .intersection(workspace.output.geometry()) + .is_some() + }) + .flat_map(|or| { + AsRenderElements::::render_elements::>( + or, + renderer, + (or.geometry().loc - workspace.output.geometry().loc.as_logical()) + .to_physical_precise_round(output_scale), + Scale::from(output_scale), + 1.0, + ) + }) + .map(|p_element| p_element.into()), + ); + } // sticky windows - if !has_fullscreen { + if !has_fullscreen && element_filter != ElementFilter::LayerShellOnly { let alpha = match &overview.0 { OverviewMode::Started(_, started) => { (1.0 - (Instant::now().duration_since(*started).as_millis() @@ -784,7 +792,7 @@ where if !has_fullscreen { elements.extend_from_workspace_elements( - background_layer_elements(renderer, output, exclude_workspace_overview), + background_layer_elements(renderer, output, element_filter), offset.to_physical_precise_round(output_scale), ); } @@ -799,23 +807,25 @@ where None => (0, 0).into(), }; - elements.extend_from_workspace_elements( - workspace - .render::( - renderer, - (!move_active && is_active_space).then_some(&last_active_seat), - overview, - resize_indicator, - active_hint, - theme, - ) - .map_err(|_| OutputNoMode)?, - offset.to_physical_precise_round(output_scale), - ); + if element_filter != ElementFilter::LayerShellOnly { + elements.extend_from_workspace_elements( + workspace + .render::( + renderer, + (!move_active && is_active_space).then_some(&last_active_seat), + overview, + resize_indicator, + active_hint, + theme, + ) + .map_err(|_| OutputNoMode)?, + offset.to_physical_precise_round(output_scale), + ); + } if !has_fullscreen { elements.extend_from_workspace_elements( - background_layer_elements(renderer, output, exclude_workspace_overview), + background_layer_elements(renderer, output, element_filter), offset.to_physical_precise_round(output_scale), ); } @@ -827,7 +837,7 @@ pub fn split_layer_elements( renderer: &mut R, output: &Output, layer: Layer, - exclude_workspace_overview: bool, + element_filter: ElementFilter, ) -> SplitRenderElements> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, @@ -844,7 +854,10 @@ where layer_map .layers_on(layer) .rev() - .filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE)) + .filter(|s| { + !(element_filter == ElementFilter::ExcludeWorkspaceOverview + && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) + }) .filter_map(|surface| { layer_map .layer_geometry(surface) @@ -894,7 +907,7 @@ where pub fn background_layer_elements( renderer: &mut R, output: &Output, - exclude_workspace_overview: bool, + element_filter: ElementFilter, ) -> SplitRenderElements> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, @@ -903,13 +916,12 @@ where CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = - split_layer_elements(renderer, output, Layer::Bottom, exclude_workspace_overview); + let mut elements = split_layer_elements(renderer, output, Layer::Bottom, element_filter); elements.extend(split_layer_elements( renderer, output, Layer::Background, - exclude_workspace_overview, + element_filter, )); elements } @@ -989,7 +1001,7 @@ where previous_workspace, workspace, cursor_mode, - false, + ElementFilter::All, ); match result { @@ -1101,7 +1113,7 @@ pub fn render_workspace<'d, R, Target, OffTarget>( previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>, current: (WorkspaceHandle, usize), cursor_mode: CursorMode, - exclude_workspace_overview: bool, + element_filter: ElementFilter, ) -> Result<(RenderOutputResult<'d>, Vec>), RenderError> where R: Renderer @@ -1127,7 +1139,7 @@ where previous, current, cursor_mode, - exclude_workspace_overview, + element_filter, None, )?; diff --git a/src/wayland/handlers/screencopy/render.rs b/src/wayland/handlers/screencopy/render.rs index 6ad8b027..ab1f95ea 100644 --- a/src/wayland/handlers/screencopy/render.rs +++ b/src/wayland/handlers/screencopy/render.rs @@ -36,7 +36,7 @@ use crate::{ backend::render::{ cursor, element::{AsGlowRenderer, CosmicElement, DamageElement, FromGlesError}, - render_workspace, CursorMode, CLEAR_COLOR, + render_workspace, CursorMode, ElementFilter, CLEAR_COLOR, }, shell::{CosmicMappedRenderElement, CosmicSurface, WorkspaceRenderElement}, state::{BackendData, Common, State}, @@ -287,7 +287,7 @@ pub fn render_workspace_to_buffer( None, handle, cursor_mode, - true, + ElementFilter::ExcludeWorkspaceOverview, ) .map(|res| res.0) } else { @@ -316,7 +316,7 @@ pub fn render_workspace_to_buffer( None, handle, cursor_mode, - true, + ElementFilter::ExcludeWorkspaceOverview, ) .map(|res| res.0) } From 91b9003ef82d0ffa04c04e1bc870326c9191ca8b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 12 Jul 2024 16:03:17 -0700 Subject: [PATCH 4/6] Add `workspace_overview_is_open` function; put in a `utils::quirks` mod This is increasingly not just related to screencopy, so it's weird to add there. I don't see any other module that fits, so add one called "quirks" (like the Linux kernel uses for device-specific handling in generic drives). --- src/backend/kms/surface/mod.rs | 13 ++++--------- src/backend/render/mod.rs | 4 ++-- src/shell/mod.rs | 6 +++--- src/utils/mod.rs | 1 + src/utils/quirks.rs | 14 ++++++++++++++ src/wayland/handlers/screencopy/mod.rs | 2 -- 6 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 src/utils/quirks.rs diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index 18114192..33c08be6 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -7,11 +7,9 @@ use crate::{ }, shell::Shell, state::SurfaceDmabufFeedback, - utils::prelude::*, + utils::{prelude::*, quirks::workspace_overview_is_open}, wayland::{ - handlers::screencopy::{ - submit_buffer, FrameHolder, SessionData, WORKSPACE_OVERVIEW_NAMESPACE, - }, + handlers::screencopy::{submit_buffer, FrameHolder, SessionData}, protocols::screencopy::{ FailureReason, Frame as ScreencopyFrame, Session as ScreencopySession, }, @@ -48,7 +46,7 @@ use smithay::{ Bind, ImportDma, Offscreen, Renderer, Texture, }, }, - desktop::{layer_map_for_output, utils::OutputPresentationFeedback}, + desktop::utils::OutputPresentationFeedback, output::{Output, OutputNoMode}, reexports::{ calloop::{ @@ -871,10 +869,7 @@ impl SurfaceThreadState { std::mem::drop(shell); - let element_filter = if layer_map_for_output(output) - .layers() - .any(|s| s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) - { + let element_filter = if workspace_overview_is_open(output) { ElementFilter::LayerShellOnly } else { ElementFilter::All diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index bf322d1c..e0aa86d9 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -20,11 +20,11 @@ use crate::{ CosmicMappedRenderElement, OverviewMode, SeatExt, SessionLock, Trigger, WorkspaceDelta, WorkspaceRenderElement, }, - utils::prelude::*, + utils::{prelude::*, quirks::WORKSPACE_OVERVIEW_NAMESPACE}, wayland::{ handlers::{ data_device::get_dnd_icon, - screencopy::{render_session, FrameHolder, SessionData, WORKSPACE_OVERVIEW_NAMESPACE}, + screencopy::{render_session, FrameHolder, SessionData}, }, protocols::workspace::WorkspaceHandle, }, diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 92f1f201..95052d92 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -52,11 +52,11 @@ use smithay::{ use crate::{ backend::render::animations::spring::{Spring, SpringParams}, config::Config, - utils::prelude::*, + utils::{prelude::*, quirks::WORKSPACE_OVERVIEW_NAMESPACE}, wayland::{ handlers::{ - screencopy::WORKSPACE_OVERVIEW_NAMESPACE, toplevel_management::minimize_rectangle, - xdg_activation::ActivationContext, xdg_shell::popup::get_popup_toplevel, + toplevel_management::minimize_rectangle, xdg_activation::ActivationContext, + xdg_shell::popup::get_popup_toplevel, }, protocols::{ toplevel_info::{ diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 75a928b3..4da680ef 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -5,6 +5,7 @@ pub(crate) use self::ids::id_gen; pub mod geometry; pub mod iced; pub mod prelude; +pub mod quirks; pub mod rlimit; pub mod screenshot; pub mod tween; diff --git a/src/utils/quirks.rs b/src/utils/quirks.rs new file mode 100644 index 00000000..2ecda9fd --- /dev/null +++ b/src/utils/quirks.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use smithay::{desktop::layer_map_for_output, output::Output}; + +/// Layer shell namespace used by `cosmic-workspaces` +// TODO: Avoid special case, or add protocol to expose required behavior +pub const WORKSPACE_OVERVIEW_NAMESPACE: &str = "cosmic-workspace-overview"; + +/// Check if a workspace overview shell surface is open on the output +pub fn workspace_overview_is_open(output: &Output) -> bool { + layer_map_for_output(output) + .layers() + .any(|s| s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) +} diff --git a/src/wayland/handlers/screencopy/mod.rs b/src/wayland/handlers/screencopy/mod.rs index 9df67879..19b04bf3 100644 --- a/src/wayland/handlers/screencopy/mod.rs +++ b/src/wayland/handlers/screencopy/mod.rs @@ -39,8 +39,6 @@ pub use self::render::*; use self::user_data::*; pub use self::user_data::{FrameHolder, ScreencopySessions, SessionData, SessionHolder}; -pub const WORKSPACE_OVERVIEW_NAMESPACE: &str = "cosmic-workspace-overview"; - impl ScreencopyHandler for State { fn screencopy_state(&mut self) -> &mut ScreencopyState { &mut self.common.screencopy_state From 17f59c5db31869bad7b0fb34867baf0abda4ff2e Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 12 Jul 2024 18:27:30 -0700 Subject: [PATCH 5/6] Set `ElementFilter` in `render_output` to match kms backend This way the same behavior will apply in winit/x11 backends. --- src/backend/render/mod.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index e0aa86d9..7257bf07 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -20,7 +20,10 @@ use crate::{ CosmicMappedRenderElement, OverviewMode, SeatExt, SessionLock, Trigger, WorkspaceDelta, WorkspaceRenderElement, }, - utils::{prelude::*, quirks::WORKSPACE_OVERVIEW_NAMESPACE}, + utils::{ + prelude::*, + quirks::{workspace_overview_is_open, WORKSPACE_OVERVIEW_NAMESPACE}, + }, wayland::{ handlers::{ data_device::get_dnd_icon, @@ -988,6 +991,12 @@ where let workspace = (workspace.handle, idx); std::mem::drop(shell_ref); + let element_filter = if workspace_overview_is_open(output) { + ElementFilter::LayerShellOnly + } else { + ElementFilter::All + }; + let result = render_workspace( gpu, renderer, @@ -1001,7 +1010,7 @@ where previous_workspace, workspace, cursor_mode, - ElementFilter::All, + element_filter, ); match result { From a996f6460a31e7b7c6828c8c44dd8500fe9ac344 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 12 Jul 2024 18:30:41 -0700 Subject: [PATCH 6/6] Disable workspace change gestures when workspaces overview is open Without animation between workspaces, the behavior is a bit jarring. Disable for now until we have a better solution. --- src/input/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index c71bed8f..2f29f2c2 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -19,7 +19,7 @@ use crate::{ FocusResult, InvalidWorkspaceIndex, MoveResult, OverviewMode, ResizeMode, SeatExt, Trigger, WorkspaceDelta, }, - utils::prelude::*, + utils::{prelude::*, quirks::workspace_overview_is_open}, wayland::{ handlers::{screencopy::SessionHolder, xdg_activation::ActivationContext}, protocols::{ @@ -1000,7 +1000,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - if event.fingers() >= 3 { + if event.fingers() >= 3 && !workspace_overview_is_open(&seat.active_output()) { self.common.gesture_state = Some(GestureState::new(event.fingers())); } else { let serial = SERIAL_COUNTER.next_serial();