tiling: Add logic to move on swap with empty workspace

This commit is contained in:
Victoria Brekenfeld 2023-09-11 21:12:52 +02:00
parent 2588b8920d
commit 9ad69fe119
2 changed files with 195 additions and 0 deletions

View file

@ -314,6 +314,25 @@ impl State {
}
}
}
} else {
let new_workspace = data.common.shell.workspaces.active(&current_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, &current_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();
}
}
}
}
}
}
}

View file

@ -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>,