render: Use render_input_order

This commit is contained in:
Victoria Brekenfeld 2024-09-27 23:41:58 +02:00 committed by Victoria Brekenfeld
parent 140d870e7b
commit 51c8588f89
10 changed files with 1154 additions and 763 deletions

View file

@ -24,7 +24,7 @@ where
<R as Renderer>::TextureId: 'static, <R as Renderer>::TextureId: 'static,
CosmicMappedRenderElement<R>: RenderElement<R>, CosmicMappedRenderElement<R>: RenderElement<R>,
{ {
Workspace(RelocateRenderElement<WorkspaceRenderElement<R>>), Workspace(RelocateRenderElement<CropRenderElement<WorkspaceRenderElement<R>>>),
Cursor(RelocateRenderElement<CursorRenderElement<R>>), Cursor(RelocateRenderElement<CursorRenderElement<R>>),
Dnd(WaylandSurfaceRenderElement<R>), Dnd(WaylandSurfaceRenderElement<R>),
MoveGrab(CosmicMappedRenderElement<R>), MoveGrab(CosmicMappedRenderElement<R>),
@ -266,13 +266,13 @@ where
} }
} }
impl<R> From<WorkspaceRenderElement<R>> for CosmicElement<R> impl<R> From<CropRenderElement<WorkspaceRenderElement<R>>> for CosmicElement<R>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: 'static, <R as Renderer>::TextureId: 'static,
CosmicMappedRenderElement<R>: RenderElement<R>, CosmicMappedRenderElement<R>: RenderElement<R>,
{ {
fn from(elem: WorkspaceRenderElement<R>) -> Self { fn from(elem: CropRenderElement<WorkspaceRenderElement<R>>) -> Self {
Self::Workspace(RelocateRenderElement::from_element( Self::Workspace(RelocateRenderElement::from_element(
elem, elem,
(0, 0), (0, 0),

View file

@ -4,6 +4,7 @@ use std::{
borrow::Borrow, borrow::Borrow,
cell::RefCell, cell::RefCell,
collections::HashMap, collections::HashMap,
ops::ControlFlow,
sync::{Arc, RwLock, Weak}, sync::{Arc, RwLock, Weak},
time::Instant, time::Instant,
}; };
@ -14,16 +15,13 @@ use crate::{
backend::{kms::render::gles::GbmGlowBackend, render::element::DamageElement}, backend::{kms::render::gles::GbmGlowBackend, render::element::DamageElement},
shell::{ shell::{
element::CosmicMappedKey, element::CosmicMappedKey,
focus::target::WindowGroup, focus::{render_input_order, target::WindowGroup, Stage},
grabs::{SeatMenuGrabState, SeatMoveGrabState}, grabs::{SeatMenuGrabState, SeatMoveGrabState},
layout::tiling::ANIMATION_DURATION, layout::tiling::ANIMATION_DURATION,
CosmicMappedRenderElement, OverviewMode, SeatExt, SessionLock, Trigger, WorkspaceDelta, CosmicMappedRenderElement, OverviewMode, SeatExt, Trigger, WorkspaceDelta,
WorkspaceRenderElement, WorkspaceRenderElement,
}, },
utils::{ utils::{prelude::*, quirks::workspace_overview_is_open},
prelude::*,
quirks::{workspace_overview_is_open, WORKSPACE_OVERVIEW_NAMESPACE},
},
wayland::{ wayland::{
handlers::{ handlers::{
data_device::get_dnd_icon, data_device::get_dnd_icon,
@ -34,9 +32,7 @@ use crate::{
}; };
use cosmic::Theme; use cosmic::Theme;
use cosmic_comp_config::workspace::WorkspaceLayout;
use element::FromGlesError; use element::FromGlesError;
use keyframe::{ease, functions::EaseInOutCubic};
use smithay::{ use smithay::{
backend::{ backend::{
allocator::dmabuf::Dmabuf, allocator::dmabuf::Dmabuf,
@ -46,7 +42,7 @@ use smithay::{
damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult}, damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult},
element::{ element::{
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
utils::{Relocate, RelocateRenderElement}, utils::{CropRenderElement, Relocate, RelocateRenderElement},
AsRenderElements, Element, Id, Kind, RenderElement, AsRenderElements, Element, Id, Kind, RenderElement,
}, },
gles::{ gles::{
@ -60,13 +56,12 @@ use smithay::{
TextureFilter, TextureFilter,
}, },
}, },
desktop::{layer_map_for_output, PopupManager},
input::Seat, input::Seat,
output::{Output, OutputNoMode}, output::{Output, OutputNoMode},
utils::{IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Time, Transform}, utils::{IsAlive, Logical, Monotonic, Point, Rectangle, Scale, Time, Transform},
wayland::{ wayland::{
dmabuf::get_dmabuf, dmabuf::get_dmabuf,
shell::wlr_layer::Layer, session_lock::LockSurface,
shm::{shm_format_to_fourcc, with_buffer_contents}, shm::{shm_format_to_fourcc, with_buffer_contents},
}, },
}; };
@ -504,60 +499,6 @@ pub enum ElementFilter {
LayerShellOnly, LayerShellOnly,
} }
#[derive(Clone, Debug)]
pub struct SplitRenderElements<E> {
pub w_elements: Vec<E>,
pub p_elements: Vec<E>,
}
impl<E> Default for SplitRenderElements<E> {
fn default() -> Self {
Self {
w_elements: Vec::new(),
p_elements: Vec::new(),
}
}
}
impl<E> SplitRenderElements<E> {
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<E2, F: FnMut(E2) -> E>(&mut self, other: SplitRenderElements<E2>, 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<E> {
self.p_elements.extend(self.w_elements);
self.p_elements
}
}
impl<R> SplitRenderElements<CosmicElement<R>>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
fn extend_from_workspace_elements<E: Into<WorkspaceRenderElement<R>>>(
&mut self,
other: SplitRenderElements<E>,
offset: Point<i32, Physical>,
) {
self.extend_map(other, |element| {
CosmicElement::Workspace(RelocateRenderElement::from_element(
element.into(),
offset,
Relocate::Relative,
))
})
}
}
#[profiling::function] #[profiling::function]
pub fn workspace_elements<R>( pub fn workspace_elements<R>(
_gpu: Option<&DrmNode>, _gpu: Option<&DrmNode>,
@ -578,7 +519,7 @@ where
CosmicMappedRenderElement<R>: RenderElement<R>, CosmicMappedRenderElement<R>: RenderElement<R>,
WorkspaceRenderElement<R>: RenderElement<R>, WorkspaceRenderElement<R>: RenderElement<R>,
{ {
let mut elements = SplitRenderElements::default(); let mut elements = Vec::new();
let theme = shell.read().unwrap().theme().clone(); let theme = shell.read().unwrap().theme().clone();
let seats = shell let seats = shell
@ -588,8 +529,9 @@ where
.iter() .iter()
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let scale = output.current_scale().fractional_scale();
elements.p_elements.extend(cursor_elements( elements.extend(cursor_elements(
renderer, renderer,
seats.iter(), seats.iter(),
&theme, &theme,
@ -602,7 +544,6 @@ where
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
{ {
let output_geo = output.geometry(); let output_geo = output.geometry();
let scale = output.current_scale().fractional_scale();
if let Some((state, timings)) = _fps { if let Some((state, timings)) = _fps {
let debug_active = shell.read().unwrap().debug_active; let debug_active = shell.read().unwrap().debug_active;
@ -621,23 +562,12 @@ where
) )
.map_err(FromGlesError::from_gles_error) .map_err(FromGlesError::from_gles_error)
.map_err(RenderError::Rendering)?; .map_err(RenderError::Rendering)?;
elements.p_elements.push(fps_overlay.into()); elements.push(fps_overlay.into());
} }
} }
let shell = shell.read().unwrap(); 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 overview = shell.overview_mode();
let (resize_mode, resize_indicator) = shell.resize_mode(); let (resize_mode, resize_indicator) = shell.resize_mode();
let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator)); let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator));
@ -666,310 +596,252 @@ where
.unwrap() .unwrap()
.is_some(); .is_some();
let focused_output = last_active_seat.focused_or_active_output(); 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 set = shell.workspaces.sets.get(output).ok_or(OutputNoMode)?;
let workspace = set let workspace = set
.workspaces .workspaces
.iter() .iter()
.find(|w| w.handle == current.0) .find(|w| w.handle == current.0)
.ok_or(OutputNoMode)?; .ok_or(OutputNoMode)?;
let is_active_space = workspace.outputs().any(|o| o == &focused_output); let is_active_space = workspace.output == 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 active_hint = if shell.active_hint { let active_hint = if shell.active_hint {
theme.active_hint as u8 theme.cosmic().active_hint as u8
} else { } else {
0 0
}; };
// overlay redirect windows let output_size = output
// they need to be over sticky windows, because they could be popups of sticky windows, .geometry()
// and we can't differenciate that. .size
if element_filter != ElementFilter::LayerShellOnly { .as_logical()
elements.p_elements.extend( .to_physical_precise_round(scale);
shell let crop_to_output = |element: WorkspaceRenderElement<R>| {
.override_redirect_windows CropRenderElement::from_element(
.iter() element.into(),
.filter(|or| { scale,
(*or) Rectangle::from_loc_and_size((0, 0), output_size),
.geometry() )
.as_global()
.intersection(workspace.output.geometry())
.is_some()
})
.flat_map(|or| {
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
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 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)
}
};
let offset = Point::<i32, Logical>::from(match (layout, *previous_idx < current.1) {
(WorkspaceLayout::Vertical, true) => {
(0, (-output_size.h as f32 * percentage).round() as i32)
}
(WorkspaceLayout::Vertical, false) => {
(0, (output_size.h as f32 * percentage).round() as i32)
}
(WorkspaceLayout::Horizontal, true) => {
((-output_size.w as f32 * percentage).round() as i32, 0)
}
(WorkspaceLayout::Horizontal, false) => {
((output_size.w as f32 * percentage).round() as i32, 0)
}
});
elements.extend_from_workspace_elements(
workspace
.render::<R>(
renderer,
(!move_active && is_active_space).then_some(last_active_seat),
overview.clone(),
resize_indicator.clone(),
active_hint,
theme,
)
.map_err(|_| OutputNoMode)?,
offset.to_physical_precise_round(output_scale),
);
if !has_fullscreen {
elements.extend_from_workspace_elements(
background_layer_elements(renderer, output, element_filter),
offset.to_physical_precise_round(output_scale),
);
}
Point::<i32, Logical>::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 { render_input_order(
elements.extend_from_workspace_elements( &*shell,
workspace output,
.render::<R>( previous,
renderer, current,
(!move_active && is_active_space).then_some(&last_active_seat), element_filter,
overview, |stage| {
resize_indicator, match stage {
active_hint, Stage::SessionLock(lock_surface) => {
theme, elements.extend(
) session_lock_elements(renderer, output, lock_surface)
.map_err(|_| OutputNoMode)?, .into_iter()
offset.to_physical_precise_round(output_scale), .map(Into::into)
); .flat_map(crop_to_output)
} .map(Into::into),
);
if !has_fullscreen { }
elements.extend_from_workspace_elements( Stage::LayerPopup {
background_layer_elements(renderer, output, element_filter), popup, location, ..
offset.to_physical_precise_round(output_scale), } => {
); elements.extend(
} render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>(
Ok(elements.join())
}
pub fn split_layer_elements<R>(
renderer: &mut R,
output: &Output,
layer: Layer,
element_filter: ElementFilter,
) -> SplitRenderElements<WorkspaceRenderElement<R>>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Clone + 'static,
<R as Renderer>::Error: FromGlesError,
CosmicMappedRenderElement<R>: RenderElement<R>,
WorkspaceRenderElement<R>: RenderElement<R>,
{
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(
renderer, renderer,
popup.wl_surface(), popup.wl_surface(),
location + offset, location
scale, .to_local(output)
.as_logical()
.to_physical_precise_round(scale),
Scale::from(scale),
1.0, 1.0,
Kind::Unspecified, Kind::Unspecified,
) )
}, .into_iter()
)); .flat_map(crop_to_output)
.map(Into::into),
);
}
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),
);
}
Stage::OverrideRedirect { surface, location } => {
elements.extend(
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
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),
);
}
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 elements.extend(
.w_elements layout
.extend(render_elements_from_surface_tree( .render_popups(renderer, alpha)
renderer, .into_iter()
surface, .map(Into::into)
location, .flat_map(crop_to_output)
scale, .map(Into::into),
1.0, );
Kind::Unspecified, }
)); 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,
};
elements let current_focus = (!move_active && is_active_space)
} .then_some(last_active_seat)
.map(|seat| workspace.focus_stack.get(seat));
// bottom and background layer surfaces elements.extend(
pub fn background_layer_elements<R>( layout
renderer: &mut R, .render(
output: &Output, renderer,
element_filter: ElementFilter, current_focus.as_ref().and_then(|stack| stack.last()),
) -> SplitRenderElements<WorkspaceRenderElement<R>> resize_indicator.clone(),
where active_hint,
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, alpha,
<R as Renderer>::TextureId: Clone + 'static, &theme.cosmic(),
<R as Renderer>::Error: FromGlesError, )
CosmicMappedRenderElement<R>: RenderElement<R>, .into_iter()
WorkspaceRenderElement<R>: RenderElement<R>, .map(Into::into)
{ .flat_map(crop_to_output)
let mut elements = split_layer_elements(renderer, output, Layer::Bottom, element_filter); .map(Into::into),
elements.extend(split_layer_elements( )
renderer, }
output, Stage::WorkspacePopups { workspace, offset } => {
Layer::Background, elements.extend(
element_filter, match workspace.render_popups(
)); renderer,
elements (!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));
}
},
);
}
};
ControlFlow::Continue(())
},
)?;
Ok(elements)
} }
fn session_lock_elements<R>( fn session_lock_elements<R>(
renderer: &mut R, renderer: &mut R,
output: &Output, output: &Output,
session_lock: &SessionLock, lock_surface: Option<&LockSurface>,
) -> Vec<WaylandSurfaceRenderElement<R>> ) -> Vec<WaylandSurfaceRenderElement<R>>
where where
R: Renderer + ImportAll, R: Renderer + ImportAll,
<R as Renderer>::TextureId: Clone + 'static, <R as Renderer>::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()); let scale = Scale::from(output.current_scale().fractional_scale());
render_elements_from_surface_tree( render_elements_from_surface_tree(
renderer, renderer,

View file

@ -1,8 +1,5 @@
use crate::{ use crate::{
backend::render::{ backend::render::element::{AsGlowRenderer, FromGlesError},
element::{AsGlowRenderer, FromGlesError},
SplitRenderElements,
},
state::State, state::State,
utils::{iced::IcedElementInternal, prelude::*}, utils::{iced::IcedElementInternal, prelude::*},
}; };
@ -657,13 +654,42 @@ impl CosmicMapped {
} }
} }
pub fn split_render_elements<R, C>( pub fn popup_render_elements<R, C>(
&self, &self,
renderer: &mut R, renderer: &mut R,
location: smithay::utils::Point<i32, smithay::utils::Physical>, location: smithay::utils::Point<i32, smithay::utils::Physical>,
scale: smithay::utils::Scale<f64>, scale: smithay::utils::Scale<f64>,
alpha: f32, alpha: f32,
) -> SplitRenderElements<C> ) -> Vec<C>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
C: From<CosmicMappedRenderElement<R>>,
{
match &self.element {
CosmicMappedInternal::Stack(s) => s
.popup_render_elements::<R, CosmicMappedRenderElement<R>>(
renderer, location, scale, alpha,
),
CosmicMappedInternal::Window(w) => w
.popup_render_elements::<R, CosmicMappedRenderElement<R>>(
renderer, location, scale, alpha,
),
_ => unreachable!(),
}
.into_iter()
.map(C::from)
.collect()
}
pub fn render_elements<R, C>(
&self,
renderer: &mut R,
location: smithay::utils::Point<i32, smithay::utils::Physical>,
scale: smithay::utils::Scale<f64>,
alpha: f32,
) -> Vec<C>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -671,7 +697,7 @@ impl CosmicMapped {
C: From<CosmicMappedRenderElement<R>>, C: From<CosmicMappedRenderElement<R>>,
{ {
#[cfg(feature = "debug")] #[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 = self.active_window();
let window_geo = window.geometry(); let window_geo = window.geometry();
let (min_size, max_size, size) = let (min_size, max_size, size) =
@ -840,30 +866,21 @@ impl CosmicMapped {
Vec::new() Vec::new()
}; };
#[cfg(not(feature = "debug"))] #[cfg(not(feature = "debug"))]
let debug_elements = Vec::new(); let mut elements = Vec::new();
let mut elements = SplitRenderElements {
w_elements: debug_elements,
p_elements: Vec::new(),
};
#[cfg_attr(not(feature = "debug"), allow(unused_mut))] #[cfg_attr(not(feature = "debug"), allow(unused_mut))]
elements.extend_map( elements.extend(match &self.element {
match &self.element { CosmicMappedInternal::Stack(s) => s.render_elements::<R, CosmicMappedRenderElement<R>>(
CosmicMappedInternal::Stack(s) => s renderer, location, scale, alpha,
.split_render_elements::<R, CosmicMappedRenderElement<R>>( ),
renderer, location, scale, alpha, CosmicMappedInternal::Window(w) => w
), .render_elements::<R, CosmicMappedRenderElement<R>>(
CosmicMappedInternal::Window(w) => w renderer, location, scale, alpha,
.split_render_elements::<R, CosmicMappedRenderElement<R>>( ),
renderer, location, scale, alpha, _ => unreachable!(),
), });
_ => unreachable!(),
},
C::from,
);
elements elements.into_iter().map(C::from).collect()
} }
pub(crate) fn update_theme(&self, theme: cosmic::Theme) { pub(crate) fn update_theme(&self, theme: cosmic::Theme) {

View file

@ -1,6 +1,6 @@
use super::{surface::RESIZE_BORDER, window::Focus, CosmicSurface}; use super::{surface::RESIZE_BORDER, window::Focus, CosmicSurface};
use crate::{ use crate::{
backend::render::{cursor::CursorState, SplitRenderElements}, backend::render::cursor::CursorState,
shell::{ shell::{
focus::target::PointerFocusTarget, focus::target::PointerFocusTarget,
grabs::{ReleaseMode, ResizeEdge}, grabs::{ReleaseMode, ResizeEdge},
@ -541,13 +541,40 @@ impl CosmicStack {
self.0.loop_handle() self.0.loop_handle()
} }
pub fn split_render_elements<R, C>( pub fn popup_render_elements<R, C>(
&self, &self,
renderer: &mut R, renderer: &mut R,
location: Point<i32, Physical>, location: Point<i32, Physical>,
scale: Scale<f64>, scale: Scale<f64>,
alpha: f32, alpha: f32,
) -> SplitRenderElements<C> ) -> Vec<C>
where
R: Renderer + ImportAll + ImportMem,
<R as Renderer>::TextureId: Send + Clone + 'static,
C: From<CosmicStackRenderElement<R>>,
{
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::<R, CosmicStackRenderElement<R>>(
renderer, window_loc, scale, alpha,
)
.into_iter()
.map(C::from)
.collect()
})
}
pub fn render_elements<R, C>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
alpha: f32,
) -> Vec<C>
where where
R: Renderer + ImportAll + ImportMem, R: Renderer + ImportAll + ImportMem,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -564,28 +591,20 @@ impl CosmicStack {
let stack_loc = location + offset; let stack_loc = location + offset;
let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32));
let w_elements = AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>( let mut elements = AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>(
&self.0, renderer, stack_loc, scale, alpha, &self.0, renderer, stack_loc, scale, alpha,
); );
let mut elements = SplitRenderElements { elements.extend(self.0.with_program(|p| {
w_elements: w_elements.into_iter().map(C::from).collect(), let windows = p.windows.lock().unwrap();
p_elements: Vec::new(), let active = p.active.load(Ordering::SeqCst);
};
elements.extend_map( windows[active].render_elements::<R, CosmicStackRenderElement<R>>(
self.0.with_program(|p| { renderer, window_loc, scale, alpha,
let windows = p.windows.lock().unwrap(); )
let active = p.active.load(Ordering::SeqCst); }));
windows[active].split_render_elements::<R, CosmicStackRenderElement<R>>( elements.into_iter().map(C::from).collect()
renderer, window_loc, scale, alpha,
)
}),
C::from,
);
elements
} }
pub(crate) fn set_theme(&self, theme: cosmic::Theme) { pub(crate) fn set_theme(&self, theme: cosmic::Theme) {

View file

@ -35,7 +35,9 @@ use smithay::{
}, },
wayland_server::protocol::wl_surface::WlSurface, 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::{ wayland::{
compositor::{with_states, SurfaceData}, compositor::{with_states, SurfaceData},
seat::WaylandFocus, seat::WaylandFocus,
@ -45,7 +47,6 @@ use smithay::{
}; };
use crate::{ use crate::{
backend::render::SplitRenderElements,
state::{State, SurfaceDmabufFeedback}, state::{State, SurfaceDmabufFeedback},
utils::prelude::*, utils::prelude::*,
wayland::handlers::decoration::PreferredDecorationMode, wayland::handlers::decoration::PreferredDecorationMode,
@ -590,13 +591,13 @@ impl CosmicSurface {
self.0.user_data() self.0.user_data()
} }
pub fn split_render_elements<R, C>( pub fn popup_render_elements<R, C>(
&self, &self,
renderer: &mut R, renderer: &mut R,
location: smithay::utils::Point<i32, smithay::utils::Physical>, location: Point<i32, Physical>,
scale: smithay::utils::Scale<f64>, scale: Scale<f64>,
alpha: f32, alpha: f32,
) -> SplitRenderElements<C> ) -> Vec<C>
where where
R: Renderer + ImportAll, R: Renderer + ImportAll,
<R as Renderer>::TextureId: Clone + 'static, <R as Renderer>::TextureId: Clone + 'static,
@ -605,9 +606,8 @@ impl CosmicSurface {
match self.0.underlying_surface() { match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => { WindowSurface::Wayland(toplevel) => {
let surface = toplevel.wl_surface(); let surface = toplevel.wl_surface();
PopupManager::popups_for_surface(surface)
let p_elements = PopupManager::popups_for_surface(surface) .flat_map(move |(popup, popup_offset)| {
.flat_map(|(popup, popup_offset)| {
let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc) let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc)
.to_physical_precise_round(scale); .to_physical_precise_round(scale);
@ -620,26 +620,40 @@ impl CosmicSurface {
element::Kind::Unspecified, element::Kind::Unspecified,
) )
}) })
.collect(); .collect()
}
WindowSurface::X11(_) => Vec::new(),
}
}
let w_elements = render_elements_from_surface_tree( pub fn render_elements<R, C>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
alpha: f32,
) -> Vec<C>
where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: Clone + 'static,
C: From<WaylandSurfaceRenderElement<R>>,
{
match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => {
let surface = toplevel.wl_surface();
render_elements_from_surface_tree(
renderer, renderer,
surface, surface,
location, location,
scale, scale,
alpha, alpha,
element::Kind::Unspecified, element::Kind::Unspecified,
); )
}
SplitRenderElements { WindowSurface::X11(surface) => {
w_elements, surface.render_elements(renderer, location, scale, alpha)
p_elements,
}
} }
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) SpaceElement::bbox(&self.0)
} }
fn is_in_input_region( fn is_in_input_region(&self, point: &Point<f64, smithay::utils::Logical>) -> bool {
&self,
point: &smithay::utils::Point<f64, smithay::utils::Logical>,
) -> bool {
SpaceElement::is_in_input_region(&self.0, point) SpaceElement::is_in_input_region(&self.0, point)
} }
@ -784,8 +795,8 @@ where
fn render_elements<C: From<Self::RenderElement>>( fn render_elements<C: From<Self::RenderElement>>(
&self, &self,
renderer: &mut R, renderer: &mut R,
location: smithay::utils::Point<i32, smithay::utils::Physical>, location: Point<i32, Physical>,
scale: smithay::utils::Scale<f64>, scale: Scale<f64>,
alpha: f32, alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
self.0.render_elements(renderer, location, scale, alpha) self.0.render_elements(renderer, location, scale, alpha)

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
backend::render::{cursor::CursorState, SplitRenderElements}, backend::render::cursor::CursorState,
shell::{ shell::{
focus::target::PointerFocusTarget, focus::target::PointerFocusTarget,
grabs::{ReleaseMode, ResizeEdge}, grabs::{ReleaseMode, ResizeEdge},
@ -41,7 +41,7 @@ use smithay::{
output::Output, output::Output,
reexports::wayland_server::protocol::wl_surface::WlSurface, reexports::wayland_server::protocol::wl_surface::WlSurface,
render_elements, render_elements,
utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size},
wayland::seat::WaylandFocus, wayland::seat::WaylandFocus,
}; };
use std::{ use std::{
@ -308,13 +308,13 @@ impl CosmicWindow {
self.0.loop_handle() self.0.loop_handle()
} }
pub fn split_render_elements<R, C>( pub fn popup_render_elements<R, C>(
&self, &self,
renderer: &mut R, renderer: &mut R,
location: smithay::utils::Point<i32, smithay::utils::Physical>, location: Point<i32, Physical>,
scale: smithay::utils::Scale<f64>, scale: Scale<f64>,
alpha: f32, alpha: f32,
) -> SplitRenderElements<C> ) -> Vec<C>
where where
R: Renderer + ImportAll + ImportMem, R: Renderer + ImportAll + ImportMem,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -328,17 +328,44 @@ impl CosmicWindow {
location location
}; };
let mut elements = SplitRenderElements::default(); self.0.with_program(|p| {
p.window
.popup_render_elements::<R, CosmicWindowRenderElement<R>>(
renderer, window_loc, scale, alpha,
)
.into_iter()
.map(C::from)
.collect()
})
}
elements.extend_map( pub fn render_elements<R, C>(
self.0.with_program(|p| { &self,
p.window renderer: &mut R,
.split_render_elements::<R, CosmicWindowRenderElement<R>>( location: Point<i32, Physical>,
renderer, window_loc, scale, alpha, scale: Scale<f64>,
) alpha: f32,
}), ) -> Vec<C>
C::from, where
); R: Renderer + ImportAll + ImportMem,
<R as Renderer>::TextureId: Send + Clone + 'static,
C: From<CosmicWindowRenderElement<R>>,
{
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::<R, CosmicWindowRenderElement<R>>(
renderer, window_loc, scale, alpha,
)
}));
if has_ssd { if has_ssd {
let ssd_loc = location let ssd_loc = location
@ -346,16 +373,12 @@ impl CosmicWindow {
.0 .0
.with_program(|p| p.window.geometry().loc) .with_program(|p| p.window.geometry().loc)
.to_physical_precise_round(scale); .to_physical_precise_round(scale);
elements.w_elements.extend( elements.extend(AsRenderElements::<R>::render_elements::<
AsRenderElements::<R>::render_elements::<CosmicWindowRenderElement<R>>( CosmicWindowRenderElement<R>,
&self.0, renderer, ssd_loc, scale, alpha, >(&self.0, renderer, ssd_loc, scale, alpha))
)
.into_iter()
.map(C::from),
)
} }
elements elements.into_iter().map(C::from).collect()
} }
pub(crate) fn set_theme(&self, theme: cosmic::Theme) { pub(crate) fn set_theme(&self, theme: cosmic::Theme) {

View file

@ -2,8 +2,7 @@
use crate::{ use crate::{
backend::render::{ backend::render::{
cursor::CursorState, element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, cursor::CursorState, element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage,
SplitRenderElements, Usage,
}, },
shell::{ shell::{
element::{ element::{
@ -181,12 +180,18 @@ impl MoveGrabState {
_ => vec![], _ => vec![],
}; };
let SplitRenderElements { let w_elements = self
w_elements,
p_elements,
} = self
.window .window
.split_render_elements::<R, CosmicMappedRenderElement<R>>( .render_elements::<R, CosmicMappedRenderElement<R>>(
renderer,
(render_location - self.window.geometry().loc)
.to_physical_precise_round(output_scale),
output_scale,
alpha,
);
let p_elements = self
.window
.popup_render_elements::<R, CosmicMappedRenderElement<R>>(
renderer, renderer,
(render_location - self.window.geometry().loc) (render_location - self.window.geometry().loc)
.to_physical_precise_round(output_scale), .to_physical_precise_round(output_scale),

View file

@ -24,7 +24,7 @@ use smithay::{
}; };
use crate::{ use crate::{
backend::render::{element::AsGlowRenderer, IndicatorShader, Key, SplitRenderElements, Usage}, backend::render::{element::AsGlowRenderer, IndicatorShader, Key, Usage},
shell::{ shell::{
element::{ element::{
resize_indicator::ResizeIndicator, resize_indicator::ResizeIndicator,
@ -1260,6 +1260,52 @@ impl FloatingLayout {
} }
self.refresh(); //fixup any out of bounds elements self.refresh(); //fixup any out of bounds elements
} }
#[profiling::function]
pub fn render_popups<R>(
&self,
renderer: &mut R,
alpha: f32,
) -> Vec<CosmicMappedRenderElement<R>>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
CosmicWindowRenderElement<R>: RenderElement<R>,
CosmicStackRenderElement<R>: RenderElement<R>,
{
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] #[profiling::function]
pub fn render<R>( pub fn render<R>(
@ -1270,7 +1316,7 @@ impl FloatingLayout {
indicator_thickness: u8, indicator_thickness: u8,
alpha: f32, alpha: f32,
theme: &cosmic::theme::CosmicTheme, theme: &cosmic::theme::CosmicTheme,
) -> SplitRenderElements<CosmicMappedRenderElement<R>> ) -> Vec<CosmicMappedRenderElement<R>>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -1285,7 +1331,7 @@ impl FloatingLayout {
}; };
let output_scale = output.current_scale().fractional_scale(); let output_scale = output.current_scale().fractional_scale();
let mut elements = SplitRenderElements::default(); let mut elements = Vec::default();
for elem in self for elem in self
.animations .animations
@ -1301,10 +1347,7 @@ impl FloatingLayout {
.unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha)); .unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha));
let render_location = geometry.loc - elem.geometry().loc.as_local(); let render_location = geometry.loc - elem.geometry().loc.as_local();
let SplitRenderElements { let mut window_elements = elem.render_elements(
mut w_elements,
p_elements,
} = elem.split_render_elements(
renderer, renderer,
render_location render_location
.as_logical() .as_logical()
@ -1331,7 +1374,7 @@ impl FloatingLayout {
y: geometry.size.h as f64 / buffer_size.h as f64, y: geometry.size.h as f64 / buffer_size.h as f64,
}; };
w_elements = w_elements window_elements = window_elements
.into_iter() .into_iter()
.map(|element| match element { .map(|element| match element {
CosmicMappedRenderElement::Stack(elem) => { CosmicMappedRenderElement::Stack(elem) => {
@ -1387,7 +1430,7 @@ impl FloatingLayout {
resize.resize(resize_geometry.size.as_logical()); resize.resize(resize_geometry.size.as_logical());
resize.output_enter(output, Rectangle::default() /* unused */); resize.output_enter(output, Rectangle::default() /* unused */);
elements.w_elements.extend( window_elements.extend(
resize resize
.render_elements::<CosmicWindowRenderElement<R>>( .render_elements::<CosmicWindowRenderElement<R>>(
renderer, renderer,
@ -1419,12 +1462,11 @@ impl FloatingLayout {
active_window_hint.blue, active_window_hint.blue,
], ],
); );
elements.w_elements.push(element.into()); window_elements.push(element.into());
} }
} }
elements.w_elements.extend(w_elements); elements.extend(window_elements);
elements.p_elements.extend(p_elements);
} }
elements elements

View file

@ -2,8 +2,8 @@
use crate::{ use crate::{
backend::render::{ backend::render::{
element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, SplitRenderElements, Usage, element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, Usage, ACTIVE_GROUP_COLOR,
ACTIVE_GROUP_COLOR, GROUP_COLOR, GROUP_COLOR,
}, },
shell::{ shell::{
element::{ element::{
@ -60,7 +60,7 @@ use smithay::{
input::Seat, input::Seat,
output::Output, output::Output,
reexports::wayland_server::Client, 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}, wayland::{compositor::add_blocker, seat::WaylandFocus},
}; };
use std::{ use std::{
@ -3863,7 +3863,7 @@ impl TilingLayout {
resize_indicator: Option<(ResizeMode, ResizeIndicator)>, resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
indicator_thickness: u8, indicator_thickness: u8,
theme: &cosmic::theme::CosmicTheme, theme: &cosmic::theme::CosmicTheme,
) -> Result<SplitRenderElements<CosmicMappedRenderElement<R>>, OutputNotMapped> ) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -3896,7 +3896,7 @@ impl TilingLayout {
}; };
let draw_groups = overview.0.alpha(); 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_overview = !matches!(overview.0, OverviewMode::None);
let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_))))
@ -3931,7 +3931,7 @@ impl TilingLayout {
.unzip(); .unzip();
// all old windows we want to fade out // all old windows we want to fade out
elements.extend(render_old_tree( elements.extend(render_old_tree_windows(
reference_tree, reference_tree,
target_tree, target_tree,
renderer, renderer,
@ -3969,7 +3969,7 @@ impl TilingLayout {
.unzip(); .unzip();
// all alive windows // all alive windows
elements.extend(render_new_tree( elements.extend(render_new_tree_windows(
target_tree, target_tree,
reference_tree, reference_tree,
renderer, renderer,
@ -4001,12 +4001,139 @@ impl TilingLayout {
// tiling hints // tiling hints
if let Some(group_elements) = group_elements { if let Some(group_elements) = group_elements {
elements.w_elements.extend(group_elements); elements.extend(group_elements);
} }
Ok(elements) Ok(elements)
} }
#[profiling::function]
pub fn render_popups<R>(
&self,
renderer: &mut R,
seat: Option<&Seat<State>>,
non_exclusive_zone: Rectangle<i32, Local>,
overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>),
theme: &cosmic::theme::CosmicTheme,
) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
CosmicWindowRenderElement<R>: RenderElement<R>,
CosmicStackRenderElement<R>: RenderElement<R>,
{
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) { fn gaps(&self) -> (i32, i32) {
let g = self.theme.cosmic().gaps; let g = self.theme.cosmic().gaps;
(g.0 as i32, g.1 as i32) (g.0 as i32, g.1 as i32)
@ -4690,7 +4817,48 @@ where
(geometries, elements) (geometries, elements)
} }
fn render_old_tree<R>( fn render_old_tree_popups<R>(
reference_tree: &Tree<Data>,
target_tree: &Tree<Data>,
renderer: &mut R,
geometries: Option<HashMap<NodeId, Rectangle<i32, Local>>>,
output_scale: f64,
percentage: f32,
is_swap_mode: bool,
) -> Vec<CosmicMappedRenderElement<R>>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
CosmicWindowRenderElement<R>: RenderElement<R>,
CosmicStackRenderElement<R>: RenderElement<R>,
{
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::<R, CosmicMappedRenderElement<R>>(
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<R>(
reference_tree: &Tree<Data>, reference_tree: &Tree<Data>,
target_tree: &Tree<Data>, target_tree: &Tree<Data>,
renderer: &mut R, renderer: &mut R,
@ -4700,7 +4868,7 @@ fn render_old_tree<R>(
indicator_thickness: u8, indicator_thickness: u8,
is_swap_mode: bool, is_swap_mode: bool,
theme: &cosmic::theme::CosmicTheme, theme: &cosmic::theme::CosmicTheme,
) -> SplitRenderElements<CosmicMappedRenderElement<R>> ) -> Vec<CosmicMappedRenderElement<R>>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -4709,8 +4877,80 @@ where
CosmicStackRenderElement<R>: RenderElement<R>, CosmicStackRenderElement<R>: RenderElement<R>,
{ {
let window_hint = crate::theme::active_window_hint(theme); 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::<R, CosmicMappedRenderElement<R>>(
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<Data>,
target_tree: &Tree<Data>,
geometries: Option<HashMap<NodeId, Rectangle<i32, Local>>>,
output_scale: f64,
percentage: f32,
is_swap_mode: bool,
mut processor: impl FnMut(&CosmicMapped, Rectangle<i32, Physical>, Rectangle<i32, Local>, f32, bool),
) {
if let Some(root) = reference_tree.root_node_id() { if let Some(root) = reference_tree.root_node_id() {
let geometries = geometries.unwrap_or_default(); let geometries = geometries.unwrap_or_default();
reference_tree reference_tree
@ -4779,71 +5019,71 @@ where
}; };
let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale);
let SplitRenderElements {
w_elements,
p_elements,
} = mapped.split_render_elements::<R, CosmicMappedRenderElement<R>>(
renderer,
geo.loc.as_logical().to_physical_precise_round(output_scale)
- elem_geometry.loc,
Scale::from(output_scale),
alpha,
);
elements processor(mapped, elem_geometry, geo, alpha, minimize_geo.is_some())
.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);
}); });
} }
elements
} }
fn render_new_tree<R>( fn render_new_tree_popups<R>(
target_tree: &Tree<Data>,
reference_tree: Option<&Tree<Data>>,
renderer: &mut R,
geometries: Option<HashMap<NodeId, Rectangle<i32, Local>>>,
old_geometries: Option<HashMap<NodeId, Rectangle<i32, Local>>>,
seat: Option<&Seat<State>>,
output: &Output,
percentage: f32,
overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>),
swap_desc: Option<NodeDesc>,
) -> Vec<CosmicMappedRenderElement<R>>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
CosmicWindowRenderElement<R>: RenderElement<R>,
CosmicStackRenderElement<R>: RenderElement<R>,
{
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::<R, CosmicMappedRenderElement<R>>(
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_windows<R>(
target_tree: &Tree<Data>, target_tree: &Tree<Data>,
reference_tree: Option<&Tree<Data>>, reference_tree: Option<&Tree<Data>>,
renderer: &mut R, renderer: &mut R,
@ -4862,7 +5102,7 @@ fn render_new_tree<R>(
swapping_stack_surface_id: &Id, swapping_stack_surface_id: &Id,
placeholder_id: &Id, placeholder_id: &Id,
theme: &cosmic::theme::CosmicTheme, theme: &cosmic::theme::CosmicTheme,
) -> SplitRenderElements<CosmicMappedRenderElement<R>> ) -> Vec<CosmicMappedRenderElement<R>>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -4905,7 +5145,6 @@ where
let mut animating_window_elements = Vec::new(); let mut animating_window_elements = Vec::new();
let mut window_elements = Vec::new(); let mut window_elements = Vec::new();
let mut popup_elements = Vec::new();
let mut group_backdrop = None; let mut group_backdrop = None;
let mut indicators = Vec::new(); let mut indicators = Vec::new();
@ -4916,10 +5155,11 @@ where
let output_scale = output.current_scale().fractional_scale(); let output_scale = output.current_scale().fractional_scale();
let (swap_indicator, swap_tree) = overview.1.unzip(); 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_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 window_hint = crate::theme::active_window_hint(theme);
let group_color = GROUP_COLOR; let group_color = GROUP_COLOR;
// render placeholder, if we are swapping to an empty workspace // render placeholder, if we are swapping to an empty workspace
if target_tree.root_node_id().is_none() && swap_desc.is_some() { if target_tree.root_node_id().is_none() && swap_desc.is_some() {
window_elements.push( window_elements.push(
@ -4968,165 +5208,48 @@ where
(swap_geo.loc.as_logical() - window_geo.loc).to_physical_precise_round(output_scale); (swap_geo.loc.as_logical() - window_geo.loc).to_physical_precise_round(output_scale);
swap_elements.extend( swap_elements.extend(
window AsRenderElements::render_elements::<CosmicWindowRenderElement<R>>(
.render_elements::<CosmicWindowRenderElement<R>>( &window,
renderer, renderer,
render_loc, render_loc,
output_scale.into(), output_scale.into(),
1.0, 1.0,
) )
.into_iter() .into_iter()
.map(|window| { .map(|window| {
CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element( CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element(
window, window,
swap_geo swap_geo
.loc .loc
.as_logical() .as_logical()
.to_physical_precise_round(output_scale), .to_physical_precise_round(output_scale),
ease( ease(
Linear, Linear,
1.0, 1.0,
swap_factor(window_geo.size), swap_factor(window_geo.size),
transition.unwrap_or(1.0), transition.unwrap_or(1.0),
), ),
)) ))
}), }),
) )
} }
// render actual tree nodes // render actual tree nodes
let old_geometries = old_geometries.unwrap_or_default(); render_new_tree(
let geometries = geometries.unwrap_or_default(); target_tree,
target_tree reference_tree,
.root_node_id() geometries,
.into_iter() old_geometries,
.flat_map(|root| target_tree.traverse_pre_order_ids(root).unwrap()) percentage,
.map(|id| (target_tree, id)) swap_tree,
.chain( swap_desc.as_ref(),
swap_tree |node_id, data, geo, original_geo, alpha, animating| {
.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)
};
if swap_desc.as_ref().map(|desc| &desc.node) == Some(&node_id) if swap_desc.as_ref().map(|desc| &desc.node) == Some(&node_id)
|| focused.as_ref() == Some(&node_id) || focused.as_ref() == Some(&node_id)
{ {
if indicator_thickness > 0 || data.is_group() { if indicator_thickness > 0 || data.is_group() {
let mut geo = geo.clone(); let mut geo = geo.clone();
if data.is_group() { if data.is_group() {
let outer_gap: i32 = (if is_overview { GAP_KEYBOARD } else { 4 } as f32 let outer_gap: i32 = (if is_overview { GAP_KEYBOARD } else { 4 } as f32
* percentage) * percentage)
@ -5251,10 +5374,8 @@ where
if let Data::Mapped { mapped, .. } = data { if let Data::Mapped { mapped, .. } = data {
let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale);
let SplitRenderElements {
mut w_elements, let mut elements = mapped.render_elements::<R, CosmicMappedRenderElement<R>>(
p_elements,
} = mapped.split_render_elements::<R, CosmicMappedRenderElement<R>>(
renderer, renderer,
//original_location, //original_location,
geo.loc.as_logical().to_physical_precise_round(output_scale) geo.loc.as_logical().to_physical_precise_round(output_scale)
@ -5262,6 +5383,7 @@ where
Scale::from(output_scale), Scale::from(output_scale),
alpha, alpha,
); );
if swap_desc if swap_desc
.as_ref() .as_ref()
.filter(|swap_desc| swap_desc.node == node_id) .filter(|swap_desc| swap_desc.node == node_id)
@ -5284,7 +5406,7 @@ where
{ {
let mut geo = mapped.active_window_geometry().as_local(); let mut geo = mapped.active_window_geometry().as_local();
geo.loc += original_geo.loc; geo.loc += original_geo.loc;
w_elements.insert( elements.insert(
0, 0,
CosmicMappedRenderElement::Overlay(BackdropShader::element( CosmicMappedRenderElement::Overlay(BackdropShader::element(
renderer, renderer,
@ -5305,7 +5427,7 @@ where
(ConstrainScaleBehavior::CutOff, ConstrainAlign::TOP_LEFT) (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( CosmicMappedRenderElement::Stack(elem) => constrain_render_elements(
std::iter::once(elem), std::iter::once(elem),
geo.loc.as_logical().to_physical_precise_round(output_scale) geo.loc.as_logical().to_physical_precise_round(output_scale)
@ -5344,6 +5466,7 @@ where
.map(CosmicMappedRenderElement::TiledOverlay), .map(CosmicMappedRenderElement::TiledOverlay),
x => Some(x), x => Some(x),
}); });
if swap_desc if swap_desc
.as_ref() .as_ref()
.map(|swap_desc| { .map(|swap_desc| {
@ -5356,21 +5479,19 @@ where
}) })
.unwrap_or(false) .unwrap_or(false)
{ {
swap_elements.extend(w_elements); swap_elements.extend(elements);
} else { } else {
if animating { if animating {
animating_window_elements.extend(w_elements); animating_window_elements.extend(elements);
} else { } else {
window_elements.extend(w_elements); window_elements.extend(elements);
}
if !mapped.is_maximized(false) {
popup_elements.extend(p_elements);
} }
} }
} }
}); },
);
window_elements = resize_elements resize_elements
.into_iter() .into_iter()
.flatten() .flatten()
.chain(swap_elements) .chain(swap_elements)
@ -5378,12 +5499,147 @@ where
.chain(window_elements) .chain(window_elements)
.chain(animating_window_elements) .chain(animating_window_elements)
.chain(group_backdrop.into_iter().map(Into::into)) .chain(group_backdrop.into_iter().map(Into::into))
.collect(); .collect()
}
SplitRenderElements { fn render_new_tree(
w_elements: window_elements, target_tree: &Tree<Data>,
p_elements: popup_elements, reference_tree: Option<&Tree<Data>>,
} geometries: Option<HashMap<NodeId, Rectangle<i32, Local>>>,
old_geometries: Option<HashMap<NodeId, Rectangle<i32, Local>>>,
percentage: f32,
swap_tree: Option<&Tree<Data>>,
swap_desc: Option<&NodeDesc>,
mut processor: impl FnMut(NodeId, &Data, Rectangle<i32, Local>, &Rectangle<i32, Local>, 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<C>( fn scale_to_center<C>(

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
backend::render::{ backend::render::{
element::{AsGlowRenderer, FromGlesError}, element::{AsGlowRenderer, FromGlesError},
BackdropShader, SplitRenderElements, BackdropShader,
}, },
shell::{ shell::{
layout::{floating::FloatingLayout, tiling::TilingLayout}, layout::{floating::FloatingLayout, tiling::TilingLayout},
@ -921,10 +921,6 @@ impl Workspace {
.chain(self.tiling_layer.mapped().map(|(w, _)| w)) .chain(self.tiling_layer.mapped().map(|(w, _)| w))
} }
pub fn outputs(&self) -> impl Iterator<Item = &Output> {
self.floating_layer.space.outputs()
}
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.floating_layer.mapped().next().is_none() self.floating_layer.mapped().next().is_none()
&& self.tiling_layer.mapped().next().is_none() && self.tiling_layer.mapped().next().is_none()
@ -1012,7 +1008,7 @@ impl Workspace {
resize_indicator: Option<(ResizeMode, ResizeIndicator)>, resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
indicator_thickness: u8, indicator_thickness: u8,
theme: &CosmicTheme, theme: &CosmicTheme,
) -> Result<SplitRenderElements<WorkspaceRenderElement<R>>, OutputNotMapped> ) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
where where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static, <R as Renderer>::TextureId: Send + Clone + 'static,
@ -1021,7 +1017,7 @@ impl Workspace {
CosmicStackRenderElement<R>: RenderElement<R>, CosmicStackRenderElement<R>: RenderElement<R>,
WorkspaceRenderElement<R>: RenderElement<R>, WorkspaceRenderElement<R>: RenderElement<R>,
{ {
let mut elements = SplitRenderElements::default(); let mut elements = Vec::default();
let output_scale = self.output.current_scale().fractional_scale(); let output_scale = self.output.current_scale().fractional_scale();
let zone = { let zone = {
@ -1104,26 +1100,19 @@ impl Workspace {
y: target_geo.size.h as f64 / bbox.size.h as f64, y: target_geo.size.h as f64 / bbox.size.h as f64,
}; };
let SplitRenderElements { elements.extend(
w_elements, fullscreen
p_elements, .surface
} = fullscreen .render_elements::<R, CosmicWindowRenderElement<R>>(
.surface renderer,
.split_render_elements::<R, CosmicWindowRenderElement<R>>( render_loc,
renderer, output_scale.into(),
render_loc, alpha,
output_scale.into(), )
alpha,
);
elements.w_elements.extend(
w_elements
.into_iter() .into_iter()
.map(|elem| RescaleRenderElement::from_element(elem, render_loc, scale)) .map(|elem| RescaleRenderElement::from_element(elem, render_loc, scale))
.map(Into::into), .map(Into::into),
); );
elements
.p_elements
.extend(p_elements.into_iter().map(Into::into))
} }
if self if self
@ -1155,16 +1144,18 @@ impl Workspace {
OverviewMode::None => 1.0, OverviewMode::None => 1.0,
}; };
elements.extend_map( elements.extend(
self.floating_layer.render::<R>( self.floating_layer
renderer, .render::<R>(
focused.as_ref(), renderer,
resize_indicator.clone(), focused.as_ref(),
indicator_thickness, resize_indicator.clone(),
alpha, indicator_thickness,
theme, alpha,
), theme,
WorkspaceRenderElement::from, )
.into_iter()
.map(WorkspaceRenderElement::from),
); );
let alpha = match &overview.0 { let alpha = match &overview.0 {
@ -1181,21 +1172,23 @@ impl Workspace {
}; };
//tiling surfaces //tiling surfaces
elements.extend_map( elements.extend(
self.tiling_layer.render::<R>( self.tiling_layer
renderer, .render::<R>(
draw_focus_indicator, renderer,
zone, draw_focus_indicator,
overview, zone,
resize_indicator, overview,
indicator_thickness, resize_indicator,
theme, indicator_thickness,
)?, theme,
WorkspaceRenderElement::from, )?
.into_iter()
.map(WorkspaceRenderElement::from),
); );
if let Some(alpha) = alpha { if let Some(alpha) = alpha {
elements.w_elements.push( elements.push(
Into::<CosmicMappedRenderElement<R>>::into(BackdropShader::element( Into::<CosmicMappedRenderElement<R>>::into(BackdropShader::element(
renderer, renderer,
self.backdrop_id.clone(), self.backdrop_id.clone(),
@ -1214,6 +1207,159 @@ impl Workspace {
Ok(elements) Ok(elements)
} }
#[profiling::function]
pub fn render_popups<'a, R>(
&self,
renderer: &mut R,
draw_focus_indicator: Option<&Seat<State>>,
overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>),
theme: &CosmicTheme,
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: Send + Clone + 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
CosmicWindowRenderElement<R>: RenderElement<R>,
CosmicStackRenderElement<R>: RenderElement<R>,
WorkspaceRenderElement<R>: RenderElement<R>,
{
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::<R, CosmicWindowRenderElement<R>>(
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::<R>(renderer, alpha)
.into_iter()
.map(WorkspaceRenderElement::from),
);
//tiling surfaces
elements.extend(
self.tiling_layer
.render_popups::<R>(renderer, draw_focus_indicator, zone, overview, theme)?
.into_iter()
.map(WorkspaceRenderElement::from),
);
}
Ok(elements)
}
} }
impl FocusStacks { impl FocusStacks {