Skip to content

Commit

Permalink
floating: Handle tiling shortcuts
Browse files Browse the repository at this point in the history
  • Loading branch information
Drakulix committed Nov 14, 2023
1 parent a098e68 commit 7f6a09a
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 13 deletions.
10 changes: 8 additions & 2 deletions src/shell/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ use tracing::debug;

use super::{
focus::FocusDirection,
layout::{floating::ResizeState, tiling::NodeDesc},
layout::{
floating::{ResizeState, TiledCorners},
tiling::NodeDesc,
},
Direction, ManagedLayer,
};

Expand Down Expand Up @@ -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>>>,
Expand All @@ -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()
}
}
Expand Down Expand Up @@ -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)),
}
Expand All @@ -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)),
}
Expand Down
212 changes: 201 additions & 11 deletions src/shell/layout/floating/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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();
Expand All @@ -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();
}
Expand Down Expand Up @@ -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()
})
Expand All @@ -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(
Expand Down Expand Up @@ -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();
Expand All @@ -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(),
));
}

// 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?

MoveResult::MoveFurther(KeyboardFocusTarget::Element(focused.clone()))
*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> {
Expand Down

0 comments on commit 7f6a09a

Please sign in to comment.