tiling: Add logic to move on swap with empty workspace
This commit is contained in:
parent
2588b8920d
commit
9ad69fe119
2 changed files with 195 additions and 0 deletions
|
|
@ -314,6 +314,25 @@ impl State {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let new_workspace = data.common.shell.workspaces.active(¤t_output).1.handle;
|
||||
if new_workspace != old_descriptor.handle {
|
||||
let spaces = data.common.shell.workspaces.spaces_mut();
|
||||
let (mut old_w, mut other_w) = spaces.partition::<Vec<_>, _>(|w| w.handle == old_descriptor.handle);
|
||||
if let Some(old_workspace) = old_w.get_mut(0) {
|
||||
if let Some(new_workspace) = other_w.iter_mut().find(|w| w.handle == new_workspace) {
|
||||
if new_workspace.tiling_layer.windows().next().is_none() {
|
||||
if let Some(focus) = TilingLayout::move_tree(&mut old_workspace.tiling_layer, &mut new_workspace.tiling_layer, ¤t_output, &new_workspace.handle, &seat, new_workspace.focus_stack.get(&seat).iter(), old_descriptor, &mut data.common.shell.toplevel_info_state) {
|
||||
let seat = seat.clone();
|
||||
data.common.event_loop_handle.insert_idle(move |data| {
|
||||
Common::set_focus(&mut data.state, Some(&focus), &seat, None);
|
||||
});
|
||||
}
|
||||
old_workspace.refresh_focus_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -616,6 +616,182 @@ impl TilingLayout {
|
|||
queue.push_tree(tree, ANIMATION_DURATION, blocker);
|
||||
}
|
||||
|
||||
pub fn move_tree<'a>(
|
||||
this: &mut Self,
|
||||
other: &mut Self,
|
||||
other_output: &Output,
|
||||
other_handle: &WorkspaceHandle,
|
||||
seat: &Seat<State>,
|
||||
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
|
||||
desc: NodeDesc,
|
||||
toplevel_info_state: &mut ToplevelInfoState<State, CosmicSurface>,
|
||||
) -> Option<KeyboardFocusTarget> {
|
||||
let this_output = desc.output.upgrade()?;
|
||||
let this_handle = &desc.handle;
|
||||
let mut this_tree = this
|
||||
.queues
|
||||
.get(&this_output)
|
||||
.map(|queue| queue.trees.back().unwrap().0.copy_clone())?;
|
||||
let mut other_tree = other
|
||||
.queues
|
||||
.get(other_output)
|
||||
.map(|queue| queue.trees.back().unwrap().0.copy_clone())?;
|
||||
|
||||
match desc.stack_window {
|
||||
Some(stack_surface) => {
|
||||
let node = this_tree.get(&desc.node).ok()?;
|
||||
let Data::Mapped { mapped: this_mapped, .. } = node.data() else { return None };
|
||||
let this_stack = this_mapped.stack_ref()?;
|
||||
this_stack.remove_window(&stack_surface);
|
||||
|
||||
let mapped: CosmicMapped =
|
||||
CosmicWindow::new(stack_surface, this_stack.loop_handle()).into();
|
||||
if &this_output != other_output {
|
||||
mapped.output_leave(&this_output);
|
||||
mapped.output_enter(other_output, mapped.bbox());
|
||||
for (ref surface, _) in mapped.windows() {
|
||||
toplevel_info_state.toplevel_leave_output(surface, &this_output);
|
||||
toplevel_info_state.toplevel_enter_output(surface, other_output);
|
||||
}
|
||||
}
|
||||
for (ref surface, _) in mapped.windows() {
|
||||
toplevel_info_state.toplevel_leave_workspace(surface, this_handle);
|
||||
toplevel_info_state.toplevel_enter_workspace(surface, other_handle);
|
||||
}
|
||||
|
||||
mapped.set_tiled(true);
|
||||
this.map(mapped.clone(), seat, focus_stack, None);
|
||||
return Some(KeyboardFocusTarget::Element(mapped));
|
||||
}
|
||||
None => {
|
||||
let node = this_tree.get(&desc.node).ok()?;
|
||||
let mut children = node
|
||||
.children()
|
||||
.into_iter()
|
||||
.map(|child_id| (desc.node.clone(), child_id.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
let node = Node::new(node.data().clone());
|
||||
TilingLayout::unmap_internal(&mut this_tree, &desc.node);
|
||||
|
||||
let id = match other_tree.root_node_id() {
|
||||
None => other_tree.insert(node, InsertBehavior::AsRoot).unwrap(),
|
||||
Some(_) => {
|
||||
let focused_node = seat
|
||||
.get_keyboard()
|
||||
.unwrap()
|
||||
.current_focus()
|
||||
.and_then(|target| {
|
||||
TilingLayout::currently_focused_node(
|
||||
&other_tree,
|
||||
&other_output,
|
||||
target,
|
||||
)
|
||||
})
|
||||
.map(|(id, _)| id)
|
||||
.unwrap_or(other_tree.root_node_id().unwrap().clone());
|
||||
let orientation = {
|
||||
let window_size = other_tree
|
||||
.get(&focused_node)
|
||||
.unwrap()
|
||||
.data()
|
||||
.geometry()
|
||||
.size;
|
||||
if window_size.w > window_size.h {
|
||||
Orientation::Vertical
|
||||
} else {
|
||||
Orientation::Horizontal
|
||||
}
|
||||
};
|
||||
let id = other_tree.insert(node, InsertBehavior::AsRoot).unwrap();
|
||||
TilingLayout::new_group(&mut other_tree, &focused_node, &id, orientation)
|
||||
.unwrap();
|
||||
id
|
||||
}
|
||||
};
|
||||
|
||||
for (ref mut parent_id, _) in children.iter_mut() {
|
||||
*parent_id = id.clone();
|
||||
}
|
||||
if let Data::Mapped { mapped, .. } = other_tree.get_mut(&id).unwrap().data_mut() {
|
||||
if &this_output != other_output {
|
||||
mapped.output_leave(&this_output);
|
||||
mapped.output_enter(other_output, mapped.bbox());
|
||||
for (ref surface, _) in mapped.windows() {
|
||||
toplevel_info_state.toplevel_leave_output(surface, &this_output);
|
||||
toplevel_info_state.toplevel_enter_output(surface, other_output);
|
||||
}
|
||||
}
|
||||
for (ref surface, _) in mapped.windows() {
|
||||
toplevel_info_state.toplevel_leave_workspace(surface, this_handle);
|
||||
toplevel_info_state.toplevel_enter_workspace(surface, other_handle);
|
||||
}
|
||||
|
||||
*mapped.tiling_node_id.lock().unwrap() = Some(id.clone());
|
||||
}
|
||||
|
||||
while !children.is_empty() {
|
||||
for (parent_id, child_id) in std::mem::take(&mut children) {
|
||||
let new_children = this_tree
|
||||
.children_ids(&child_id)
|
||||
.unwrap()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
let child_node = this_tree
|
||||
.remove_node(child_id, RemoveBehavior::OrphanChildren)
|
||||
.unwrap();
|
||||
let maybe_mapped = match child_node.data() {
|
||||
Data::Mapped { mapped, .. } => Some(mapped.clone()),
|
||||
_ => None,
|
||||
};
|
||||
let new_id = other_tree
|
||||
.insert(child_node, InsertBehavior::UnderNode(&parent_id))
|
||||
.unwrap();
|
||||
if let Some(mapped) = maybe_mapped {
|
||||
if &this_output != other_output {
|
||||
mapped.output_leave(&this_output);
|
||||
mapped.output_enter(other_output, mapped.bbox());
|
||||
for (ref surface, _) in mapped.windows() {
|
||||
toplevel_info_state
|
||||
.toplevel_leave_output(surface, &this_output);
|
||||
toplevel_info_state
|
||||
.toplevel_enter_output(surface, other_output);
|
||||
}
|
||||
}
|
||||
for (ref surface, _) in mapped.windows() {
|
||||
toplevel_info_state.toplevel_leave_workspace(surface, this_handle);
|
||||
toplevel_info_state.toplevel_enter_workspace(surface, other_handle);
|
||||
}
|
||||
|
||||
*mapped.tiling_node_id.lock().unwrap() = Some(new_id.clone());
|
||||
}
|
||||
children.extend(
|
||||
new_children
|
||||
.into_iter()
|
||||
.map(|new_child| (new_id.clone(), new_child)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let this_queue = this.queues.get_mut(&this_output).unwrap();
|
||||
let blocker =
|
||||
TilingLayout::update_positions(&this_output, &mut this_tree, this.gaps);
|
||||
this_queue.push_tree(this_tree, ANIMATION_DURATION, blocker);
|
||||
|
||||
let other_queue = other.queues.get_mut(other_output).unwrap();
|
||||
let blocker =
|
||||
TilingLayout::update_positions(&other_output, &mut other_tree, other.gaps);
|
||||
other_queue.push_tree(other_tree, ANIMATION_DURATION, blocker);
|
||||
|
||||
other.node_desc_to_focus(&NodeDesc {
|
||||
handle: other_handle.clone(),
|
||||
output: other_output.downgrade(),
|
||||
node: id,
|
||||
stack_window: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_trees(
|
||||
this: &mut Self,
|
||||
mut other: Option<&mut Self>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue