tiling: Don't store trees for outputs, but for indices
This commit is contained in:
parent
91863adcf1
commit
3bc58ec02a
7 changed files with 283 additions and 291 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -74,6 +74,12 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f"
|
||||
|
||||
[[package]]
|
||||
name = "atomic_float"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62af46d040ba9df09edc6528dae9d8e49f5f3e82f55b7d2ec31a733c38dbc49d"
|
||||
|
||||
[[package]]
|
||||
name = "atomic_refcell"
|
||||
version = "0.1.8"
|
||||
|
|
@ -292,6 +298,7 @@ name = "cosmic-comp"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atomic_float",
|
||||
"bitflags",
|
||||
"edid-rs",
|
||||
"egui",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ xkbcommon = "0.4"
|
|||
indexmap = "1.8.0"
|
||||
xdg = "^2.1"
|
||||
ron = "0.7"
|
||||
atomic_float = "0.1"
|
||||
|
||||
[dependencies.smithay]
|
||||
version = "0.3"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl Layout for FloatingLayout {
|
|||
seat: &Seat,
|
||||
_focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||
) {
|
||||
let output = super::output_from_seat(seat, space);
|
||||
let output = super::output_from_seat(Some(seat), space);
|
||||
let win_geo = window.bbox();
|
||||
let layers = layer_map_for_output(&output);
|
||||
let geometry = layers.non_exclusive_zone();
|
||||
|
|
|
|||
|
|
@ -87,9 +87,9 @@ pub trait Layout {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_default_layout(idx: u8) -> Box<dyn Layout> {
|
||||
pub fn new_default_layout() -> Box<dyn Layout> {
|
||||
Box::new(combined::Combined::new(
|
||||
tiling::TilingLayout::new(idx),
|
||||
tiling::TilingLayout::new(),
|
||||
floating::FloatingLayout,
|
||||
|window| {
|
||||
if let Some(surface) = window.toplevel().get_surface() {
|
||||
|
|
@ -128,14 +128,16 @@ pub fn new_default_layout(idx: u8) -> Box<dyn Layout> {
|
|||
))
|
||||
}
|
||||
|
||||
fn output_from_seat(seat: &Seat, space: &Space) -> Output {
|
||||
seat.user_data()
|
||||
.get::<ActiveOutput>()
|
||||
.map(|active| active.0.borrow().clone())
|
||||
.or_else(|| {
|
||||
seat.get_pointer()
|
||||
.map(|ptr| space.output_under(ptr.current_location()).next().unwrap())
|
||||
.cloned()
|
||||
})
|
||||
.unwrap_or_else(|| space.outputs().next().cloned().unwrap())
|
||||
fn output_from_seat(seat: Option<&Seat>, space: &Space) -> Output {
|
||||
seat.and_then(|seat| {
|
||||
seat.user_data()
|
||||
.get::<ActiveOutput>()
|
||||
.map(|active| active.0.borrow().clone())
|
||||
.or_else(|| {
|
||||
seat.get_pointer()
|
||||
.map(|ptr| space.output_under(ptr.current_location()).next().unwrap())
|
||||
.cloned()
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| space.outputs().next().cloned().unwrap())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,22 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
use super::{Data, Orientation, OutputInfo};
|
||||
use id_tree::{NodeId, Tree};
|
||||
use super::Orientation;
|
||||
use atomic_float::AtomicF64;
|
||||
use smithay::{
|
||||
desktop::layer_map_for_output,
|
||||
reexports::wayland_server::protocol::{wl_pointer::ButtonState, wl_surface},
|
||||
utils::{Logical, Point},
|
||||
utils::{Logical, Point, Size},
|
||||
wayland::{
|
||||
output::Output,
|
||||
seat::{AxisFrame, PointerGrab, PointerGrabStartData, PointerInnerHandle},
|
||||
Serial,
|
||||
},
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::sync::{atomic::Ordering, Arc};
|
||||
|
||||
pub struct ResizeForkGrab {
|
||||
pub start_data: PointerGrabStartData,
|
||||
pub node_id: NodeId,
|
||||
pub orientation: Orientation,
|
||||
pub initial_size: Size<i32, Logical>,
|
||||
pub initial_ratio: f64,
|
||||
pub idx: u8,
|
||||
pub output: Output,
|
||||
pub ratio: Arc<AtomicF64>,
|
||||
}
|
||||
|
||||
impl PointerGrab for ResizeForkGrab {
|
||||
|
|
@ -34,28 +32,14 @@ impl PointerGrab for ResizeForkGrab {
|
|||
handle.motion(location, None, serial, time);
|
||||
|
||||
let delta = location - self.start_data.location;
|
||||
|
||||
let mut output_info = self
|
||||
.output
|
||||
.user_data()
|
||||
.get::<RefCell<OutputInfo>>()
|
||||
.unwrap()
|
||||
.borrow_mut();
|
||||
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||
if let Some(&mut Data::Fork {
|
||||
ref mut ratio,
|
||||
ref orientation,
|
||||
}) = tree.get_mut(&self.node_id).map(|x| x.data_mut()).ok()
|
||||
{
|
||||
let size = layer_map_for_output(&self.output).non_exclusive_zone().size;
|
||||
let delta = match orientation {
|
||||
Orientation::Vertical => delta.x / size.w as f64,
|
||||
Orientation::Horizontal => delta.y / size.h as f64,
|
||||
};
|
||||
*ratio = 0.9f64.min(0.1f64.max(self.initial_ratio + delta));
|
||||
} else {
|
||||
handle.unset_grab(serial, time);
|
||||
}
|
||||
let delta = match self.orientation {
|
||||
Orientation::Vertical => delta.x / self.initial_size.w as f64,
|
||||
Orientation::Horizontal => delta.y / self.initial_size.h as f64,
|
||||
};
|
||||
self.ratio.store(
|
||||
0.9f64.min(0.1f64.max(self.initial_ratio + delta)),
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
|
||||
fn button(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::shell::layout::{FocusDirection, Layout, Orientation};
|
||||
use atomic_float::AtomicF64;
|
||||
use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree};
|
||||
use smithay::{
|
||||
desktop::{layer_map_for_output, Kind, Space, Window},
|
||||
|
|
@ -9,27 +10,29 @@ use smithay::{
|
|||
},
|
||||
utils::Rectangle,
|
||||
wayland::{
|
||||
output::Output,
|
||||
seat::{PointerGrabStartData, Seat},
|
||||
Serial,
|
||||
},
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{atomic::Ordering, Arc},
|
||||
};
|
||||
|
||||
mod grabs;
|
||||
pub use self::grabs::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TilingLayout {
|
||||
idx: u8,
|
||||
gaps: (i32, i32),
|
||||
trees: Vec<Tree<Data>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Data {
|
||||
Fork {
|
||||
orientation: Orientation,
|
||||
ratio: f64,
|
||||
ratio: Arc<AtomicF64>,
|
||||
},
|
||||
Stack {
|
||||
active: usize,
|
||||
|
|
@ -41,33 +44,24 @@ pub enum Data {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct WindowInfo {
|
||||
node: NodeId,
|
||||
output: Output,
|
||||
}
|
||||
|
||||
pub struct OutputInfo {
|
||||
trees: HashMap<u8, Tree<Data>>,
|
||||
}
|
||||
|
||||
impl Default for OutputInfo {
|
||||
fn default() -> OutputInfo {
|
||||
OutputInfo {
|
||||
trees: HashMap::new(),
|
||||
}
|
||||
}
|
||||
output: usize,
|
||||
}
|
||||
|
||||
impl Data {
|
||||
fn fork() -> Data {
|
||||
Data::Fork {
|
||||
orientation: Orientation::Vertical,
|
||||
ratio: 0.5,
|
||||
ratio: Arc::new(AtomicF64::new(0.5)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TilingLayout {
|
||||
pub fn new(idx: u8) -> TilingLayout {
|
||||
TilingLayout { idx, gaps: (0, 4) }
|
||||
pub fn new() -> TilingLayout {
|
||||
TilingLayout {
|
||||
gaps: (0, 4),
|
||||
trees: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,72 +71,9 @@ impl Layout for TilingLayout {
|
|||
space: &mut Space,
|
||||
window: &Window,
|
||||
seat: &Seat,
|
||||
mut focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||
focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||
) {
|
||||
{
|
||||
let output = super::output_from_seat(seat, space);
|
||||
output
|
||||
.user_data()
|
||||
.insert_if_missing(|| RefCell::new(OutputInfo::default()));
|
||||
let mut output_info = output
|
||||
.user_data()
|
||||
.get::<RefCell<OutputInfo>>()
|
||||
.unwrap()
|
||||
.borrow_mut();
|
||||
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||
|
||||
let new_window = Node::new(Data::Window(window.clone()));
|
||||
|
||||
let last_active = focus_stack
|
||||
.find_map(|window| tree.root_node_id()
|
||||
.and_then(|root| tree.traverse_pre_order_ids(root).unwrap()
|
||||
.find(|id| matches!(tree.get(id).map(|n| n.data()), Ok(Data::Window(w)) if w == window))
|
||||
)
|
||||
);
|
||||
let window_id = if let Some(ref node_id) = last_active {
|
||||
let parent_id = tree.get(node_id).unwrap().parent().cloned();
|
||||
if let Some(stack_id) = parent_id
|
||||
.filter(|id| matches!(tree.get(id).unwrap().data(), Data::Stack { .. }))
|
||||
{
|
||||
// we add to the stack
|
||||
let window_id = tree
|
||||
.insert(new_window, InsertBehavior::UnderNode(&stack_id))
|
||||
.unwrap();
|
||||
if let Data::Stack {
|
||||
ref mut len,
|
||||
ref mut active,
|
||||
} = tree.get_mut(&stack_id).unwrap().data_mut()
|
||||
{
|
||||
*active = *len;
|
||||
*len += 1;
|
||||
}
|
||||
Ok(window_id)
|
||||
} else {
|
||||
// we create a new fork
|
||||
TilingLayout::new_fork(tree, node_id, new_window)
|
||||
}
|
||||
} else {
|
||||
// nothing? then we add to the root
|
||||
if let Some(root_id) = tree.root_node_id().cloned() {
|
||||
TilingLayout::new_fork(tree, &root_id, new_window)
|
||||
} else {
|
||||
tree.insert(new_window, InsertBehavior::AsRoot)
|
||||
}
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
{
|
||||
let user_data = window.user_data();
|
||||
let window_info = WindowInfo {
|
||||
node: window_id.clone(),
|
||||
output: output.clone(),
|
||||
};
|
||||
// insert or update
|
||||
if !user_data.insert_if_missing(|| RefCell::new(window_info.clone())) {
|
||||
*user_data.get::<RefCell<WindowInfo>>().unwrap().borrow_mut() = window_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.map_window(space, window, Some(seat), Some(focus_stack));
|
||||
self.refresh(space);
|
||||
}
|
||||
|
||||
|
|
@ -153,18 +84,10 @@ impl Layout for TilingLayout {
|
|||
space: &mut Space,
|
||||
focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||
) -> Option<Window> {
|
||||
let output = super::output_from_seat(seat, space);
|
||||
output
|
||||
.user_data()
|
||||
.insert_if_missing(|| RefCell::new(OutputInfo::default()));
|
||||
let mut output_info = output
|
||||
.user_data()
|
||||
.get::<RefCell<OutputInfo>>()
|
||||
.unwrap()
|
||||
.borrow_mut();
|
||||
let tree = output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||
|
||||
if let Some(last_active) = TilingLayout::last_active(tree, focus_stack) {
|
||||
let output = super::output_from_seat(Some(seat), space);
|
||||
let idx = space.outputs().position(|o| *o == output).unwrap_or(0);
|
||||
let tree = TilingLayout::active_tree(&mut self.trees, idx);
|
||||
if let Some(last_active) = TilingLayout::last_active_window(tree, focus_stack) {
|
||||
let mut node_id = last_active;
|
||||
while let Some((fork, child)) = TilingLayout::find_fork(tree, node_id) {
|
||||
if let &Data::Fork {
|
||||
|
|
@ -217,36 +140,45 @@ impl Layout for TilingLayout {
|
|||
space: &mut Space,
|
||||
focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||
) {
|
||||
{
|
||||
let output = super::output_from_seat(seat, space);
|
||||
output
|
||||
.user_data()
|
||||
.insert_if_missing(|| RefCell::new(OutputInfo::default()));
|
||||
let mut output_info = output
|
||||
.user_data()
|
||||
.get::<RefCell<OutputInfo>>()
|
||||
.unwrap()
|
||||
.borrow_mut();
|
||||
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||
|
||||
if let Some(last_active) = TilingLayout::last_active(tree, focus_stack) {
|
||||
if let Some((fork, _child)) = TilingLayout::find_fork(tree, last_active) {
|
||||
if let &mut Data::Fork {
|
||||
ref mut orientation,
|
||||
..
|
||||
} = tree.get_mut(&fork).unwrap().data_mut()
|
||||
{
|
||||
*orientation = new_orientation;
|
||||
}
|
||||
let output = super::output_from_seat(Some(seat), space);
|
||||
let idx = space.outputs().position(|o| *o == output).unwrap_or(0);
|
||||
let tree = TilingLayout::active_tree(&mut self.trees, idx);
|
||||
if let Some(last_active) = TilingLayout::last_active_window(tree, focus_stack) {
|
||||
if let Some((fork, _child)) = TilingLayout::find_fork(tree, last_active) {
|
||||
if let &mut Data::Fork {
|
||||
ref mut orientation,
|
||||
..
|
||||
} = tree.get_mut(&fork).unwrap().data_mut()
|
||||
{
|
||||
*orientation = new_orientation;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.refresh(space);
|
||||
}
|
||||
|
||||
fn refresh(&mut self, space: &mut Space) {
|
||||
fn refresh<'a>(&mut self, space: &mut Space) {
|
||||
let active_outputs = space.outputs().count();
|
||||
if self.trees.len() > active_outputs {
|
||||
for tree in self
|
||||
.trees
|
||||
.drain(active_outputs..self.trees.len())
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
{
|
||||
if let Some(root_id) = tree.root_node_id() {
|
||||
for node in tree.traverse_pre_order(root_id).unwrap() {
|
||||
if let Data::Window(window) = node.data() {
|
||||
self.map_window(space, window, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while let Some(dead_windows) = Some(TilingLayout::update_space_positions(
|
||||
self.idx, space, self.gaps,
|
||||
&mut self.trees,
|
||||
space,
|
||||
self.gaps,
|
||||
))
|
||||
.filter(|v| !v.is_empty())
|
||||
{
|
||||
|
|
@ -264,7 +196,7 @@ impl Layout for TilingLayout {
|
|||
|
||||
fn resize_request(
|
||||
&mut self,
|
||||
_space: &mut Space,
|
||||
space: &mut Space,
|
||||
window: &Window,
|
||||
seat: &Seat,
|
||||
serial: Serial,
|
||||
|
|
@ -273,14 +205,8 @@ impl Layout for TilingLayout {
|
|||
) {
|
||||
if let Some(pointer) = seat.get_pointer() {
|
||||
if let Some(info) = window.user_data().get::<RefCell<WindowInfo>>() {
|
||||
let output = &info.borrow().output;
|
||||
let mut output_info = output
|
||||
.user_data()
|
||||
.get::<RefCell<OutputInfo>>()
|
||||
.unwrap()
|
||||
.borrow_mut();
|
||||
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||
|
||||
let output = info.borrow().output;
|
||||
let tree = TilingLayout::active_tree(&mut self.trees, output);
|
||||
let mut node_id = info.borrow().node.clone();
|
||||
|
||||
while let Some((fork, child)) = TilingLayout::find_fork(tree, node_id) {
|
||||
|
|
@ -297,15 +223,19 @@ impl Layout for TilingLayout {
|
|||
| (false, Orientation::Horizontal, ResizeEdge::Top)
|
||||
| (true, Orientation::Vertical, ResizeEdge::Right)
|
||||
| (false, Orientation::Vertical, ResizeEdge::Left) => {
|
||||
let grab = ResizeForkGrab {
|
||||
start_data,
|
||||
node_id: fork,
|
||||
initial_ratio: *ratio,
|
||||
idx: self.idx,
|
||||
output: output.clone(),
|
||||
};
|
||||
if let Some(output) = space.outputs().nth(output) {
|
||||
let grab = ResizeForkGrab {
|
||||
start_data,
|
||||
orientation: *orientation,
|
||||
initial_ratio: ratio.load(Ordering::SeqCst),
|
||||
initial_size: layer_map_for_output(output)
|
||||
.non_exclusive_zone()
|
||||
.size,
|
||||
ratio: ratio.clone(),
|
||||
};
|
||||
|
||||
pointer.set_grab(grab, serial, 0);
|
||||
pointer.set_grab(grab, serial, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_ => {} // continue iterating
|
||||
|
|
@ -319,9 +249,16 @@ impl Layout for TilingLayout {
|
|||
}
|
||||
|
||||
impl TilingLayout {
|
||||
fn last_active<'a>(
|
||||
fn active_tree<'a>(trees: &'a mut Vec<Tree<Data>>, output: usize) -> &'a mut Tree<Data> {
|
||||
while trees.len() <= output {
|
||||
trees.push(Tree::new())
|
||||
}
|
||||
&mut trees[output]
|
||||
}
|
||||
|
||||
fn last_active_window<'a>(
|
||||
tree: &mut Tree<Data>,
|
||||
mut focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||
mut focus_stack: impl Iterator<Item = &'a Window>,
|
||||
) -> Option<NodeId> {
|
||||
let last_active = focus_stack
|
||||
.find_map(|window| tree.root_node_id()
|
||||
|
|
@ -343,18 +280,74 @@ impl TilingLayout {
|
|||
None
|
||||
}
|
||||
|
||||
fn map_window<'a>(
|
||||
&mut self,
|
||||
space: &mut Space,
|
||||
window: &Window,
|
||||
seat: Option<&Seat>,
|
||||
focus_stack: Option<Box<dyn Iterator<Item = &'a Window> + 'a>>,
|
||||
) {
|
||||
let output = super::output_from_seat(seat, space);
|
||||
let idx = space.outputs().position(|o| *o == output).unwrap_or(0);
|
||||
let tree = TilingLayout::active_tree(&mut self.trees, idx);
|
||||
let new_window = Node::new(Data::Window(window.clone()));
|
||||
|
||||
let last_active = focus_stack.and_then(|mut iter|
|
||||
iter.find_map(|window| tree.root_node_id()
|
||||
.and_then(|root| tree.traverse_pre_order_ids(root).unwrap()
|
||||
.find(|id| matches!(tree.get(id).map(|n| n.data()), Ok(Data::Window(w)) if w == window))
|
||||
)
|
||||
)
|
||||
);
|
||||
let window_id = if let Some(ref node_id) = last_active {
|
||||
let parent_id = tree.get(node_id).unwrap().parent().cloned();
|
||||
if let Some(stack_id) =
|
||||
parent_id.filter(|id| matches!(tree.get(id).unwrap().data(), Data::Stack { .. }))
|
||||
{
|
||||
// we add to the stack
|
||||
let window_id = tree
|
||||
.insert(new_window, InsertBehavior::UnderNode(&stack_id))
|
||||
.unwrap();
|
||||
if let Data::Stack {
|
||||
ref mut len,
|
||||
ref mut active,
|
||||
} = tree.get_mut(&stack_id).unwrap().data_mut()
|
||||
{
|
||||
*active = *len;
|
||||
*len += 1;
|
||||
}
|
||||
Ok(window_id)
|
||||
} else {
|
||||
// we create a new fork
|
||||
TilingLayout::new_fork(tree, node_id, new_window)
|
||||
}
|
||||
} else {
|
||||
// nothing? then we add to the root
|
||||
if let Some(root_id) = tree.root_node_id().cloned() {
|
||||
TilingLayout::new_fork(tree, &root_id, new_window)
|
||||
} else {
|
||||
tree.insert(new_window, InsertBehavior::AsRoot)
|
||||
}
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
{
|
||||
let user_data = window.user_data();
|
||||
let window_info = WindowInfo {
|
||||
node: window_id.clone(),
|
||||
output: idx,
|
||||
};
|
||||
// insert or update
|
||||
if !user_data.insert_if_missing(|| RefCell::new(window_info.clone())) {
|
||||
*user_data.get::<RefCell<WindowInfo>>().unwrap().borrow_mut() = window_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unmap_window(&mut self, window: &Window) {
|
||||
if let Some(info) = window.user_data().get::<RefCell<WindowInfo>>() {
|
||||
let output = &info.borrow().output;
|
||||
output
|
||||
.user_data()
|
||||
.insert_if_missing(|| RefCell::new(OutputInfo::default()));
|
||||
let mut output_info = output
|
||||
.user_data()
|
||||
.get::<RefCell<OutputInfo>>()
|
||||
.unwrap()
|
||||
.borrow_mut();
|
||||
let tree = output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||
let output = info.borrow().output;
|
||||
let tree = TilingLayout::active_tree(&mut self.trees, output);
|
||||
|
||||
let node_id = info.borrow().node.clone();
|
||||
let parent_id = tree
|
||||
|
|
@ -453,110 +446,115 @@ impl TilingLayout {
|
|||
tree.insert(new, InsertBehavior::UnderNode(&fork_id))
|
||||
}
|
||||
|
||||
fn update_space_positions(idx: u8, space: &mut Space, gaps: (i32, i32)) -> Vec<Window> {
|
||||
fn update_space_positions(
|
||||
trees: &mut Vec<Tree<Data>>,
|
||||
space: &mut Space,
|
||||
gaps: (i32, i32),
|
||||
) -> Vec<Window> {
|
||||
let mut dead_windows = Vec::new();
|
||||
let (outer, inner) = gaps;
|
||||
for output in space.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
||||
if let Some(mut info) = output
|
||||
.user_data()
|
||||
.get::<RefCell<OutputInfo>>()
|
||||
.map(|x| x.borrow_mut())
|
||||
{
|
||||
let tree = &mut info.trees.entry(idx).or_insert_with(Tree::new);
|
||||
if let Some(root) = tree.root_node_id() {
|
||||
let mut stack = Vec::new();
|
||||
for (idx, output) in space
|
||||
.outputs()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
{
|
||||
let tree = TilingLayout::active_tree(trees, idx);
|
||||
if let Some(root) = tree.root_node_id() {
|
||||
let mut stack = Vec::new();
|
||||
|
||||
let mut geo = Some(layer_map_for_output(&output).non_exclusive_zone());
|
||||
// TODO saturate? minimum?
|
||||
if let Some(mut geo) = geo.as_mut() {
|
||||
geo.loc.x += outer;
|
||||
geo.loc.y += outer;
|
||||
geo.size.w -= outer * 2;
|
||||
geo.size.h -= outer * 2;
|
||||
}
|
||||
let mut geo = Some(layer_map_for_output(&output).non_exclusive_zone());
|
||||
// TODO saturate? minimum?
|
||||
if let Some(mut geo) = geo.as_mut() {
|
||||
geo.loc.x += outer;
|
||||
geo.loc.y += outer;
|
||||
geo.size.w -= outer * 2;
|
||||
geo.size.h -= outer * 2;
|
||||
}
|
||||
|
||||
for node in tree.traverse_pre_order(root).unwrap() {
|
||||
let geo = stack.pop().unwrap_or(geo);
|
||||
match node.data() {
|
||||
Data::Fork { orientation, ratio } => {
|
||||
if let Some(geo) = geo {
|
||||
match orientation {
|
||||
Orientation::Horizontal => {
|
||||
let top_size = (
|
||||
geo.size.w,
|
||||
((geo.size.h as f64) * ratio).ceil() as i32,
|
||||
);
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
(geo.loc.x, geo.loc.y + top_size.1),
|
||||
(geo.size.w, geo.size.h - top_size.1),
|
||||
)));
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
geo.loc, top_size,
|
||||
)));
|
||||
}
|
||||
Orientation::Vertical => {
|
||||
let left_size = (
|
||||
((geo.size.w as f64) * ratio).ceil() as i32,
|
||||
geo.size.h,
|
||||
);
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
(geo.loc.x + left_size.0, geo.loc.y),
|
||||
(geo.size.w - left_size.0, geo.size.h),
|
||||
)));
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
geo.loc, left_size,
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stack.push(None);
|
||||
stack.push(None);
|
||||
}
|
||||
}
|
||||
Data::Stack { active, len } => {
|
||||
for i in 0..*len {
|
||||
if i == *active {
|
||||
stack.push(geo);
|
||||
} else {
|
||||
stack.push(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Window(window) => {
|
||||
if window.toplevel().alive() {
|
||||
if let Some(geo) = geo {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Kind::Xdg(xdg) = &window.toplevel() {
|
||||
let ret = xdg.with_pending_state(|state| {
|
||||
state.size = Some(
|
||||
(
|
||||
geo.size.w - inner * 2,
|
||||
geo.size.h - inner * 2,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
state.states.set(XdgState::TiledLeft);
|
||||
state.states.set(XdgState::TiledRight);
|
||||
state.states.set(XdgState::TiledTop);
|
||||
state.states.set(XdgState::TiledBottom);
|
||||
});
|
||||
if ret.is_ok() {
|
||||
xdg.send_configure();
|
||||
}
|
||||
}
|
||||
let window_geo = window.geometry();
|
||||
space.map_window(
|
||||
&window,
|
||||
(
|
||||
geo.loc.x + inner - window_geo.loc.x,
|
||||
geo.loc.y + inner - window_geo.loc.y,
|
||||
),
|
||||
false,
|
||||
for node in tree.traverse_pre_order(root).unwrap() {
|
||||
let geo = stack.pop().unwrap_or(geo);
|
||||
match node.data() {
|
||||
Data::Fork { orientation, ratio } => {
|
||||
if let Some(geo) = geo {
|
||||
match orientation {
|
||||
Orientation::Horizontal => {
|
||||
let top_size = (
|
||||
geo.size.w,
|
||||
((geo.size.h as f64) * ratio.load(Ordering::SeqCst))
|
||||
.ceil()
|
||||
as i32,
|
||||
);
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
(geo.loc.x, geo.loc.y + top_size.1),
|
||||
(geo.size.w, geo.size.h - top_size.1),
|
||||
)));
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
geo.loc, top_size,
|
||||
)));
|
||||
}
|
||||
Orientation::Vertical => {
|
||||
let left_size = (
|
||||
((geo.size.w as f64) * ratio.load(Ordering::SeqCst))
|
||||
.ceil()
|
||||
as i32,
|
||||
geo.size.h,
|
||||
);
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
(geo.loc.x + left_size.0, geo.loc.y),
|
||||
(geo.size.w - left_size.0, geo.size.h),
|
||||
)));
|
||||
stack.push(Some(Rectangle::from_loc_and_size(
|
||||
geo.loc, left_size,
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
dead_windows.push(window.clone());
|
||||
}
|
||||
} else {
|
||||
stack.push(None);
|
||||
stack.push(None);
|
||||
}
|
||||
}
|
||||
Data::Stack { active, len } => {
|
||||
for i in 0..*len {
|
||||
if i == *active {
|
||||
stack.push(geo);
|
||||
} else {
|
||||
stack.push(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Window(window) => {
|
||||
if window.toplevel().alive() {
|
||||
if let Some(geo) = geo {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let Kind::Xdg(xdg) = &window.toplevel() {
|
||||
let ret = xdg.with_pending_state(|state| {
|
||||
state.size = Some(
|
||||
(geo.size.w - inner * 2, geo.size.h - inner * 2)
|
||||
.into(),
|
||||
);
|
||||
state.states.set(XdgState::TiledLeft);
|
||||
state.states.set(XdgState::TiledRight);
|
||||
state.states.set(XdgState::TiledTop);
|
||||
state.states.set(XdgState::TiledBottom);
|
||||
});
|
||||
if ret.is_ok() {
|
||||
xdg.send_configure();
|
||||
}
|
||||
}
|
||||
let window_geo = window.geometry();
|
||||
space.map_window(
|
||||
&window,
|
||||
(
|
||||
geo.loc.x + inner - window_geo.loc.x,
|
||||
geo.loc.y + inner - window_geo.loc.y,
|
||||
),
|
||||
false,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
dead_windows.push(window.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl Workspace {
|
|||
Workspace {
|
||||
idx,
|
||||
space: Space::new(None),
|
||||
layout: layout::new_default_layout(idx),
|
||||
layout: layout::new_default_layout(),
|
||||
pending_windows: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue