floating: New window spawn positions

This commit is contained in:
Victoria Brekenfeld 2023-11-08 22:59:46 +01:00 committed by Victoria Brekenfeld
parent 495d772a38
commit d09abc4728
3 changed files with 172 additions and 18 deletions

View file

@ -50,7 +50,7 @@ use std::{
collections::HashMap, collections::HashMap,
fmt, fmt,
hash::Hash, hash::Hash,
sync::{Arc, Mutex}, sync::{atomic::AtomicBool, Arc, Mutex},
}; };
pub mod surface; pub mod surface;
@ -103,6 +103,7 @@ pub struct CosmicMapped {
//floating //floating
pub(super) resize_state: Arc<Mutex<Option<ResizeState>>>, pub(super) resize_state: Arc<Mutex<Option<ResizeState>>>,
pub last_geometry: Arc<Mutex<Option<Rectangle<i32, Local>>>>, pub last_geometry: Arc<Mutex<Option<Rectangle<i32, Local>>>>,
pub moved_since_mapped: Arc<AtomicBool>,
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug: Arc<Mutex<Option<smithay_egui::EguiState>>>, debug: Arc<Mutex<Option<smithay_egui::EguiState>>>,
@ -117,6 +118,7 @@ impl fmt::Debug for CosmicMapped {
.field("tiling_node_id", &self.tiling_node_id) .field("tiling_node_id", &self.tiling_node_id)
.field("resize_state", &self.resize_state) .field("resize_state", &self.resize_state)
.field("last_geometry", &self.last_geometry) .field("last_geometry", &self.last_geometry)
.field("moved_since_mapped", &self.moved_since_mapped)
.finish() .finish()
} }
} }
@ -224,7 +226,7 @@ impl CosmicMapped {
} }
if surface_type.contains(WindowSurfaceType::SUBSURFACE) { if surface_type.contains(WindowSurfaceType::SUBSURFACE) {
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::Ordering;
let found = AtomicBool::new(false); let found = AtomicBool::new(false);
with_surface_tree_downward( with_surface_tree_downward(
@ -1102,6 +1104,7 @@ impl From<CosmicWindow> for CosmicMapped {
tiling_node_id: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)),
resize_state: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)),
last_geometry: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)),
moved_since_mapped: Arc::new(AtomicBool::new(false)),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug: Arc::new(Mutex::new(None)), debug: Arc::new(Mutex::new(None)),
} }
@ -1117,6 +1120,8 @@ impl From<CosmicStack> for CosmicMapped {
tiling_node_id: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)),
resize_state: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)),
last_geometry: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)),
moved_since_mapped: Arc::new(AtomicBool::new(false)),
#[cfg(feature = "debug")]
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug: Arc::new(Mutex::new(None)), debug: Arc::new(Mutex::new(None)),
} }

View file

@ -42,6 +42,7 @@ use smithay::{
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::HashSet, collections::HashSet,
sync::atomic::Ordering,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -442,6 +443,7 @@ impl MoveGrab {
let mut outputs = HashSet::new(); let mut outputs = HashSet::new();
outputs.insert(output.clone()); outputs.insert(output.clone());
window.output_enter(&output, window.geometry()); // not accurate but... window.output_enter(&output, window.geometry()); // not accurate but...
window.moved_since_mapped.store(true, Ordering::SeqCst);
let grab_state = MoveGrabState { let grab_state = MoveGrabState {
window: window.clone(), window: window.clone(),

View file

@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use std::sync::atomic::Ordering;
use smithay::{ use smithay::{
backend::renderer::{ backend::renderer::{
element::{AsRenderElements, RenderElement}, element::{AsRenderElements, RenderElement},
@ -36,6 +38,7 @@ pub use self::grabs::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct FloatingLayout { pub struct FloatingLayout {
pub(crate) space: Space<CosmicMapped>, pub(crate) space: Space<CosmicMapped>,
spawn_order: Vec<CosmicMapped>,
} }
impl FloatingLayout { impl FloatingLayout {
@ -79,6 +82,12 @@ impl FloatingLayout {
mapped.set_geometry(geometry.to_global(&output)); mapped.set_geometry(geometry.to_global(&output));
mapped.configure(); mapped.configure();
if let Some(pos) = self.spawn_order.iter().position(|m| m == &mapped) {
self.spawn_order.truncate(pos);
}
mapped.moved_since_mapped.store(true, Ordering::SeqCst);
self.space self.space
.map_element(mapped, geometry.loc.as_logical(), true); .map_element(mapped, geometry.loc.as_logical(), true);
} }
@ -93,9 +102,10 @@ impl FloatingLayout {
let output = self.space.outputs().next().unwrap().clone(); let output = self.space.outputs().next().unwrap().clone();
let layers = layer_map_for_output(&output); let layers = layer_map_for_output(&output);
let geometry = layers.non_exclusive_zone(); let output_geometry = layers.non_exclusive_zone();
mapped.set_bounds(geometry.size); mapped.set_bounds(output_geometry.size);
let last_geometry = mapped.last_geometry.lock().unwrap().clone(); let last_geometry = mapped.last_geometry.lock().unwrap().clone();
let min_size = mapped.min_size().unwrap_or((320, 240).into());
if let Some(size) = size if let Some(size) = size
.map(SizeExt::as_local) .map(SizeExt::as_local)
@ -103,13 +113,18 @@ impl FloatingLayout {
{ {
win_geo.size = size; win_geo.size = size;
} else { } else {
let (min_size, max_size) = ( let max_size = mapped.max_size().unwrap_or(
mapped.min_size().unwrap_or((0, 0).into()), (
mapped.max_size().unwrap_or((0, 0).into()), min_size.w.max(output_geometry.size.w / 3 * 2),
min_size.h.max(output_geometry.size.h / 3 * 2),
)
.into(),
); );
if win_geo.size.w > geometry.size.w / 3 * 2 {
// if the last_geometry is too large
if win_geo.size.w > output_geometry.size.w {
// try a more reasonable size // try a more reasonable size
let mut width = geometry.size.w / 3 * 2; let mut width = output_geometry.size.w / 3 * 2;
if max_size.w != 0 { if max_size.w != 0 {
// don't go larger then the max_size ... // don't go larger then the max_size ...
width = std::cmp::min(max_size.w, width); width = std::cmp::min(max_size.w, width);
@ -119,11 +134,11 @@ impl FloatingLayout {
width = std::cmp::max(min_size.w, width); width = std::cmp::max(min_size.w, width);
} }
// but no matter the supported sizes, don't be larger than our non-exclusive-zone // but no matter the supported sizes, don't be larger than our non-exclusive-zone
win_geo.size.w = std::cmp::min(width, geometry.size.w); win_geo.size.w = std::cmp::min(width, output_geometry.size.w);
} }
if win_geo.size.h > geometry.size.h / 3 * 2 { if win_geo.size.h > output_geometry.size.h {
// try a more reasonable size // try a more reasonable size
let mut height = geometry.size.h / 3 * 2; let mut height = output_geometry.size.h / 3 * 2;
if max_size.h != 0 { if max_size.h != 0 {
// don't go larger then the max_size ... // don't go larger then the max_size ...
height = std::cmp::min(max_size.h, height); height = std::cmp::min(max_size.h, height);
@ -133,18 +148,139 @@ impl FloatingLayout {
height = std::cmp::max(min_size.h, height); height = std::cmp::max(min_size.h, height);
} }
// but no matter the supported sizes, don't be larger than our non-exclusive-zone // but no matter the supported sizes, don't be larger than our non-exclusive-zone
win_geo.size.h = std::cmp::min(height, geometry.size.h); win_geo.size.h = std::cmp::min(height, output_geometry.size.h);
} }
} }
let position = position let position = position
.or_else(|| last_geometry.map(|g| g.loc)) .or_else(|| last_geometry.map(|g| g.loc))
.unwrap_or_else(|| { .unwrap_or_else(|| {
( // cleanup moved windows
geometry.loc.x + (geometry.size.w / 2) - (win_geo.size.w / 2) + win_geo.loc.x, if let Some(pos) = self
geometry.loc.y + (geometry.size.h / 2) - (win_geo.size.h / 2) + win_geo.loc.y, .spawn_order
) .iter()
.into() .position(|w| !w.alive() || w.moved_since_mapped.load(Ordering::SeqCst))
{
self.spawn_order.truncate(pos);
}
let three_fours_width = (output_geometry.size.w / 4 * 3).max(360);
// figure out new position
let pos = self
.spawn_order
.last()
.and_then(|window| self.space.element_geometry(window))
.filter(|geo| {
geo.size.w < three_fours_width && win_geo.size.w < three_fours_width
})
.map(|geometry| {
let mut geometry: Rectangle<u32, Logical> = Rectangle::from_loc_and_size(
(geometry.loc.x as u32, geometry.loc.y as u32),
(geometry.size.w as u32, geometry.size.h as u32),
);
// move down
geometry.loc.y += 48;
// do we need to address the height?
let new_column = if geometry.loc.y + min_size.h as u32
<= (output_geometry.loc.y + output_geometry.size.h - 16) as u32
{
// alternate to the sides
let offset = if self
.spawn_order
.iter()
.flat_map(|w| self.space.element_geometry(w))
.filter(|geo| geo.size.w < three_fours_width)
.count()
% 2
== 0
{
(geometry.loc.x + geometry.size.w)
.checked_sub(96 + (win_geo.size.w as u32))
} else {
(geometry.loc.x + geometry.size.w)
.checked_sub((win_geo.size.w as u32).saturating_sub(48))
};
if let Some(offset) = offset {
geometry.loc.x = offset;
// do we need to resize?
if geometry.loc.y as i32 + win_geo.size.h
<= output_geometry.loc.y + output_geometry.size.h - 16
{
win_geo.size.h =
(output_geometry.loc.y + output_geometry.size.h - 16)
- geometry.loc.y as i32;
}
false
} else {
true
}
} else {
true
};
if new_column {
let min_y = self
.spawn_order
.iter()
.flat_map(|w| {
self.space
.element_geometry(w)
.filter(|geo| geo.size.w < three_fours_width)
.map(|geo| geo.loc.y)
})
.min()
.unwrap() as u32;
geometry.loc.y = min_y.saturating_sub(16);
match geometry.loc.x.checked_sub(144) {
Some(new_x) => geometry.loc.x = new_x,
None => {
// if we go out to the left, cycle around to the right
geometry.loc.x =
((output_geometry.loc.x + output_geometry.size.w) as u32)
.saturating_sub(geometry.size.w + 16)
}
};
}
// check padding again
if geometry.loc.x < (output_geometry.loc.x + 16) as u32 {
geometry.loc.x = (output_geometry.loc.x + 16) as u32;
}
if geometry.loc.y < (output_geometry.loc.y + 16) as u32 {
geometry.loc.y = (output_geometry.loc.y + 16) as u32;
}
// if the width would be too high, we wouldn't be here
if geometry.loc.y as i32 + win_geo.size.h
> (output_geometry.loc.y + output_geometry.size.h - 16)
{
win_geo.size.h = output_geometry.loc.y + output_geometry.size.h
- 16
- geometry.loc.y as i32;
}
Point::<i32, Logical>::from((geometry.loc.x as i32, geometry.loc.y as i32))
})
.unwrap_or_else(|| {
(
output_geometry.loc.x + output_geometry.size.w / 2 - win_geo.size.w / 2,
output_geometry.loc.y
+ (output_geometry.size.h / 2 - win_geo.size.h / 2)
.min(output_geometry.size.h / 8),
)
.into()
})
.as_local();
mapped.moved_since_mapped.store(false, Ordering::SeqCst);
self.spawn_order.push(mapped.clone());
pos
}); });
mapped.set_tiled(false); mapped.set_tiled(false);
@ -171,6 +307,12 @@ impl FloatingLayout {
let was_unmaped = self.space.elements().any(|e| e == window); let was_unmaped = self.space.elements().any(|e| e == window);
self.space.unmap_elem(&window); self.space.unmap_elem(&window);
if was_unmaped {
if let Some(pos) = self.spawn_order.iter().position(|w| w == window) {
self.spawn_order.truncate(pos);
}
window.moved_since_mapped.store(true, Ordering::SeqCst);
}
was_unmaped was_unmaped
} }
@ -188,6 +330,7 @@ impl FloatingLayout {
if seat.get_pointer().is_some() { if seat.get_pointer().is_some() {
let location = self.space.element_location(&mapped).unwrap(); let location = self.space.element_location(&mapped).unwrap();
let size = mapped.geometry().size; let size = mapped.geometry().size;
mapped.moved_since_mapped.store(true, Ordering::SeqCst);
Some(grabs::ResizeSurfaceGrab::new( Some(grabs::ResizeSurfaceGrab::new(
start_data, start_data,
@ -286,6 +429,7 @@ impl FloatingLayout {
initial_window_size: original_geo.size, initial_window_size: original_geo.size,
})); }));
mapped.moved_since_mapped.store(true, Ordering::SeqCst);
mapped.set_resizing(true); mapped.set_resizing(true);
mapped.set_geometry( mapped.set_geometry(
geo.as_local() geo.as_local()
@ -439,6 +583,9 @@ impl FloatingLayout {
puffin::profile_function!(); puffin::profile_function!();
self.space.refresh(); self.space.refresh();
if let Some(pos) = self.spawn_order.iter().position(|w| !w.alive()) {
self.spawn_order.truncate(pos);
}
for element in self for element in self
.space .space
.elements() .elements()