floating: Handle tiling shortcuts
This commit is contained in:
parent
d09abc4728
commit
2d15fb9766
2 changed files with 209 additions and 13 deletions
|
|
@ -73,7 +73,10 @@ use tracing::debug;
|
|||
|
||||
use super::{
|
||||
focus::FocusDirection,
|
||||
layout::{floating::ResizeState, tiling::NodeDesc},
|
||||
layout::{
|
||||
floating::{ResizeState, TiledCorners},
|
||||
tiling::NodeDesc,
|
||||
},
|
||||
Direction, ManagedLayer,
|
||||
};
|
||||
|
||||
|
|
@ -104,6 +107,7 @@ pub struct CosmicMapped {
|
|||
pub(super) resize_state: Arc<Mutex<Option<ResizeState>>>,
|
||||
pub last_geometry: Arc<Mutex<Option<Rectangle<i32, Local>>>>,
|
||||
pub moved_since_mapped: Arc<AtomicBool>,
|
||||
pub floating_tiled: Arc<Mutex<Option<TiledCorners>>>,
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
debug: Arc<Mutex<Option<smithay_egui::EguiState>>>,
|
||||
|
|
@ -119,6 +123,7 @@ impl fmt::Debug for CosmicMapped {
|
|||
.field("resize_state", &self.resize_state)
|
||||
.field("last_geometry", &self.last_geometry)
|
||||
.field("moved_since_mapped", &self.moved_since_mapped)
|
||||
.field("floating_tiled", &self.floating_tiled)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -1105,6 +1110,7 @@ impl From<CosmicWindow> for CosmicMapped {
|
|||
resize_state: Arc::new(Mutex::new(None)),
|
||||
last_geometry: Arc::new(Mutex::new(None)),
|
||||
moved_since_mapped: Arc::new(AtomicBool::new(false)),
|
||||
floating_tiled: Arc::new(Mutex::new(None)),
|
||||
#[cfg(feature = "debug")]
|
||||
debug: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
|
|
@ -1121,7 +1127,7 @@ impl From<CosmicStack> for CosmicMapped {
|
|||
resize_state: Arc::new(Mutex::new(None)),
|
||||
last_geometry: Arc::new(Mutex::new(None)),
|
||||
moved_since_mapped: Arc::new(AtomicBool::new(false)),
|
||||
#[cfg(feature = "debug")]
|
||||
floating_tiled: Arc::new(Mutex::new(None)),
|
||||
#[cfg(feature = "debug")]
|
||||
debug: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use smithay::{
|
|||
desktop::{layer_map_for_output, space::SpaceElement, PopupKind, Space, WindowSurfaceType},
|
||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||
output::Output,
|
||||
utils::{Logical, Point, Rectangle, Size},
|
||||
utils::{IsAlive, Logical, Point, Rectangle, Size},
|
||||
wayland::seat::WaylandFocus,
|
||||
};
|
||||
|
||||
|
|
@ -41,6 +41,77 @@ pub struct FloatingLayout {
|
|||
spawn_order: Vec<CosmicMapped>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum TiledCorners {
|
||||
Top,
|
||||
TopRight,
|
||||
Right,
|
||||
BottomRight,
|
||||
Bottom,
|
||||
BottomLeft,
|
||||
Left,
|
||||
TopLeft,
|
||||
}
|
||||
|
||||
impl TiledCorners {
|
||||
pub fn relative_geometry(
|
||||
&self,
|
||||
output_geometry: Rectangle<i32, Logical>,
|
||||
) -> Rectangle<i32, Local> {
|
||||
let (loc, size) = match self {
|
||||
TiledCorners::Bottom => (
|
||||
Point::from((
|
||||
output_geometry.loc.x,
|
||||
output_geometry.loc.y + (output_geometry.size.h / 2),
|
||||
)),
|
||||
Size::from((output_geometry.size.w, output_geometry.size.h / 2)),
|
||||
),
|
||||
TiledCorners::BottomLeft => (
|
||||
Point::from((
|
||||
output_geometry.loc.x,
|
||||
output_geometry.loc.y + (output_geometry.size.h / 2),
|
||||
)),
|
||||
Size::from((output_geometry.size.w / 2, output_geometry.size.h / 2)),
|
||||
),
|
||||
TiledCorners::BottomRight => (
|
||||
Point::from((
|
||||
output_geometry.loc.x + (output_geometry.size.w / 2),
|
||||
output_geometry.loc.y + (output_geometry.size.h / 2),
|
||||
)),
|
||||
Size::from((output_geometry.size.w / 2, output_geometry.size.h / 2)),
|
||||
),
|
||||
TiledCorners::Left => (
|
||||
output_geometry.loc,
|
||||
Size::from((output_geometry.size.w / 2, output_geometry.size.h)),
|
||||
),
|
||||
TiledCorners::Top => (
|
||||
output_geometry.loc,
|
||||
Size::from((output_geometry.size.w, output_geometry.size.h / 2)),
|
||||
),
|
||||
TiledCorners::TopLeft => (
|
||||
output_geometry.loc,
|
||||
Size::from((output_geometry.size.w / 2, output_geometry.size.h / 2)),
|
||||
),
|
||||
TiledCorners::TopRight => (
|
||||
Point::from((
|
||||
output_geometry.loc.x + (output_geometry.size.w / 2),
|
||||
output_geometry.loc.y,
|
||||
)),
|
||||
Size::from((output_geometry.size.w / 2, output_geometry.size.h / 2)),
|
||||
),
|
||||
TiledCorners::Right => (
|
||||
Point::from((
|
||||
output_geometry.loc.x + (output_geometry.size.w / 2),
|
||||
output_geometry.loc.y,
|
||||
)),
|
||||
Size::from((output_geometry.size.w / 2, output_geometry.size.h)),
|
||||
),
|
||||
};
|
||||
|
||||
Rectangle::from_loc_and_size(loc, size).as_local()
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatingLayout {
|
||||
pub fn new(output: &Output) -> FloatingLayout {
|
||||
let mut layout = Self::default();
|
||||
|
|
@ -53,9 +124,41 @@ impl FloatingLayout {
|
|||
self.space.unmap_output(&old_output);
|
||||
self.space.map_output(output, (0, 0));
|
||||
|
||||
/*
|
||||
TODO: rescale all positions? (evem rescale windows?)
|
||||
*/
|
||||
let old_output_geometry = {
|
||||
let layers = layer_map_for_output(&old_output);
|
||||
layers.non_exclusive_zone()
|
||||
};
|
||||
let output_geometry = {
|
||||
let layers = layer_map_for_output(&output);
|
||||
layers.non_exclusive_zone()
|
||||
};
|
||||
|
||||
for mapped in self
|
||||
.space
|
||||
.elements()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
{
|
||||
let tiled_state = mapped.floating_tiled.lock().unwrap().clone();
|
||||
if let Some(tiled_state) = tiled_state {
|
||||
let geometry = tiled_state.relative_geometry(output_geometry);
|
||||
self.map_internal(mapped, Some(geometry.loc), Some(geometry.size.as_logical()));
|
||||
} else {
|
||||
let geometry = self.space.element_geometry(&mapped).unwrap();
|
||||
let new_loc = (
|
||||
geometry.loc.x.saturating_sub(old_output_geometry.loc.x)
|
||||
/ old_output_geometry.size.w
|
||||
* output_geometry.size.w
|
||||
+ output_geometry.loc.x,
|
||||
geometry.loc.y.saturating_sub(old_output_geometry.loc.y)
|
||||
/ old_output_geometry.size.h
|
||||
* output_geometry.size.h
|
||||
+ output_geometry.loc.y,
|
||||
);
|
||||
self.map_internal(mapped, Some(Point::from(new_loc)), None);
|
||||
}
|
||||
}
|
||||
|
||||
self.refresh();
|
||||
}
|
||||
|
|
@ -271,7 +374,7 @@ impl FloatingLayout {
|
|||
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),
|
||||
.min(output_geometry.size.h / 8),
|
||||
)
|
||||
.into()
|
||||
})
|
||||
|
|
@ -291,7 +394,19 @@ impl FloatingLayout {
|
|||
}
|
||||
|
||||
pub fn unmap(&mut self, window: &CosmicMapped) -> bool {
|
||||
if !window.is_maximized(true) || !window.is_fullscreen(true) {
|
||||
if let Some(_) = window.floating_tiled.lock().unwrap().take() {
|
||||
if let Some(last_size) = window.last_geometry.lock().unwrap().map(|geo| geo.size) {
|
||||
if let Some(location) = self.space.element_location(window) {
|
||||
window.set_tiled(false);
|
||||
window.set_geometry(
|
||||
Rectangle::from_loc_and_size(location, last_size.as_logical())
|
||||
.as_local()
|
||||
.to_global(self.space.outputs().next().unwrap()),
|
||||
);
|
||||
window.configure();
|
||||
}
|
||||
}
|
||||
} else if !window.is_maximized(true) || !window.is_fullscreen(true) {
|
||||
if let Some(location) = self.space.element_location(window) {
|
||||
*window.last_geometry.lock().unwrap() = Some(
|
||||
Rectangle::from_loc_and_size(
|
||||
|
|
@ -539,7 +654,7 @@ impl FloatingLayout {
|
|||
};
|
||||
|
||||
match focused.handle_move(direction) {
|
||||
StackMoveResult::Handled => return MoveResult::Done,
|
||||
StackMoveResult::Handled => MoveResult::Done,
|
||||
StackMoveResult::MoveOut(surface, loop_handle) => {
|
||||
let mapped: CosmicMapped = CosmicWindow::new(surface, loop_handle, theme).into();
|
||||
let output = seat.active_output();
|
||||
|
|
@ -562,12 +677,87 @@ impl FloatingLayout {
|
|||
.then_some(pos);
|
||||
|
||||
self.map_internal(mapped.clone(), position.map(PointExt::as_local), None);
|
||||
return MoveResult::ShiftFocus(KeyboardFocusTarget::Element(mapped));
|
||||
MoveResult::ShiftFocus(KeyboardFocusTarget::Element(mapped))
|
||||
}
|
||||
StackMoveResult::Default => {}
|
||||
};
|
||||
StackMoveResult::Default => {
|
||||
let mut tiled_state = focused.floating_tiled.lock().unwrap();
|
||||
let new_state = match (direction, &*tiled_state) {
|
||||
// figure out if we are moving between workspaces/outputs
|
||||
(
|
||||
Direction::Up,
|
||||
Some(TiledCorners::Top)
|
||||
| Some(TiledCorners::TopLeft)
|
||||
| Some(TiledCorners::TopRight),
|
||||
)
|
||||
| (
|
||||
Direction::Down,
|
||||
Some(TiledCorners::Bottom)
|
||||
| Some(TiledCorners::BottomLeft)
|
||||
| Some(TiledCorners::BottomRight),
|
||||
)
|
||||
| (
|
||||
Direction::Left,
|
||||
Some(TiledCorners::Left)
|
||||
| Some(TiledCorners::TopLeft)
|
||||
| Some(TiledCorners::BottomLeft),
|
||||
)
|
||||
| (
|
||||
Direction::Right,
|
||||
Some(TiledCorners::Right)
|
||||
| Some(TiledCorners::TopRight)
|
||||
| Some(TiledCorners::BottomRight),
|
||||
) => {
|
||||
return MoveResult::MoveFurther(KeyboardFocusTarget::Element(
|
||||
focused.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
MoveResult::MoveFurther(KeyboardFocusTarget::Element(focused.clone()))
|
||||
// figure out if we need to quater tile
|
||||
(Direction::Up, Some(TiledCorners::Left))
|
||||
| (Direction::Left, Some(TiledCorners::Top)) => TiledCorners::TopLeft,
|
||||
(Direction::Right, Some(TiledCorners::Top))
|
||||
| (Direction::Up, Some(TiledCorners::Right)) => TiledCorners::TopRight,
|
||||
(Direction::Down, Some(TiledCorners::Left))
|
||||
| (Direction::Left, Some(TiledCorners::Bottom)) => TiledCorners::BottomLeft,
|
||||
(Direction::Right, Some(TiledCorners::Bottom))
|
||||
| (Direction::Down, Some(TiledCorners::Right)) => TiledCorners::BottomRight,
|
||||
// figure out if we need to extend a quater tile
|
||||
(Direction::Up, Some(TiledCorners::BottomLeft))
|
||||
| (Direction::Down, Some(TiledCorners::TopLeft)) => TiledCorners::Left,
|
||||
(Direction::Up, Some(TiledCorners::BottomRight))
|
||||
| (Direction::Down, Some(TiledCorners::TopRight)) => TiledCorners::Right,
|
||||
(Direction::Left, Some(TiledCorners::TopRight))
|
||||
| (Direction::Right, Some(TiledCorners::TopLeft)) => TiledCorners::Top,
|
||||
(Direction::Left, Some(TiledCorners::BottomRight))
|
||||
| (Direction::Right, Some(TiledCorners::BottomLeft)) => TiledCorners::Bottom,
|
||||
// else we have a simple case
|
||||
(Direction::Up, _) => TiledCorners::Top,
|
||||
(Direction::Right, _) => TiledCorners::Right,
|
||||
(Direction::Down, _) => TiledCorners::Bottom,
|
||||
(Direction::Left, _) => TiledCorners::Left,
|
||||
};
|
||||
|
||||
let output = self.space.outputs().next().unwrap().clone();
|
||||
let layers = layer_map_for_output(&output);
|
||||
let output_geometry = layers.non_exclusive_zone();
|
||||
std::mem::drop(layers);
|
||||
|
||||
let new_geo = new_state.relative_geometry(output_geometry);
|
||||
let (new_pos, new_size) = (new_geo.loc, new_geo.size);
|
||||
focused.set_tiled(true); // TODO: More fine grained?
|
||||
|
||||
*tiled_state = Some(new_state);
|
||||
std::mem::drop(tiled_state);
|
||||
|
||||
*focused.last_geometry.lock().unwrap() =
|
||||
self.space.element_geometry(focused).map(RectExt::as_local);
|
||||
focused.moved_since_mapped.store(true, Ordering::SeqCst);
|
||||
let focused = focused.clone();
|
||||
self.map_internal(focused, Some(new_pos), Some(new_size.as_logical()));
|
||||
|
||||
MoveResult::Done
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mapped(&self) -> impl Iterator<Item = &CosmicMapped> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue