From 13f6428ce32ace8cbd480144ca42dd568cb91560 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Fri, 27 Sep 2024 23:41:58 +0200 Subject: [PATCH] render: Use `render_input_order` --- src/backend/render/element.rs | 6 +- src/backend/render/mod.rs | 580 ++++++++++-------------- src/shell/element/mod.rs | 73 +-- src/shell/element/stack.rs | 59 ++- src/shell/element/surface.rs | 65 +-- src/shell/element/window.rs | 71 ++- src/shell/grabs/moving.rs | 19 +- src/shell/layout/floating/mod.rs | 66 ++- src/shell/layout/tiling/mod.rs | 740 +++++++++++++++++++++---------- src/shell/workspace.rs | 236 ++++++++-- 10 files changed, 1153 insertions(+), 762 deletions(-) diff --git a/src/backend/render/element.rs b/src/backend/render/element.rs index dfedb3b8..3f8af67e 100644 --- a/src/backend/render/element.rs +++ b/src/backend/render/element.rs @@ -24,7 +24,7 @@ where ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - Workspace(RelocateRenderElement>), + Workspace(RelocateRenderElement>>), Cursor(RelocateRenderElement>), Dnd(WaylandSurfaceRenderElement), MoveGrab(CosmicMappedRenderElement), @@ -266,13 +266,13 @@ where } } -impl From> for CosmicElement +impl From>> for CosmicElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - fn from(elem: WorkspaceRenderElement) -> Self { + fn from(elem: CropRenderElement>) -> Self { Self::Workspace(RelocateRenderElement::from_element( elem, (0, 0), diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 80c78225..aa545068 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -4,6 +4,7 @@ use std::{ borrow::Borrow, cell::RefCell, collections::HashMap, + ops::ControlFlow, sync::{Arc, RwLock, Weak}, time::Instant, }; @@ -14,16 +15,13 @@ use crate::{ backend::{kms::render::gles::GbmGlowBackend, render::element::DamageElement}, shell::{ element::CosmicMappedKey, - focus::target::WindowGroup, + focus::{render_input_order, target::WindowGroup, Stage}, grabs::{SeatMenuGrabState, SeatMoveGrabState}, layout::tiling::ANIMATION_DURATION, - CosmicMappedRenderElement, OverviewMode, SeatExt, SessionLock, Trigger, WorkspaceDelta, + CosmicMappedRenderElement, OverviewMode, SeatExt, Trigger, WorkspaceDelta, WorkspaceRenderElement, }, - utils::{ - prelude::*, - quirks::{workspace_overview_is_open, WORKSPACE_OVERVIEW_NAMESPACE}, - }, + utils::{prelude::*, quirks::workspace_overview_is_open}, wayland::{ handlers::{ data_device::get_dnd_icon, @@ -34,9 +32,7 @@ use crate::{ }; use cosmic::Theme; -use cosmic_comp_config::workspace::WorkspaceLayout; use element::FromGlesError; -use keyframe::{ease, functions::EaseInOutCubic}; use smithay::{ backend::{ allocator::dmabuf::Dmabuf, @@ -46,7 +42,7 @@ use smithay::{ damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult}, element::{ surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, - utils::{Relocate, RelocateRenderElement}, + utils::{CropRenderElement, Relocate, RelocateRenderElement}, AsRenderElements, Element, Id, Kind, RenderElement, }, gles::{ @@ -60,13 +56,12 @@ use smithay::{ TextureFilter, }, }, - desktop::{layer_map_for_output, PopupManager}, input::Seat, output::{Output, OutputNoMode}, - utils::{IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Time, Transform}, + utils::{IsAlive, Logical, Monotonic, Point, Rectangle, Scale, Time, Transform}, wayland::{ dmabuf::get_dmabuf, - shell::wlr_layer::Layer, + session_lock::LockSurface, shm::{shm_format_to_fourcc, with_buffer_contents}, }, }; @@ -504,60 +499,6 @@ pub enum ElementFilter { LayerShellOnly, } -#[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>, @@ -578,7 +519,7 @@ where CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = SplitRenderElements::default(); + let mut elements = Vec::new(); let theme = shell.read().unwrap().theme().clone(); let seats = shell @@ -588,8 +529,9 @@ where .iter() .cloned() .collect::>(); + let scale = output.current_scale().fractional_scale(); - elements.p_elements.extend(cursor_elements( + elements.extend(cursor_elements( renderer, seats.iter(), &theme, @@ -602,7 +544,6 @@ where #[cfg(feature = "debug")] { let output_geo = output.geometry(); - let scale = output.current_scale().fractional_scale(); if let Some((state, timings)) = _fps { let debug_active = shell.read().unwrap().debug_active; @@ -621,23 +562,12 @@ where ) .map_err(FromGlesError::from_gles_error) .map_err(RenderError::Rendering)?; - elements.p_elements.push(fps_overlay.into()); + elements.push(fps_overlay.into()); } } let shell = shell.read().unwrap(); - // If session locked, only show session lock surfaces - if let Some(session_lock) = &shell.session_lock { - elements.p_elements.extend( - session_lock_elements(renderer, output, session_lock) - .into_iter() - .map(|x| WorkspaceRenderElement::from(x).into()), - ); - return Ok(elements.join()); - } - - let theme = theme.cosmic(); let overview = shell.overview_mode(); let (resize_mode, resize_indicator) = shell.resize_mode(); let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator)); @@ -666,310 +596,252 @@ where .unwrap() .is_some(); let focused_output = last_active_seat.focused_or_active_output(); - let output_size = output.geometry().size; - let output_scale = output.current_scale().fractional_scale(); - let set = shell.workspaces.sets.get(output).ok_or(OutputNoMode)?; let workspace = set .workspaces .iter() .find(|w| w.handle == current.0) .ok_or(OutputNoMode)?; - let is_active_space = workspace.outputs().any(|o| o == &focused_output); - - let has_fullscreen = workspace - .fullscreen - .as_ref() - .filter(|f| !f.is_animating()) - .is_some(); - let overlay_elements = split_layer_elements(renderer, output, Layer::Overlay, element_filter); - - // overlay is above everything - 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, element_filter), - (0, 0).into(), - ); - }; - + let is_active_space = workspace.output == focused_output; let active_hint = if shell.active_hint { - theme.active_hint as u8 + theme.cosmic().active_hint as u8 } else { 0 }; - // overlay redirect windows - // they need to be over sticky windows, because they could be popups of sticky windows, - // and we can't differenciate that. - 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 && element_filter != ElementFilter::LayerShellOnly { - let alpha = match &overview.0 { - OverviewMode::Started(_, started) => { - (1.0 - (Instant::now().duration_since(*started).as_millis() - / ANIMATION_DURATION.as_millis()) as f32) - .max(0.0) - * 0.4 - + 0.6 - } - OverviewMode::Ended(_, ended) => { - ((Instant::now().duration_since(*ended).as_millis() - / ANIMATION_DURATION.as_millis()) as f32) - * 0.4 - + 0.6 - } - OverviewMode::Active(_) => 0.6, - OverviewMode::None => 1.0, - }; - - let current_focus = (!move_active && is_active_space) - .then_some(last_active_seat) - .map(|seat| workspace.focus_stack.get(seat)); - - 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(), - ); - } - - let offset = match previous.as_ref() { - Some((previous, previous_idx, start)) => { - let layout = shell.workspaces.layout; + let output_size = output + .geometry() + .size + .as_logical() + .to_physical_precise_round(scale); + let crop_to_output = |element: WorkspaceRenderElement| { + CropRenderElement::from_element( + element.into(), + scale, + Rectangle::from_loc_and_size((0, 0), output_size), + ) + }; - let workspace = shell - .workspaces - .space_for_handle(&previous) - .ok_or(OutputNoMode)?; - let has_fullscreen = workspace.fullscreen.is_some(); - let is_active_space = workspace.outputs().any(|o| o == &focused_output); - - let percentage = match start { - WorkspaceDelta::Shortcut(st) => ease( - EaseInOutCubic, - 0.0, - 1.0, - Instant::now().duration_since(*st).as_millis() as f32 - / ANIMATION_DURATION.as_millis() as f32, - ), - WorkspaceDelta::Gesture(prog) => *prog as f32, - WorkspaceDelta::GestureEnd(st, spring) => { - (spring.value_at(Instant::now().duration_since(*st)) as f32).clamp(0.0, 1.0) + render_input_order( + &*shell, + output, + previous, + current, + element_filter, + |stage| { + match stage { + Stage::SessionLock(lock_surface) => { + elements.extend( + session_lock_elements(renderer, output, lock_surface) + .into_iter() + .map(Into::into) + .flat_map(crop_to_output) + .map(Into::into), + ); } - }; - let offset = Point::::from(match (layout, *previous_idx < current.1) { - (WorkspaceLayout::Vertical, true) => { - (0, (-output_size.h as f32 * percentage).round() as i32) + Stage::LayerPopup { + popup, location, .. + } => { + elements.extend( + render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( + renderer, + popup.wl_surface(), + location + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + Scale::from(scale), + 1.0, + Kind::Unspecified, + ) + .into_iter() + .flat_map(crop_to_output) + .map(Into::into), + ); } - (WorkspaceLayout::Vertical, false) => { - (0, (output_size.h as f32 * percentage).round() as i32) + Stage::LayerSurface { layer, location } => { + elements.extend( + render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( + renderer, + &layer.wl_surface(), + location + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + Scale::from(scale), + 1.0, + Kind::Unspecified, + ) + .into_iter() + .flat_map(crop_to_output) + .map(Into::into), + ); } - (WorkspaceLayout::Horizontal, true) => { - ((-output_size.w as f32 * percentage).round() as i32, 0) + Stage::OverrideRedirect { surface, location } => { + elements.extend( + AsRenderElements::::render_elements::>( + surface, + renderer, + location + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + Scale::from(scale), + 1.0, + ) + .into_iter() + .flat_map(crop_to_output) + .map(Into::into), + ); } - (WorkspaceLayout::Horizontal, false) => { - ((output_size.w as f32 * percentage).round() as i32, 0) + Stage::StickyPopups(layout) => { + let alpha = match &overview.0 { + OverviewMode::Started(_, started) => { + (1.0 - (Instant::now().duration_since(*started).as_millis() + / ANIMATION_DURATION.as_millis()) + as f32) + .max(0.0) + * 0.4 + + 0.6 + } + OverviewMode::Ended(_, ended) => { + ((Instant::now().duration_since(*ended).as_millis() + / ANIMATION_DURATION.as_millis()) + as f32) + * 0.4 + + 0.6 + } + OverviewMode::Active(_) => 0.6, + OverviewMode::None => 1.0, + }; + + elements.extend( + layout + .render_popups(renderer, alpha) + .into_iter() + .map(Into::into) + .flat_map(crop_to_output) + .map(Into::into), + ); } - }); - - 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, + Stage::Sticky(layout) => { + let alpha = match &overview.0 { + OverviewMode::Started(_, started) => { + (1.0 - (Instant::now().duration_since(*started).as_millis() + / ANIMATION_DURATION.as_millis()) + as f32) + .max(0.0) + * 0.4 + + 0.6 + } + OverviewMode::Ended(_, ended) => { + ((Instant::now().duration_since(*ended).as_millis() + / ANIMATION_DURATION.as_millis()) + as f32) + * 0.4 + + 0.6 + } + OverviewMode::Active(_) => 0.6, + OverviewMode::None => 1.0, + }; + + let current_focus = (!move_active && is_active_space) + .then_some(last_active_seat) + .map(|seat| workspace.focus_stack.get(seat)); + + elements.extend( + layout + .render( + renderer, + current_focus.as_ref().and_then(|stack| stack.last()), + resize_indicator.clone(), + active_hint, + alpha, + &theme.cosmic(), + ) + .into_iter() + .map(Into::into) + .flat_map(crop_to_output) + .map(Into::into), ) - .map_err(|_| OutputNoMode)?, - offset.to_physical_precise_round(output_scale), - ); - - if !has_fullscreen { - elements.extend_from_workspace_elements( - background_layer_elements(renderer, output, element_filter), - offset.to_physical_precise_round(output_scale), - ); - } - - Point::::from(match (layout, *previous_idx < current.1) { - (WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y), - (WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)), - (WorkspaceLayout::Horizontal, true) => (output_size.w + offset.x, 0), - (WorkspaceLayout::Horizontal, false) => (-(output_size.w - offset.x), 0), - }) - } - None => (0, 0).into(), - }; - - 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, element_filter), - offset.to_physical_precise_round(output_scale), - ); - } - - Ok(elements.join()) -} - -pub fn split_layer_elements( - renderer: &mut R, - output: &Output, - layer: Layer, - element_filter: ElementFilter, -) -> SplitRenderElements> -where - R: Renderer + ImportAll + ImportMem + AsGlowRenderer, - ::TextureId: Clone + 'static, - ::Error: FromGlesError, - CosmicMappedRenderElement: RenderElement, - WorkspaceRenderElement: RenderElement, -{ - let layer_map = layer_map_for_output(output); - let output_scale = output.current_scale().fractional_scale(); - - let mut elements = SplitRenderElements::default(); - - layer_map - .layers_on(layer) - .rev() - .filter(|s| { - !(element_filter == ElementFilter::ExcludeWorkspaceOverview - && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) - }) - .filter_map(|surface| { - layer_map - .layer_geometry(surface) - .map(|geo| (geo.loc, surface)) - }) - .for_each(|(location, surface)| { - let location = location.to_physical_precise_round(output_scale); - let surface = surface.wl_surface(); - let scale = Scale::from(output_scale); - - 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( + } + Stage::WorkspacePopups { workspace, offset } => { + elements.extend( + match workspace.render_popups( renderer, - popup.wl_surface(), - location + offset, - scale, - 1.0, - Kind::Unspecified, - ) - }, - )); - - elements - .w_elements - .extend(render_elements_from_surface_tree( - renderer, - surface, - location, - scale, - 1.0, - Kind::Unspecified, - )); - }); + (!move_active && is_active_space).then_some(last_active_seat), + overview.clone(), + &theme.cosmic(), + ) { + Ok(elements) => { + elements + .into_iter() + .flat_map(crop_to_output) + .map(|element| { + CosmicElement::Workspace( + RelocateRenderElement::from_element( + element, + offset.to_physical_precise_round(scale), + Relocate::Relative, + ), + ) + }) + } + Err(_) => { + return ControlFlow::Break(Err(OutputNoMode)); + } + }, + ); + } + Stage::Workspace { workspace, offset } => { + elements.extend( + match workspace.render( + renderer, + (!move_active && is_active_space).then_some(last_active_seat), + overview.clone(), + resize_indicator.clone(), + active_hint, + &theme.cosmic(), + ) { + Ok(elements) => { + elements + .into_iter() + .flat_map(crop_to_output) + .map(|element| { + CosmicElement::Workspace( + RelocateRenderElement::from_element( + element, + offset.to_physical_precise_round(scale), + Relocate::Relative, + ), + ) + }) + } + Err(_) => { + return ControlFlow::Break(Err(OutputNoMode)); + } + }, + ); + } + }; - elements -} + ControlFlow::Continue(()) + }, + )?; -// bottom and background layer surfaces -pub fn background_layer_elements( - renderer: &mut R, - output: &Output, - element_filter: ElementFilter, -) -> SplitRenderElements> -where - R: Renderer + ImportAll + ImportMem + AsGlowRenderer, - ::TextureId: Clone + 'static, - ::Error: FromGlesError, - CosmicMappedRenderElement: RenderElement, - WorkspaceRenderElement: RenderElement, -{ - let mut elements = split_layer_elements(renderer, output, Layer::Bottom, element_filter); - elements.extend(split_layer_elements( - renderer, - output, - Layer::Background, - element_filter, - )); - elements + Ok(elements) } fn session_lock_elements( renderer: &mut R, output: &Output, - session_lock: &SessionLock, + lock_surface: Option<&LockSurface>, ) -> Vec> where R: Renderer + ImportAll, ::TextureId: Clone + 'static, { - if let Some(surface) = session_lock.surfaces.get(output) { + if let Some(surface) = lock_surface { let scale = Scale::from(output.current_scale().fractional_scale()); render_elements_from_surface_tree( renderer, diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 4a2cfb67..0860c07d 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -1,8 +1,5 @@ use crate::{ - backend::render::{ - element::{AsGlowRenderer, FromGlesError}, - SplitRenderElements, - }, + backend::render::element::{AsGlowRenderer, FromGlesError}, state::State, utils::{iced::IcedElementInternal, prelude::*}, }; @@ -657,13 +654,42 @@ impl CosmicMapped { } } - pub fn split_render_elements( + pub fn popup_render_elements( &self, renderer: &mut R, location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, - ) -> SplitRenderElements + ) -> Vec + where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Send + Clone + 'static, + CosmicMappedRenderElement: RenderElement, + C: From>, + { + match &self.element { + CosmicMappedInternal::Stack(s) => s + .popup_render_elements::>( + renderer, location, scale, alpha, + ), + CosmicMappedInternal::Window(w) => w + .popup_render_elements::>( + renderer, location, scale, alpha, + ), + _ => unreachable!(), + } + .into_iter() + .map(C::from) + .collect() + } + + pub fn render_elements( + &self, + renderer: &mut R, + location: smithay::utils::Point, + scale: smithay::utils::Scale, + alpha: f32, + ) -> Vec where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -671,7 +697,7 @@ impl CosmicMapped { C: From>, { #[cfg(feature = "debug")] - let debug_elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { + 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) = @@ -840,30 +866,21 @@ impl CosmicMapped { Vec::new() }; #[cfg(not(feature = "debug"))] - let debug_elements = Vec::new(); - - let mut elements = SplitRenderElements { - w_elements: debug_elements, - p_elements: Vec::new(), - }; + let mut elements = Vec::new(); #[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.extend(match &self.element { + CosmicMappedInternal::Stack(s) => s.render_elements::>( + renderer, location, scale, alpha, + ), + CosmicMappedInternal::Window(w) => w + .render_elements::>( + renderer, location, scale, alpha, + ), + _ => unreachable!(), + }); - elements + elements.into_iter().map(C::from).collect() } pub(crate) fn update_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 2a9167a4..388eb813 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -1,6 +1,6 @@ use super::{surface::RESIZE_BORDER, window::Focus, CosmicSurface}; use crate::{ - backend::render::{cursor::CursorState, SplitRenderElements}, + backend::render::cursor::CursorState, shell::{ focus::target::PointerFocusTarget, grabs::{ReleaseMode, ResizeEdge}, @@ -541,13 +541,40 @@ impl CosmicStack { self.0.loop_handle() } - pub fn split_render_elements( + pub fn popup_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, - ) -> SplitRenderElements + ) -> Vec + where + R: Renderer + ImportAll + ImportMem, + ::TextureId: Send + Clone + 'static, + C: From>, + { + let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); + self.0.with_program(|p| { + let windows = p.windows.lock().unwrap(); + let active = p.active.load(Ordering::SeqCst); + + windows[active] + .popup_render_elements::>( + renderer, window_loc, scale, alpha, + ) + .into_iter() + .map(C::from) + .collect() + }) + } + + pub fn render_elements( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + alpha: f32, + ) -> Vec where R: Renderer + ImportAll + ImportMem, ::TextureId: Send + Clone + 'static, @@ -564,28 +591,20 @@ impl CosmicStack { let stack_loc = location + offset; let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); - let w_elements = AsRenderElements::::render_elements::>( + let mut elements = AsRenderElements::::render_elements::>( &self.0, renderer, stack_loc, scale, alpha, ); - let mut elements = SplitRenderElements { - w_elements: w_elements.into_iter().map(C::from).collect(), - p_elements: Vec::new(), - }; - - elements.extend_map( - self.0.with_program(|p| { - let windows = p.windows.lock().unwrap(); - let active = p.active.load(Ordering::SeqCst); + elements.extend(self.0.with_program(|p| { + let windows = p.windows.lock().unwrap(); + let active = p.active.load(Ordering::SeqCst); - windows[active].split_render_elements::>( - renderer, window_loc, scale, alpha, - ) - }), - C::from, - ); + windows[active].render_elements::>( + renderer, window_loc, scale, alpha, + ) + })); - elements + elements.into_iter().map(C::from).collect() } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index d13272e6..512f7e84 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -35,7 +35,9 @@ use smithay::{ }, wayland_server::protocol::wl_surface::WlSurface, }, - utils::{user_data::UserDataMap, IsAlive, Logical, Rectangle, Serial, Size}, + utils::{ + user_data::UserDataMap, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, + }, wayland::{ compositor::{with_states, SurfaceData}, seat::WaylandFocus, @@ -45,7 +47,6 @@ use smithay::{ }; use crate::{ - backend::render::SplitRenderElements, state::{State, SurfaceDmabufFeedback}, utils::prelude::*, wayland::handlers::decoration::PreferredDecorationMode, @@ -590,13 +591,13 @@ impl CosmicSurface { self.0.user_data() } - pub fn split_render_elements( + pub fn popup_render_elements( &self, renderer: &mut R, - location: smithay::utils::Point, - scale: smithay::utils::Scale, + location: Point, + scale: Scale, alpha: f32, - ) -> SplitRenderElements + ) -> Vec where R: Renderer + ImportAll, ::TextureId: Clone + 'static, @@ -605,9 +606,8 @@ impl CosmicSurface { match self.0.underlying_surface() { WindowSurface::Wayland(toplevel) => { let surface = toplevel.wl_surface(); - - let p_elements = PopupManager::popups_for_surface(surface) - .flat_map(|(popup, popup_offset)| { + PopupManager::popups_for_surface(surface) + .flat_map(move |(popup, popup_offset)| { let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc) .to_physical_precise_round(scale); @@ -620,26 +620,40 @@ impl CosmicSurface { element::Kind::Unspecified, ) }) - .collect(); + .collect() + } + WindowSurface::X11(_) => Vec::new(), + } + } + + pub fn render_elements( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + alpha: f32, + ) -> Vec + where + R: Renderer + ImportAll, + ::TextureId: Clone + 'static, + C: From>, + { + match self.0.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + let surface = toplevel.wl_surface(); - let w_elements = render_elements_from_surface_tree( + render_elements_from_surface_tree( renderer, surface, location, scale, alpha, element::Kind::Unspecified, - ); - - SplitRenderElements { - w_elements, - p_elements, - } + ) + } + WindowSurface::X11(surface) => { + surface.render_elements(renderer, location, scale, alpha) } - WindowSurface::X11(surface) => SplitRenderElements { - w_elements: surface.render_elements(renderer, location, scale, alpha), - p_elements: Vec::new(), - }, } } @@ -663,10 +677,7 @@ impl SpaceElement for CosmicSurface { SpaceElement::bbox(&self.0) } - fn is_in_input_region( - &self, - point: &smithay::utils::Point, - ) -> bool { + fn is_in_input_region(&self, point: &Point) -> bool { SpaceElement::is_in_input_region(&self.0, point) } @@ -784,8 +795,8 @@ where fn render_elements>( &self, renderer: &mut R, - location: smithay::utils::Point, - scale: smithay::utils::Scale, + location: Point, + scale: Scale, alpha: f32, ) -> Vec { self.0.render_elements(renderer, location, scale, alpha) diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 887ce664..9070994c 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -1,5 +1,5 @@ use crate::{ - backend::render::{cursor::CursorState, SplitRenderElements}, + backend::render::cursor::CursorState, shell::{ focus::target::PointerFocusTarget, grabs::{ReleaseMode, ResizeEdge}, @@ -41,7 +41,7 @@ use smithay::{ output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface, render_elements, - utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, + utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size}, wayland::seat::WaylandFocus, }; use std::{ @@ -308,13 +308,13 @@ impl CosmicWindow { self.0.loop_handle() } - pub fn split_render_elements( + pub fn popup_render_elements( &self, renderer: &mut R, - location: smithay::utils::Point, - scale: smithay::utils::Scale, + location: Point, + scale: Scale, alpha: f32, - ) -> SplitRenderElements + ) -> Vec where R: Renderer + ImportAll + ImportMem, ::TextureId: Send + Clone + 'static, @@ -328,17 +328,44 @@ impl CosmicWindow { location }; - let mut elements = SplitRenderElements::default(); + self.0.with_program(|p| { + p.window + .popup_render_elements::>( + renderer, window_loc, scale, alpha, + ) + .into_iter() + .map(C::from) + .collect() + }) + } - elements.extend_map( - self.0.with_program(|p| { - p.window - .split_render_elements::>( - renderer, window_loc, scale, alpha, - ) - }), - C::from, - ); + pub fn render_elements( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + alpha: f32, + ) -> Vec + where + R: Renderer + ImportAll + ImportMem, + ::TextureId: Send + Clone + '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 elements = Vec::new(); + + elements.extend(self.0.with_program(|p| { + p.window.render_elements::>( + renderer, window_loc, scale, alpha, + ) + })); if has_ssd { let ssd_loc = location @@ -346,16 +373,12 @@ impl CosmicWindow { .0 .with_program(|p| p.window.geometry().loc) .to_physical_precise_round(scale); - elements.w_elements.extend( - AsRenderElements::::render_elements::>( - &self.0, renderer, ssd_loc, scale, alpha, - ) - .into_iter() - .map(C::from), - ) + elements.extend(AsRenderElements::::render_elements::< + CosmicWindowRenderElement, + >(&self.0, renderer, ssd_loc, scale, alpha)) } - elements + elements.into_iter().map(C::from).collect() } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 9a41702e..25106fa6 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -2,8 +2,7 @@ use crate::{ backend::render::{ - cursor::CursorState, element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, - SplitRenderElements, Usage, + cursor::CursorState, element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage, }, shell::{ element::{ @@ -181,12 +180,18 @@ impl MoveGrabState { _ => vec![], }; - let SplitRenderElements { - w_elements, - p_elements, - } = self + let w_elements = self .window - .split_render_elements::>( + .render_elements::>( + renderer, + (render_location - self.window.geometry().loc) + .to_physical_precise_round(output_scale), + output_scale, + alpha, + ); + let p_elements = self + .window + .popup_render_elements::>( renderer, (render_location - self.window.geometry().loc) .to_physical_precise_round(output_scale), diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 140fb5d5..5c80fe62 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, SplitRenderElements, Usage}, + backend::render::{element::AsGlowRenderer, IndicatorShader, Key, Usage}, shell::{ element::{ resize_indicator::ResizeIndicator, @@ -1260,6 +1260,52 @@ impl FloatingLayout { } self.refresh(); //fixup any out of bounds elements } + #[profiling::function] + pub fn render_popups( + &self, + renderer: &mut R, + alpha: f32, + ) -> Vec> + where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Send + Clone + 'static, + CosmicMappedRenderElement: RenderElement, + CosmicWindowRenderElement: RenderElement, + CosmicStackRenderElement: RenderElement, + { + let output = self.space.outputs().next().unwrap(); + let output_scale = output.current_scale().fractional_scale(); + + let mut elements = Vec::default(); + + for elem in self + .animations + .iter() + .filter(|(_, anim)| matches!(anim, Animation::Minimize { .. })) + .map(|(elem, _)| elem) + .chain(self.space.elements().rev()) + { + let (geometry, alpha) = self + .animations + .get(elem) + .map(|anim| (*anim.previous_geometry(), alpha * anim.alpha())) + .unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha)); + + let render_location = geometry.loc - elem.geometry().loc.as_local(); + elements.extend( + elem.popup_render_elements( + renderer, + render_location + .as_logical() + .to_physical_precise_round(output_scale), + output_scale.into(), + alpha, + ), + ); + } + + elements + } #[profiling::function] pub fn render( @@ -1270,7 +1316,7 @@ impl FloatingLayout { indicator_thickness: u8, alpha: f32, theme: &cosmic::theme::CosmicTheme, - ) -> SplitRenderElements> + ) -> Vec> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -1285,7 +1331,7 @@ impl FloatingLayout { }; let output_scale = output.current_scale().fractional_scale(); - let mut elements = SplitRenderElements::default(); + let mut elements = Vec::default(); for elem in self .animations @@ -1301,10 +1347,7 @@ 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 SplitRenderElements { - mut w_elements, - p_elements, - } = elem.split_render_elements( + let mut window_elements = elem.render_elements( renderer, render_location .as_logical() @@ -1331,7 +1374,7 @@ impl FloatingLayout { y: geometry.size.h as f64 / buffer_size.h as f64, }; - w_elements = w_elements + window_elements = window_elements .into_iter() .map(|element| match element { CosmicMappedRenderElement::Stack(elem) => { @@ -1387,7 +1430,7 @@ impl FloatingLayout { resize.resize(resize_geometry.size.as_logical()); resize.output_enter(output, Rectangle::default() /* unused */); - elements.w_elements.extend( + window_elements.extend( resize .render_elements::>( renderer, @@ -1419,12 +1462,11 @@ impl FloatingLayout { active_window_hint.blue, ], ); - elements.w_elements.push(element.into()); + window_elements.push(element.into()); } } - elements.w_elements.extend(w_elements); - elements.p_elements.extend(p_elements); + elements.extend(window_elements); } elements diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index feeebcd8..308f8f8e 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, SplitRenderElements, Usage, - ACTIVE_GROUP_COLOR, GROUP_COLOR, + element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage, ACTIVE_GROUP_COLOR, + GROUP_COLOR, }, shell::{ element::{ @@ -60,7 +60,7 @@ use smithay::{ input::Seat, output::Output, reexports::wayland_server::Client, - utils::{IsAlive, Logical, Point, Rectangle, Scale, Size}, + utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Size}, wayland::{compositor::add_blocker, seat::WaylandFocus}, }; use std::{ @@ -3863,7 +3863,7 @@ impl TilingLayout { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &cosmic::theme::CosmicTheme, - ) -> Result>, OutputNotMapped> + ) -> Result>, OutputNotMapped> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -3896,7 +3896,7 @@ impl TilingLayout { }; let draw_groups = overview.0.alpha(); - let mut elements = SplitRenderElements::default(); + let mut elements = Vec::default(); let is_overview = !matches!(overview.0, OverviewMode::None); let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) @@ -3931,7 +3931,7 @@ impl TilingLayout { .unzip(); // all old windows we want to fade out - elements.extend(render_old_tree( + elements.extend(render_old_tree_windows( reference_tree, target_tree, renderer, @@ -3969,7 +3969,7 @@ impl TilingLayout { .unzip(); // all alive windows - elements.extend(render_new_tree( + elements.extend(render_new_tree_windows( target_tree, reference_tree, renderer, @@ -4001,12 +4001,139 @@ impl TilingLayout { // tiling hints if let Some(group_elements) = group_elements { - elements.w_elements.extend(group_elements); + elements.extend(group_elements); } Ok(elements) } + #[profiling::function] + pub fn render_popups( + &self, + renderer: &mut R, + seat: Option<&Seat>, + non_exclusive_zone: Rectangle, + overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), + theme: &cosmic::theme::CosmicTheme, + ) -> Result>, OutputNotMapped> + where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Send + Clone + 'static, + CosmicMappedRenderElement: RenderElement, + CosmicWindowRenderElement: RenderElement, + CosmicStackRenderElement: RenderElement, + { + let output_scale = self.output.current_scale().fractional_scale(); + + let (target_tree, duration, _) = if self.queue.animation_start.is_some() { + self.queue + .trees + .get(1) + .expect("Animation ongoing, should have two trees") + } else { + self.queue.trees.front().unwrap() + }; + let reference_tree = self + .queue + .animation_start + .is_some() + .then(|| &self.queue.trees.front().unwrap().0); + + let percentage = if let Some(animation_start) = self.queue.animation_start { + let percentage = Instant::now().duration_since(animation_start).as_millis() as f32 + / duration.as_millis() as f32; + ease(EaseInOutCubic, 0.0, 1.0, percentage) + } else { + 1.0 + }; + let draw_groups = overview.0.alpha(); + + let mut elements = Vec::default(); + + let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) + .then(|| self.last_overview_hover.as_ref().map(|x| &x.1)); + let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() { + Some(desc.clone()) + } else { + None + }; + + // all gone windows and fade them out + let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() { + let (geometries, _) = if let Some(transition) = draw_groups { + Some(geometries_for_groupview( + reference_tree, + &mut *renderer, + non_exclusive_zone, + seat, // TODO: Would be better to be an old focus, + // but for that we have to associate focus with a tree (and animate focus changes properly) + 1.0 - transition, + transition, + output_scale, + &self.placeholder_id, + is_mouse_tiling, + swap_desc.clone(), + overview.1.as_ref().and_then(|(_, tree)| tree.clone()), + theme, + )) + } else { + None + } + .unzip(); + + // all old windows we want to fade out + elements.extend(render_old_tree_popups( + reference_tree, + target_tree, + renderer, + geometries.clone(), + output_scale, + percentage, + swap_desc.is_some(), + )); + + geometries + } else { + None + }; + + let (geometries, _) = if let Some(transition) = draw_groups { + Some(geometries_for_groupview( + target_tree, + &mut *renderer, + non_exclusive_zone, + seat, + transition, + transition, + output_scale, + &self.placeholder_id, + is_mouse_tiling, + swap_desc.clone(), + overview.1.as_ref().and_then(|(_, tree)| tree.clone()), + theme, + )) + } else { + None + } + .unzip(); + + // all alive windows + elements.extend(render_new_tree_popups( + target_tree, + reference_tree, + renderer, + geometries, + old_geometries, + seat, + &self.output, + percentage, + overview, + swap_desc.clone(), + )); + + Ok(elements) + } + fn gaps(&self) -> (i32, i32) { let g = self.theme.cosmic().gaps; (g.0 as i32, g.1 as i32) @@ -4690,7 +4817,48 @@ where (geometries, elements) } -fn render_old_tree( +fn render_old_tree_popups( + reference_tree: &Tree, + target_tree: &Tree, + renderer: &mut R, + geometries: Option>>, + output_scale: f64, + percentage: f32, + is_swap_mode: bool, +) -> Vec> +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Send + Clone + 'static, + CosmicMappedRenderElement: RenderElement, + CosmicWindowRenderElement: RenderElement, + CosmicStackRenderElement: RenderElement, +{ + let mut elements = Vec::default(); + + render_old_tree( + reference_tree, + target_tree, + geometries, + output_scale, + percentage, + is_swap_mode, + |mapped, elem_geometry, geo, alpha, _| { + elements.extend( + mapped.popup_render_elements::>( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + Scale::from(output_scale), + alpha, + ), + ); + }, + ); + + elements +} + +fn render_old_tree_windows( reference_tree: &Tree, target_tree: &Tree, renderer: &mut R, @@ -4700,7 +4868,7 @@ fn render_old_tree( indicator_thickness: u8, is_swap_mode: bool, theme: &cosmic::theme::CosmicTheme, -) -> SplitRenderElements> +) -> Vec> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -4709,8 +4877,80 @@ where CosmicStackRenderElement: RenderElement, { let window_hint = crate::theme::active_window_hint(theme); - let mut elements = SplitRenderElements::default(); + let mut elements = Vec::default(); + + render_old_tree( + reference_tree, + target_tree, + geometries, + output_scale, + percentage, + is_swap_mode, + |mapped, elem_geometry, geo, alpha, is_minimizing| { + let window_elements = mapped.render_elements::>( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + Scale::from(output_scale), + alpha, + ); + + elements.extend(window_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 is_minimizing && indicator_thickness > 0 { + 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 +} +fn render_old_tree( + reference_tree: &Tree, + target_tree: &Tree, + geometries: Option>>, + output_scale: f64, + percentage: f32, + is_swap_mode: bool, + mut processor: impl FnMut(&CosmicMapped, Rectangle, Rectangle, f32, bool), +) { if let Some(root) = reference_tree.root_node_id() { let geometries = geometries.unwrap_or_default(); reference_tree @@ -4779,71 +5019,71 @@ where }; let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); - 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, - ); - 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 { - 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], - ), - )); - } - elements.p_elements.extend(p_elements); + processor(mapped, elem_geometry, geo, alpha, minimize_geo.is_some()) }); } +} - elements +fn render_new_tree_popups( + target_tree: &Tree, + reference_tree: Option<&Tree>, + renderer: &mut R, + geometries: Option>>, + old_geometries: Option>>, + seat: Option<&Seat>, + output: &Output, + percentage: f32, + overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), + swap_desc: Option, +) -> Vec> +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Send + Clone + 'static, + CosmicMappedRenderElement: RenderElement, + CosmicWindowRenderElement: RenderElement, + CosmicStackRenderElement: RenderElement, +{ + let mut popup_elements = Vec::new(); + let output_scale = output.current_scale().fractional_scale(); + + let is_active_output = seat + .map(|seat| &seat.active_output() == output) + .unwrap_or(false); + + let (_, swap_tree) = overview.1.unzip(); + let swap_desc = swap_desc.filter(|_| is_active_output); + let swap_tree = swap_tree.flatten().filter(|_| is_active_output); + + render_new_tree( + target_tree, + reference_tree, + geometries, + old_geometries, + percentage, + swap_tree, + swap_desc.as_ref(), + |_node_id, data, geo, _original_geo, alpha, _| { + if let Data::Mapped { mapped, .. } = data { + let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); + + popup_elements.extend( + mapped.popup_render_elements::>( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + Scale::from(output_scale), + alpha, + ), + ); + } + }, + ); + + popup_elements } -fn render_new_tree( +fn render_new_tree_windows( target_tree: &Tree, reference_tree: Option<&Tree>, renderer: &mut R, @@ -4862,7 +5102,7 @@ fn render_new_tree( swapping_stack_surface_id: &Id, placeholder_id: &Id, theme: &cosmic::theme::CosmicTheme, -) -> SplitRenderElements> +) -> Vec> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -4905,7 +5145,6 @@ where let mut animating_window_elements = Vec::new(); let mut window_elements = Vec::new(); - let mut popup_elements = Vec::new(); let mut group_backdrop = None; let mut indicators = Vec::new(); @@ -4916,10 +5155,11 @@ where let output_scale = output.current_scale().fractional_scale(); let (swap_indicator, swap_tree) = overview.1.unzip(); - let swap_tree = swap_tree.flatten().filter(|_| is_active_output); let swap_desc = swap_desc.filter(|_| is_active_output); + let swap_tree = swap_tree.flatten().filter(|_| is_active_output); let window_hint = crate::theme::active_window_hint(theme); let group_color = GROUP_COLOR; + // render placeholder, if we are swapping to an empty workspace if target_tree.root_node_id().is_none() && swap_desc.is_some() { window_elements.push( @@ -4968,165 +5208,48 @@ where (swap_geo.loc.as_logical() - window_geo.loc).to_physical_precise_round(output_scale); swap_elements.extend( - window - .render_elements::>( - renderer, - render_loc, - output_scale.into(), - 1.0, - ) - .into_iter() - .map(|window| { - CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element( - window, - swap_geo - .loc - .as_logical() - .to_physical_precise_round(output_scale), - ease( - Linear, - 1.0, - swap_factor(window_geo.size), - transition.unwrap_or(1.0), - ), - )) - }), + AsRenderElements::render_elements::>( + &window, + renderer, + render_loc, + output_scale.into(), + 1.0, + ) + .into_iter() + .map(|window| { + CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element( + window, + swap_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale), + ease( + Linear, + 1.0, + swap_factor(window_geo.size), + transition.unwrap_or(1.0), + ), + )) + }), ) } // render actual tree nodes - let old_geometries = old_geometries.unwrap_or_default(); - let geometries = geometries.unwrap_or_default(); - target_tree - .root_node_id() - .into_iter() - .flat_map(|root| target_tree.traverse_pre_order_ids(root).unwrap()) - .map(|id| (target_tree, id)) - .chain( - swap_tree - .into_iter() - .flat_map(|tree| { - let sub_root = &swap_desc.as_ref().unwrap().node; - if swap_desc.as_ref().unwrap().stack_window.is_none() { - Some( - tree.traverse_pre_order_ids(sub_root) - .unwrap() - .map(move |id| (tree, id)), - ) - } else { - None - } - }) - .flatten(), - ) - .for_each(|(target_tree, node_id)| { - let data = target_tree.get(&node_id).unwrap().data(); - let (original_geo, scaled_geo) = (data.geometry(), geometries.get(&node_id)); - - let (old_original_geo, old_scaled_geo) = - if let Some(reference_tree) = reference_tree.as_ref() { - if let Some(root) = reference_tree.root_node_id() { - reference_tree - .traverse_pre_order_ids(root) - .unwrap() - .find(|id| &node_id == id) - .map(|node_id| { - ( - reference_tree.get(&node_id).unwrap().data().geometry(), - old_geometries.get(&node_id), - ) - }) - } else { - None - } - } else { - None - } - .unzip(); - let mut old_geo = old_original_geo.map(|original_geo| { - let (scale, offset) = old_scaled_geo - .unwrap() - .map(|adapted_geo| scale_to_center(original_geo, adapted_geo)) - .unwrap_or_else(|| (1.0.into(), (0, 0).into())); - ( - old_scaled_geo - .unwrap() - .map(|adapted_geo| { - Rectangle::from_loc_and_size( - adapted_geo.loc + offset, - ( - (original_geo.size.w as f64 * scale).round() as i32, - (original_geo.size.h as f64 * scale).round() as i32, - ), - ) - }) - .unwrap_or(*original_geo), - 1.0, - ) - }); - - let was_minimized = if let Data::Mapped { - minimize_rect: Some(minimize_rect), - .. - } = &data - { - old_geo = Some((*minimize_rect, (percentage * 2.0).min(1.0))); - true - } else { - false - }; - - let (scale, offset) = scaled_geo - .map(|adapted_geo| scale_to_center(original_geo, adapted_geo)) - .unwrap_or_else(|| (1.0.into(), (0, 0).into())); - let new_geo = scaled_geo - .map(|adapted_geo| { - Rectangle::from_loc_and_size( - adapted_geo.loc + offset, - ( - (original_geo.size.w as f64 * scale).round() as i32, - (original_geo.size.h as f64 * scale).round() as i32, - ), - ) - }) - .unwrap_or(*original_geo); - - let (geo, alpha, animating) = if let Some((old_geo, alpha)) = old_geo.filter(|_| { - swap_desc - .as_ref() - .map(|desc| desc.node != node_id && desc.stack_window.is_none()) - .unwrap_or(true) - }) { - ( - if was_minimized { - ease( - EaseInOutCubic, - EaseRectangle(old_geo), - EaseRectangle(new_geo), - percentage, - ) - .unwrap() - } else { - ease( - Linear, - EaseRectangle(old_geo), - EaseRectangle(new_geo), - percentage, - ) - .unwrap() - }, - alpha, - old_geo != new_geo, - ) - } else { - (new_geo, percentage, false) - }; - + render_new_tree( + target_tree, + reference_tree, + geometries, + old_geometries, + percentage, + swap_tree, + swap_desc.as_ref(), + |node_id, data, geo, original_geo, alpha, animating| { if swap_desc.as_ref().map(|desc| &desc.node) == Some(&node_id) || focused.as_ref() == Some(&node_id) { if indicator_thickness > 0 || data.is_group() { let mut geo = geo.clone(); + if data.is_group() { let outer_gap: i32 = (if is_overview { GAP_KEYBOARD } else { 4 } as f32 * percentage) @@ -5251,10 +5374,8 @@ where if let Data::Mapped { mapped, .. } = data { let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); - let SplitRenderElements { - mut w_elements, - p_elements, - } = mapped.split_render_elements::>( + + let mut elements = mapped.render_elements::>( renderer, //original_location, geo.loc.as_logical().to_physical_precise_round(output_scale) @@ -5262,6 +5383,7 @@ where Scale::from(output_scale), alpha, ); + if swap_desc .as_ref() .filter(|swap_desc| swap_desc.node == node_id) @@ -5284,7 +5406,7 @@ where { let mut geo = mapped.active_window_geometry().as_local(); geo.loc += original_geo.loc; - w_elements.insert( + elements.insert( 0, CosmicMappedRenderElement::Overlay(BackdropShader::element( renderer, @@ -5305,7 +5427,7 @@ where (ConstrainScaleBehavior::CutOff, ConstrainAlign::TOP_LEFT) }; - let w_elements = w_elements.into_iter().flat_map(|element| match element { + let elements = 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) @@ -5344,6 +5466,7 @@ where .map(CosmicMappedRenderElement::TiledOverlay), x => Some(x), }); + if swap_desc .as_ref() .map(|swap_desc| { @@ -5356,21 +5479,19 @@ where }) .unwrap_or(false) { - swap_elements.extend(w_elements); + swap_elements.extend(elements); } else { if animating { - animating_window_elements.extend(w_elements); + animating_window_elements.extend(elements); } else { - window_elements.extend(w_elements); - } - if !mapped.is_maximized(false) { - popup_elements.extend(p_elements); + window_elements.extend(elements); } } } - }); + }, + ); - window_elements = resize_elements + resize_elements .into_iter() .flatten() .chain(swap_elements) @@ -5378,12 +5499,147 @@ where .chain(window_elements) .chain(animating_window_elements) .chain(group_backdrop.into_iter().map(Into::into)) - .collect(); + .collect() +} - SplitRenderElements { - w_elements: window_elements, - p_elements: popup_elements, - } +fn render_new_tree( + target_tree: &Tree, + reference_tree: Option<&Tree>, + geometries: Option>>, + old_geometries: Option>>, + percentage: f32, + swap_tree: Option<&Tree>, + swap_desc: Option<&NodeDesc>, + mut processor: impl FnMut(NodeId, &Data, Rectangle, &Rectangle, f32, bool), +) { + let old_geometries = old_geometries.unwrap_or_default(); + let geometries = geometries.unwrap_or_default(); + target_tree + .root_node_id() + .into_iter() + .flat_map(|root| target_tree.traverse_pre_order_ids(root).unwrap()) + .map(|id| (target_tree, id)) + .chain( + swap_tree + .into_iter() + .flat_map(|tree| { + let sub_root = &swap_desc.unwrap().node; + if swap_desc.unwrap().stack_window.is_none() { + Some( + tree.traverse_pre_order_ids(sub_root) + .unwrap() + .map(move |id| (tree, id)), + ) + } else { + None + } + }) + .flatten(), + ) + .for_each(|(target_tree, node_id)| { + let data = target_tree.get(&node_id).unwrap().data(); + let (original_geo, scaled_geo) = (data.geometry(), geometries.get(&node_id)); + + let (old_original_geo, old_scaled_geo) = + if let Some(reference_tree) = reference_tree.as_ref() { + if let Some(root) = reference_tree.root_node_id() { + reference_tree + .traverse_pre_order_ids(root) + .unwrap() + .find(|id| &node_id == id) + .map(|node_id| { + ( + reference_tree.get(&node_id).unwrap().data().geometry(), + old_geometries.get(&node_id), + ) + }) + } else { + None + } + } else { + None + } + .unzip(); + let mut old_geo = old_original_geo.map(|original_geo| { + let (scale, offset) = old_scaled_geo + .unwrap() + .map(|adapted_geo| scale_to_center(original_geo, adapted_geo)) + .unwrap_or_else(|| (1.0.into(), (0, 0).into())); + ( + old_scaled_geo + .unwrap() + .map(|adapted_geo| { + Rectangle::from_loc_and_size( + adapted_geo.loc + offset, + ( + (original_geo.size.w as f64 * scale).round() as i32, + (original_geo.size.h as f64 * scale).round() as i32, + ), + ) + }) + .unwrap_or(*original_geo), + 1.0, + ) + }); + + let was_minimized = if let Data::Mapped { + minimize_rect: Some(minimize_rect), + .. + } = &data + { + old_geo = Some((*minimize_rect, (percentage * 2.0).min(1.0))); + true + } else { + false + }; + + let (scale, offset) = scaled_geo + .map(|adapted_geo| scale_to_center(original_geo, adapted_geo)) + .unwrap_or_else(|| (1.0.into(), (0, 0).into())); + let new_geo = scaled_geo + .map(|adapted_geo| { + Rectangle::from_loc_and_size( + adapted_geo.loc + offset, + ( + (original_geo.size.w as f64 * scale).round() as i32, + (original_geo.size.h as f64 * scale).round() as i32, + ), + ) + }) + .unwrap_or(*original_geo); + + let (geo, alpha, animating) = if let Some((old_geo, alpha)) = old_geo.filter(|_| { + swap_desc + .map(|desc| desc.node != node_id && desc.stack_window.is_none()) + .unwrap_or(true) + }) { + ( + if was_minimized { + ease( + EaseInOutCubic, + EaseRectangle(old_geo), + EaseRectangle(new_geo), + percentage, + ) + .unwrap() + } else { + ease( + Linear, + EaseRectangle(old_geo), + EaseRectangle(new_geo), + percentage, + ) + .unwrap() + }, + alpha, + old_geo != new_geo, + ) + } else { + (new_geo, percentage, false) + }; + + processor(node_id, data, geo, original_geo, alpha, animating) + }); } fn scale_to_center( diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 8da5c2f5..0d0ac5f1 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -1,7 +1,7 @@ use crate::{ backend::render::{ element::{AsGlowRenderer, FromGlesError}, - BackdropShader, SplitRenderElements, + BackdropShader, }, shell::{ layout::{floating::FloatingLayout, tiling::TilingLayout}, @@ -921,10 +921,6 @@ impl Workspace { .chain(self.tiling_layer.mapped().map(|(w, _)| w)) } - pub fn outputs(&self) -> impl Iterator { - self.floating_layer.space.outputs() - } - pub fn is_empty(&self) -> bool { self.floating_layer.mapped().next().is_none() && self.tiling_layer.mapped().next().is_none() @@ -1012,7 +1008,7 @@ impl Workspace { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &CosmicTheme, - ) -> Result>, OutputNotMapped> + ) -> Result>, OutputNotMapped> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: Send + Clone + 'static, @@ -1021,7 +1017,7 @@ impl Workspace { CosmicStackRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = SplitRenderElements::default(); + let mut elements = Vec::default(); let output_scale = self.output.current_scale().fractional_scale(); let zone = { @@ -1104,26 +1100,19 @@ impl Workspace { y: target_geo.size.h as f64 / bbox.size.h as f64, }; - let SplitRenderElements { - w_elements, - p_elements, - } = fullscreen - .surface - .split_render_elements::>( - renderer, - render_loc, - output_scale.into(), - alpha, - ); - elements.w_elements.extend( - w_elements + elements.extend( + fullscreen + .surface + .render_elements::>( + renderer, + render_loc, + output_scale.into(), + alpha, + ) .into_iter() .map(|elem| RescaleRenderElement::from_element(elem, render_loc, scale)) .map(Into::into), ); - elements - .p_elements - .extend(p_elements.into_iter().map(Into::into)) } if self @@ -1155,16 +1144,18 @@ impl Workspace { OverviewMode::None => 1.0, }; - elements.extend_map( - self.floating_layer.render::( - renderer, - focused.as_ref(), - resize_indicator.clone(), - indicator_thickness, - alpha, - theme, - ), - WorkspaceRenderElement::from, + elements.extend( + self.floating_layer + .render::( + renderer, + focused.as_ref(), + resize_indicator.clone(), + indicator_thickness, + alpha, + theme, + ) + .into_iter() + .map(WorkspaceRenderElement::from), ); let alpha = match &overview.0 { @@ -1181,21 +1172,23 @@ impl Workspace { }; //tiling surfaces - elements.extend_map( - self.tiling_layer.render::( - renderer, - draw_focus_indicator, - zone, - overview, - resize_indicator, - indicator_thickness, - theme, - )?, - WorkspaceRenderElement::from, + elements.extend( + self.tiling_layer + .render::( + renderer, + draw_focus_indicator, + zone, + overview, + resize_indicator, + indicator_thickness, + theme, + )? + .into_iter() + .map(WorkspaceRenderElement::from), ); if let Some(alpha) = alpha { - elements.w_elements.push( + elements.push( Into::>::into(BackdropShader::element( renderer, self.backdrop_id.clone(), @@ -1214,6 +1207,159 @@ impl Workspace { Ok(elements) } + + #[profiling::function] + pub fn render_popups<'a, R>( + &self, + renderer: &mut R, + draw_focus_indicator: Option<&Seat>, + overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), + theme: &CosmicTheme, + ) -> Result>, OutputNotMapped> + where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Send + Clone + 'static, + CosmicMappedRenderElement: RenderElement, + CosmicWindowRenderElement: RenderElement, + CosmicStackRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, + { + let mut elements = Vec::default(); + + let output_scale = self.output.current_scale().fractional_scale(); + let zone = { + let layer_map = layer_map_for_output(&self.output); + layer_map.non_exclusive_zone().as_local() + }; + + if let Some(fullscreen) = self.fullscreen.as_ref() { + // fullscreen window + let bbox = fullscreen.surface.bbox().as_local(); + let element_geo = Rectangle::from_loc_and_size( + self.element_for_surface(&fullscreen.surface) + .and_then(|elem| { + self.floating_layer + .element_geometry(elem) + .or_else(|| self.tiling_layer.element_geometry(elem)) + .map(|mut geo| { + geo.loc -= elem.geometry().loc.as_local(); + geo + }) + }) + .unwrap_or(bbox) + .loc, + fullscreen.original_geometry.size.as_local(), + ); + + let mut full_geo = + Rectangle::from_loc_and_size((0, 0), self.output.geometry().size.as_local()); + if fullscreen.start_at.is_none() { + if bbox != full_geo { + if bbox.size.w < full_geo.size.w { + full_geo.loc.x += (full_geo.size.w - bbox.size.w) / 2; + full_geo.size.w = bbox.size.w; + } + if bbox.size.h < full_geo.size.h { + full_geo.loc.y += (full_geo.size.h - bbox.size.h) / 2; + full_geo.size.h = bbox.size.h; + } + } + } + + let (target_geo, alpha) = match (fullscreen.start_at, fullscreen.ended_at) { + (Some(started), _) => { + let duration = Instant::now().duration_since(started).as_secs_f64() + / FULLSCREEN_ANIMATION_DURATION.as_secs_f64(); + ( + ease( + EaseInOutCubic, + EaseRectangle(element_geo), + EaseRectangle(full_geo), + duration, + ) + .0, + ease(EaseInOutCubic, 0.0, 1.0, duration), + ) + } + (_, Some(ended)) => { + let duration = Instant::now().duration_since(ended).as_secs_f64() + / FULLSCREEN_ANIMATION_DURATION.as_secs_f64(); + ( + ease( + EaseInOutCubic, + EaseRectangle(full_geo), + EaseRectangle(element_geo), + duration, + ) + .0, + ease(EaseInOutCubic, 1.0, 0.0, duration), + ) + } + (None, None) => (full_geo, 1.0), + }; + + let render_loc = target_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale); + + elements.extend( + fullscreen + .surface + .popup_render_elements::>( + renderer, + render_loc, + output_scale.into(), + alpha, + ) + .into_iter() + .map(Into::into), + ); + } + + if self + .fullscreen + .as_ref() + .map(|f| f.start_at.is_some() || f.ended_at.is_some()) + .unwrap_or(true) + { + // floating surfaces + let alpha = match &overview.0 { + OverviewMode::Started(_, started) => { + (1.0 - (Instant::now().duration_since(*started).as_millis() + / ANIMATION_DURATION.as_millis()) as f32) + .max(0.0) + * 0.4 + + 0.6 + } + OverviewMode::Ended(_, ended) => { + ((Instant::now().duration_since(*ended).as_millis() + / ANIMATION_DURATION.as_millis()) as f32) + * 0.4 + + 0.6 + } + OverviewMode::Active(_) => 0.6, + OverviewMode::None => 1.0, + }; + + elements.extend( + self.floating_layer + .render_popups::(renderer, alpha) + .into_iter() + .map(WorkspaceRenderElement::from), + ); + + //tiling surfaces + elements.extend( + self.tiling_layer + .render_popups::(renderer, draw_focus_indicator, zone, overview, theme)? + .into_iter() + .map(WorkspaceRenderElement::from), + ); + } + + Ok(elements) + } } impl FocusStacks {