2023-08-01 11:06:35 -05:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2023-06-25 17:18:50 -05:00
|
|
|
|
2023-07-17 18:48:01 -05:00
|
|
|
use itertools::{Either, Itertools};
|
2023-07-04 21:27:23 -05:00
|
|
|
use smithay::{
|
2023-08-14 14:54:34 -05:00
|
|
|
desktop::layer_map_for_output,
|
2023-07-04 21:27:23 -05:00
|
|
|
output::Output,
|
2023-08-11 10:08:38 -05:00
|
|
|
utils::{Logical, Point, Rectangle, Size},
|
2023-07-04 21:27:23 -05:00
|
|
|
};
|
|
|
|
|
2023-07-09 17:48:46 -05:00
|
|
|
use crate::{
|
|
|
|
backend::Backend,
|
2023-07-10 17:14:37 -05:00
|
|
|
state::{State, WithState},
|
2023-08-11 10:08:38 -05:00
|
|
|
window::{
|
2023-08-21 17:56:18 -05:00
|
|
|
window_state::{FloatingOrTiled, FullscreenOrMaximized, LocationRequestState},
|
2023-08-11 10:08:38 -05:00
|
|
|
WindowElement,
|
|
|
|
},
|
2023-07-09 17:48:46 -05:00
|
|
|
};
|
2023-07-04 21:27:23 -05:00
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
// -------------------------------------------
|
|
|
|
|
|
|
|
impl<B: Backend> State<B> {
|
|
|
|
/// Compute the positions and sizes of tiled windows on
|
|
|
|
/// `output` according to the provided [`Layout`].
|
|
|
|
///
|
|
|
|
/// This will call `request_size_change` on tiled windows.
|
|
|
|
fn tile_windows(&self, output: &Output, windows: Vec<WindowElement>, layout: Layout) {
|
|
|
|
let Some(rect) = self.space.output_geometry(output).map(|op_geo| {
|
|
|
|
let map = layer_map_for_output(output);
|
|
|
|
if map.layers().peekable().peek().is_none() {
|
|
|
|
// INFO: Sometimes the exclusive zone is some weird number that doesn't match the
|
|
|
|
// | output res, even when there are no layer surfaces mapped. In this case, we
|
|
|
|
// | just return the output geometry.
|
|
|
|
op_geo
|
|
|
|
} else {
|
|
|
|
let zone = map.non_exclusive_zone();
|
|
|
|
tracing::debug!("non_exclusive_zone is {zone:?}");
|
|
|
|
Rectangle::from_loc_and_size(op_geo.loc + zone.loc, zone.size)
|
|
|
|
}
|
|
|
|
}) else {
|
|
|
|
// TODO: maybe default to something like 800x800 like in anvil so people still see
|
|
|
|
// | windows open
|
|
|
|
tracing::error!("Failed to get output geometry");
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
match layout {
|
|
|
|
Layout::MasterStack => master_stack(windows, rect),
|
|
|
|
Layout::Dwindle => dwindle(windows, rect),
|
|
|
|
Layout::Spiral => spiral(windows, rect),
|
|
|
|
layout @ (Layout::CornerTopLeft
|
|
|
|
| Layout::CornerTopRight
|
|
|
|
| Layout::CornerBottomLeft
|
|
|
|
| Layout::CornerBottomRight) => corner(&layout, windows, rect),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_windows(&mut self, output: &Output) {
|
|
|
|
let Some(layout) = output.with_state(|state| {
|
|
|
|
state.focused_tags().next().cloned().map(|tag| tag.layout())
|
|
|
|
}) else { return };
|
|
|
|
|
2023-08-14 21:01:00 -05:00
|
|
|
let (windows_on_foc_tags, mut windows_not_on_foc_tags): (Vec<_>, _) =
|
2023-08-11 10:08:38 -05:00
|
|
|
output.with_state(|state| {
|
|
|
|
let focused_tags = state.focused_tags().collect::<Vec<_>>();
|
|
|
|
self.windows.iter().cloned().partition(|win| {
|
|
|
|
win.with_state(|state| state.tags.iter().any(|tg| focused_tags.contains(&tg)))
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2023-08-14 21:01:00 -05:00
|
|
|
windows_not_on_foc_tags.retain(|win| win.output(self) == Some(output.clone()));
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
let tiled_windows = windows_on_foc_tags
|
|
|
|
.iter()
|
2023-08-14 13:54:50 -05:00
|
|
|
.filter(|win| {
|
|
|
|
win.with_state(|state| {
|
|
|
|
state.floating_or_tiled.is_tiled() && state.fullscreen_or_maximized.is_neither()
|
|
|
|
})
|
|
|
|
})
|
2023-08-11 10:08:38 -05:00
|
|
|
.cloned()
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
self.tile_windows(output, tiled_windows, layout);
|
|
|
|
|
|
|
|
let output_geo = self.space.output_geometry(output).expect("no output geo");
|
|
|
|
for window in windows_on_foc_tags.iter() {
|
2023-08-14 13:54:50 -05:00
|
|
|
match window.with_state(|state| state.fullscreen_or_maximized) {
|
|
|
|
FullscreenOrMaximized::Fullscreen => {
|
2023-08-11 10:08:38 -05:00
|
|
|
window.change_geometry(output_geo);
|
|
|
|
}
|
2023-08-14 13:54:50 -05:00
|
|
|
FullscreenOrMaximized::Maximized => {
|
2023-08-11 10:08:38 -05:00
|
|
|
let map = layer_map_for_output(output);
|
|
|
|
let geo = if map.layers().peekable().peek().is_none() {
|
|
|
|
// INFO: Sometimes the exclusive zone is some weird number that doesn't match the
|
|
|
|
// | output res, even when there are no layer surfaces mapped. In this case, we
|
|
|
|
// | just return the output geometry.
|
|
|
|
output_geo
|
|
|
|
} else {
|
|
|
|
let zone = map.non_exclusive_zone();
|
|
|
|
tracing::debug!("non_exclusive_zone is {zone:?}");
|
|
|
|
Rectangle::from_loc_and_size(output_geo.loc + zone.loc, zone.size)
|
|
|
|
};
|
|
|
|
window.change_geometry(geo);
|
|
|
|
}
|
2023-08-21 17:56:18 -05:00
|
|
|
FullscreenOrMaximized::Neither => {
|
|
|
|
if let FloatingOrTiled::Floating(rect) =
|
|
|
|
window.with_state(|state| state.floating_or_tiled)
|
|
|
|
{
|
|
|
|
window.change_geometry(rect);
|
|
|
|
}
|
|
|
|
}
|
2023-08-11 10:08:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for window in windows_on_foc_tags.iter() {
|
|
|
|
window.with_state(|state| {
|
|
|
|
if let LocationRequestState::Sent(loc) = state.loc_request_state {
|
|
|
|
match &window {
|
|
|
|
WindowElement::Wayland(window) => {
|
|
|
|
let serial = window.toplevel().send_configure();
|
|
|
|
state.loc_request_state = LocationRequestState::Requested(serial, loc);
|
|
|
|
}
|
2023-08-21 17:56:18 -05:00
|
|
|
WindowElement::X11(surface) => {
|
2023-08-11 10:08:38 -05:00
|
|
|
// already configured, just need to map
|
|
|
|
// maybe wait for all wayland windows to commit before mapping
|
|
|
|
self.space.map_element(window.clone(), loc, false);
|
2023-08-21 17:56:18 -05:00
|
|
|
surface
|
|
|
|
.set_mapped(true)
|
|
|
|
.expect("failed to set x11 win to mapped");
|
2023-08-11 10:08:38 -05:00
|
|
|
state.loc_request_state = LocationRequestState::Idle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
self.loop_handle.insert_idle(|data| {
|
|
|
|
crate::state::schedule_on_commit(data, windows_on_foc_tags, |dt| {
|
|
|
|
for win in windows_not_on_foc_tags {
|
|
|
|
dt.state.space.unmap_elem(&win);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------
|
|
|
|
|
2023-07-12 18:50:41 -05:00
|
|
|
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
2023-07-11 21:07:51 -05:00
|
|
|
pub enum Layout {
|
|
|
|
MasterStack,
|
|
|
|
Dwindle,
|
2023-07-12 18:50:41 -05:00
|
|
|
Spiral,
|
2023-07-17 18:48:01 -05:00
|
|
|
CornerTopLeft,
|
|
|
|
CornerTopRight,
|
|
|
|
CornerBottomLeft,
|
|
|
|
CornerBottomRight,
|
2023-07-04 21:27:23 -05:00
|
|
|
}
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
fn master_stack(windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
2023-08-07 11:25:36 -05:00
|
|
|
let size = rect.size;
|
|
|
|
let loc = rect.loc;
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
let master = windows.first();
|
|
|
|
let stack = windows.iter().skip(1);
|
|
|
|
|
|
|
|
let Some(master) = master else { return };
|
|
|
|
|
|
|
|
let stack_count = stack.clone().count();
|
|
|
|
|
|
|
|
if stack_count == 0 {
|
|
|
|
// one window
|
2023-08-11 10:08:38 -05:00
|
|
|
master.change_geometry(Rectangle::from_loc_and_size(loc, size));
|
2023-07-24 18:59:05 -05:00
|
|
|
} else {
|
2023-08-11 10:08:38 -05:00
|
|
|
let loc: Point<i32, Logical> = (loc.x, loc.y).into();
|
2023-08-07 11:25:36 -05:00
|
|
|
let new_master_size: Size<i32, Logical> = (size.w / 2, size.h).into();
|
2023-08-11 10:08:38 -05:00
|
|
|
master.change_geometry(Rectangle::from_loc_and_size(loc, new_master_size));
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
let stack_count = stack_count;
|
|
|
|
|
2023-08-07 11:25:36 -05:00
|
|
|
let height = size.h as f32 / stack_count as f32;
|
2023-07-24 18:59:05 -05:00
|
|
|
let mut y_s = vec![];
|
|
|
|
for i in 0..stack_count {
|
|
|
|
y_s.push((i as f32 * height).round() as i32);
|
|
|
|
}
|
|
|
|
let heights = y_s
|
|
|
|
.windows(2)
|
|
|
|
.map(|pair| pair[1] - pair[0])
|
2023-08-07 11:25:36 -05:00
|
|
|
.chain(vec![size.h - y_s.last().expect("vec was empty")])
|
2023-07-24 18:59:05 -05:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for (i, win) in stack.enumerate() {
|
2023-08-11 10:08:38 -05:00
|
|
|
win.change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
Point::from((size.w / 2 + loc.x, y_s[i] + loc.y)),
|
|
|
|
Size::from((size.w / 2, i32::max(heights[i], 40))),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
fn dwindle(windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
2023-08-07 11:25:36 -05:00
|
|
|
let size = rect.size;
|
|
|
|
let loc = rect.loc;
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
let mut iter = windows.windows(2).peekable();
|
|
|
|
|
|
|
|
if iter.peek().is_none() {
|
|
|
|
if let Some(window) = windows.first() {
|
2023-08-11 10:08:38 -05:00
|
|
|
window.change_geometry(Rectangle::from_loc_and_size(loc, size));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
} else {
|
2023-08-07 11:25:36 -05:00
|
|
|
let mut win1_size = size;
|
|
|
|
let mut win1_loc = loc;
|
2023-07-24 18:59:05 -05:00
|
|
|
for (i, wins) in iter.enumerate() {
|
|
|
|
let win1 = &wins[0];
|
|
|
|
let win2 = &wins[1];
|
|
|
|
|
|
|
|
enum Slice {
|
|
|
|
Right,
|
|
|
|
Below,
|
2023-07-11 21:07:51 -05:00
|
|
|
}
|
2023-07-04 21:27:23 -05:00
|
|
|
|
2023-08-04 09:36:40 -05:00
|
|
|
let slice = if i % 2 == 0 { Slice::Right } else { Slice::Below };
|
2023-07-10 17:14:37 -05:00
|
|
|
|
2023-07-24 18:59:05 -05:00
|
|
|
match slice {
|
|
|
|
Slice::Right => {
|
|
|
|
let width_partition = win1_size.w / 2;
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win1.change_geometry(Rectangle::from_loc_and_size(
|
2023-07-24 18:59:05 -05:00
|
|
|
win1_loc,
|
2023-08-11 10:08:38 -05:00
|
|
|
Size::from((win1_size.w - width_partition, i32::max(win1_size.h, 40))),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
win1_loc = (win1_loc.x + (win1_size.w - width_partition), win1_loc.y).into();
|
|
|
|
win1_size = (width_partition, i32::max(win1_size.h, 40)).into();
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
2023-07-12 18:50:41 -05:00
|
|
|
}
|
2023-07-24 18:59:05 -05:00
|
|
|
Slice::Below => {
|
|
|
|
let height_partition = win1_size.h / 2;
|
2023-07-12 18:50:41 -05:00
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win1.change_geometry(Rectangle::from_loc_and_size(
|
2023-07-24 18:59:05 -05:00
|
|
|
win1_loc,
|
2023-08-11 10:08:38 -05:00
|
|
|
Size::from((win1_size.w, i32::max(win1_size.h - height_partition, 40))),
|
|
|
|
));
|
2023-07-12 18:50:41 -05:00
|
|
|
|
2023-07-24 18:59:05 -05:00
|
|
|
win1_loc = (win1_loc.x, win1_loc.y + (win1_size.h - height_partition)).into();
|
|
|
|
win1_size = (win1_size.w, i32::max(height_partition, 40)).into();
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
2023-07-11 21:07:51 -05:00
|
|
|
}
|
|
|
|
}
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
fn spiral(windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
2023-08-07 11:25:36 -05:00
|
|
|
let size = rect.size;
|
|
|
|
let loc = rect.loc;
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
let mut iter = windows.windows(2).peekable();
|
|
|
|
|
|
|
|
if iter.peek().is_none() {
|
|
|
|
if let Some(window) = windows.first() {
|
2023-08-11 10:08:38 -05:00
|
|
|
window.change_geometry(Rectangle::from_loc_and_size(loc, size));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
} else {
|
2023-08-07 11:25:36 -05:00
|
|
|
let mut win1_loc = loc;
|
|
|
|
let mut win1_size = size;
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
for (i, wins) in iter.enumerate() {
|
|
|
|
let win1 = &wins[0];
|
|
|
|
let win2 = &wins[1];
|
|
|
|
|
|
|
|
enum Slice {
|
|
|
|
Above,
|
|
|
|
Below,
|
|
|
|
Left,
|
|
|
|
Right,
|
|
|
|
}
|
|
|
|
|
|
|
|
let slice = match i % 4 {
|
|
|
|
0 => Slice::Right,
|
|
|
|
1 => Slice::Below,
|
|
|
|
2 => Slice::Left,
|
|
|
|
3 => Slice::Above,
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
|
|
|
match slice {
|
|
|
|
Slice::Above => {
|
|
|
|
let height_partition = win1_size.h / 2;
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win1.change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
Point::from((win1_loc.x, win1_loc.y + height_partition)),
|
|
|
|
Size::from((win1_size.w, i32::max(win1_size.h - height_partition, 40))),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
win1_size = (win1_size.w, i32::max(height_partition, 40)).into();
|
2023-08-11 10:08:38 -05:00
|
|
|
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
2023-07-17 18:48:01 -05:00
|
|
|
}
|
2023-07-24 18:59:05 -05:00
|
|
|
Slice::Below => {
|
|
|
|
let height_partition = win1_size.h / 2;
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win1.change_geometry(Rectangle::from_loc_and_size(
|
2023-07-24 18:59:05 -05:00
|
|
|
win1_loc,
|
2023-08-11 10:08:38 -05:00
|
|
|
Size::from((win1_size.w, win1_size.h - i32::max(height_partition, 40))),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
win1_loc = (win1_loc.x, win1_loc.y + (win1_size.h - height_partition)).into();
|
|
|
|
win1_size = (win1_size.w, i32::max(height_partition, 40)).into();
|
2023-08-11 10:08:38 -05:00
|
|
|
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
2023-07-17 18:48:01 -05:00
|
|
|
}
|
2023-07-24 18:59:05 -05:00
|
|
|
Slice::Left => {
|
|
|
|
let width_partition = win1_size.w / 2;
|
2023-07-17 20:40:56 -05:00
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win1.change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
Point::from((win1_loc.x + width_partition, win1_loc.y)),
|
|
|
|
Size::from((win1_size.w - width_partition, i32::max(win1_size.h, 40))),
|
|
|
|
));
|
2023-07-17 20:40:56 -05:00
|
|
|
|
2023-07-24 18:59:05 -05:00
|
|
|
win1_size = (width_partition, i32::max(win1_size.h, 40)).into();
|
2023-08-11 10:08:38 -05:00
|
|
|
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
Slice::Right => {
|
|
|
|
let width_partition = win1_size.w / 2;
|
2023-07-17 20:40:56 -05:00
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
win1.change_geometry(Rectangle::from_loc_and_size(
|
2023-07-24 18:59:05 -05:00
|
|
|
win1_loc,
|
2023-08-11 10:08:38 -05:00
|
|
|
Size::from((win1_size.w - width_partition, i32::max(win1_size.h, 40))),
|
|
|
|
));
|
2023-07-17 20:40:56 -05:00
|
|
|
|
2023-07-24 18:59:05 -05:00
|
|
|
win1_loc = (win1_loc.x + (win1_size.w - width_partition), win1_loc.y).into();
|
|
|
|
win1_size = (width_partition, i32::max(win1_size.h, 40)).into();
|
2023-08-11 10:08:38 -05:00
|
|
|
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
fn corner(layout: &Layout, windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
2023-08-07 11:25:36 -05:00
|
|
|
let size = rect.size;
|
|
|
|
let loc = rect.loc;
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
match windows.len() {
|
|
|
|
0 => (),
|
|
|
|
1 => {
|
2023-08-11 10:08:38 -05:00
|
|
|
windows[0].change_geometry(rect);
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
2 => {
|
2023-08-11 10:08:38 -05:00
|
|
|
windows[0].change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
loc,
|
|
|
|
Size::from((size.w / 2, size.h)),
|
|
|
|
));
|
|
|
|
|
|
|
|
windows[1].change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
Point::from((loc.x + size.w / 2, loc.y)),
|
|
|
|
Size::from((size.w / 2, size.h)),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let mut windows = windows.into_iter();
|
|
|
|
let Some(corner) = windows.next() else { unreachable!() };
|
|
|
|
let (horiz_stack, vert_stack): (Vec<WindowElement>, Vec<WindowElement>) =
|
|
|
|
windows.enumerate().partition_map(|(i, win)| {
|
|
|
|
if i % 2 == 0 {
|
|
|
|
Either::Left(win)
|
|
|
|
} else {
|
|
|
|
Either::Right(win)
|
2023-07-17 20:40:56 -05:00
|
|
|
}
|
2023-07-24 18:59:05 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
let div_factor = 2;
|
|
|
|
|
2023-08-11 10:08:38 -05:00
|
|
|
corner.change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
Point::from(match layout {
|
2023-08-07 11:25:36 -05:00
|
|
|
Layout::CornerTopLeft => (loc.x, loc.y),
|
|
|
|
Layout::CornerTopRight => (loc.x + size.w - size.w / div_factor, loc.y),
|
|
|
|
Layout::CornerBottomLeft => (loc.x, loc.y + size.h - size.h / div_factor),
|
2023-07-24 18:59:05 -05:00
|
|
|
Layout::CornerBottomRight => (
|
2023-08-07 11:25:36 -05:00
|
|
|
loc.x + size.w - size.w / div_factor,
|
|
|
|
loc.y + size.h - size.h / div_factor,
|
2023-07-24 18:59:05 -05:00
|
|
|
),
|
|
|
|
_ => unreachable!(),
|
2023-08-11 10:08:38 -05:00
|
|
|
}),
|
|
|
|
Size::from((size.w / div_factor, size.h / div_factor)),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
|
|
|
|
let vert_stack_count = vert_stack.len();
|
|
|
|
|
2023-08-07 11:25:36 -05:00
|
|
|
let height = size.h as f32 / vert_stack_count as f32;
|
2023-07-24 18:59:05 -05:00
|
|
|
let mut y_s = vec![];
|
|
|
|
for i in 0..vert_stack_count {
|
|
|
|
y_s.push((i as f32 * height).round() as i32);
|
|
|
|
}
|
|
|
|
let heights = y_s
|
|
|
|
.windows(2)
|
|
|
|
.map(|pair| pair[1] - pair[0])
|
2023-08-07 11:25:36 -05:00
|
|
|
.chain(vec![size.h - y_s.last().expect("vec was empty")])
|
2023-07-24 18:59:05 -05:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for (i, win) in vert_stack.iter().enumerate() {
|
2023-08-11 10:08:38 -05:00
|
|
|
win.change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
Point::from((
|
2023-07-24 18:59:05 -05:00
|
|
|
match layout {
|
2023-08-07 11:25:36 -05:00
|
|
|
Layout::CornerTopLeft | Layout::CornerBottomLeft => size.w / 2 + loc.x,
|
|
|
|
Layout::CornerTopRight | Layout::CornerBottomRight => loc.x,
|
2023-07-24 18:59:05 -05:00
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
2023-08-07 11:25:36 -05:00
|
|
|
y_s[i] + loc.y,
|
2023-08-11 10:08:38 -05:00
|
|
|
)),
|
|
|
|
Size::from((size.w / 2, i32::max(heights[i], 40))),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
let horiz_stack_count = horiz_stack.len();
|
|
|
|
|
2023-08-07 11:25:36 -05:00
|
|
|
let width = size.w as f32 / 2.0 / horiz_stack_count as f32;
|
2023-07-24 18:59:05 -05:00
|
|
|
let mut x_s = vec![];
|
|
|
|
for i in 0..horiz_stack_count {
|
|
|
|
x_s.push((i as f32 * width).round() as i32);
|
|
|
|
}
|
|
|
|
let widths = x_s
|
|
|
|
.windows(2)
|
|
|
|
.map(|pair| pair[1] - pair[0])
|
2023-08-07 11:25:36 -05:00
|
|
|
.chain(vec![size.w / 2 - x_s.last().expect("vec was empty")])
|
2023-07-24 18:59:05 -05:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for (i, win) in horiz_stack.iter().enumerate() {
|
2023-08-11 10:08:38 -05:00
|
|
|
win.change_geometry(Rectangle::from_loc_and_size(
|
|
|
|
Point::from(match layout {
|
2023-08-07 11:25:36 -05:00
|
|
|
Layout::CornerTopLeft => (x_s[i] + loc.x, loc.y + size.h / 2),
|
|
|
|
Layout::CornerTopRight => (x_s[i] + loc.x + size.w / 2, loc.y + size.h / 2),
|
|
|
|
Layout::CornerBottomLeft => (x_s[i] + loc.x, loc.y),
|
|
|
|
Layout::CornerBottomRight => (x_s[i] + loc.x + size.w / 2, loc.y),
|
2023-07-24 18:59:05 -05:00
|
|
|
_ => unreachable!(),
|
2023-08-11 10:08:38 -05:00
|
|
|
}),
|
|
|
|
Size::from((i32::max(widths[i], 1), size.h / 2)),
|
|
|
|
));
|
2023-07-24 18:59:05 -05:00
|
|
|
}
|
2023-07-10 17:14:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<B: Backend> State<B> {
|
2023-07-24 18:59:05 -05:00
|
|
|
pub fn swap_window_positions(&mut self, win1: &WindowElement, win2: &WindowElement) {
|
2023-07-10 17:14:37 -05:00
|
|
|
let mut elems = self
|
|
|
|
.windows
|
|
|
|
.iter_mut()
|
|
|
|
.filter(|win| *win == win1 || *win == win2);
|
|
|
|
|
|
|
|
let (first, second) = (elems.next(), elems.next());
|
|
|
|
|
|
|
|
if let Some(first) = first {
|
|
|
|
if let Some(second) = second {
|
|
|
|
std::mem::swap(first, second);
|
|
|
|
}
|
2023-07-09 17:48:46 -05:00
|
|
|
}
|
2023-07-18 12:57:04 -05:00
|
|
|
|
2023-07-28 14:33:14 -05:00
|
|
|
// TODO: don't use the focused output, use the outputs the two windows are on
|
|
|
|
let output = self
|
|
|
|
.focus_state
|
|
|
|
.focused_output
|
|
|
|
.clone()
|
|
|
|
.expect("no focused output");
|
2023-08-11 10:08:38 -05:00
|
|
|
self.update_windows(&output);
|
|
|
|
// self.re_layout(&output);
|
2023-07-04 21:27:23 -05:00
|
|
|
}
|
|
|
|
}
|