shell: Lift/Refactor (interactive) resize to consider sticky windows

This commit is contained in:
Victoria Brekenfeld 2023-12-20 20:49:37 +00:00 committed by Victoria Brekenfeld
parent a333753c96
commit 97a13ea515
4 changed files with 101 additions and 73 deletions

View file

@ -290,17 +290,34 @@ impl ResizeSurfaceGrab {
} }
} }
pub fn apply_resize_to_location(window: CosmicMapped, space: &mut Workspace) { pub fn apply_resize_to_location(window: CosmicMapped, shell: &mut Shell) {
if let Some(location) = space let mut resize_state = window.resize_state.lock().unwrap();
.floating_layer
if resize_state.is_none() {
return;
}
let (output, floating_layer) = if let Some((output, set)) = shell
.workspaces
.sets
.iter_mut()
.find(|(_, set)| set.sticky_layer.mapped().any(|m| m == &window))
{
(output, &mut set.sticky_layer)
} else if let Some(workspace) = shell.space_for_mut(&window) {
(&workspace.output, &mut workspace.floating_layer)
} else {
return;
};
if let Some(location) = floating_layer
.space .space
.element_location(&window) .element_location(&window)
.map(PointExt::as_local) .map(PointExt::as_local)
.map(|p| p.to_global(space.output())) .map(|p| p.to_global(output))
{ {
let mut new_location = None; let mut new_location = None;
let mut resize_state = window.resize_state.lock().unwrap();
// If the window is being resized by top or left, its location must be adjusted // If the window is being resized by top or left, its location must be adjusted
// accordingly. // accordingly.
match *resize_state { match *resize_state {
@ -311,7 +328,7 @@ impl ResizeSurfaceGrab {
initial_window_location, initial_window_location,
initial_window_size, initial_window_size,
} = resize_data; } = resize_data;
let initial_window_location = initial_window_location.to_global(space.output()); let initial_window_location = initial_window_location.to_global(output);
if edges.intersects(ResizeEdge::TOP_LEFT) { if edges.intersects(ResizeEdge::TOP_LEFT) {
let size = window.geometry().size; let size = window.geometry().size;
@ -344,7 +361,7 @@ impl ResizeSurfaceGrab {
update_reactive_popups( update_reactive_popups(
&window, &window,
new_location + offset.as_global(), new_location + offset.as_global(),
space.floating_layer.space.outputs(), floating_layer.space.outputs(),
); );
} }
CosmicSurface::X11(surface) => { CosmicSurface::X11(surface) => {
@ -355,8 +372,7 @@ impl ResizeSurfaceGrab {
_ => unreachable!(), _ => unreachable!(),
} }
} }
space floating_layer
.floating_layer
.space .space
.map_element(window, new_location.as_logical(), false); .map_element(window, new_location.as_logical(), false);
} }

View file

@ -2479,16 +2479,38 @@ impl Shell {
check_grab_preconditions(&seat, surface, serial, ReleaseMode::NoMouseButtons) check_grab_preconditions(&seat, surface, serial, ReleaseMode::NoMouseButtons)
{ {
if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() { if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() {
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) { if mapped.is_fullscreen(true) || mapped.is_maximized(true) {
if let Some(grab) = workspace.resize_request(&mapped, &seat, start_data, edges) return;
{ }
let floating_layer = if let Some(set) = state
.common
.shell
.workspaces
.sets
.values_mut()
.find(|set| set.sticky_layer.mapped().any(|m| m == &mapped))
{
&mut set.sticky_layer
} else if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
&mut workspace.floating_layer
} else {
return;
};
if let Some(grab) = floating_layer.resize_request(
&mapped,
seat,
start_data.clone(),
edges,
ReleaseMode::NoMouseButtons,
) {
seat.get_pointer().unwrap().set_grab( seat.get_pointer().unwrap().set_grab(
state, state,
grab, grab,
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()), serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
Focus::Clear, Focus::Clear,
); );
}
} }
} }
} }
@ -2500,8 +2522,6 @@ impl Shell {
let Some(focused) = seat.get_keyboard().unwrap().current_focus() else { let Some(focused) = seat.get_keyboard().unwrap().current_focus() else {
return; return;
}; };
if let Some(workspace) = self.workspaces.get_mut(idx, &output) {
let amount = (self let amount = (self
.resize_state .resize_state
.take() .take()
@ -2509,6 +2529,17 @@ impl Shell {
.unwrap_or(10) .unwrap_or(10)
+ 2) + 2)
.min(20); .min(20);
if self
.workspaces
.sets
.get_mut(&output)
.unwrap()
.sticky_layer
.resize(&focused, direction, edge, amount)
{
self.resize_state = Some((focused, direction, edge, amount, idx, output));
} else if let Some(workspace) = self.workspaces.get_mut(idx, &output) {
if workspace.resize(&focused, direction, edge, amount) { if workspace.resize(&focused, direction, edge, amount) {
self.resize_state = Some((focused, direction, edge, amount, idx, output)); self.resize_state = Some((focused, direction, edge, amount, idx, output));
} }
@ -2519,18 +2550,25 @@ impl Shell {
if let Some((old_focused, old_direction, old_edge, _, idx, output)) = if let Some((old_focused, old_direction, old_edge, _, idx, output)) =
self.resize_state.take() self.resize_state.take()
{ {
let workspace = self.workspaces.get(idx, &output).unwrap();
if old_direction == direction && old_edge == edge { if old_direction == direction && old_edge == edge {
let Some(toplevel) = old_focused.toplevel() else { let Some(toplevel) = old_focused.toplevel() else {
return; return;
}; };
let Some(mapped) = workspace let Some(mapped) = self.workspaces.sets.values()
.find_map(|set| set.sticky_layer.mapped()
.find(|m| m.has_surface(&toplevel, WindowSurfaceType::TOPLEVEL))
).cloned()
.or_else(|| {
let workspace = self.workspaces.get(idx, &output).unwrap();
workspace
.mapped() .mapped()
.find(|m| m.has_surface(&toplevel, WindowSurfaceType::TOPLEVEL)) .find(|m| m.has_surface(&toplevel, WindowSurfaceType::TOPLEVEL))
.cloned() .cloned()
})
else { else {
return; return
}; };
let mut resize_state = mapped.resize_state.lock().unwrap(); let mut resize_state = mapped.resize_state.lock().unwrap();
if let Some(ResizeState::Resizing(data)) = *resize_state { if let Some(ResizeState::Resizing(data)) = *resize_state {
*resize_state = Some(ResizeState::WaitingForCommit(data)); *resize_state = Some(ResizeState::WaitingForCommit(data));

View file

@ -69,7 +69,7 @@ use super::{
target::{KeyboardFocusTarget, PointerFocusTarget, WindowGroup}, target::{KeyboardFocusTarget, PointerFocusTarget, WindowGroup},
FocusDirection, FocusStack, FocusStackMut, FocusDirection, FocusStack, FocusStackMut,
}, },
grabs::{ReleaseMode, ResizeEdge, ResizeGrab}, grabs::ResizeEdge,
layout::tiling::{Data, NodeDesc}, layout::tiling::{Data, NodeDesc},
CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode, CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode,
}; };
@ -449,34 +449,34 @@ impl Workspace {
} }
pub fn unmaximize_request(&mut self, elem: &CosmicMapped) -> Option<Size<i32, Logical>> { pub fn unmaximize_request(&mut self, elem: &CosmicMapped) -> Option<Size<i32, Logical>> {
let mut state = elem.maximized_state.lock().unwrap(); let mut state = elem.maximized_state.lock().unwrap();
if let Some(state) = state.take() { if let Some(state) = state.take() {
match state.original_layer { match state.original_layer {
ManagedLayer::Tiling => { ManagedLayer::Tiling => {
// should still be mapped in tiling // should still be mapped in tiling
self.floating_layer.unmap(&elem); self.floating_layer.unmap(&elem);
elem.output_enter(&self.output, elem.bbox()); elem.output_enter(&self.output, elem.bbox());
elem.set_maximized(false); elem.set_maximized(false);
elem.set_geometry(state.original_geometry.to_global(&self.output)); elem.set_geometry(state.original_geometry.to_global(&self.output));
elem.configure(); elem.configure();
self.tiling_layer.recalculate(); self.tiling_layer.recalculate();
self.tiling_layer self.tiling_layer
.element_geometry(&elem) .element_geometry(&elem)
.map(|geo| geo.size.as_logical()) .map(|geo| geo.size.as_logical())
}
ManagedLayer::Floating => {
elem.set_maximized(false);
self.floating_layer.map_internal(
elem.clone(),
Some(state.original_geometry.loc),
Some(state.original_geometry.size.as_logical()),
);
Some(state.original_geometry.size.as_logical())
}
ManagedLayer::Sticky => unreachable!(),
} }
ManagedLayer::Floating => {
elem.set_maximized(false);
self.floating_layer.map_internal(
elem.clone(),
Some(state.original_geometry.loc),
Some(state.original_geometry.size.as_logical()),
);
Some(state.original_geometry.size.as_logical())
}
ManagedLayer::Sticky => unreachable!(),
}
} else { } else {
None None
} }
} }
@ -595,32 +595,6 @@ impl Workspace {
.map(|f| &f.surface) .map(|f| &f.surface)
} }
pub fn resize_request(
&mut self,
mapped: &CosmicMapped,
seat: &Seat<State>,
start_data: PointerGrabStartData<State>,
edges: ResizeEdge,
) -> Option<ResizeGrab> {
if mapped.is_fullscreen(true) || mapped.is_maximized(true) {
return None;
}
if self.floating_layer.mapped().any(|m| m == mapped) {
self.floating_layer
.resize_request(
mapped,
seat,
start_data.clone(),
edges,
ReleaseMode::NoMouseButtons,
)
.map(Into::into)
} else {
None
}
}
pub fn resize( pub fn resize(
&mut self, &mut self,
focused: &KeyboardFocusTarget, focused: &KeyboardFocusTarget,

View file

@ -219,11 +219,11 @@ impl CompositorHandler for State {
// We only want to resize once the client has acknoledged & commited the new size, // We only want to resize once the client has acknoledged & commited the new size,
// so we need to carefully track the state through different handlers. // so we need to carefully track the state through different handlers.
if let Some(element) = self.common.shell.element_for_wl_surface(surface).cloned() { if let Some(element) = self.common.shell.element_for_wl_surface(surface).cloned() {
crate::shell::layout::floating::ResizeSurfaceGrab::apply_resize_to_location(
element.clone(),
&mut self.common.shell,
);
if let Some(workspace) = self.common.shell.space_for_mut(&element) { if let Some(workspace) = self.common.shell.space_for_mut(&element) {
crate::shell::layout::floating::ResizeSurfaceGrab::apply_resize_to_location(
element.clone(),
workspace,
);
workspace.commit(surface); workspace.commit(surface);
} }
} }