input: Implement focus switched on tiling layout
This commit is contained in:
parent
f7ac9654d1
commit
69c71179d4
7 changed files with 336 additions and 166 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use crate::shell::layout::FocusDirection;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use smithay::wayland::seat::Keysym;
|
use smithay::wayland::seat::Keysym;
|
||||||
pub use smithay::{
|
pub use smithay::{
|
||||||
|
|
@ -181,15 +182,7 @@ pub enum Action {
|
||||||
Close,
|
Close,
|
||||||
Workspace(u8),
|
Workspace(u8),
|
||||||
MoveToWorkspace(u8),
|
MoveToWorkspace(u8),
|
||||||
Focus(FocusAction),
|
Focus(FocusDirection),
|
||||||
Orientation(crate::shell::layout::Orientation),
|
Orientation(crate::shell::layout::Orientation),
|
||||||
Spawn(String),
|
Spawn(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum FocusAction {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Up,
|
|
||||||
Down,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -302,9 +302,15 @@ impl Common {
|
||||||
*num,
|
*num,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Action::Focus(focus) => match focus {
|
Action::Focus(focus) => {
|
||||||
_ => { /* TODO */ }
|
let current_output = active_output(seat, &self);
|
||||||
},
|
self.shell.move_focus(
|
||||||
|
seat,
|
||||||
|
¤t_output,
|
||||||
|
*focus,
|
||||||
|
self.seats.iter(),
|
||||||
|
);
|
||||||
|
}
|
||||||
Action::Orientation(orientation) => {
|
Action::Orientation(orientation) => {
|
||||||
let output = active_output(seat, &self);
|
let output = active_output(seat, &self);
|
||||||
self.shell.set_orientation(
|
self.shell.set_orientation(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::Layout;
|
use super::{FocusDirection, Layout, Orientation};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::{Space, Window},
|
desktop::{Space, Window},
|
||||||
reexports::wayland_protocols::xdg_shell::server::xdg_toplevel::ResizeEdge,
|
reexports::wayland_protocols::xdg_shell::server::xdg_toplevel::ResizeEdge,
|
||||||
|
|
@ -108,4 +108,44 @@ impl<A: Layout, B: Layout> Layout for Combined<A, B> {
|
||||||
.resize_request(space, window, seat, serial, start_data, edges)
|
.resize_request(space, window, seat, serial, start_data, edges)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn move_focus<'a>(
|
||||||
|
&mut self,
|
||||||
|
direction: FocusDirection,
|
||||||
|
seat: &Seat,
|
||||||
|
space: &mut Space,
|
||||||
|
focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||||
|
) -> Option<Window> {
|
||||||
|
let focus_stack = focus_stack.collect::<Vec<_>>();
|
||||||
|
match self.first.move_focus(
|
||||||
|
direction,
|
||||||
|
seat,
|
||||||
|
space,
|
||||||
|
Box::new(focus_stack.clone().into_iter()),
|
||||||
|
) {
|
||||||
|
Some(window) => Some(window),
|
||||||
|
None => {
|
||||||
|
self.second
|
||||||
|
.move_focus(direction, seat, space, Box::new(focus_stack.into_iter()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_orientation<'a>(
|
||||||
|
&mut self,
|
||||||
|
orientation: Orientation,
|
||||||
|
seat: &Seat,
|
||||||
|
space: &mut Space,
|
||||||
|
focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||||
|
) {
|
||||||
|
let focus_stack = focus_stack.collect::<Vec<_>>();
|
||||||
|
self.first.update_orientation(
|
||||||
|
orientation,
|
||||||
|
seat,
|
||||||
|
space,
|
||||||
|
Box::new(focus_stack.clone().into_iter()),
|
||||||
|
);
|
||||||
|
self.second
|
||||||
|
.update_orientation(orientation, seat, space, Box::new(focus_stack.into_iter()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,14 @@ pub enum Orientation {
|
||||||
Vertical,
|
Vertical,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum FocusDirection {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Layout {
|
pub trait Layout {
|
||||||
fn map_window<'a>(
|
fn map_window<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -34,6 +42,16 @@ pub trait Layout {
|
||||||
fn refresh(&mut self, space: &mut Space);
|
fn refresh(&mut self, space: &mut Space);
|
||||||
fn unmap_window(&mut self, space: &mut Space, window: &Window);
|
fn unmap_window(&mut self, space: &mut Space, window: &Window);
|
||||||
|
|
||||||
|
fn move_focus<'a>(
|
||||||
|
&mut self,
|
||||||
|
direction: FocusDirection,
|
||||||
|
seat: &Seat,
|
||||||
|
space: &mut Space,
|
||||||
|
focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||||
|
) -> Option<Window> {
|
||||||
|
let _ = (direction, seat, space, focus_stack);
|
||||||
|
None
|
||||||
|
}
|
||||||
fn update_orientation<'a>(
|
fn update_orientation<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
orientation: Orientation,
|
orientation: Orientation,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::shell::layout::{Layout, Orientation};
|
use crate::shell::layout::{FocusDirection, Layout, Orientation};
|
||||||
use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree};
|
use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::{layer_map_for_output, Kind, Space, Window},
|
desktop::{layer_map_for_output, Kind, Space, Window},
|
||||||
|
|
@ -119,12 +119,12 @@ impl Layout for TilingLayout {
|
||||||
Ok(window_id)
|
Ok(window_id)
|
||||||
} else {
|
} else {
|
||||||
// we create a new fork
|
// we create a new fork
|
||||||
new_fork(tree, node_id, new_window)
|
TilingLayout::new_fork(tree, node_id, new_window)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// nothing? then we add to the root
|
// nothing? then we add to the root
|
||||||
if let Some(root_id) = tree.root_node_id().cloned() {
|
if let Some(root_id) = tree.root_node_id().cloned() {
|
||||||
new_fork(tree, &root_id, new_window)
|
TilingLayout::new_fork(tree, &root_id, new_window)
|
||||||
} else {
|
} else {
|
||||||
tree.insert(new_window, InsertBehavior::AsRoot)
|
tree.insert(new_window, InsertBehavior::AsRoot)
|
||||||
}
|
}
|
||||||
|
|
@ -146,12 +146,76 @@ impl Layout for TilingLayout {
|
||||||
self.refresh(space);
|
self.refresh(space);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn move_focus<'a>(
|
||||||
|
&mut self,
|
||||||
|
direction: FocusDirection,
|
||||||
|
seat: &Seat,
|
||||||
|
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 mut node_id = last_active;
|
||||||
|
while let Some((fork, child)) = TilingLayout::find_fork(tree, node_id) {
|
||||||
|
if let &Data::Fork {
|
||||||
|
ref orientation, ..
|
||||||
|
} = tree.get(&fork).unwrap().data()
|
||||||
|
{
|
||||||
|
// found a fork
|
||||||
|
// which child are we?
|
||||||
|
let first = tree.children_ids(&fork).unwrap().next() == Some(&child);
|
||||||
|
let focus_subtree = match (first, orientation, direction) {
|
||||||
|
(true, Orientation::Horizontal, FocusDirection::Down)
|
||||||
|
| (true, Orientation::Vertical, FocusDirection::Right) => {
|
||||||
|
tree.children_ids(&fork).unwrap().skip(1).next()
|
||||||
|
}
|
||||||
|
(false, Orientation::Horizontal, FocusDirection::Up)
|
||||||
|
| (false, Orientation::Vertical, FocusDirection::Left) => {
|
||||||
|
tree.children_ids(&fork).unwrap().next()
|
||||||
|
}
|
||||||
|
_ => None, // continue iterating
|
||||||
|
};
|
||||||
|
|
||||||
|
if focus_subtree.is_some() {
|
||||||
|
let mut node_id = focus_subtree;
|
||||||
|
while node_id.is_some()
|
||||||
|
&& !matches!(
|
||||||
|
tree.get(node_id.as_ref().unwrap()).unwrap().data(),
|
||||||
|
Data::Window(_)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// TODO, if ndoe_id is a stack, we want to assign the active node instead of the first
|
||||||
|
node_id = tree.children_ids(node_id.as_ref().unwrap()).unwrap().next();
|
||||||
|
}
|
||||||
|
if let Some(Data::Window(window)) =
|
||||||
|
node_id.and_then(|i| tree.get(&i).ok()).map(|n| n.data())
|
||||||
|
{
|
||||||
|
return Some(window.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node_id = fork;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
fn update_orientation<'a>(
|
fn update_orientation<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
new_orientation: Orientation,
|
new_orientation: Orientation,
|
||||||
seat: &Seat,
|
seat: &Seat,
|
||||||
space: &mut Space,
|
space: &mut Space,
|
||||||
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);
|
let output = super::output_from_seat(seat, space);
|
||||||
|
|
@ -165,25 +229,15 @@ impl Layout for TilingLayout {
|
||||||
.borrow_mut();
|
.borrow_mut();
|
||||||
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||||
|
|
||||||
let last_active = focus_stack
|
if let Some(last_active) = TilingLayout::last_active(tree, focus_stack) {
|
||||||
.find_map(|window| tree.root_node_id()
|
if let Some((fork, _child)) = TilingLayout::find_fork(tree, last_active) {
|
||||||
.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))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(ref node_id) = last_active {
|
|
||||||
let mut node_id = node_id.clone();
|
|
||||||
while let Some(parent_id) = tree.get(&node_id).unwrap().parent().cloned() {
|
|
||||||
if let &mut Data::Fork {
|
if let &mut Data::Fork {
|
||||||
ref mut orientation,
|
ref mut orientation,
|
||||||
..
|
..
|
||||||
} = tree.get_mut(&parent_id).unwrap().data_mut()
|
} = tree.get_mut(&fork).unwrap().data_mut()
|
||||||
{
|
{
|
||||||
*orientation = new_orientation;
|
*orientation = new_orientation;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
node_id = parent_id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,8 +245,10 @@ impl Layout for TilingLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refresh(&mut self, space: &mut Space) {
|
fn refresh(&mut self, space: &mut Space) {
|
||||||
while let Some(dead_windows) =
|
while let Some(dead_windows) = Some(TilingLayout::update_space_positions(
|
||||||
Some(update_space_positions(self.idx, space, self.gaps)).filter(|v| !v.is_empty())
|
self.idx, space, self.gaps,
|
||||||
|
))
|
||||||
|
.filter(|v| !v.is_empty())
|
||||||
{
|
{
|
||||||
for window in dead_windows {
|
for window in dead_windows {
|
||||||
self.unmap_window(&window);
|
self.unmap_window(&window);
|
||||||
|
|
@ -226,15 +282,16 @@ impl Layout for TilingLayout {
|
||||||
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||||
|
|
||||||
let mut node_id = info.borrow().node.clone();
|
let mut node_id = info.borrow().node.clone();
|
||||||
while let Some(parent_id) = tree.get(&node_id).unwrap().parent().cloned() {
|
|
||||||
|
while let Some((fork, child)) = TilingLayout::find_fork(tree, node_id) {
|
||||||
if let &Data::Fork {
|
if let &Data::Fork {
|
||||||
ref orientation,
|
ref orientation,
|
||||||
ref ratio,
|
ref ratio,
|
||||||
} = tree.get(&parent_id).unwrap().data()
|
} = tree.get(&fork).unwrap().data()
|
||||||
{
|
{
|
||||||
// found a fork
|
// found a fork
|
||||||
// which child are we?
|
// which child are we?
|
||||||
let first = tree.children_ids(&parent_id).unwrap().next() == Some(&node_id);
|
let first = tree.children_ids(&fork).unwrap().next() == Some(&child);
|
||||||
match (first, orientation, edges) {
|
match (first, orientation, edges) {
|
||||||
(true, Orientation::Horizontal, ResizeEdge::Bottom)
|
(true, Orientation::Horizontal, ResizeEdge::Bottom)
|
||||||
| (false, Orientation::Horizontal, ResizeEdge::Top)
|
| (false, Orientation::Horizontal, ResizeEdge::Top)
|
||||||
|
|
@ -242,22 +299,19 @@ impl Layout for TilingLayout {
|
||||||
| (false, Orientation::Vertical, ResizeEdge::Left) => {
|
| (false, Orientation::Vertical, ResizeEdge::Left) => {
|
||||||
let grab = ResizeForkGrab {
|
let grab = ResizeForkGrab {
|
||||||
start_data,
|
start_data,
|
||||||
node_id: parent_id,
|
node_id: fork,
|
||||||
initial_ratio: *ratio,
|
initial_ratio: *ratio,
|
||||||
idx: self.idx,
|
idx: self.idx,
|
||||||
output: output.clone(),
|
output: output.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
slog_scope::debug!("Tiling resize grabs");
|
|
||||||
pointer.set_grab(grab, serial, 0);
|
pointer.set_grab(grab, serial, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(x, y, z) => {
|
_ => {} // continue iterating
|
||||||
slog_scope::debug!("Nope: {:?}, {:?}, {:?}", x, y, z);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node_id = parent_id;
|
node_id = fork;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,15 +319,42 @@ impl Layout for TilingLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TilingLayout {
|
impl TilingLayout {
|
||||||
|
fn last_active<'a>(
|
||||||
|
tree: &mut Tree<Data>,
|
||||||
|
mut focus_stack: Box<dyn Iterator<Item = &'a Window> + 'a>,
|
||||||
|
) -> Option<NodeId> {
|
||||||
|
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))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
last_active
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_fork(tree: &mut Tree<Data>, mut node_id: NodeId) -> Option<(NodeId, NodeId)> {
|
||||||
|
while let Some(parent_id) = tree.get(&node_id).unwrap().parent().cloned() {
|
||||||
|
if let &Data::Fork { .. } = tree.get(&parent_id).unwrap().data() {
|
||||||
|
return Some((parent_id, node_id));
|
||||||
|
}
|
||||||
|
node_id = parent_id;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn unmap_window(&mut self, window: &Window) {
|
fn unmap_window(&mut self, window: &Window) {
|
||||||
if let Some(info) = window.user_data().get::<RefCell<WindowInfo>>() {
|
if let Some(info) = window.user_data().get::<RefCell<WindowInfo>>() {
|
||||||
let output = &info.borrow().output;
|
let output = &info.borrow().output;
|
||||||
|
output
|
||||||
|
.user_data()
|
||||||
|
.insert_if_missing(|| RefCell::new(OutputInfo::default()));
|
||||||
let mut output_info = output
|
let mut output_info = output
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<RefCell<OutputInfo>>()
|
.get::<RefCell<OutputInfo>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut();
|
.borrow_mut();
|
||||||
let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
let tree = output_info.trees.entry(self.idx).or_insert_with(Tree::new);
|
||||||
|
|
||||||
let node_id = info.borrow().node.clone();
|
let node_id = info.borrow().node.clone();
|
||||||
let parent_id = tree
|
let parent_id = tree
|
||||||
|
|
@ -335,151 +416,153 @@ impl TilingLayout {
|
||||||
None => {} // root
|
None => {} // root
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
// update_space_positions(space, self.gaps);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn new_fork(
|
fn new_fork(
|
||||||
tree: &mut Tree<Data>,
|
tree: &mut Tree<Data>,
|
||||||
old_id: &NodeId,
|
old_id: &NodeId,
|
||||||
new: Node<Data>,
|
new: Node<Data>,
|
||||||
) -> Result<NodeId, NodeIdError> {
|
) -> Result<NodeId, NodeIdError> {
|
||||||
let new_fork = Node::new(Data::fork());
|
let new_fork = Node::new(Data::fork());
|
||||||
let old = tree.get(old_id)?;
|
let old = tree.get(old_id)?;
|
||||||
let parent_id = old.parent().cloned();
|
let parent_id = old.parent().cloned();
|
||||||
let pos = parent_id.as_ref().and_then(|parent_id| {
|
let pos = parent_id.as_ref().and_then(|parent_id| {
|
||||||
tree.children_ids(parent_id)
|
tree.children_ids(parent_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.position(|id| id == old_id)
|
.position(|id| id == old_id)
|
||||||
});
|
});
|
||||||
|
|
||||||
let fork_id = tree
|
let fork_id = tree
|
||||||
.insert(
|
.insert(
|
||||||
new_fork,
|
new_fork,
|
||||||
if let Some(parent) = parent_id.as_ref() {
|
if let Some(parent) = parent_id.as_ref() {
|
||||||
InsertBehavior::UnderNode(parent)
|
InsertBehavior::UnderNode(parent)
|
||||||
} else {
|
} else {
|
||||||
InsertBehavior::AsRoot
|
InsertBehavior::AsRoot
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
tree.move_node(old_id, MoveBehavior::ToParent(&fork_id))
|
tree.move_node(old_id, MoveBehavior::ToParent(&fork_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// keep position
|
// keep position
|
||||||
if let Some(old_pos) = pos {
|
if let Some(old_pos) = pos {
|
||||||
tree.make_nth_sibling(&fork_id, old_pos).unwrap();
|
tree.make_nth_sibling(&fork_id, old_pos).unwrap();
|
||||||
|
}
|
||||||
|
tree.insert(new, InsertBehavior::UnderNode(&fork_id))
|
||||||
}
|
}
|
||||||
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(idx: u8, space: &mut Space, gaps: (i32, i32)) -> Vec<Window> {
|
||||||
let mut dead_windows = Vec::new();
|
let mut dead_windows = Vec::new();
|
||||||
let (outer, inner) = gaps;
|
let (outer, inner) = gaps;
|
||||||
for output in space.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
for output in space.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
||||||
if let Some(mut info) = output
|
if let Some(mut info) = output
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<RefCell<OutputInfo>>()
|
.get::<RefCell<OutputInfo>>()
|
||||||
.map(|x| x.borrow_mut())
|
.map(|x| x.borrow_mut())
|
||||||
{
|
{
|
||||||
let tree = &mut info.trees.entry(idx).or_insert_with(Tree::new);
|
let tree = &mut info.trees.entry(idx).or_insert_with(Tree::new);
|
||||||
if let Some(root) = tree.root_node_id() {
|
if let Some(root) = tree.root_node_id() {
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
let mut geo = Some(layer_map_for_output(&output).non_exclusive_zone());
|
let mut geo = Some(layer_map_for_output(&output).non_exclusive_zone());
|
||||||
// TODO saturate? minimum?
|
// TODO saturate? minimum?
|
||||||
if let Some(mut geo) = geo.as_mut() {
|
if let Some(mut geo) = geo.as_mut() {
|
||||||
geo.loc.x += outer;
|
geo.loc.x += outer;
|
||||||
geo.loc.y += outer;
|
geo.loc.y += outer;
|
||||||
geo.size.w -= outer * 2;
|
geo.size.w -= outer * 2;
|
||||||
geo.size.h -= outer * 2;
|
geo.size.h -= outer * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
for node in tree.traverse_pre_order(root).unwrap() {
|
for node in tree.traverse_pre_order(root).unwrap() {
|
||||||
let geo = stack.pop().unwrap_or(geo);
|
let geo = stack.pop().unwrap_or(geo);
|
||||||
match node.data() {
|
match node.data() {
|
||||||
Data::Fork { orientation, ratio } => {
|
Data::Fork { orientation, ratio } => {
|
||||||
if let Some(geo) = geo {
|
if let Some(geo) = geo {
|
||||||
match orientation {
|
match orientation {
|
||||||
Orientation::Horizontal => {
|
Orientation::Horizontal => {
|
||||||
let top_size = (
|
let top_size = (
|
||||||
geo.size.w,
|
geo.size.w,
|
||||||
((geo.size.h as f64) * ratio).ceil() as i32,
|
((geo.size.h as f64) * ratio).ceil() as i32,
|
||||||
);
|
);
|
||||||
stack.push(Some(Rectangle::from_loc_and_size(
|
stack.push(Some(Rectangle::from_loc_and_size(
|
||||||
(geo.loc.x, geo.loc.y + top_size.1),
|
(geo.loc.x, geo.loc.y + top_size.1),
|
||||||
(geo.size.w, geo.size.h - top_size.1),
|
(geo.size.w, geo.size.h - top_size.1),
|
||||||
)));
|
)));
|
||||||
stack.push(Some(Rectangle::from_loc_and_size(
|
stack.push(Some(Rectangle::from_loc_and_size(
|
||||||
geo.loc, top_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,
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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 {
|
} else {
|
||||||
stack.push(None);
|
stack.push(None);
|
||||||
|
stack.push(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Data::Stack { active, len } => {
|
||||||
Data::Window(window) => {
|
for i in 0..*len {
|
||||||
if window.toplevel().alive() {
|
if i == *active {
|
||||||
if let Some(geo) = geo {
|
stack.push(geo);
|
||||||
#[allow(irrefutable_let_patterns)]
|
} else {
|
||||||
if let Kind::Xdg(xdg) = &window.toplevel() {
|
stack.push(None);
|
||||||
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());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dead_windows
|
||||||
}
|
}
|
||||||
dead_windows
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -409,6 +409,22 @@ impl Shell {
|
||||||
.update_orientation(seat, orientation)
|
.update_orientation(seat, orientation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn move_focus<'a>(
|
||||||
|
&mut self,
|
||||||
|
seat: &Seat,
|
||||||
|
output: &Output,
|
||||||
|
focus: layout::FocusDirection,
|
||||||
|
seats: impl Iterator<Item = &'a Seat>,
|
||||||
|
) {
|
||||||
|
if let Some(surface) = self
|
||||||
|
.active_space_mut(output)
|
||||||
|
.move_focus(seat, focus)
|
||||||
|
.and_then(|window| window.toplevel().get_surface().cloned())
|
||||||
|
{
|
||||||
|
self.set_focus(Some(&surface), seat, seats, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_focus<'a>(
|
fn set_focus<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
surface: Option<&WlSurface>,
|
surface: Option<&WlSurface>,
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,20 @@ impl Workspace {
|
||||||
.update_orientation(orientation, seat, &mut self.space, focus_stack.iter())
|
.update_orientation(orientation, seat, &mut self.space, focus_stack.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn move_focus(&mut self, seat: &Seat, focus: layout::FocusDirection) -> Option<Window> {
|
||||||
|
seat.user_data()
|
||||||
|
.insert_if_missing(|| FocusStackData::new((HashMap::new(), IndexSet::new())));
|
||||||
|
let focus_stack = FocusStackMut(RefMut::map(
|
||||||
|
seat.user_data()
|
||||||
|
.get::<FocusStackData>()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut(),
|
||||||
|
|map| map.0.entry(self.idx).or_insert_with(|| IndexSet::new()),
|
||||||
|
));
|
||||||
|
self.layout
|
||||||
|
.move_focus(focus, seat, &mut self.space, focus_stack.iter())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn maximize_request(&mut self, window: &Window, output: &Output) {
|
pub fn maximize_request(&mut self, window: &Window, output: &Output) {
|
||||||
self.layout
|
self.layout
|
||||||
.maximize_request(&mut self.space, window, output)
|
.maximize_request(&mut self.space, window, output)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue