tiling: Add code to render group hints
This commit is contained in:
parent
84b3213146
commit
4ea0136a9b
8 changed files with 739 additions and 276 deletions
|
|
@ -1,2 +1,2 @@
|
|||
[toolchain]
|
||||
channel = "1.65"
|
||||
channel = "1.66"
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
use std::{
|
||||
borrow::{Borrow, BorrowMut},
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
sync::Weak,
|
||||
};
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
|
|
@ -12,8 +14,8 @@ use crate::{
|
|||
};
|
||||
use crate::{
|
||||
shell::{
|
||||
element::window::CosmicWindowRenderElement, layout::floating::SeatMoveGrabState,
|
||||
CosmicMappedRenderElement,
|
||||
element::window::CosmicWindowRenderElement, focus::target::WindowGroup,
|
||||
layout::floating::SeatMoveGrabState, CosmicMapped, CosmicMappedRenderElement,
|
||||
},
|
||||
state::{Common, Fps},
|
||||
utils::prelude::SeatExt,
|
||||
|
|
@ -47,7 +49,7 @@ use smithay::{
|
|||
},
|
||||
},
|
||||
output::Output,
|
||||
utils::{Logical, Physical, Point, Rectangle, Size},
|
||||
utils::{IsAlive, Logical, Physical, Point, Rectangle, Size},
|
||||
wayland::{
|
||||
dmabuf::get_dmabuf,
|
||||
shm::{shm_format_to_fourcc, with_buffer_contents},
|
||||
|
|
@ -66,11 +68,54 @@ pub type GlMultiFrame<'a, 'b, 'frame> =
|
|||
MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
|
||||
|
||||
pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0];
|
||||
pub static ACTIVE_GROUP_COLOR: [f32; 3] = [0.678, 0.635, 0.619];
|
||||
pub static GROUP_COLOR: [f32; 3] = [0.431, 0.404, 0.396];
|
||||
pub static FOCUS_INDICATOR_COLOR: [f32; 3] = [0.580, 0.921, 0.921];
|
||||
pub static FOCUS_INDICATOR_SHADER: &str = include_str!("./shaders/focus_indicator.frag");
|
||||
|
||||
pub struct IndicatorShader(pub GlesPixelProgram);
|
||||
struct IndicatorElement(pub RefCell<PixelShaderElement>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Key {
|
||||
Group(Weak<()>),
|
||||
Window(CosmicMapped),
|
||||
}
|
||||
impl std::hash::Hash for Key {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
Key::Group(arc) => (arc.as_ptr() as usize).hash(state),
|
||||
Key::Window(window) => window.hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PartialEq for Key {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Key::Group(g1), Key::Group(g2)) => Weak::ptr_eq(g1, g2),
|
||||
(Key::Window(w1), Key::Window(w2)) => w1 == w2,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Eq for Key {}
|
||||
impl From<CosmicMapped> for Key {
|
||||
fn from(window: CosmicMapped) -> Self {
|
||||
Key::Window(window)
|
||||
}
|
||||
}
|
||||
impl From<WindowGroup> for Key {
|
||||
fn from(group: WindowGroup) -> Self {
|
||||
Key::Group(group.alive.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct IndicatorSettings {
|
||||
thickness: u8,
|
||||
alpha: f32,
|
||||
color: [f32; 3],
|
||||
}
|
||||
type IndicatorCache = RefCell<HashMap<Key, (IndicatorSettings, PixelShaderElement)>>;
|
||||
|
||||
impl IndicatorShader {
|
||||
pub fn get<R: AsGlowRenderer>(renderer: &R) -> GlesPixelProgram {
|
||||
|
|
@ -85,50 +130,63 @@ impl IndicatorShader {
|
|||
|
||||
pub fn element<R: AsGlowRenderer>(
|
||||
renderer: &R,
|
||||
key: impl Into<Key>,
|
||||
geo: Rectangle<i32, Logical>,
|
||||
thickness: u8,
|
||||
alpha: f32,
|
||||
color: [f32; 3],
|
||||
) -> PixelShaderElement {
|
||||
let thickness: f32 = thickness as f32;
|
||||
let thickness_loc = (thickness as i32, thickness as i32);
|
||||
let thickness_size = ((thickness * 2.0) as i32, (thickness * 2.0) as i32);
|
||||
let geo = Rectangle::from_loc_and_size(
|
||||
geo.loc - Point::from(thickness_loc),
|
||||
geo.size + Size::from(thickness_size),
|
||||
);
|
||||
let settings = IndicatorSettings {
|
||||
thickness,
|
||||
alpha,
|
||||
color,
|
||||
};
|
||||
|
||||
let user_data = Borrow::<GlesRenderer>::borrow(renderer.glow_renderer())
|
||||
.egl_context()
|
||||
.user_data();
|
||||
|
||||
match user_data.get::<IndicatorElement>() {
|
||||
Some(elem) => {
|
||||
let mut elem = elem.0.borrow_mut();
|
||||
if elem.geometry(1.0.into()).to_logical(1) != geo {
|
||||
elem.resize(geo, None);
|
||||
}
|
||||
elem.clone()
|
||||
}
|
||||
None => {
|
||||
let shader = Self::get(renderer);
|
||||
user_data.insert_if_missing(|| IndicatorCache::new(HashMap::new()));
|
||||
let mut cache = user_data.get::<IndicatorCache>().unwrap().borrow_mut();
|
||||
cache.retain(|k, _| match k {
|
||||
Key::Group(w) => w.upgrade().is_some(),
|
||||
Key::Window(w) => w.alive(),
|
||||
});
|
||||
|
||||
let elem = PixelShaderElement::new(
|
||||
shader,
|
||||
geo,
|
||||
None, //TODO
|
||||
alpha,
|
||||
vec![
|
||||
Uniform::new("color", FOCUS_INDICATOR_COLOR),
|
||||
Uniform::new("thickness", thickness),
|
||||
Uniform::new("radius", thickness * 2.0),
|
||||
],
|
||||
);
|
||||
if !user_data.insert_if_missing(|| IndicatorElement(RefCell::new(elem.clone()))) {
|
||||
*user_data.get::<IndicatorElement>().unwrap().0.borrow_mut() = elem.clone();
|
||||
}
|
||||
elem
|
||||
}
|
||||
let key = key.into();
|
||||
if cache
|
||||
.get(&key)
|
||||
.filter(|(old_settings, _)| &settings == old_settings)
|
||||
.is_none()
|
||||
{
|
||||
let thickness: f32 = thickness as f32;
|
||||
let thickness_loc = (thickness as i32, thickness as i32);
|
||||
let thickness_size = ((thickness * 2.0) as i32, (thickness * 2.0) as i32);
|
||||
let geo = Rectangle::from_loc_and_size(
|
||||
geo.loc - Point::from(thickness_loc),
|
||||
geo.size + Size::from(thickness_size),
|
||||
);
|
||||
let shader = Self::get(renderer);
|
||||
|
||||
let elem = PixelShaderElement::new(
|
||||
shader,
|
||||
geo,
|
||||
None, //TODO
|
||||
alpha,
|
||||
vec![
|
||||
Uniform::new("color", color),
|
||||
Uniform::new("thickness", thickness),
|
||||
Uniform::new("radius", thickness * 2.0),
|
||||
],
|
||||
);
|
||||
cache.insert(key.clone(), (settings, elem));
|
||||
}
|
||||
|
||||
let elem = &mut cache.get_mut(&key).unwrap().1;
|
||||
if elem.geometry(1.0.into()).to_logical(1) != geo {
|
||||
elem.resize(geo, None);
|
||||
}
|
||||
elem.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,6 +365,7 @@ where
|
|||
&state.shell.override_redirect_windows,
|
||||
state.xwayland_state.as_mut(),
|
||||
(!move_active && is_active_space).then_some(&last_active_seat),
|
||||
true,
|
||||
state.config.static_conf.active_hint,
|
||||
exclude_workspace_overview,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use smithay::{
|
|||
input::KeyState,
|
||||
renderer::{
|
||||
element::{
|
||||
utils::CropRenderElement, AsRenderElements, Element, RenderElement,
|
||||
UnderlyingStorage,
|
||||
utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement},
|
||||
AsRenderElements, Element, RenderElement, UnderlyingStorage,
|
||||
},
|
||||
gles::element::PixelShaderElement,
|
||||
glow::GlowRenderer,
|
||||
|
|
@ -259,7 +259,7 @@ impl CosmicMapped {
|
|||
}
|
||||
|
||||
pub fn set_tiled(&self, tiled: bool) {
|
||||
for window in match &self.element {
|
||||
if let Some(window) = match &self.element {
|
||||
// we use the tiled state of stack windows anyway to get rid of decorations
|
||||
CosmicMappedInternal::Stack(_) => None,
|
||||
CosmicMappedInternal::Window(w) => Some(w.surface()),
|
||||
|
|
@ -681,8 +681,16 @@ where
|
|||
{
|
||||
Stack(self::stack::CosmicStackRenderElement<R>),
|
||||
Window(self::window::CosmicWindowRenderElement<R>),
|
||||
CroppedStack(CropRenderElement<self::stack::CosmicStackRenderElement<R>>),
|
||||
CroppedWindow(CropRenderElement<self::window::CosmicWindowRenderElement<R>>),
|
||||
TiledStack(
|
||||
RelocateRenderElement<
|
||||
RescaleRenderElement<CropRenderElement<self::stack::CosmicStackRenderElement<R>>>,
|
||||
>,
|
||||
),
|
||||
TiledWindow(
|
||||
RelocateRenderElement<
|
||||
RescaleRenderElement<CropRenderElement<self::window::CosmicWindowRenderElement<R>>>,
|
||||
>,
|
||||
),
|
||||
Indicator(PixelShaderElement),
|
||||
#[cfg(feature = "debug")]
|
||||
Egui(TextureRenderElement<GlesTexture>),
|
||||
|
|
@ -697,8 +705,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.id(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.id(),
|
||||
|
|
@ -709,8 +717,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.current_commit(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.current_commit(),
|
||||
|
|
@ -721,8 +729,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.src(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.src(),
|
||||
|
|
@ -733,8 +741,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.geometry(scale),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.geometry(scale),
|
||||
|
|
@ -745,8 +753,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.location(scale),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.location(scale),
|
||||
|
|
@ -757,8 +765,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.transform(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.transform(),
|
||||
|
|
@ -773,8 +781,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.damage_since(scale, commit),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.damage_since(scale, commit),
|
||||
|
|
@ -785,8 +793,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.opaque_regions(scale),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.opaque_regions(scale),
|
||||
|
|
@ -797,8 +805,8 @@ where
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.alpha(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.alpha(),
|
||||
|
|
@ -817,8 +825,8 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::Indicator(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
|
||||
}
|
||||
|
|
@ -833,8 +841,8 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::Indicator(elem) => elem.underlying_storage(renderer),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.underlying_storage(renderer),
|
||||
|
|
@ -855,8 +863,8 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::Indicator(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage)
|
||||
.map_err(|err| MultiError::Render(err))
|
||||
|
|
@ -877,8 +885,8 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
|
|||
match self {
|
||||
CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::CroppedStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::CroppedWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::Indicator(elem) => {
|
||||
elem.underlying_storage(renderer.glow_renderer_mut())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ impl From<KeyboardFocusTarget> for PointerFocusTarget {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowGroup {
|
||||
pub(in crate::shell) node: NodeId,
|
||||
pub(in crate::shell) output: WeakOutput,
|
||||
pub(in crate::shell) alive: Weak<()>,
|
||||
pub node: NodeId,
|
||||
pub output: WeakOutput,
|
||||
pub alive: Weak<()>,
|
||||
}
|
||||
|
||||
impl PartialEq for WindowGroup {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::{
|
||||
backend::render::{element::AsGlowRenderer, IndicatorShader},
|
||||
backend::render::{element::AsGlowRenderer, IndicatorShader, FOCUS_INDICATOR_COLOR},
|
||||
shell::{
|
||||
element::{window::CosmicWindowRenderElement, CosmicMapped, CosmicMappedRenderElement},
|
||||
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||
|
|
@ -66,9 +66,11 @@ impl MoveGrabState {
|
|||
elements.push(
|
||||
CosmicMappedRenderElement::from(IndicatorShader::element(
|
||||
renderer,
|
||||
self.window.clone(),
|
||||
Rectangle::from_loc_and_size(render_location, self.window.geometry().size),
|
||||
self.indicator_thickness,
|
||||
1.0,
|
||||
FOCUS_INDICATOR_COLOR,
|
||||
))
|
||||
.into(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use smithay::{
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
backend::render::{element::AsGlowRenderer, IndicatorShader},
|
||||
backend::render::{element::AsGlowRenderer, IndicatorShader, FOCUS_INDICATOR_COLOR},
|
||||
shell::{
|
||||
element::{window::CosmicWindowRenderElement, CosmicMapped, CosmicMappedRenderElement},
|
||||
grabs::ResizeEdge,
|
||||
|
|
@ -380,12 +380,14 @@ impl FloatingLayout {
|
|||
if indicator_thickness > 0 {
|
||||
let element = IndicatorShader::element(
|
||||
renderer,
|
||||
elem.clone(),
|
||||
Rectangle::from_loc_and_size(
|
||||
self.space.element_location(elem).unwrap() - output_loc,
|
||||
elem.geometry().size,
|
||||
),
|
||||
indicator_thickness,
|
||||
1.0,
|
||||
FOCUS_INDICATOR_COLOR,
|
||||
);
|
||||
elements.insert(0, element.into());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::{
|
||||
backend::render::{element::AsGlowRenderer, IndicatorShader},
|
||||
backend::render::{
|
||||
element::AsGlowRenderer, IndicatorShader, Key, ACTIVE_GROUP_COLOR, FOCUS_INDICATOR_COLOR,
|
||||
GROUP_COLOR,
|
||||
},
|
||||
shell::{
|
||||
element::{window::CosmicWindowRenderElement, CosmicMapped, CosmicMappedRenderElement},
|
||||
focus::{
|
||||
|
|
@ -23,7 +26,10 @@ use cosmic_time::{Cubic, Ease, Tween};
|
|||
use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree};
|
||||
use smithay::{
|
||||
backend::renderer::{
|
||||
element::{utils::CropRenderElement, AsRenderElements, RenderElement},
|
||||
element::{
|
||||
utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement},
|
||||
AsRenderElements, RenderElement,
|
||||
},
|
||||
ImportAll, ImportMem, Renderer,
|
||||
},
|
||||
desktop::{layer_map_for_output, space::SpaceElement, PopupKind},
|
||||
|
|
@ -1432,6 +1438,8 @@ impl TilingLayout {
|
|||
renderer: &mut R,
|
||||
output: &Output,
|
||||
focused: Option<&CosmicMapped>,
|
||||
non_exclusive_zone: Rectangle<i32, Logical>,
|
||||
draw_groups: bool,
|
||||
indicator_thickness: u8,
|
||||
) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
|
||||
where
|
||||
|
|
@ -1473,213 +1481,589 @@ impl TilingLayout {
|
|||
|
||||
let mut elements = Vec::new();
|
||||
|
||||
// all old windows and fade them out
|
||||
if let Some(reference_tree) = reference_tree.as_ref() {
|
||||
if let Some(root) = reference_tree.root_node_id() {
|
||||
elements.extend(
|
||||
reference_tree
|
||||
.traverse_pre_order(root)
|
||||
.unwrap()
|
||||
.filter(|node| node.data().is_mapped(None))
|
||||
.map(|node| match node.data() {
|
||||
Data::Mapped {
|
||||
mapped,
|
||||
last_geometry,
|
||||
..
|
||||
} => (mapped, last_geometry),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.filter(|(mapped, _)| {
|
||||
if let Some(root) = target_tree.root_node_id() {
|
||||
!target_tree
|
||||
.traverse_pre_order(root)
|
||||
.unwrap()
|
||||
.any(|node| node.data().is_mapped(Some(mapped)))
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.flat_map(|(mapped, geo)| {
|
||||
let crop_rect = geo.clone();
|
||||
AsRenderElements::<R>::render_elements::<CosmicMappedRenderElement<R>>(
|
||||
mapped,
|
||||
renderer,
|
||||
geo.loc.to_physical_precise_round(output_scale)
|
||||
- mapped
|
||||
.geometry()
|
||||
.loc
|
||||
.to_physical_precise_round(output_scale),
|
||||
Scale::from(output_scale),
|
||||
1.0 - percentage,
|
||||
)
|
||||
.into_iter()
|
||||
.flat_map(|element| match element {
|
||||
CosmicMappedRenderElement::Stack(elem) => {
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)
|
||||
.map(CosmicMappedRenderElement::CroppedStack)
|
||||
}
|
||||
CosmicMappedRenderElement::Window(elem) => {
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)
|
||||
.map(CosmicMappedRenderElement::CroppedWindow)
|
||||
}
|
||||
x => Some(x),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}),
|
||||
// all gone windows and fade them out
|
||||
let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() {
|
||||
let (geometries, _) = if draw_groups {
|
||||
geometries_for_groupview(
|
||||
reference_tree,
|
||||
renderer,
|
||||
non_exclusive_zone,
|
||||
focused, // 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 - percentage,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
.unzip();
|
||||
|
||||
if let Some(root) = target_tree.root_node_id() {
|
||||
elements.extend(
|
||||
target_tree
|
||||
.traverse_pre_order(root)
|
||||
.unwrap()
|
||||
.filter(|node| node.data().is_mapped(None))
|
||||
.filter(|node| match node.data() {
|
||||
Data::Mapped { mapped, .. } => mapped.is_activated(),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.map(|node| match node.data() {
|
||||
Data::Mapped {
|
||||
mapped,
|
||||
last_geometry,
|
||||
..
|
||||
} => (mapped, last_geometry),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.chain(
|
||||
target_tree
|
||||
.traverse_pre_order(root)
|
||||
.unwrap()
|
||||
.filter(|node| node.data().is_mapped(None))
|
||||
.filter(|node| match node.data() {
|
||||
Data::Mapped { mapped, .. } => !mapped.is_activated(),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.map(|node| match node.data() {
|
||||
Data::Mapped {
|
||||
mapped,
|
||||
last_geometry,
|
||||
..
|
||||
} => (mapped, last_geometry),
|
||||
_ => unreachable!(),
|
||||
}),
|
||||
)
|
||||
.flat_map(|(mapped, new_geo)| {
|
||||
let old_geo = if let Some(reference_tree) = reference_tree.as_ref() {
|
||||
if let Some(root) = reference_tree.root_node_id() {
|
||||
reference_tree
|
||||
.traverse_pre_order(root)
|
||||
.unwrap()
|
||||
.find(|node| node.data().is_mapped(Some(mapped)))
|
||||
.map(|node| match node.data() {
|
||||
Data::Mapped { last_geometry, .. } => last_geometry,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// all old windows we want to fade out
|
||||
elements.extend(render_old_tree(
|
||||
reference_tree,
|
||||
target_tree,
|
||||
renderer,
|
||||
geometries.clone(),
|
||||
output_scale,
|
||||
percentage,
|
||||
));
|
||||
|
||||
let (geo, alpha) = if let Some(old_geo) = old_geo {
|
||||
(
|
||||
Rectangle::from_loc_and_size(
|
||||
(
|
||||
old_geo.loc.x
|
||||
+ ((new_geo.loc.x - old_geo.loc.x) as f32 * percentage)
|
||||
.round()
|
||||
as i32,
|
||||
old_geo.loc.y
|
||||
+ ((new_geo.loc.y - old_geo.loc.y) as f32 * percentage)
|
||||
.round()
|
||||
as i32,
|
||||
),
|
||||
(
|
||||
old_geo.size.w
|
||||
+ ((new_geo.size.w - old_geo.size.w) as f32
|
||||
* percentage)
|
||||
.round()
|
||||
as i32,
|
||||
old_geo.size.h
|
||||
+ ((new_geo.size.h - old_geo.size.h) as f32
|
||||
* percentage)
|
||||
.round()
|
||||
as i32,
|
||||
),
|
||||
),
|
||||
1.0,
|
||||
)
|
||||
} else {
|
||||
// TODO: If old_geo.is_none() animate alpha - fade in
|
||||
(*new_geo, percentage)
|
||||
};
|
||||
geometries
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if alpha < 1.0 {
|
||||
dbg!(alpha);
|
||||
}
|
||||
|
||||
let crop_rect = geo.clone();
|
||||
let mut elements =
|
||||
AsRenderElements::<R>::render_elements::<CosmicMappedRenderElement<R>>(
|
||||
mapped,
|
||||
renderer,
|
||||
geo.loc.to_physical_precise_round(output_scale)
|
||||
- mapped
|
||||
.geometry()
|
||||
.loc
|
||||
.to_physical_precise_round(output_scale),
|
||||
Scale::from(output_scale),
|
||||
alpha,
|
||||
)
|
||||
.into_iter()
|
||||
.flat_map(|element| match element {
|
||||
CosmicMappedRenderElement::Stack(elem) => {
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)
|
||||
.map(CosmicMappedRenderElement::CroppedStack)
|
||||
}
|
||||
CosmicMappedRenderElement::Window(elem) => {
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)
|
||||
.map(CosmicMappedRenderElement::CroppedWindow)
|
||||
}
|
||||
x => Some(x),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if focused == Some(mapped) {
|
||||
if indicator_thickness > 0 {
|
||||
let element = IndicatorShader::element(
|
||||
renderer,
|
||||
geo,
|
||||
indicator_thickness,
|
||||
1.0,
|
||||
);
|
||||
elements.insert(0, element.into());
|
||||
}
|
||||
}
|
||||
elements
|
||||
}),
|
||||
let (geometries, group_elements) = if draw_groups {
|
||||
geometries_for_groupview(
|
||||
target_tree,
|
||||
renderer,
|
||||
non_exclusive_zone,
|
||||
focused,
|
||||
percentage,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.unzip();
|
||||
|
||||
// tiling hints
|
||||
if let Some(group_elements) = group_elements {
|
||||
elements.extend(group_elements);
|
||||
}
|
||||
|
||||
// all alive windows
|
||||
elements.extend(render_new_tree(
|
||||
target_tree,
|
||||
reference_tree,
|
||||
renderer,
|
||||
geometries,
|
||||
old_geometries,
|
||||
focused,
|
||||
output_scale,
|
||||
percentage,
|
||||
if draw_groups { 3 } else { indicator_thickness },
|
||||
));
|
||||
|
||||
Ok(elements)
|
||||
}
|
||||
}
|
||||
|
||||
fn geometries_for_groupview<R>(
|
||||
tree: &Tree<Data>,
|
||||
renderer: &mut R,
|
||||
non_exclusive_zone: Rectangle<i32, Logical>,
|
||||
focused: Option<&CosmicMapped>,
|
||||
alpha: f32,
|
||||
) -> Option<(
|
||||
HashMap<NodeId, Rectangle<i32, Logical>>,
|
||||
Vec<CosmicMappedRenderElement<R>>,
|
||||
)>
|
||||
where
|
||||
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||
<R as Renderer>::TextureId: 'static,
|
||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||
CosmicWindowRenderElement<R>: RenderElement<R>,
|
||||
{
|
||||
// we need to recalculate geometry for all elements, if we are drawing groups
|
||||
if let Some(root) = tree.root_node_id() {
|
||||
let mut stack = vec![non_exclusive_zone];
|
||||
let mut elements = Vec::new();
|
||||
let mut geometries = HashMap::new();
|
||||
|
||||
const GAP: i32 = 16;
|
||||
for node_id in tree.traverse_pre_order_ids(root).unwrap() {
|
||||
if let Some(mut geo) = stack.pop() {
|
||||
// zoom in windows
|
||||
geo.loc += (GAP, GAP).into();
|
||||
geo.size -= (GAP * 2, GAP * 2).into();
|
||||
|
||||
let node: &Node<Data> = tree.get(&node_id).unwrap();
|
||||
let data = node.data();
|
||||
|
||||
let is_potential_group = if let Some(focused) = focused {
|
||||
// 1. focused can move into us directly
|
||||
if let Some(parent) = node.parent() {
|
||||
let parent_data = tree.get(parent).unwrap().data();
|
||||
|
||||
let idx = tree
|
||||
.children_ids(parent)
|
||||
.unwrap()
|
||||
.position(|id| id == &node_id)
|
||||
.unwrap();
|
||||
if let Some((focused_idx, _focused_id)) = tree
|
||||
.children_ids(parent)
|
||||
.unwrap()
|
||||
.enumerate()
|
||||
.find(|(_, child_id)| {
|
||||
tree.get(child_id).unwrap().data().is_mapped(Some(focused))
|
||||
})
|
||||
{
|
||||
// only direct neighbors
|
||||
focused_idx.abs_diff(idx) == 1
|
||||
// skip neighbors, if this is a group of two windows
|
||||
&& !(parent_data.len() == 2 && data.is_mapped(None))
|
||||
// skip groups of two in opposite orientation to indicate move between
|
||||
&& !(parent_data.len() == 2 && if data.is_group() { parent_data.orientation() != data.orientation() } else { false } )
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
// 2. focused can move out into us
|
||||
else {
|
||||
tree.children_ids(&node_id)
|
||||
.unwrap()
|
||||
.find(|child_id| {
|
||||
tree.children(child_id)
|
||||
.unwrap()
|
||||
.any(|child| child.data().is_mapped(Some(focused)))
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
match data {
|
||||
Data::Group {
|
||||
orientation,
|
||||
last_geometry,
|
||||
sizes,
|
||||
alive,
|
||||
} => {
|
||||
let has_active_child = if let Some(focused) = focused {
|
||||
tree.children(&node_id)
|
||||
.unwrap()
|
||||
.any(|child| child.data().is_mapped(Some(focused)))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if (is_potential_group || has_active_child) && &node_id != root {
|
||||
elements.push(
|
||||
IndicatorShader::element(
|
||||
renderer,
|
||||
Key::Group(Arc::downgrade(&alive)),
|
||||
geo,
|
||||
3,
|
||||
alpha,
|
||||
if has_active_child {
|
||||
ACTIVE_GROUP_COLOR
|
||||
} else {
|
||||
GROUP_COLOR
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
geometries.insert(node_id.clone(), geo);
|
||||
|
||||
let previous_length = match orientation {
|
||||
Orientation::Horizontal => last_geometry.size.h,
|
||||
Orientation::Vertical => last_geometry.size.w,
|
||||
};
|
||||
let new_length = match orientation {
|
||||
Orientation::Horizontal => geo.size.h,
|
||||
Orientation::Vertical => geo.size.w,
|
||||
};
|
||||
|
||||
let mut sizes = sizes
|
||||
.iter()
|
||||
.map(|len| {
|
||||
(((*len as f64) / (previous_length as f64)) * (new_length as f64))
|
||||
.round() as i32
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let sum: i32 = sizes.iter().sum();
|
||||
if sum < new_length {
|
||||
*sizes.last_mut().unwrap() += new_length - sum;
|
||||
}
|
||||
|
||||
match orientation {
|
||||
Orientation::Horizontal => {
|
||||
let mut previous: i32 = sizes.iter().sum();
|
||||
for size in sizes.iter().rev() {
|
||||
previous -= *size;
|
||||
stack.push(Rectangle::from_loc_and_size(
|
||||
(geo.loc.x, geo.loc.y + previous),
|
||||
(geo.size.w, *size),
|
||||
));
|
||||
}
|
||||
}
|
||||
Orientation::Vertical => {
|
||||
let mut previous: i32 = sizes.iter().sum();
|
||||
for size in sizes.iter().rev() {
|
||||
previous -= *size;
|
||||
stack.push(Rectangle::from_loc_and_size(
|
||||
(geo.loc.x + previous, geo.loc.y),
|
||||
(*size, geo.size.h),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Mapped { mapped, .. } => {
|
||||
if is_potential_group {
|
||||
elements.push(
|
||||
IndicatorShader::element(
|
||||
renderer,
|
||||
mapped.clone(),
|
||||
geo,
|
||||
3,
|
||||
alpha,
|
||||
GROUP_COLOR,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
|
||||
geo.loc += (GAP, GAP).into();
|
||||
geo.size -= (GAP * 2, GAP * 2).into();
|
||||
}
|
||||
|
||||
geometries.insert(node_id.clone(), geo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some((geometries, elements))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn render_old_tree<R>(
|
||||
reference_tree: &Tree<Data>,
|
||||
target_tree: &Tree<Data>,
|
||||
renderer: &mut R,
|
||||
geometries: Option<HashMap<NodeId, Rectangle<i32, Logical>>>,
|
||||
output_scale: f64,
|
||||
percentage: f32,
|
||||
) -> Vec<CosmicMappedRenderElement<R>>
|
||||
where
|
||||
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||
<R as Renderer>::TextureId: 'static,
|
||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||
CosmicWindowRenderElement<R>: RenderElement<R>,
|
||||
{
|
||||
if let Some(root) = reference_tree.root_node_id() {
|
||||
let geometries = geometries.unwrap_or_default();
|
||||
reference_tree
|
||||
.traverse_pre_order_ids(root)
|
||||
.unwrap()
|
||||
.filter(|node_id| reference_tree.get(node_id).unwrap().data().is_mapped(None))
|
||||
.map(
|
||||
|node_id| match reference_tree.get(&node_id).unwrap().data() {
|
||||
Data::Mapped {
|
||||
mapped,
|
||||
last_geometry,
|
||||
..
|
||||
} => (mapped, last_geometry, geometries.get(&node_id)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
)
|
||||
.filter(|(mapped, _, _)| {
|
||||
if let Some(root) = target_tree.root_node_id() {
|
||||
!target_tree
|
||||
.traverse_pre_order(root)
|
||||
.unwrap()
|
||||
.any(|node| node.data().is_mapped(Some(mapped)))
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.flat_map(|(mapped, original_geo, scaled_geo)| {
|
||||
let (scale, offset) = scaled_geo
|
||||
.map(|adapted_geo| scale_to_center(&original_geo, adapted_geo))
|
||||
.unwrap_or_else(|| (1.0.into(), (0, 0).into()));
|
||||
let 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 crop_rect = geo.clone();
|
||||
let original_location = original_geo.loc.to_physical_precise_round(output_scale)
|
||||
- mapped
|
||||
.geometry()
|
||||
.loc
|
||||
.to_physical_precise_round(output_scale);
|
||||
AsRenderElements::<R>::render_elements::<CosmicMappedRenderElement<R>>(
|
||||
mapped,
|
||||
renderer,
|
||||
original_location,
|
||||
Scale::from(output_scale),
|
||||
1.0 - percentage,
|
||||
)
|
||||
.into_iter()
|
||||
.flat_map(|element| match element {
|
||||
CosmicMappedRenderElement::Stack(elem) => Some(
|
||||
CosmicMappedRenderElement::TiledStack(RelocateRenderElement::from_element(
|
||||
RescaleRenderElement::from_element(
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)?,
|
||||
original_location,
|
||||
scale,
|
||||
),
|
||||
geo.loc.to_physical_precise_round(output_scale),
|
||||
Relocate::Absolute,
|
||||
)),
|
||||
),
|
||||
CosmicMappedRenderElement::Window(elem) => {
|
||||
Some(CosmicMappedRenderElement::TiledWindow(
|
||||
RelocateRenderElement::from_element(
|
||||
RescaleRenderElement::from_element(
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)?,
|
||||
(0, 0).into(),
|
||||
scale,
|
||||
),
|
||||
geo.loc.to_physical_precise_round(output_scale),
|
||||
Relocate::Absolute,
|
||||
),
|
||||
))
|
||||
}
|
||||
x => Some(x),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn render_new_tree<R>(
|
||||
target_tree: &Tree<Data>,
|
||||
reference_tree: Option<&Tree<Data>>,
|
||||
renderer: &mut R,
|
||||
geometries: Option<HashMap<NodeId, Rectangle<i32, Logical>>>,
|
||||
old_geometries: Option<HashMap<NodeId, Rectangle<i32, Logical>>>,
|
||||
focused: Option<&CosmicMapped>,
|
||||
output_scale: f64,
|
||||
percentage: f32,
|
||||
indicator_thickness: u8,
|
||||
) -> Vec<CosmicMappedRenderElement<R>>
|
||||
where
|
||||
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||
<R as Renderer>::TextureId: 'static,
|
||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||
CosmicWindowRenderElement<R>: RenderElement<R>,
|
||||
{
|
||||
if let Some(root) = target_tree.root_node_id() {
|
||||
let old_geometries = old_geometries.unwrap_or_default();
|
||||
let geometries = geometries.unwrap_or_default();
|
||||
target_tree
|
||||
.traverse_pre_order_ids(root)
|
||||
.unwrap()
|
||||
.filter(|node_id| target_tree.get(node_id).unwrap().data().is_mapped(None))
|
||||
.map(|node_id| match target_tree.get(&node_id).unwrap().data() {
|
||||
Data::Mapped {
|
||||
mapped,
|
||||
last_geometry,
|
||||
..
|
||||
} => (mapped, last_geometry, geometries.get(&node_id)),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.flat_map(|(mapped, original_geo, scaled_geo)| {
|
||||
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(|node_id| {
|
||||
reference_tree
|
||||
.get(node_id)
|
||||
.unwrap()
|
||||
.data()
|
||||
.is_mapped(Some(mapped))
|
||||
})
|
||||
.map(
|
||||
|node_id| match reference_tree.get(&node_id).unwrap().data() {
|
||||
Data::Mapped { last_geometry, .. } => {
|
||||
(last_geometry, old_geometries.get(&node_id))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.unzip();
|
||||
let 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)
|
||||
});
|
||||
|
||||
let crop_rect = original_geo;
|
||||
let (scale, offset) = scaled_geo
|
||||
.map(|adapted_geo| scale_to_center(original_geo, adapted_geo))
|
||||
.unwrap_or_else(|| (1.0.into(), (0, 0).into()));
|
||||
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) = if let Some(old_geo) = old_geo {
|
||||
(
|
||||
Rectangle::from_loc_and_size(
|
||||
(
|
||||
old_geo.loc.x
|
||||
+ ((new_geo.loc.x - old_geo.loc.x) as f32 * percentage).round()
|
||||
as i32,
|
||||
old_geo.loc.y
|
||||
+ ((new_geo.loc.y - old_geo.loc.y) as f32 * percentage).round()
|
||||
as i32,
|
||||
),
|
||||
(
|
||||
old_geo.size.w
|
||||
+ ((new_geo.size.w - old_geo.size.w) as f32 * percentage)
|
||||
.round() as i32,
|
||||
old_geo.size.h
|
||||
+ ((new_geo.size.h - old_geo.size.h) as f32 * percentage)
|
||||
.round() as i32,
|
||||
),
|
||||
),
|
||||
1.0,
|
||||
)
|
||||
} else {
|
||||
(new_geo, percentage)
|
||||
};
|
||||
|
||||
let original_location = original_geo.loc.to_physical_precise_round(output_scale)
|
||||
- mapped
|
||||
.geometry()
|
||||
.loc
|
||||
.to_physical_precise_round(output_scale);
|
||||
let mut elements = AsRenderElements::<R>::render_elements::<
|
||||
CosmicMappedRenderElement<R>,
|
||||
>(
|
||||
mapped,
|
||||
renderer,
|
||||
original_location,
|
||||
Scale::from(output_scale),
|
||||
alpha,
|
||||
)
|
||||
.into_iter()
|
||||
.flat_map(|element| match element {
|
||||
CosmicMappedRenderElement::Stack(elem) => Some(
|
||||
CosmicMappedRenderElement::TiledStack(RelocateRenderElement::from_element(
|
||||
RescaleRenderElement::from_element(
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)?,
|
||||
original_location,
|
||||
scale,
|
||||
),
|
||||
geo.loc.to_physical_precise_round(output_scale),
|
||||
Relocate::Absolute,
|
||||
)),
|
||||
),
|
||||
CosmicMappedRenderElement::Window(elem) => {
|
||||
Some(CosmicMappedRenderElement::TiledWindow(
|
||||
RelocateRenderElement::from_element(
|
||||
RescaleRenderElement::from_element(
|
||||
CropRenderElement::from_element(
|
||||
elem,
|
||||
output_scale,
|
||||
crop_rect.to_physical_precise_round(output_scale),
|
||||
)?,
|
||||
(0, 0).into(),
|
||||
scale,
|
||||
),
|
||||
geo.loc.to_physical_precise_round(output_scale),
|
||||
Relocate::Absolute,
|
||||
),
|
||||
))
|
||||
}
|
||||
x => Some(x),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if focused == Some(mapped) {
|
||||
if indicator_thickness > 0 {
|
||||
let element = IndicatorShader::element(
|
||||
renderer,
|
||||
mapped.clone(),
|
||||
geo,
|
||||
indicator_thickness,
|
||||
1.0,
|
||||
FOCUS_INDICATOR_COLOR,
|
||||
);
|
||||
elements.insert(0, element.into());
|
||||
}
|
||||
}
|
||||
|
||||
elements
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn scale_to_center(
|
||||
old_geo: &Rectangle<i32, Logical>,
|
||||
new_geo: &Rectangle<i32, Logical>,
|
||||
) -> (f64, Point<i32, Logical>) {
|
||||
let scale_w = new_geo.size.w as f64 / old_geo.size.w as f64;
|
||||
let scale_h = new_geo.size.h as f64 / old_geo.size.h as f64;
|
||||
|
||||
if scale_w > scale_h {
|
||||
(
|
||||
scale_h,
|
||||
(
|
||||
((new_geo.size.w as f64 - old_geo.size.w as f64 * scale_h) / 2.0).round() as i32,
|
||||
0,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
scale_w,
|
||||
(
|
||||
0,
|
||||
((new_geo.size.h as f64 - old_geo.size.h as f64 * scale_w) / 2.0).round() as i32,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,6 +454,7 @@ impl Workspace {
|
|||
override_redirect_windows: &[X11Surface],
|
||||
xwm_state: Option<&'a mut XWaylandState>,
|
||||
draw_focus_indicator: Option<&Seat<State>>,
|
||||
draw_groups: bool,
|
||||
indicator_thickness: u8,
|
||||
exclude_workspace_overview: bool,
|
||||
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
|
||||
|
|
@ -604,7 +605,14 @@ impl Workspace {
|
|||
//tiling surfaces
|
||||
render_elements.extend(
|
||||
self.tiling_layer
|
||||
.render_output::<R>(renderer, output, focused.as_ref(), indicator_thickness)?
|
||||
.render_output::<R>(
|
||||
renderer,
|
||||
output,
|
||||
focused.as_ref(),
|
||||
layer_map.non_exclusive_zone(),
|
||||
draw_groups,
|
||||
indicator_thickness,
|
||||
)?
|
||||
.into_iter()
|
||||
.map(WorkspaceRenderElement::from),
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue