From c7d4fa5d53fa1d6b5289487ff5351335f35ecd53 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 13 Jul 2023 17:19:29 +0200 Subject: [PATCH] shell: Fix render order regarding popups --- src/backend/render/mod.rs | 281 ++++++++------- src/shell/element/mod.rs | 399 +++++++++++----------- src/shell/element/stack.rs | 88 ++--- src/shell/element/surface.rs | 69 +++- src/shell/element/window.rs | 89 ++--- src/shell/layout/floating/grabs/moving.rs | 29 +- src/shell/layout/floating/mod.rs | 64 ++-- src/shell/layout/tiling/mod.rs | 113 +++--- src/shell/workspace.rs | 88 ++--- 9 files changed, 676 insertions(+), 544 deletions(-) diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 9f9509e3..0bd5e877 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -46,8 +46,9 @@ use smithay::{ buffer_dimensions, damage::{Error as RenderError, OutputDamageTracker, OutputNoMode, RenderOutputResult}, element::{ + surface::render_elements_from_surface_tree, utils::{Relocate, RelocateRenderElement}, - AsRenderElements, Element, Id, RenderElement, + Element, Id, RenderElement, }, gles::{ element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform, @@ -59,7 +60,7 @@ use smithay::{ Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter, }, }, - desktop::layer_map_for_output, + desktop::{layer_map_for_output, PopupManager}, output::Output, utils::{IsAlive, Logical, Point, Rectangle, Scale}, wayland::{ @@ -495,14 +496,23 @@ where .shell .space_for_handle(¤t.0) .ok_or(OutputNoMode)?; - let has_fullscreen = workspace.fullscreen.contains_key(output); - // foreground layers are static - elements.extend( - foreground_layer_elements(renderer, output, has_fullscreen, exclude_workspace_overview) - .into_iter() - .map(Into::into), - ); + let has_fullscreen = workspace.fullscreen.contains_key(output); + let (overlay_elements, overlay_popups) = + 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() + }; let offset = match previous.as_ref() { Some((previous, previous_idx, start)) => { @@ -534,40 +544,49 @@ where } }); - elements.extend( - workspace - .render_output::( - renderer, - output, - &state.shell.override_redirect_windows, - state.xwayland_state.as_mut(), - (!move_active && is_active_space).then_some(&last_active_seat), - overview.clone(), - resize_indicator.clone(), - state.config.static_conf.active_hint, - ) - .map_err(|_| OutputNoMode)? - .into_iter() - .map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - }), - ); + let (w_elements, p_elements) = workspace + .render_output::( + renderer, + output, + &state.shell.override_redirect_windows, + state.xwayland_state.as_mut(), + (!move_active && is_active_space).then_some(&last_active_seat), + overview.clone(), + resize_indicator.clone(), + state.config.static_conf.active_hint, + ) + .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( - background_layer_elements(renderer, output, exclude_workspace_overview) - .into_iter() - .map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - }), - ); + 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, + )) + })); Point::::from(match (layout, *previous_idx < current.1) { (WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y), @@ -581,51 +600,66 @@ where let is_active_space = workspace.outputs().any(|o| o == &active_output); - elements.extend( - workspace - .render_output::( - renderer, - output, - &state.shell.override_redirect_windows, - state.xwayland_state.as_mut(), - (!move_active && is_active_space).then_some(&last_active_seat), - overview, - resize_indicator, - state.config.static_conf.active_hint, - ) - .map_err(|_| OutputNoMode)? - .into_iter() - .map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - }), - ); + let (w_elements, p_elements) = workspace + .render_output::( + renderer, + output, + &state.shell.override_redirect_windows, + state.xwayland_state.as_mut(), + (!move_active && is_active_space).then_some(&last_active_seat), + overview, + resize_indicator, + state.config.static_conf.active_hint, + ) + .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( - background_layer_elements(renderer, output, exclude_workspace_overview) - .into_iter() - .map(|w_element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - w_element, - offset.to_physical_precise_round(output_scale), - Relocate::Relative, - )) - }), - ); + 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(window_elements); Ok(elements) } -// bottom and background layer surfaces -pub fn foreground_layer_elements( +pub fn split_layer_elements( renderer: &mut R, output: &Output, - has_fullscreen: bool, + layer: Layer, exclude_workspace_overview: bool, -) -> Vec> +) -> ( + Vec>, + Vec>, +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Clone + 'static, @@ -636,32 +670,46 @@ 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(); + layer_map - .layers() + .layers_on(layer) .rev() .filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE)) - .filter(|s| { - if has_fullscreen { - matches!(s.layer(), Layer::Overlay) - } else { - matches!(s.layer(), Layer::Top | Layer::Overlay) - } - }) .filter_map(|surface| { layer_map .layer_geometry(surface) .map(|geo| (geo.loc, surface)) }) - .flat_map(|(loc, surface)| { - AsRenderElements::::render_elements::>( - surface, - renderer, - loc.to_physical_precise_round(output_scale), - Scale::from(output_scale), - 1.0, - ) - }) - .collect() + .for_each(|(location, surface)| { + let location = location.to_physical_precise_round(output_scale); + 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, + ) + }, + )); + + layer_elements.extend(render_elements_from_surface_tree( + renderer, surface, location, scale, 1.0, + )); + }); + + (layer_elements, popup_elements) } // bottom and background layer surfaces @@ -669,7 +717,10 @@ pub fn background_layer_elements( renderer: &mut R, output: &Output, exclude_workspace_overview: bool, -) -> Vec> +) -> ( + Vec>, + Vec>, +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Clone + 'static, @@ -677,29 +728,17 @@ where CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let layer_map = layer_map_for_output(output); - let output_scale = output.current_scale().fractional_scale(); - - layer_map - .layers() - .rev() - .filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE)) - .filter(|s| matches!(s.layer(), Layer::Background | Layer::Bottom)) - .filter_map(|surface| { - layer_map - .layer_geometry(surface) - .map(|geo| (geo.loc, surface)) - }) - .flat_map(|(loc, surface)| { - AsRenderElements::::render_elements::>( - surface, - renderer, - loc.to_physical_precise_round(output_scale), - Scale::from(output_scale), - 1.0, - ) - }) - .collect() + let (mut layer_elements, mut popup_elements) = + split_layer_elements(renderer, output, Layer::Bottom, exclude_workspace_overview); + let more = split_layer_elements( + renderer, + output, + Layer::Background, + exclude_workspace_overview, + ); + layer_elements.extend(more.0); + popup_elements.extend(more.1); + (layer_elements, popup_elements) } pub fn render_output( diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 2f4652d5..367948dd 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -14,7 +14,7 @@ use smithay::{ renderer::{ element::{ utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement}, - AsRenderElements, Element, RenderElement, UnderlyingStorage, + Element, RenderElement, UnderlyingStorage, }, gles::element::PixelShaderElement, glow::GlowRenderer, @@ -550,6 +550,206 @@ impl CosmicMapped { debug.take(); } } + + pub fn split_render_elements( + &self, + renderer: &mut R, + location: smithay::utils::Point, + scale: smithay::utils::Scale, + alpha: f32, + ) -> (Vec, Vec) + where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: 'static, + CosmicMappedRenderElement: RenderElement, + C: From>, + { + #[cfg(feature = "debug")] + let mut debug_elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { + let window = self.active_window(); + let window_geo = window.geometry(); + let (min_size, max_size, size) = + (window.min_size(), window.max_size(), window.geometry().size); + + let area = Rectangle::::from_loc_and_size( + location.to_f64().to_logical(scale).to_i32_round(), + self.bbox().size, + ); + + let glow_renderer = renderer.glow_renderer_mut(); + match debug.render( + |ctx| { + egui::Area::new("window") + .anchor( + egui::Align2::RIGHT_TOP, + [ + -window_geo.loc.x as f32 - 10.0, + window_geo.loc.y as f32 - 10.0, + ], + ) + .show(ctx, |ui| { + egui::Frame::none() + .fill(egui::Color32::BLACK) + .rounding(5.0) + .inner_margin(10.0) + .show(ui, |ui| { + ui.heading(window.title()); + ui.horizontal(|ui| { + ui.label("App ID: "); + ui.label(window.app_id()); + }); + ui.label(match window { + CosmicSurface::Wayland(_) => "Protocol: Wayland", + CosmicSurface::X11(_) => "Protocol: X11", + _ => unreachable!(), + }); + ui.horizontal(|ui| { + ui.label("States: "); + if window.is_maximized() { + ui.label("🗖"); + } + if window.is_fullscreen() { + ui.label("⬜"); + } + if window.is_activated() { + ui.label("🖱"); + } + if window.is_resizing().is_some() { + ui.label("↔"); + } + }); + + let plot = Plot::new("Sizes") + .legend(Legend::default().position(Corner::RightBottom)) + .data_aspect(1.0) + .view_aspect(1.0) + .show_x(false) + .show_y(false) + .width(200.0) + .height(200.0); + plot.show(ui, |plot_ui| { + let center = if let Some(max_size) = max_size { + ((max_size.w + 20) / 2, (max_size.h + 20) / 2) + } else { + (100, 100) + }; + + if let Some(max_size) = max_size { + let max_size_rect = + Polygon::new(PlotPoints::new(vec![ + [10.0, 10.0], + [max_size.w as f64 + 10.0, 10.0], + [ + max_size.w as f64 + 10.0, + max_size.h as f64 + 10.0, + ], + [10.0, max_size.h as f64 + 10.0], + [10.0, 10.0], + ])); + plot_ui.polygon( + max_size_rect + .name(format!("{}x{}", max_size.w, max_size.h)), + ); + } + + let size_rect = Polygon::new(PlotPoints::new(vec![ + [ + (center.0 - size.w / 2) as f64, + (center.1 - size.h / 2) as f64, + ], + [ + (center.0 + size.w / 2) as f64, + (center.1 - size.h / 2) as f64, + ], + [ + (center.0 + size.w / 2) as f64, + (center.1 + size.h / 2) as f64, + ], + [ + (center.0 - size.w / 2) as f64, + (center.1 + size.h / 2) as f64, + ], + [ + (center.0 - size.w / 2) as f64, + (center.1 - size.h / 2) as f64, + ], + ])); + plot_ui.polygon( + size_rect.name(format!("{}x{}", size.w, size.h)), + ); + + if let Some(min_size) = min_size { + let min_size_rect = + Polygon::new(PlotPoints::new(vec![ + [ + (center.0 - min_size.w / 2) as f64, + (center.1 - min_size.h / 2) as f64, + ], + [ + (center.0 + min_size.w / 2) as f64, + (center.1 - min_size.h / 2) as f64, + ], + [ + (center.0 + min_size.w / 2) as f64, + (center.1 + min_size.h / 2) as f64, + ], + [ + (center.0 - min_size.w / 2) as f64, + (center.1 + min_size.h / 2) as f64, + ], + [ + (center.0 - min_size.w / 2) as f64, + (center.1 - min_size.h / 2) as f64, + ], + ])); + plot_ui.polygon( + min_size_rect + .name(format!("{}x{}", min_size.w, min_size.h)), + ); + } + }) + }) + }); + }, + glow_renderer, + area, + scale.x, + 0.8, + ) { + Ok(element) => vec![element.into()], + Err(err) => { + debug!(?err, "Error rendering debug overlay."); + Vec::new() + } + } + } else { + Vec::new() + }; + #[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!(), + }; + + ( + debug_elements + .into_iter() + .map(C::from) + .chain(window_elements.into_iter().map(C::from)) + .collect(), + popup_elements.into_iter().map(C::from).collect(), + ) + } } impl IsAlive for CosmicMapped { @@ -1026,200 +1226,3 @@ where CosmicMappedRenderElement::Egui(elem) } } - -impl AsRenderElements for CosmicMapped -where - R: Renderer + ImportAll + ImportMem + AsGlowRenderer, - ::TextureId: 'static, - CosmicMappedRenderElement: RenderElement, -{ - type RenderElement = CosmicMappedRenderElement; - fn render_elements>( - &self, - renderer: &mut R, - location: Point, - scale: Scale, - alpha: f32, - ) -> Vec { - #[cfg(feature = "debug")] - let mut elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { - let window = self.active_window(); - let window_geo = window.geometry(); - let (min_size, max_size, size) = - (window.min_size(), window.max_size(), window.geometry().size); - - let area = Rectangle::::from_loc_and_size( - location.to_f64().to_logical(scale).to_i32_round(), - self.bbox().size, - ); - - let glow_renderer = renderer.glow_renderer_mut(); - match debug.render( - |ctx| { - egui::Area::new("window") - .anchor( - egui::Align2::RIGHT_TOP, - [ - -window_geo.loc.x as f32 - 10.0, - window_geo.loc.y as f32 - 10.0, - ], - ) - .show(ctx, |ui| { - egui::Frame::none() - .fill(egui::Color32::BLACK) - .rounding(5.0) - .inner_margin(10.0) - .show(ui, |ui| { - ui.heading(window.title()); - ui.horizontal(|ui| { - ui.label("App ID: "); - ui.label(window.app_id()); - }); - ui.label(match window { - CosmicSurface::Wayland(_) => "Protocol: Wayland", - CosmicSurface::X11(_) => "Protocol: X11", - _ => unreachable!(), - }); - ui.horizontal(|ui| { - ui.label("States: "); - if window.is_maximized() { - ui.label("🗖"); - } - if window.is_fullscreen() { - ui.label("⬜"); - } - if window.is_activated() { - ui.label("🖱"); - } - if window.is_resizing().is_some() { - ui.label("↔"); - } - }); - - let plot = Plot::new("Sizes") - .legend(Legend::default().position(Corner::RightBottom)) - .data_aspect(1.0) - .view_aspect(1.0) - .show_x(false) - .show_y(false) - .width(200.0) - .height(200.0); - plot.show(ui, |plot_ui| { - let center = if let Some(max_size) = max_size { - ((max_size.w + 20) / 2, (max_size.h + 20) / 2) - } else { - (100, 100) - }; - - if let Some(max_size) = max_size { - let max_size_rect = - Polygon::new(PlotPoints::new(vec![ - [10.0, 10.0], - [max_size.w as f64 + 10.0, 10.0], - [ - max_size.w as f64 + 10.0, - max_size.h as f64 + 10.0, - ], - [10.0, max_size.h as f64 + 10.0], - [10.0, 10.0], - ])); - plot_ui.polygon( - max_size_rect - .name(format!("{}x{}", max_size.w, max_size.h)), - ); - } - - let size_rect = Polygon::new(PlotPoints::new(vec![ - [ - (center.0 - size.w / 2) as f64, - (center.1 - size.h / 2) as f64, - ], - [ - (center.0 + size.w / 2) as f64, - (center.1 - size.h / 2) as f64, - ], - [ - (center.0 + size.w / 2) as f64, - (center.1 + size.h / 2) as f64, - ], - [ - (center.0 - size.w / 2) as f64, - (center.1 + size.h / 2) as f64, - ], - [ - (center.0 - size.w / 2) as f64, - (center.1 - size.h / 2) as f64, - ], - ])); - plot_ui.polygon( - size_rect.name(format!("{}x{}", size.w, size.h)), - ); - - if let Some(min_size) = min_size { - let min_size_rect = - Polygon::new(PlotPoints::new(vec![ - [ - (center.0 - min_size.w / 2) as f64, - (center.1 - min_size.h / 2) as f64, - ], - [ - (center.0 + min_size.w / 2) as f64, - (center.1 - min_size.h / 2) as f64, - ], - [ - (center.0 + min_size.w / 2) as f64, - (center.1 + min_size.h / 2) as f64, - ], - [ - (center.0 - min_size.w / 2) as f64, - (center.1 + min_size.h / 2) as f64, - ], - [ - (center.0 - min_size.w / 2) as f64, - (center.1 - min_size.h / 2) as f64, - ], - ])); - plot_ui.polygon( - min_size_rect - .name(format!("{}x{}", min_size.w, min_size.h)), - ); - } - }) - }) - }); - }, - glow_renderer, - area, - scale.x, - 0.8, - ) { - Ok(element) => vec![element.into()], - Err(err) => { - debug!(?err, "Error rendering debug overlay."); - Vec::new() - } - } - } else { - Vec::new() - }; - #[cfg(not(feature = "debug"))] - let mut elements = Vec::new(); - - #[cfg_attr(not(feature = "debug"), allow(unused_mut))] - match &self.element { - CosmicMappedInternal::Stack(s) => { - elements.extend(AsRenderElements::::render_elements::< - CosmicMappedRenderElement, - >(s, renderer, location, scale, alpha)) - } - CosmicMappedInternal::Window(w) => { - elements.extend(AsRenderElements::::render_elements::< - CosmicMappedRenderElement, - >(w, renderer, location, scale, alpha)) - } - _ => {} - }; - - elements.into_iter().map(C::from).collect() - } -} diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 88f702c9..475cc985 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -36,7 +36,7 @@ use smithay::{ }, output::Output, render_elements, - utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size}, + utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, wayland::seat::WaylandFocus, }; use std::{ @@ -462,6 +462,50 @@ impl CosmicStack { pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> { self.0.loop_handle() } + + pub fn split_render_elements( + &self, + renderer: &mut R, + location: smithay::utils::Point, + scale: smithay::utils::Scale, + alpha: f32, + ) -> (Vec, Vec) + where + R: Renderer + ImportAll + ImportMem, + ::TextureId: 'static, + C: From>, + { + let stack_loc = location + + self + .0 + .with_program(|p| { + p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] + .geometry() + .loc + }) + .to_physical_precise_round(scale); + let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); + + let elements = AsRenderElements::::render_elements::>( + &self.0, renderer, stack_loc, scale, alpha, + ); + + let (window_elements, popup_elements) = self.0.with_program(|p| { + p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] + .split_render_elements::>( + renderer, window_loc, scale, alpha, + ) + }); + + ( + elements + .into_iter() + .map(C::from) + .chain(window_elements.into_iter().map(C::from)) + .collect(), + popup_elements.into_iter().map(C::from).collect(), + ) + } } #[derive(Debug, Clone, Copy)] @@ -1061,45 +1105,3 @@ render_elements! { Header = MemoryRenderBufferRenderElement, Window = WaylandSurfaceRenderElement, } - -impl AsRenderElements for CosmicStack -where - R: Renderer + ImportAll + ImportMem, - ::TextureId: 'static, -{ - type RenderElement = CosmicStackRenderElement; - fn render_elements>( - &self, - renderer: &mut R, - location: Point, - scale: Scale, - alpha: f32, - ) -> Vec { - let stack_loc = location - + self - .0 - .with_program(|p| { - p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] - .geometry() - .loc - }) - .to_physical_precise_round(scale); - let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); - - let mut elements = AsRenderElements::::render_elements::>( - &self.0, renderer, stack_loc, scale, alpha, - ); - - elements.extend(self.0.with_program(|p| { - AsRenderElements::::render_elements::>( - &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)], - renderer, - window_loc, - scale, - alpha, - ) - })); - - elements.into_iter().map(C::from).collect() - } -} diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index ec29685c..e0cd6414 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -3,8 +3,9 @@ use std::time::Duration; use smithay::{ backend::renderer::{ element::{ - surface::WaylandSurfaceRenderElement, utils::select_dmabuf_feedback, AsRenderElements, - RenderElementStates, + surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, + utils::select_dmabuf_feedback, + AsRenderElements, RenderElementStates, }, ImportAll, Renderer, }, @@ -14,7 +15,7 @@ use smithay::{ take_presentation_feedback_surface_tree, with_surfaces_surface_tree, OutputPresentationFeedback, }, - Window, + PopupManager, Window, }, input::{keyboard::KeyboardTarget, pointer::PointerTarget}, output::Output, @@ -591,6 +592,50 @@ impl CosmicSurface { _ => unreachable!(), } } + + pub fn split_render_elements( + &self, + renderer: &mut R, + location: smithay::utils::Point, + scale: smithay::utils::Scale, + alpha: f32, + ) -> (Vec, Vec) + where + R: Renderer + ImportAll, + ::TextureId: 'static, + C: From>, + { + match self { + CosmicSurface::Wayland(window) => { + let surface = window.toplevel().wl_surface(); + + let popup_render_elements = PopupManager::popups_for_surface(surface) + .flat_map(|(popup, popup_offset)| { + let offset = (window.geometry().loc + popup_offset - popup.geometry().loc) + .to_physical_precise_round(scale); + + render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + location + offset, + scale, + alpha, + ) + }) + .collect(); + + let window_render_elements = + render_elements_from_surface_tree(renderer, surface, location, scale, alpha); + + (window_render_elements, popup_render_elements) + } + CosmicSurface::X11(surface) => ( + surface.render_elements(renderer, location, scale, alpha), + Vec::new(), + ), + _ => unreachable!(), + } + } } impl KeyboardTarget for CosmicSurface { @@ -761,6 +806,15 @@ impl WaylandFocus for CosmicSurface { } } +impl X11Relatable for CosmicSurface { + fn is_window(&self, window: &X11Surface) -> bool { + match self { + CosmicSurface::X11(surface) => surface == window, + _ => false, + } + } +} + impl AsRenderElements for CosmicSurface where R: Renderer + ImportAll, @@ -786,12 +840,3 @@ where } } } - -impl X11Relatable for CosmicSurface { - fn is_window(&self, window: &X11Surface) -> bool { - match self { - CosmicSurface::X11(surface) => surface == window, - _ => false, - } - } -} diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 614c72d7..ef6634b5 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -29,9 +29,7 @@ use smithay::{ }, output::Output, render_elements, - utils::{ - Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, - }, + utils::{Buffer as BufferCoords, IsAlive, Logical, Point, Rectangle, Serial, Size}, wayland::seat::WaylandFocus, }; use std::{ @@ -164,6 +162,50 @@ impl CosmicWindow { pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> { self.0.loop_handle() } + + pub fn split_render_elements( + &self, + renderer: &mut R, + location: smithay::utils::Point, + scale: smithay::utils::Scale, + alpha: f32, + ) -> (Vec, Vec) + where + R: Renderer + ImportAll + ImportMem, + ::TextureId: 'static, + C: From>, + { + let has_ssd = self.0.with_program(|p| p.has_ssd(false)); + + let window_loc = if has_ssd { + location + Point::from((0, (SSD_HEIGHT as f64 * scale.y) as i32)) + } else { + location + }; + + let (mut window_elements, popup_elements) = self.0.with_program(|p| { + p.window + .split_render_elements::>( + renderer, window_loc, scale, alpha, + ) + }); + + if has_ssd { + let ssd_loc = location + + self + .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)) + } + + ( + window_elements.into_iter().map(C::from).collect(), + popup_elements.into_iter().map(C::from).collect(), + ) + } } #[derive(Debug, Clone, Copy)] @@ -555,44 +597,3 @@ render_elements! { Header = MemoryRenderBufferRenderElement, Window = WaylandSurfaceRenderElement, } - -impl AsRenderElements for CosmicWindow -where - R: Renderer + ImportAll + ImportMem, - ::TextureId: 'static, -{ - type RenderElement = CosmicWindowRenderElement; - fn render_elements>( - &self, - renderer: &mut R, - location: Point, - scale: Scale, - alpha: f32, - ) -> Vec { - let has_ssd = self.0.with_program(|p| p.has_ssd(false)); - - let window_loc = if has_ssd { - location + Point::from((0, (SSD_HEIGHT as f64 * scale.y) as i32)) - } else { - location - }; - - let mut elements = self.0.with_program(|p| { - AsRenderElements::::render_elements::>( - &p.window, renderer, window_loc, scale, alpha, - ) - }); - if has_ssd { - let ssd_loc = location - + self - .0 - .with_program(|p| p.window.geometry().loc) - .to_physical_precise_round(scale); - elements.extend(AsRenderElements::::render_elements::< - CosmicWindowRenderElement, - >(&self.0, renderer, ssd_loc, scale, alpha)) - } - - elements.into_iter().map(C::from).collect() - } -} diff --git a/src/shell/layout/floating/grabs/moving.rs b/src/shell/layout/floating/grabs/moving.rs index a0e76164..404aa4cc 100644 --- a/src/shell/layout/floating/grabs/moving.rs +++ b/src/shell/layout/floating/grabs/moving.rs @@ -11,10 +11,7 @@ use crate::{ }; use smithay::{ - backend::renderer::{ - element::{AsRenderElements, RenderElement}, - ImportAll, ImportMem, Renderer, - }, + backend::renderer::{element::RenderElement, ImportAll, ImportMem, Renderer}, desktop::space::SpaceElement, input::{ pointer::{ @@ -60,9 +57,8 @@ impl MoveGrabState { let scale = output.current_scale().fractional_scale().into(); let render_location = cursor_at.to_i32_round() - output.geometry().loc + self.window_offset; - let mut elements: Vec = Vec::new(); - if self.indicator_thickness > 0 { - elements.push( + let focus_element = if self.indicator_thickness > 0 { + Some( CosmicMappedRenderElement::from(IndicatorShader::focus_element( renderer, self.window.clone(), @@ -71,16 +67,23 @@ impl MoveGrabState { 1.0, )) .into(), - ); - } - elements.extend(AsRenderElements::::render_elements::( - &self.window, + ) + } else { + None + }; + + let (window_elements, popup_elements) = self.window.split_render_elements::( renderer, (render_location - self.window.geometry().loc).to_physical_precise_round(scale), scale, 1.0, - )); - elements + ); + + popup_elements + .into_iter() + .chain(focus_element) + .chain(window_elements) + .collect() } pub fn send_frames( diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 273331f3..c0293563 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -438,7 +438,10 @@ impl FloatingLayout { mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, alpha: f32, - ) -> Vec> + ) -> ( + Vec>, + Vec>, + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, @@ -452,25 +455,49 @@ impl FloatingLayout { let output_scale = output.current_scale().fractional_scale(); let output_geo = self.space.output_geometry(output).unwrap(); + let mut window_elements = Vec::new(); + let mut popup_elements = Vec::new(); + self.space .elements_for_output(output) .rev() - .flat_map(|elem| { + .for_each(|elem| { let render_location = self.space.element_location(elem).unwrap() - output_geo.loc - elem.geometry().loc; - let mut elements = elem.render_elements( + let (w_elements, p_elements) = elem.split_render_elements( renderer, render_location.to_physical_precise_round(output_scale), output_scale.into(), alpha, ); + if focused == Some(elem) { let mut indicator_geometry = Rectangle::from_loc_and_size( self.space.element_location(elem).unwrap() - output_geo.loc, elem.geometry().size, ); + if let Some((mode, resize)) = resize_indicator.as_mut() { + indicator_geometry.loc -= (18, 18).into(); + indicator_geometry.size += (36, 36).into(); + resize.resize(indicator_geometry.size); + resize.output_enter(output, output_geo); + window_elements.extend( + resize + .render_elements::>( + renderer, + indicator_geometry + .loc + .to_physical_precise_round(output_scale), + output_scale.into(), + alpha * mode.alpha().unwrap_or(1.0), + ) + .into_iter() + .map(CosmicMappedRenderElement::Window), + ); + } + if indicator_thickness > 0 { let element = IndicatorShader::focus_element( renderer, @@ -479,31 +506,14 @@ impl FloatingLayout { indicator_thickness, alpha, ); - elements.insert(0, element.into()); - } - - if let Some((mode, resize)) = resize_indicator.as_mut() { - indicator_geometry.loc -= (18, 18).into(); - indicator_geometry.size += (36, 36).into(); - resize.resize(indicator_geometry.size); - resize.output_enter(output, output_geo); - elements = resize - .render_elements::>( - renderer, - indicator_geometry - .loc - .to_physical_precise_round(output_scale), - output_scale.into(), - alpha * mode.alpha().unwrap_or(1.0), - ) - .into_iter() - .map(CosmicMappedRenderElement::Window) - .chain(elements.into_iter()) - .collect(); + window_elements.push(element.into()); } } - elements - }) - .collect() + + window_elements.extend(w_elements); + popup_elements.extend(p_elements); + }); + + (window_elements, popup_elements) } } diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index a0555cc0..62cea022 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -1974,7 +1974,13 @@ impl TilingLayout { overview: OverviewMode, resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, - ) -> Result>, OutputNotMapped> + ) -> Result< + ( + Vec>, + Vec>, + ), + OutputNotMapped, + > where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, @@ -2014,7 +2020,8 @@ impl TilingLayout { }; let draw_groups = overview.alpha(); - let mut elements = Vec::new(); + let mut window_elements = Vec::new(); + let mut popup_elements = Vec::new(); // all gone windows and fade them out let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() { @@ -2034,14 +2041,16 @@ impl TilingLayout { .unzip(); // all old windows we want to fade out - elements.extend(render_old_tree( + let (w_elements, p_elements) = render_old_tree( reference_tree, target_tree, renderer, geometries.clone(), output_scale, percentage, - )); + ); + window_elements.extend(w_elements); + popup_elements.extend(p_elements); geometries } else { @@ -2063,7 +2072,7 @@ impl TilingLayout { .unzip(); // all alive windows - elements.extend(render_new_tree( + let (w_elements, p_elements) = render_new_tree( target_tree, reference_tree, renderer, @@ -2083,14 +2092,16 @@ impl TilingLayout { indicator_thickness }, resize_indicator, - )); + ); + window_elements.extend(w_elements); + popup_elements.extend(p_elements); // tiling hints if let Some(group_elements) = group_elements { - elements.extend(group_elements); + window_elements.extend(group_elements); } - Ok(elements) + Ok((window_elements, popup_elements)) } } @@ -2340,7 +2351,10 @@ fn render_old_tree( geometries: Option>>, output_scale: f64, percentage: f32, -) -> Vec> +) -> ( + Vec>, + Vec>, +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, @@ -2348,6 +2362,9 @@ where CosmicWindowRenderElement: RenderElement, CosmicStackRenderElement: RenderElement, { + let mut window_elements = Vec::new(); + let mut popup_elements = Vec::new(); + if let Some(root) = reference_tree.root_node_id() { let geometries = geometries.unwrap_or_default(); reference_tree @@ -2374,7 +2391,7 @@ where true } }) - .flat_map(|(mapped, original_geo, scaled_geo)| { + .for_each(|(mapped, original_geo, scaled_geo)| { let (scale, offset) = scaled_geo .map(|adapted_geo| scale_to_center(&original_geo, adapted_geo)) .unwrap_or_else(|| (1.0.into(), (0, 0).into())); @@ -2396,15 +2413,16 @@ where .geometry() .loc .to_physical_precise_round(output_scale); - AsRenderElements::::render_elements::>( - mapped, - renderer, - original_location, - Scale::from(output_scale), - 1.0 - percentage, - ) - .into_iter() - .flat_map(|element| match element { + + let (w_elements, p_elements) = mapped + .split_render_elements::>( + renderer, + original_location, + Scale::from(output_scale), + 1.0 - percentage, + ); + + window_elements.extend(w_elements.into_iter().flat_map(|element| match element { CosmicMappedRenderElement::Stack(elem) => { Some(CosmicMappedRenderElement::TiledStack({ let cropped = CropRenderElement::from_element( @@ -2448,13 +2466,12 @@ where })) } x => Some(x), - }) - .collect::>() - }) - .collect() - } else { - Vec::new() + })); + popup_elements.extend(p_elements); + }); } + + (window_elements, popup_elements) } fn render_new_tree( @@ -2468,7 +2485,10 @@ fn render_new_tree( percentage: f32, indicator_thickness: u8, mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>, -) -> Vec> +) -> ( + Vec>, + Vec>, +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, @@ -2491,6 +2511,9 @@ where }) .map(|(id, _)| id); + let mut window_elements = Vec::new(); + let mut popup_elements = Vec::new(); + let mut group_backdrop = None; let mut indicator = None; let mut resize_elements = None; @@ -2501,10 +2524,10 @@ where if let Some(root) = target_tree.root_node_id() { let old_geometries = old_geometries.unwrap_or_default(); let geometries = geometries.unwrap_or_default(); - let elements: Vec> = target_tree + target_tree .traverse_pre_order_ids(root) .unwrap() - .flat_map(|node_id| { + .for_each(|node_id| { let data = target_tree.get(&node_id).unwrap().data(); let (original_geo, scaled_geo) = (data.geometry(), geometries.get(&node_id)); @@ -2589,8 +2612,6 @@ where (new_geo, percentage) }; - let mut elements = Vec::new(); - if focused.as_ref() == Some(&node_id) { if indicator_thickness > 0 || data.is_group() { let mut geo = geo.clone(); @@ -2668,16 +2689,16 @@ where let original_location = (original_geo.loc - mapped.geometry().loc) .to_physical_precise_round(output_scale); - elements.extend( - AsRenderElements::::render_elements::>( - mapped, + let (w_elements, p_elements) = mapped + .split_render_elements::>( renderer, original_location, Scale::from(output_scale), alpha, - ) - .into_iter() - .flat_map(|element| match element { + ); + + window_elements.extend(w_elements.into_iter().flat_map( + |element| match element { CosmicMappedRenderElement::Stack(elem) => { Some(CosmicMappedRenderElement::TiledStack({ let cropped = CropRenderElement::from_element( @@ -2721,24 +2742,22 @@ where })) } x => Some(x), - }), - ); + }, + )); + popup_elements.extend(p_elements) } + }); - elements - }) - .collect(); - - resize_elements + window_elements = resize_elements .into_iter() .flatten() .chain(indicator.into_iter().map(Into::into)) - .chain(elements) + .chain(window_elements) .chain(group_backdrop.into_iter().map(Into::into)) - .collect() - } else { - Vec::new() + .collect(); } + + (window_elements, popup_elements) } fn scale_to_center( diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 65aefa2b..6bacf04a 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -493,7 +493,13 @@ impl Workspace { overview: OverviewMode, resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, - ) -> Result>, OutputNotMapped> + ) -> Result< + ( + Vec>, + Vec>, + ), + OutputNotMapped, + > where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, @@ -505,14 +511,15 @@ impl Workspace { #[cfg(feature = "debug")] puffin::profile_function!(); - let mut render_elements = Vec::new(); + let mut window_elements = Vec::new(); + let mut popup_elements = Vec::new(); let output_scale = output.current_scale().fractional_scale(); let layer_map = layer_map_for_output(output); let zone = layer_map.non_exclusive_zone(); if let Some(fullscreen) = self.fullscreen.get(output) { - render_elements.extend( + popup_elements.extend( override_redirect_windows .iter() .filter(|or| or.geometry().intersection(output.geometry()).is_some()) @@ -529,7 +536,7 @@ impl Workspace { ); // fullscreen window - render_elements.extend(AsRenderElements::::render_elements::< + window_elements.extend(AsRenderElements::::render_elements::< WorkspaceRenderElement, >( fullscreen, @@ -540,9 +547,13 @@ impl Workspace { )); if let Some(xwm) = xwm_state.and_then(|state| state.xwm.as_mut()) { - if let Err(err) = - xwm.update_stacking_order_upwards(render_elements.iter().rev().map(|e| e.id())) - { + if let Err(err) = xwm.update_stacking_order_upwards( + popup_elements + .iter() + .rev() + .map(|e| e.id()) + .chain(window_elements.iter().rev().map(|e| e.id())), + ) { warn!( wm_id = ?xwm.id(), ?err, @@ -556,7 +567,7 @@ impl Workspace { // - resizing in tiling // OR windows above all - render_elements.extend( + popup_elements.extend( override_redirect_windows .iter() .filter(|or| or.geometry().intersection(output.geometry()).is_some()) @@ -592,40 +603,39 @@ impl Workspace { } OverviewMode::None => 1.0, }; - render_elements.extend( - self.floating_layer - .render_output::( - renderer, - output, - focused.as_ref(), - resize_indicator.clone(), - indicator_thickness, - alpha, - ) - .into_iter() - .map(WorkspaceRenderElement::from), + + let (w_elements, p_elements) = self.floating_layer.render_output::( + renderer, + output, + focused.as_ref(), + resize_indicator.clone(), + indicator_thickness, + alpha, ); + popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); + window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); //tiling surfaces - render_elements.extend( - self.tiling_layer - .render_output::( - renderer, - output, - draw_focus_indicator, - layer_map.non_exclusive_zone(), - overview.clone(), - resize_indicator, - indicator_thickness, - )? - .into_iter() - .map(WorkspaceRenderElement::from), - ); + let (w_elements, p_elements) = self.tiling_layer.render_output::( + renderer, + output, + draw_focus_indicator, + layer_map.non_exclusive_zone(), + overview.clone(), + resize_indicator, + indicator_thickness, + )?; + popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from)); + window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from)); if let Some(xwm) = xwm_state.and_then(|state| state.xwm.as_mut()) { - if let Err(err) = - xwm.update_stacking_order_upwards(render_elements.iter().rev().map(|e| e.id())) - { + if let Err(err) = xwm.update_stacking_order_upwards( + popup_elements + .iter() + .rev() + .map(|e| e.id()) + .chain(window_elements.iter().rev().map(|e| e.id())), + ) { warn!( wm_id = ?xwm.id(), ?err, @@ -647,7 +657,7 @@ impl Workspace { }; if let Some(alpha) = alpha { - render_elements.push( + window_elements.push( Into::>::into(BackdropShader::element( renderer, self.backdrop_id.clone(), @@ -661,7 +671,7 @@ impl Workspace { } } - Ok(render_elements) + Ok((window_elements, popup_elements)) } }