tiling: Add support for placeholder nodes

This commit is contained in:
Victoria Brekenfeld 2023-07-17 21:35:59 +02:00
parent f00dda7591
commit 8f2aa4e8a5

View file

@ -15,7 +15,7 @@ use crate::{
}, },
grabs::ResizeEdge, grabs::ResizeEdge,
layout::Orientation, layout::Orientation,
CosmicSurface, OutputNotMapped, OverviewMode, ResizeDirection, ResizeMode, CosmicSurface, OutputNotMapped, OverviewMode, ResizeDirection, ResizeMode, Trigger,
}, },
utils::prelude::*, utils::prelude::*,
wayland::{ wayland::{
@ -29,7 +29,7 @@ use smithay::{
backend::renderer::{ backend::renderer::{
element::{ element::{
utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement}, utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement},
AsRenderElements, RenderElement, AsRenderElements, Id, RenderElement,
}, },
ImportAll, ImportMem, Renderer, ImportAll, ImportMem, Renderer,
}, },
@ -147,6 +147,7 @@ pub struct TilingLayout {
queues: HashMap<OutputData, TreeQueue>, queues: HashMap<OutputData, TreeQueue>,
standby_tree: Option<Tree<Data>>, standby_tree: Option<Tree<Data>>,
pending_blockers: Vec<TilingBlocker>, pending_blockers: Vec<TilingBlocker>,
placeholder_id: Id,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -161,6 +162,9 @@ pub enum Data {
mapped: CosmicMapped, mapped: CosmicMapped,
last_geometry: Rectangle<i32, Logical>, last_geometry: Rectangle<i32, Logical>,
}, },
Placeholder {
last_geometry: Rectangle<i32, Logical>,
},
} }
impl Data { impl Data {
@ -194,6 +198,12 @@ impl Data {
_ => false, _ => false,
} }
} }
fn is_placeholder(&self) -> bool {
match self {
Data::Placeholder { .. } => true,
_ => false,
}
}
fn orientation(&self) -> Orientation { fn orientation(&self) -> Orientation {
match self { match self {
@ -225,7 +235,7 @@ impl Data {
sizes.insert(idx, new_size); sizes.insert(idx, new_size);
} }
Data::Mapped { .. } => panic!("Adding window to leaf?"), _ => panic!("Adding window to leaf?"),
} }
} }
@ -234,7 +244,7 @@ impl Data {
Data::Group { sizes, .. } => { Data::Group { sizes, .. } => {
sizes.swap(i, j); sizes.swap(i, j);
} }
Data::Mapped { .. } => panic!("Swapping windows to a leaf?"), _ => panic!("Swapping windows to a leaf?"),
} }
} }
@ -263,7 +273,7 @@ impl Data {
*sizes.last_mut().unwrap() += overflow; *sizes.last_mut().unwrap() += overflow;
} }
} }
Data::Mapped { .. } => panic!("Added window to leaf?"), _ => panic!("Added window to leaf?"),
} }
} }
@ -271,6 +281,7 @@ impl Data {
match self { match self {
Data::Group { last_geometry, .. } => last_geometry, Data::Group { last_geometry, .. } => last_geometry,
Data::Mapped { last_geometry, .. } => last_geometry, Data::Mapped { last_geometry, .. } => last_geometry,
Data::Placeholder { last_geometry } => last_geometry,
} }
} }
@ -301,7 +312,7 @@ impl Data {
} }
*last_geometry = geo; *last_geometry = geo;
} }
Data::Mapped { last_geometry, .. } => { Data::Mapped { last_geometry, .. } | Data::Placeholder { last_geometry } => {
*last_geometry = geo; *last_geometry = geo;
} }
} }
@ -310,7 +321,7 @@ impl Data {
fn len(&self) -> usize { fn len(&self) -> usize {
match self { match self {
Data::Group { sizes, .. } => sizes.len(), Data::Group { sizes, .. } => sizes.len(),
Data::Mapped { .. } => 1, _ => 1,
} }
} }
} }
@ -328,6 +339,7 @@ impl TilingLayout {
queues: HashMap::new(), queues: HashMap::new(),
standby_tree: None, standby_tree: None,
pending_blockers: Vec::new(), pending_blockers: Vec::new(),
placeholder_id: Id::new(),
} }
} }
@ -551,6 +563,44 @@ impl TilingLayout {
Some(output) Some(output)
} }
pub fn unmap_as_placeholder(&mut self, window: &CosmicMapped) -> Option<(Output, NodeId)> {
let node_id = window.tiling_node_id.lock().unwrap().clone()?;
let output = {
self.queues
.iter()
.find(|(_, queue)| {
queue
.trees
.back()
.unwrap()
.0
.get(&node_id)
.map(|node| node.data().is_mapped(Some(window)))
.unwrap_or(false)
})
.map(|(o, _)| o.output.clone())?
};
let data = self
.queues
.get_mut(&output)
.unwrap()
.trees
.back_mut()
.unwrap()
.0
.get_mut(&node_id)
.unwrap()
.data_mut();
*data = Data::Placeholder {
last_geometry: data.geometry().clone(),
};
window.output_leave(&output);
window.set_tiled(false);
Some((output, node_id))
}
fn unmap_window_internal(&mut self, mapped: &CosmicMapped) { fn unmap_window_internal(&mut self, mapped: &CosmicMapped) {
let tiling_node_id = mapped.tiling_node_id.lock().unwrap().as_ref().cloned(); let tiling_node_id = mapped.tiling_node_id.lock().unwrap().as_ref().cloned();
if let Some(node_id) = tiling_node_id { if let Some(node_id) = tiling_node_id {
@ -1018,6 +1068,7 @@ impl TilingLayout {
} }
.into(), .into(),
), ),
Data::Placeholder { .. } => return FocusResult::None,
}; };
} }
} }
@ -1144,6 +1195,7 @@ impl TilingLayout {
Data::Mapped { mapped, .. } => { Data::Mapped { mapped, .. } => {
return FocusResult::Some(mapped.clone().into()); return FocusResult::Some(mapped.clone().into());
} }
Data::Placeholder { .. } => return FocusResult::None,
} }
} }
} else { } else {
@ -1274,7 +1326,7 @@ impl TilingLayout {
} }
Some(mapped.windows().map(|(s, _)| s)) Some(mapped.windows().map(|(s, _)| s))
} }
Data::Group { .. } => None, _ => None,
}) })
.flatten() .flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -1511,6 +1563,52 @@ impl TilingLayout {
true true
} }
pub fn drop_window(
&mut self,
window: CosmicMapped,
output: &Output,
_cursor_pos: Point<f64, Logical>,
) -> Point<i32, Logical> {
// TODO: placeholder until we have proper logic in `element_under` to utilize
let queue = if self.queues.contains_key(output) {
self.queues.get_mut(output)
} else {
self.queues.values_mut().next()
};
let tree = if let Some(queue) = queue {
queue.trees.back_mut().map(|x| &mut x.0)
} else {
self.standby_tree.as_mut()
}
.unwrap();
window.output_enter(&output, window.bbox());
window.set_bounds(output.geometry().size);
if let Some(id) = tree.root_node_id().and_then(|root_id| {
tree.traverse_pre_order_ids(root_id)
.unwrap()
.find(|id| tree.get(id).unwrap().data().is_placeholder())
}) {
let data = tree.get_mut(&id).unwrap().data_mut();
let geo = data.geometry().clone();
*data = Data::Mapped {
mapped: window,
last_geometry: geo,
};
output.geometry().loc + geo.loc
} else {
self.map_internal(
window.clone(),
output,
Option::<std::iter::Empty<_>>::None,
None,
);
output.geometry().loc + self.element_geometry(&window).unwrap().loc
}
}
fn last_active_window<'a>( fn last_active_window<'a>(
tree: &Tree<Data>, tree: &Tree<Data>,
mut focus_stack: impl Iterator<Item = &'a CosmicMapped>, mut focus_stack: impl Iterator<Item = &'a CosmicMapped>,
@ -1723,6 +1821,7 @@ impl TilingLayout {
} }
} }
} }
Data::Placeholder { .. } => {}
} }
} }
} }
@ -2023,6 +2122,8 @@ impl TilingLayout {
let mut window_elements = Vec::new(); let mut window_elements = Vec::new();
let mut popup_elements = Vec::new(); let mut popup_elements = Vec::new();
let is_mouse_tiling = matches!(overview, OverviewMode::Started(Trigger::Pointer(_), _));
// all gone windows and fade them out // all gone windows and fade them out
let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() { let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() {
let (geometries, _) = if let Some(transition) = draw_groups { let (geometries, _) = if let Some(transition) = draw_groups {
@ -2034,6 +2135,8 @@ impl TilingLayout {
// but for that we have to associate focus with a tree (and animate focus changes properly) // but for that we have to associate focus with a tree (and animate focus changes properly)
1.0 - transition, 1.0 - transition,
transition, transition,
&self.placeholder_id,
is_mouse_tiling,
) )
} else { } else {
None None
@ -2065,6 +2168,8 @@ impl TilingLayout {
seat, seat,
transition, transition,
transition, transition,
&self.placeholder_id,
is_mouse_tiling,
) )
} else { } else {
None None
@ -2105,8 +2210,11 @@ impl TilingLayout {
} }
} }
const OUTER_GAP: i32 = 8; const OUTER_GAP_KEYBOARD: i32 = 8;
const INNER_GAP: i32 = 16; const INNER_GAP_KEYBOARD: i32 = 16;
const OUTER_GAP_MOUSE: i32 = 32;
const INNER_GAP_MOUSE: i32 = 16;
fn geometries_for_groupview<R>( fn geometries_for_groupview<R>(
tree: &Tree<Data>, tree: &Tree<Data>,
@ -2115,6 +2223,8 @@ fn geometries_for_groupview<R>(
seat: Option<&Seat<State>>, seat: Option<&Seat<State>>,
alpha: f32, alpha: f32,
transition: f32, transition: f32,
placeholder_id: &Id,
mouse_tiling: bool,
) -> Option<( ) -> Option<(
HashMap<NodeId, Rectangle<i32, Logical>>, HashMap<NodeId, Rectangle<i32, Logical>>,
Vec<CosmicMappedRenderElement<R>>, Vec<CosmicMappedRenderElement<R>>,
@ -2127,8 +2237,20 @@ where
{ {
// we need to recalculate geometry for all elements, if we are drawing groups // we need to recalculate geometry for all elements, if we are drawing groups
if let Some(root) = tree.root_node_id() { if let Some(root) = tree.root_node_id() {
let outer_gap: i32 = (OUTER_GAP as f32 * transition).round() as i32; let outer_gap: i32 = (if mouse_tiling {
let inner_gap: i32 = (INNER_GAP as f32 * transition).round() as i32; OUTER_GAP_MOUSE
} else {
OUTER_GAP_KEYBOARD
} as f32
* transition)
.round() as i32;
let inner_gap: i32 = (if mouse_tiling {
INNER_GAP_MOUSE
} else {
INNER_GAP_KEYBOARD
} as f32
* transition)
.round() as i32;
let mut stack = vec![Rectangle::from_loc_and_size( let mut stack = vec![Rectangle::from_loc_and_size(
non_exclusive_zone.loc + Point::from((outer_gap, outer_gap)), non_exclusive_zone.loc + Point::from((outer_gap, outer_gap)),
@ -2227,6 +2349,19 @@ where
) )
.into(), .into(),
); );
} else if mouse_tiling && node.parent() == Some(&root) {
elements.push(
IndicatorShader::element(
renderer,
Key::Group(Arc::downgrade(alive)),
geo,
4,
8,
alpha * 0.40,
GROUP_COLOR,
)
.into(),
);
} }
geometries.insert(node_id.clone(), geo); geometries.insert(node_id.clone(), geo);
@ -2305,7 +2440,7 @@ where
.unwrap() .unwrap()
.any(|id| id == focused_id) .any(|id| id == focused_id)
}) })
.unwrap_or(false) .unwrap_or(mouse_tiling)
{ {
elements.push( elements.push(
BackdropShader::element( BackdropShader::element(
@ -2332,6 +2467,26 @@ where
geo.loc += (inner_gap, inner_gap).into(); geo.loc += (inner_gap, inner_gap).into();
geo.size -= (inner_gap * 2, inner_gap * 2).into(); geo.size -= (inner_gap * 2, inner_gap * 2).into();
geometries.insert(node_id.clone(), geo);
}
Data::Placeholder { .. } => {
geo.loc += (outer_gap, outer_gap).into();
geo.size -= (outer_gap * 2, outer_gap * 2).into();
geo.loc += (inner_gap, inner_gap).into();
geo.size -= (inner_gap * 2, inner_gap * 2).into();
elements.push(
BackdropShader::element(
renderer,
placeholder_id.clone(),
geo,
8.,
alpha * 0.4,
GROUP_COLOR,
)
.into(),
);
geometries.insert(node_id.clone(), geo); geometries.insert(node_id.clone(), geo);
} }
} }
@ -2616,7 +2771,8 @@ where
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 = (OUTER_GAP as f32 * percentage).round() as i32; let outer_gap: i32 =
(OUTER_GAP_KEYBOARD as f32 * percentage).round() as i32;
geo.loc += (outer_gap, outer_gap).into(); geo.loc += (outer_gap, outer_gap).into();
geo.size -= (outer_gap * 2, outer_gap * 2).into(); geo.size -= (outer_gap * 2, outer_gap * 2).into();
@ -2638,6 +2794,7 @@ where
match data { match data {
Data::Mapped { mapped, .. } => mapped.clone().into(), Data::Mapped { mapped, .. } => mapped.clone().into(),
Data::Group { alive, .. } => Key::Group(Arc::downgrade(alive)), Data::Group { alive, .. } => Key::Group(Arc::downgrade(alive)),
_ => unreachable!(),
}, },
geo, geo,
if data.is_group() { if data.is_group() {