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
|
|
|
|
2023-07-05 04:27:23 +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-07-05 04:27:23 +02:00
|
|
|
|
2023-06-06 04:08:37 +02:00
|
|
|
pub enum Direction {
|
|
|
|
Left,
|
|
|
|
Right,
|
|
|
|
Top,
|
|
|
|
Bottom,
|
2023-05-31 03:47:12 +02:00
|
|
|
}
|
2023-07-05 04:27:23 +02:00
|
|
|
|
2023-07-10 00:48:46 +02:00
|
|
|
pub struct MasterStack<S: SpaceElement> {
|
|
|
|
inner: Vec<S>,
|
2023-07-05 04:27:23 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 23:03:02 +02:00
|
|
|
pub trait Layout<'a, S: SpaceElement> {
|
2023-07-05 04:27:23 +02:00
|
|
|
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 04:27:23 +02:00
|
|
|
}
|
|
|
|
|
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-05 04:27:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-10 00:48:46 +02:00
|
|
|
impl MasterStack<Window> {
|
2023-07-05 04:27:23 +02:00
|
|
|
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| {
|
2023-07-05 04:27:23 +02:00
|
|
|
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-05 04:27:23 +02:00
|
|
|
|
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-05 04:27:23 +02:00
|
|
|
|
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-05 04:27:23 +02:00
|
|
|
|
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-05 04:27:23 +02:00
|
|
|
|
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());
|
|
|
|
|
2023-07-05 04:27:23 +02:00
|
|
|
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-05 04:27:23 +02:00
|
|
|
|
2023-07-10 00:48:46 +02:00
|
|
|
impl<'a> Layout<'a, Window> for MasterStack<Window> {
|
2023-07-05 04:27:23 +02:00
|
|
|
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| {
|
2023-07-05 04:27:23 +02:00
|
|
|
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| {
|
2023-07-05 04:27:23 +02:00
|
|
|
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>;
|
2023-07-05 04:27:23 +02:00
|
|
|
// 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(),
|
|
|
|
}
|
2023-07-05 04:27:23 +02:00
|
|
|
}
|
|
|
|
}
|