focus-stack: Keep dragged surface in focus stack in move_request()

Replacement for https://github.com/pop-os/cosmic-comp/pull/1687, that
works correctly with multiple outputs.

We don't want another window to show a focus indicator while a window is
being dragged, so keep the window in the focus stack. If a window is
being moved out of a stack, change the focus from the stack to the
window.

`refresh_focus_stack()` doesn't seem to be called here, but for good
measure, make sure that calling that function also won't remove a
`CosmicMapped` from the focus stack if it is currently part of a move
grab for the seat.
This commit is contained in:
Ian Douglas Scott 2025-10-30 13:59:26 -07:00 committed by Ian Douglas Scott
parent e09fcec9f3
commit 7fd033295f
3 changed files with 29 additions and 13 deletions

View file

@ -129,11 +129,11 @@ impl FocusStackMut<'_> {
self.0.insert(target);
}
pub fn remove<T>(&mut self, target: &T)
pub fn remove<T>(&mut self, target: &T) -> bool
where
T: Hash + indexmap::Equivalent<FocusTarget>,
{
self.0.shift_remove(target);
self.0.shift_remove(target)
}
pub fn last(&self) -> Option<&FocusTarget> {

View file

@ -3415,15 +3415,6 @@ impl Shell {
return None;
}
if !move_out_of_stack {
for workspace in self.workspaces.spaces_mut() {
for seat in self.seats.iter() {
let mut stack = workspace.focus_stack.get_mut(seat);
stack.remove(&old_mapped);
}
}
}
let (window, _) = old_mapped
.windows()
.find(|(w, _)| w.wl_surface().as_deref() == Some(surface))
@ -3441,6 +3432,15 @@ impl Shell {
old_mapped.clone()
};
if move_out_of_stack {
// Update focus stack to set focus to the window being dragged out of
// the stack.
if let Some(workspace) = self.space_for_mut(&old_mapped) {
let mut stack = workspace.focus_stack.get_mut(seat);
stack.append(mapped.clone());
}
}
let trigger = match &start_data {
GrabStartData::Pointer(start_data) => Trigger::Pointer(start_data.button),
GrabStartData::Touch(start_data) => Trigger::Touch(start_data.slot),

View file

@ -7,7 +7,7 @@ use crate::{
element::{AsGlowRenderer, FromGlesError},
},
shell::{
ANIMATION_DURATION, OverviewMode,
ANIMATION_DURATION, OverviewMode, SeatMoveGrabState,
layout::{floating::FloatingLayout, tiling::TilingLayout},
},
state::State,
@ -455,17 +455,33 @@ impl Workspace {
}
pub fn refresh_focus_stack(&mut self) {
for stack in self.focus_stack.0.values_mut() {
for (seat, stack) in self.focus_stack.0.iter_mut() {
let fullscreen = self
.fullscreen
.as_ref()
.filter(|f| f.alive())
.filter(|f| f.ended_at.is_none())
.map(|f| &f.surface);
// Move grab is treated as focused, so don't change focus to a
// window while grab exists.
let move_grab_state = seat
.user_data()
.get::<SeatMoveGrabState>()
.unwrap()
.lock()
.unwrap();
let move_mapped = if let Some(move_grab_state) = &*move_grab_state {
Some(move_grab_state.element())
} else {
None
};
let mapped = || {
self.floating_layer
.mapped()
.chain(self.tiling_layer.mapped().map(|(w, _)| w))
.chain(move_mapped.iter())
};
stack.retain(|w| match w {
FocusTarget::Fullscreen(s) => fullscreen.is_some_and(|f| f == s),