pinnacle/src/layout.rs

181 lines
5.4 KiB
Rust
Raw Normal View History

2023-06-26 00:18:50 +02:00
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
2023-06-26 00:49:06 +02:00
//
// SPDX-License-Identifier: MPL-2.0
2023-06-26 00:18:50 +02:00
use smithay::{
desktop::{space::SpaceElement, Space, Window},
output::Output,
utils::{Logical, Size},
};
2023-07-10 00:48:46 +02:00
use crate::{
backend::Backend,
state::State,
tag::TagId,
window::window_state::{WindowResizeState, WindowState},
};
2023-06-06 04:08:37 +02:00
pub enum Direction {
Left,
Right,
Top,
Bottom,
}
2023-07-10 00:48:46 +02:00
pub struct MasterStack<S: SpaceElement> {
inner: Vec<S>,
}
2023-07-05 23:03:02 +02:00
pub trait Layout<'a, S: SpaceElement> {
fn layout(&self, space: &Space<S>, output: &Output);
}
2023-07-10 00:48:46 +02:00
impl MasterStack<Window> {
2023-07-05 23:03:02 +02:00
pub fn master(&self) -> Option<&Window> {
2023-07-10 00:48:46 +02:00
self.inner.first()
}
2023-07-05 23:03:02 +02:00
pub fn stack(&self) -> impl Iterator<Item = &Window> {
2023-07-10 00:48:46 +02:00
self.inner.iter().skip(1)
}
}
2023-07-10 00:48:46 +02:00
impl MasterStack<Window> {
fn layout_stack(&self, space: &Space<Window>, output: &Output) {
let stack_count = self.stack().count();
let Some(output_geo) = space.output_geometry(output) else {
tracing::error!("could not get output geometry");
return;
};
let height = output_geo.size.h / stack_count as i32;
for (i, win) in self.stack().enumerate() {
win.toplevel().with_pending_state(|state| {
state.size = Some((output_geo.size.w / 2, height).into());
});
2023-07-09 17:00:16 +02:00
WindowState::with(win, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
win.toplevel().send_configure(),
(output_geo.size.w / 2, i as i32 * height).into(),
);
});
}
}
}
2023-07-10 00:48:46 +02:00
impl<B: Backend> State<B> {
pub fn swap_window_positions(&mut self, win1: &Window, win2: &Window) {
// FIXME: moving the mouse quickly will break swapping
2023-07-10 00:48:46 +02:00
let win1_loc = self.space.element_location(win1).unwrap(); // TODO: handle unwraps
let win2_loc = self.space.element_location(win2).unwrap();
let win1_geo = win1.geometry();
let win2_geo = win2.geometry();
2023-07-10 00:48:46 +02:00
win1.toplevel().with_pending_state(|state| {
state.size = Some(win2_geo.size);
});
win2.toplevel().with_pending_state(|state| {
state.size = Some(win1_geo.size);
});
2023-07-10 00:48:46 +02:00
let serial = win1.toplevel().send_configure();
WindowState::with(win1, |state| {
state.resize_state = WindowResizeState::WaitingForAck(serial, win2_loc);
});
2023-07-10 00:48:46 +02:00
let serial = win2.toplevel().send_configure();
WindowState::with(win2, |state| {
state.resize_state = WindowResizeState::WaitingForAck(serial, win1_loc);
});
2023-07-09 17:00:16 +02:00
let mut elems = self
2023-07-10 00:48:46 +02:00
.windows
2023-07-09 17:00:16 +02:00
.iter_mut()
2023-07-10 00:48:46 +02:00
.filter(|win| *win == win1 || *win == win2);
2023-07-09 17:00:16 +02:00
let (first, second) = (elems.next(), elems.next());
if let Some(first) = first {
if let Some(second) = second {
std::mem::swap(first, second);
}
}
}
2023-07-10 00:48:46 +02:00
}
2023-07-10 00:48:46 +02:00
impl<'a> Layout<'a, Window> for MasterStack<Window> {
fn layout(&self, space: &Space<Window>, output: &Output) {
let Some(master) = self.master() else {
return;
};
let Some(output_geo) = space.output_geometry(output) else {
tracing::error!("could not get output geometry");
return;
};
if self.stack().count() == 0 {
// one window
master.toplevel().with_pending_state(|state| {
state.size = Some(output_geo.size);
});
2023-07-09 17:00:16 +02:00
WindowState::with(master, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
master.toplevel().send_configure(),
(0, 0).into(),
);
});
} else {
let new_master_size: Size<i32, Logical> =
(output_geo.size.w / 2, output_geo.size.h).into();
master.toplevel().with_pending_state(|state| {
state.size = Some(new_master_size);
});
2023-07-09 17:00:16 +02:00
WindowState::with(master, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
master.toplevel().send_configure(),
(0, 0).into(),
);
});
self.layout_stack(space, output);
}
}
}
pub trait LayoutVec<S: SpaceElement> {
/// Interpret this vec as a master-stack layout.
2023-07-10 00:48:46 +02:00
fn to_master_stack(&self, tags: Vec<TagId>) -> MasterStack<S>;
// fn as_binary_tree(&mut self); TODO:
}
2023-07-10 00:48:46 +02:00
impl LayoutVec<Window> for Vec<Window> {
fn to_master_stack(&self, tags: Vec<TagId>) -> MasterStack<Window> {
MasterStack {
inner: self
.iter()
.filter(|window| {
WindowState::with(window, |state| {
state.floating.is_tiled() && {
for tag_id in state.tags.iter() {
if tags.iter().any(|tag| tag == tag_id) {
return true;
}
}
false
}
})
})
.cloned()
.collect(),
}
}
}