shell: Introduce MoveResult to implement stacking
This commit is contained in:
parent
f00753071e
commit
b400939dd9
3 changed files with 175 additions and 63 deletions
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
focus::{target::PointerFocusTarget, FocusDirection},
|
||||
layout::{
|
||||
floating::SeatMoveGrabState,
|
||||
tiling::{Direction, FocusResult},
|
||||
tiling::{Direction, FocusResult, MoveResult},
|
||||
},
|
||||
OverviewMode, Workspace,
|
||||
}, // shell::grabs::SeatMoveGrabState
|
||||
|
|
@ -1048,53 +1048,55 @@ impl State {
|
|||
return; // TODO, is this what we want? How do we indicate the switch?
|
||||
}
|
||||
|
||||
if let Some(_move_further) =
|
||||
workspace.tiling_layer.move_current_node(direction, seat)
|
||||
{
|
||||
// TODO: Being able to move Groups (move_further should be KeyboardFocusTarget instead)
|
||||
match (direction, self.common.config.static_conf.workspace_layout) {
|
||||
(Direction::Left, WorkspaceLayout::Horizontal)
|
||||
| (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action(
|
||||
Action::MoveToPreviousWorkspace,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
(Direction::Right, WorkspaceLayout::Horizontal)
|
||||
| (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action(
|
||||
Action::MoveToNextWorkspace,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
(Direction::Left, WorkspaceLayout::Vertical)
|
||||
| (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action(
|
||||
Action::MoveToPreviousOutput,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
(Direction::Right, WorkspaceLayout::Vertical)
|
||||
| (Direction::Down, WorkspaceLayout::Horizontal) => self.handle_action(
|
||||
Action::MoveToNextOutput,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
match workspace.tiling_layer.move_current_node(direction, seat) {
|
||||
MoveResult::MoveFurther(_move_further) => {
|
||||
match (direction, self.common.config.static_conf.workspace_layout) {
|
||||
(Direction::Left, WorkspaceLayout::Horizontal)
|
||||
| (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action(
|
||||
Action::MoveToPreviousWorkspace,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
(Direction::Right, WorkspaceLayout::Horizontal)
|
||||
| (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action(
|
||||
Action::MoveToNextWorkspace,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
(Direction::Left, WorkspaceLayout::Vertical)
|
||||
| (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action(
|
||||
Action::MoveToPreviousOutput,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
(Direction::Right, WorkspaceLayout::Vertical)
|
||||
| (Direction::Down, WorkspaceLayout::Horizontal) => self.handle_action(
|
||||
Action::MoveToNextOutput,
|
||||
seat,
|
||||
serial,
|
||||
time,
|
||||
mods,
|
||||
Some(direction),
|
||||
),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let focus_stack = workspace.focus_stack.get(seat);
|
||||
if let Some(focused_window) = focus_stack.last() {
|
||||
if workspace.is_tiled(focused_window) {
|
||||
self.common.shell.set_overview_mode(Some(mods));
|
||||
MoveResult::ShiftFocus(shift) => {
|
||||
Common::set_focus(self, Some(&shift), seat, None);
|
||||
}
|
||||
MoveResult::Done => {
|
||||
if let Some(focused_window) = workspace.focus_stack.get(seat).last() {
|
||||
if workspace.is_tiled(focused_window) {
|
||||
self.common.shell.set_overview_mode(Some(mods));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ use std::{
|
|||
};
|
||||
|
||||
pub mod surface;
|
||||
use self::stack::MoveResult;
|
||||
pub use self::surface::CosmicSurface;
|
||||
pub mod stack;
|
||||
pub use self::stack::CosmicStack;
|
||||
|
|
@ -61,7 +62,10 @@ use smithay::backend::renderer::{element::texture::TextureRenderElement, gles::G
|
|||
#[cfg(feature = "debug")]
|
||||
use tracing::debug;
|
||||
|
||||
use super::{focus::FocusDirection, layout::floating::ResizeState};
|
||||
use super::{
|
||||
focus::FocusDirection,
|
||||
layout::{floating::ResizeState, tiling::Direction},
|
||||
};
|
||||
|
||||
space_elements! {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
@ -226,6 +230,14 @@ impl CosmicMapped {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn handle_move(&self, direction: Direction) -> MoveResult {
|
||||
if let CosmicMappedInternal::Stack(stack) = &self.element {
|
||||
stack.handle_move(direction)
|
||||
} else {
|
||||
MoveResult::Default
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_focus(&self, direction: FocusDirection) -> bool {
|
||||
if let CosmicMappedInternal::Stack(stack) = &self.element {
|
||||
stack.handle_focus(direction)
|
||||
|
|
@ -453,6 +465,13 @@ impl CosmicMapped {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn stack_ref_mut(&mut self) -> Option<&mut CosmicStack> {
|
||||
match &mut self.element {
|
||||
CosmicMappedInternal::Stack(stack) => Some(stack),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_stack<'a>(
|
||||
&mut self,
|
||||
outputs: impl Iterator<Item = (&'a Output, Rectangle<i32, Logical>)>,
|
||||
|
|
@ -460,7 +479,7 @@ impl CosmicMapped {
|
|||
match &self.element {
|
||||
CosmicMappedInternal::Window(window) => {
|
||||
let surface = window.surface();
|
||||
let activated = surface.is_activated();
|
||||
let activated = surface.is_activated(true);
|
||||
let handle = window.loop_handle();
|
||||
|
||||
let stack = CosmicStack::new(std::iter::once(surface), handle);
|
||||
|
|
@ -494,7 +513,7 @@ impl CosmicMapped {
|
|||
for (output, overlap) in outputs {
|
||||
window.output_enter(output, overlap);
|
||||
}
|
||||
window.set_activate(self.is_activated());
|
||||
window.set_activate(self.is_activated(true));
|
||||
window.surface().send_configure();
|
||||
window.refresh();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ use crate::{
|
|||
backend::render::{element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, GROUP_COLOR},
|
||||
shell::{
|
||||
element::{
|
||||
stack::CosmicStackRenderElement, window::CosmicWindowRenderElement, CosmicMapped,
|
||||
CosmicMappedRenderElement, CosmicStack, CosmicWindow,
|
||||
stack::{CosmicStackRenderElement, MoveResult as StackMoveResult},
|
||||
window::CosmicWindowRenderElement,
|
||||
CosmicMapped, CosmicMappedRenderElement, CosmicStack, CosmicWindow,
|
||||
},
|
||||
focus::{
|
||||
target::{KeyboardFocusTarget, WindowGroup},
|
||||
|
|
@ -101,6 +102,13 @@ pub enum FocusResult {
|
|||
Some(KeyboardFocusTarget),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum MoveResult {
|
||||
Done,
|
||||
MoveFurther(KeyboardFocusTarget),
|
||||
ShiftFocus(KeyboardFocusTarget),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct TreeQueue {
|
||||
trees: VecDeque<(Tree<Data>, Option<TilingBlocker>)>,
|
||||
|
|
@ -160,6 +168,12 @@ impl Data {
|
|||
None => matches!(self, Data::Mapped { .. }),
|
||||
}
|
||||
}
|
||||
fn is_stack(&self) -> bool {
|
||||
match self {
|
||||
Data::Mapped { mapped, .. } => mapped.is_stack(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn orientation(&self) -> Orientation {
|
||||
match self {
|
||||
|
|
@ -595,19 +609,57 @@ impl TilingLayout {
|
|||
&mut self,
|
||||
direction: Direction,
|
||||
seat: &Seat<State>,
|
||||
) -> Option<KeyboardFocusTarget> {
|
||||
) -> MoveResult {
|
||||
let output = seat.active_output();
|
||||
let queue = self.queues.get_mut(&output).unwrap();
|
||||
let mut tree = queue.trees.back().unwrap().0.copy_clone();
|
||||
|
||||
let (node_id, data) = TilingLayout::currently_focused_node(&mut tree, seat)?;
|
||||
let Some((node_id, data)) = TilingLayout::currently_focused_node(&mut tree, seat) else {
|
||||
return MoveResult::Done
|
||||
};
|
||||
|
||||
// stacks may handle movement internally
|
||||
if let FocusedNodeData::Window(window) = data.clone() {
|
||||
match window.handle_move(direction) {
|
||||
StackMoveResult::Handled => return MoveResult::Done,
|
||||
StackMoveResult::MoveOut(surface, loop_handle) => {
|
||||
let mapped: CosmicMapped = CosmicWindow::new(surface, loop_handle).into();
|
||||
mapped.output_enter(&output, mapped.bbox());
|
||||
let orientation = match direction {
|
||||
Direction::Left | Direction::Right => Orientation::Vertical,
|
||||
Direction::Up | Direction::Down => Orientation::Horizontal,
|
||||
};
|
||||
|
||||
let new_node = Node::new(Data::Mapped {
|
||||
mapped: mapped.clone(),
|
||||
last_geometry: Rectangle::from_loc_and_size((0, 0), (100, 100)),
|
||||
});
|
||||
let new_id = tree.insert(new_node, InsertBehavior::AsRoot).unwrap();
|
||||
TilingLayout::new_group(&mut tree, &node_id, &new_id, orientation).unwrap();
|
||||
tree.make_nth_sibling(
|
||||
&new_id,
|
||||
match direction {
|
||||
Direction::Left | Direction::Up => 0,
|
||||
Direction::Right | Direction::Down => 1,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
*mapped.tiling_node_id.lock().unwrap() = Some(new_id);
|
||||
|
||||
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
|
||||
queue.push_tree(tree, blocker);
|
||||
return MoveResult::ShiftFocus(mapped.into());
|
||||
}
|
||||
StackMoveResult::Default => {} // continue normally
|
||||
}
|
||||
}
|
||||
|
||||
let mut child_id = node_id.clone();
|
||||
// Without a parent to start with, just return
|
||||
let Some(og_parent) = tree.get(&node_id).unwrap().parent().cloned() else {
|
||||
return match data {
|
||||
FocusedNodeData::Window(window) => Some(window.into()),
|
||||
FocusedNodeData::Group(focus_stack, alive) => Some(WindowGroup {
|
||||
FocusedNodeData::Window(window) => MoveResult::MoveFurther(window.into()),
|
||||
FocusedNodeData::Group(focus_stack, alive) => MoveResult::MoveFurther(WindowGroup {
|
||||
node: node_id,
|
||||
output: output.downgrade(),
|
||||
alive,
|
||||
|
|
@ -670,7 +722,7 @@ impl TilingLayout {
|
|||
|
||||
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
|
||||
queue.push_tree(tree, blocker);
|
||||
return None;
|
||||
return MoveResult::Done;
|
||||
}
|
||||
|
||||
// now if the orientation matches
|
||||
|
|
@ -696,7 +748,7 @@ impl TilingLayout {
|
|||
|
||||
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
|
||||
queue.push_tree(tree, blocker);
|
||||
return None;
|
||||
return MoveResult::Done;
|
||||
}
|
||||
|
||||
// we can maybe move inside the group, if we don't run out of elements
|
||||
|
|
@ -722,7 +774,40 @@ impl TilingLayout {
|
|||
.nth(next_idx)
|
||||
.unwrap()
|
||||
.clone();
|
||||
if tree.get(&next_child_id).unwrap().data().is_group() && len == 2 {
|
||||
|
||||
let result = if tree.get(&next_child_id).unwrap().data().is_stack()
|
||||
&& tree.get(&node_id).unwrap().data().is_mapped(None)
|
||||
&& !tree.get(&node_id).unwrap().data().is_stack()
|
||||
{
|
||||
let node = tree
|
||||
.remove_node(node_id, RemoveBehavior::DropChildren)
|
||||
.unwrap();
|
||||
|
||||
let stack_data = tree.get_mut(&next_child_id).unwrap().data_mut();
|
||||
let mut mapped = match stack_data {
|
||||
Data::Mapped { mapped, .. } => mapped.clone(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let stack = mapped.stack_ref_mut().unwrap();
|
||||
|
||||
let surface = match node.data() {
|
||||
Data::Mapped { mapped, .. } => mapped.active_window(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
stack.add_window(
|
||||
surface,
|
||||
match direction {
|
||||
Direction::Right => Some(0),
|
||||
_ => None,
|
||||
},
|
||||
);
|
||||
tree.get_mut(&og_parent)
|
||||
.unwrap()
|
||||
.data_mut()
|
||||
.remove_window(og_idx);
|
||||
|
||||
MoveResult::ShiftFocus(mapped.into())
|
||||
} else if tree.get(&next_child_id).unwrap().data().is_group() && len == 2 {
|
||||
// if it is a group, we want to move into the group
|
||||
tree.move_node(&node_id, MoveBehavior::ToParent(&next_child_id))
|
||||
.unwrap();
|
||||
|
|
@ -783,6 +868,8 @@ impl TilingLayout {
|
|||
.unwrap()
|
||||
.data_mut()
|
||||
.remove_window(og_idx);
|
||||
|
||||
MoveResult::Done
|
||||
} else if len == 2 && child_id == node_id {
|
||||
// if we are just us two in the group, lets swap
|
||||
tree.make_nth_sibling(&node_id, next_idx).unwrap();
|
||||
|
|
@ -791,6 +878,8 @@ impl TilingLayout {
|
|||
.unwrap()
|
||||
.data_mut()
|
||||
.swap_windows(idx, next_idx);
|
||||
|
||||
MoveResult::Done
|
||||
} else {
|
||||
// else we make a new fork
|
||||
TilingLayout::new_group(&mut tree, &next_child_id, &node_id, orientation)
|
||||
|
|
@ -808,11 +897,13 @@ impl TilingLayout {
|
|||
.unwrap()
|
||||
.data_mut()
|
||||
.remove_window(og_idx);
|
||||
}
|
||||
|
||||
MoveResult::Done
|
||||
};
|
||||
|
||||
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
|
||||
queue.push_tree(tree, blocker);
|
||||
return None;
|
||||
return result;
|
||||
}
|
||||
|
||||
// We have reached the end of our parent group, try to move out even higher.
|
||||
|
|
@ -821,8 +912,8 @@ impl TilingLayout {
|
|||
}
|
||||
|
||||
match data {
|
||||
FocusedNodeData::Window(window) => Some(window.into()),
|
||||
FocusedNodeData::Group(focus_stack, alive) => Some(
|
||||
FocusedNodeData::Window(window) => MoveResult::MoveFurther(window.into()),
|
||||
FocusedNodeData::Group(focus_stack, alive) => MoveResult::MoveFurther(
|
||||
WindowGroup {
|
||||
node: node_id,
|
||||
output: output.downgrade(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue