Clean up old layouts

This commit is contained in:
Seaotatop 2023-07-09 10:00:16 -05:00 committed by Ottatop
parent 170addbad1
commit d860172334
10 changed files with 160 additions and 304 deletions

View file

@ -47,7 +47,6 @@ use smithay::{
};
use crate::{
layout::{Direction, Layouts},
render::{pointer::PointerElement, CustomRenderElements, OutputRenderElements},
state::{CalloopData, State},
};
@ -220,11 +219,7 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
None,
None,
);
Layouts::master_stack(
state,
state.space.elements().cloned().collect(),
Direction::Left,
);
state.re_layout();
}
WinitEvent::Focus(_) => {}
WinitEvent::Input(input_evt) => {

View file

@ -19,7 +19,13 @@ use smithay::{
utils::{IsAlive, Logical, Point, Rectangle},
};
use crate::{backend::Backend, state::State, window::window_state::WindowState};
use crate::{
backend::Backend,
layout::{Layout, LayoutVec},
output::OutputState,
state::State,
window::window_state::{WindowResizeState, WindowState},
};
pub struct MoveSurfaceGrab<S: SeatHandler> {
pub start_data: GrabStartData<S>,
@ -47,7 +53,7 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
// tracing::info!("window geo is: {:?}", self.window.geometry());
// tracing::info!("loc is: {:?}", data.space.element_location(&self.window));
let tiled = WindowState::with_state(&self.window, |state| state.floating.is_tiled());
let tiled = WindowState::with(&self.window, |state| state.floating.is_tiled());
if tiled {
// INFO: this is being used instead of space.element_under(event.location) because that
@ -72,28 +78,46 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
return;
}
let window_under_floating =
WindowState::with_state(&window_under, |state| state.floating.is_floating());
let is_floating =
WindowState::with(&window_under, |state| state.floating.is_floating());
if window_under_floating {
if is_floating {
return;
}
data.swap_window_positions(&self.window, &window_under);
let has_pending_resize = WindowState::with(&window_under, |state| {
!matches!(state.resize_state, WindowResizeState::Idle)
});
if has_pending_resize {
return;
}
// data.swap_window_positions(&self.window, &window_under);
let output = data.focus_state.focused_output.as_ref().unwrap();
OutputState::with(output, |state| {
let mut tags = data
.tag_state
.tags
.iter_mut()
.filter(|tg| state.tags.contains(&tg.id));
if let Some(first) = tags.next() {
let mut layout = first.windows.as_master_stack();
for tg in tags {
layout = layout.chain_with(&mut tg.windows);
}
layout.swap(&data.space, &self.window, &window_under);
}
})
}
} else {
let delta = event.location - self.start_data.location;
let new_loc = self.initial_window_loc.to_f64() + delta;
data.space
.map_element(self.window.clone(), new_loc.to_i32_round(), true);
// let loc = data
// .space
// .element_location(&self.window)
// .unwrap_or((0, 0).into());
// tracing::info!("new loc from element_location: {}, {}", loc.x, loc.y);
// let geo = self.window.geometry();
// tracing::info!("geo loc: {}, {}", geo.loc.x, geo.loc.y);
// tracing::info!("geo size: {}, {}", geo.size.w, geo.size.h);
}
}

View file

@ -117,7 +117,7 @@ impl<B: Backend> CompositorHandler for State<B> {
crate::grab::resize_grab::handle_commit(self, surface);
if let Some(window) = self.window_for_surface(surface) {
WindowState::with_state(&window, |state| {
WindowState::with(&window, |state| {
if let WindowResizeState::WaitingForCommit(new_pos) = state.resize_state {
state.resize_state = WindowResizeState::Idle;
self.space.map_element(window.clone(), new_pos, false);
@ -225,11 +225,10 @@ impl<B: Backend> XdgShellHandler for State<B> {
fn new_toplevel(&mut self, surface: ToplevelSurface) {
let window = Window::new(surface);
WindowState::with_state(&window, |state| {
WindowState::with(&window, |state| {
state.tags = if let Some(focused_output) = &self.focus_state.focused_output {
OutputState::with(focused_output, |state| {
let output_tags: Vec<crate::tag::TagId> =
state.focused_tags.iter().cloned().collect();
let output_tags: Vec<crate::tag::TagId> = state.tags.iter().cloned().collect();
if !output_tags.is_empty() {
output_tags
} else if let Some(first_tag) = self.tag_state.tags.first() {
@ -270,7 +269,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
.tag_state
.tags
.iter_mut()
.filter(|tg| state.focused_tags.contains(&tg.id));
.filter(|tg| state.tags.contains(&tg.id));
if let Some(first) = tags.next() {
let mut layout = first.windows.as_master_stack();
@ -302,7 +301,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
.tag_state
.tags
.iter_mut()
.filter(|tg| state.focused_tags.contains(&tg.id));
.filter(|tg| state.tags.contains(&tg.id));
if let Some(first) = tags.next() {
tracing::debug!("first tag: {:?}", first.id);
@ -429,10 +428,10 @@ impl<B: Backend> XdgShellHandler for State<B> {
}
fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
tracing::debug!("start of ack_configure");
// tracing::debug!("start of ack_configure");
if let Some(window) = self.window_for_surface(&surface) {
tracing::debug!("found window for surface");
WindowState::with_state(&window, |state| {
// tracing::debug!("found window for surface");
WindowState::with(&window, |state| {
if let WindowResizeState::WaitingForAck(serial, new_loc) = state.resize_state {
match &configure {
Configure::Toplevel(configure) => {
@ -453,7 +452,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
// | mapping the element in commit, this means that the window won't reappear on a tag
// | change. The code below is a workaround until I can figure it out.
if !self.space.elements().any(|win| win == &window) {
WindowState::with_state(&window, |state| {
WindowState::with(&window, |state| {
if let WindowResizeState::WaitingForCommit(new_loc) = state.resize_state {
tracing::debug!("remapping window");
let win = window.clone();

View file

@ -9,15 +9,11 @@ use smithay::{
desktop::{space::SpaceElement, Space, Window},
output::Output,
utils::{Logical, Size},
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
};
use crate::window::window_state::{WindowResizeState, WindowState};
pub mod automatic;
pub mod manual;
pub struct Layouts;
pub enum Direction {
Left,
Right,
@ -75,7 +71,7 @@ impl MasterStack<'_, Window> {
state.size = Some((output_geo.size.w / 2, height).into());
});
WindowState::with_state(win, |state| {
WindowState::with(win, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
win.toplevel().send_configure(),
(output_geo.size.w / 2, i as i32 * height).into(),
@ -101,12 +97,12 @@ pub fn swap_window_positions(space: &Space<Window>, win1: &Window, win2: &Window
});
let serial = win1.toplevel().send_configure();
WindowState::with_state(win1, |state| {
WindowState::with(win1, |state| {
state.resize_state = WindowResizeState::WaitingForAck(serial, win2_loc);
});
let serial = win2.toplevel().send_configure();
WindowState::with_state(win2, |state| {
WindowState::with(win2, |state| {
state.resize_state = WindowResizeState::WaitingForAck(serial, win1_loc);
});
}
@ -127,7 +123,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
state.size = Some(output_geo.size);
});
WindowState::with_state(master, |state| {
WindowState::with(master, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
master.toplevel().send_configure(),
(0, 0).into(),
@ -143,7 +139,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
state.size = Some((output_geo.size.w / 2, output_geo.size.h).into());
});
WindowState::with_state(master, |state| {
WindowState::with(master, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
master.toplevel().send_configure(),
(0, 0).into(),
@ -172,7 +168,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
state.size = Some(output_geo.size);
});
WindowState::with_state(master, |state| {
WindowState::with(master, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
master.toplevel().send_configure(),
(0, 0).into(),
@ -184,15 +180,46 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
}
fn swap(&mut self, space: &Space<Window>, elem1: &Window, elem2: &Window) {
let mut elems = self.inner.iter_mut().flat_map(|vec| vec.iter_mut());
let first = elems.find(|elem| *elem == elem1);
let second = elems.find(|elem| *elem == elem2);
tracing::debug!("top of swap");
let mut elems = self
.inner
.iter_mut()
.flat_map(|vec| vec.iter_mut())
.filter(|elem| *elem == elem1 || *elem == elem2)
.unique_by(|win| WindowState::with(win, |state| state.id));
let (first, second) = (elems.next(), elems.next());
if let Some(first) = first {
if let Some(second) = second {
std::mem::swap(first, second);
}
}
let wins = self
.inner
.iter()
.map(|vec| {
vec.iter()
.enumerate()
.map(|(i, win)| {
compositor::with_states(win.toplevel().wl_surface(), |states| {
let lock = states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData doesn't exist")
.lock()
.expect("Couldn't lock XdgToplevelSurfaceData");
(i, lock.app_id.clone().unwrap_or("".to_string()))
})
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
tracing::debug!("windows are: {wins:?}");
swap_window_positions(space, elem1, elem2);
}
@ -205,6 +232,27 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
tracing::error!("could not get output geometry");
return;
};
let wins = self
.inner
.iter()
.map(|vec| {
vec.iter()
.enumerate()
.map(|(i, win)| {
compositor::with_states(win.toplevel().wl_surface(), |states| {
let lock = states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData doesn't exist")
.lock()
.expect("Couldn't lock XdgToplevelSurfaceData");
(i, lock.app_id.clone().unwrap_or("".to_string()))
})
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
tracing::debug!("windows are: {wins:?}");
if self.stack().count() == 0 {
// one window
@ -212,7 +260,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
state.size = Some(output_geo.size);
});
WindowState::with_state(master, |state| {
WindowState::with(master, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
master.toplevel().send_configure(),
(0, 0).into(),
@ -224,7 +272,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
master.toplevel().with_pending_state(|state| {
state.size = Some(new_master_size);
});
WindowState::with_state(master, |state| {
WindowState::with(master, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
master.toplevel().send_configure(),
(0, 0).into(),

View file

@ -1,160 +0,0 @@
// 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/.
//
// SPDX-License-Identifier: MPL-2.0
use smithay::{
desktop::Window,
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
};
use crate::{
backend::Backend,
state::State,
window::window_state::{WindowResizeState, WindowState},
};
use super::{Direction, Layouts};
impl Layouts {
pub fn master_stack<B: Backend>(
state: &mut State<B>,
mut windows: Vec<Window>,
side: Direction,
) {
windows.retain(|win| WindowState::with_state(win, |state| state.floating.is_tiled()));
match side {
Direction::Left => {
let window_count = windows.len();
if window_count == 0 {
return;
}
// TODO: change focused_output to be not an option
let Some(output) = state
.focus_state
.focused_output
.as_ref()
.or_else(|| state.space.outputs().next())
else {
tracing::warn!("no connected outputs");
return;
// TODO: no idea what happens if you spawn a window while no monitors are
// | connected, figure that out
};
let output_size = state.space.output_geometry(output).unwrap().size;
if window_count == 1 {
tracing::debug!("Laying out only window");
let window = windows[0].clone();
window.toplevel().with_pending_state(|tl_state| {
tl_state.size = Some(state.space.output_geometry(output).unwrap().size);
tracing::debug!("only size is {:?}", tl_state.size);
});
let initial_configure_sent =
compositor::with_states(window.toplevel().wl_surface(), |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap()
.initial_configure_sent
});
tracing::debug!("initial configure sent is {initial_configure_sent}");
if initial_configure_sent {
WindowState::with_state(&window, |state| {
tracing::debug!("sending configure");
state.resize_state = WindowResizeState::WaitingForAck(
window.toplevel().send_configure(),
output.current_location(),
);
});
}
return;
}
tracing::debug!("layed out first window");
let mut windows = windows.iter();
let first_window = windows.next().unwrap();
first_window.toplevel().with_pending_state(|tl_state| {
let mut size = state.space.output_geometry(output).unwrap().size;
size.w /= 2;
tl_state.size = Some(size);
tracing::debug!("first size is {:?}", tl_state.size);
});
let initial_configure_sent =
compositor::with_states(first_window.toplevel().wl_surface(), |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap()
.initial_configure_sent
});
if initial_configure_sent {
WindowState::with_state(first_window, |state| {
tracing::debug!("sending resize state");
state.resize_state = WindowResizeState::WaitingForAck(
first_window.toplevel().send_configure(),
output.current_location(),
);
});
}
let window_count = windows.len() as i32;
let height = output_size.h / window_count;
let x = output.current_location().x + output_size.w / 2;
for (i, win) in windows.enumerate() {
win.toplevel().with_pending_state(|state| {
let mut new_size = output_size;
new_size.w /= 2;
new_size.w = new_size.w.clamp(1, i32::MAX);
new_size.h /= window_count;
// INFO: The newest window won't have its geometry.loc set until after here and I don't know
// | why, so this is hardcoded to 40. I don't anticipate people using
// | windows that are that short, so figuring it out is low priority.
// | Kitty specifically will crash the compositor if it's resized such
// | that the bottom border goes above the bottom of the title bar if
// | this is set too low.
new_size.h = new_size.h.clamp(40, i32::MAX);
state.size = Some(new_size);
tracing::debug!("size is {:?}", state.size);
});
let mut new_loc = output.current_location();
new_loc.x = x;
new_loc.y = (i as i32) * height;
let initial_configure_sent =
compositor::with_states(win.toplevel().wl_surface(), |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap()
.initial_configure_sent
});
if initial_configure_sent {
WindowState::with_state(win, |state| {
state.resize_state = WindowResizeState::WaitingForAck(
win.toplevel().send_configure(),
new_loc,
);
});
}
}
}
Direction::Right => todo!(),
Direction::Top => todo!(),
Direction::Bottom => todo!(),
}
}
}

View file

@ -1,7 +0,0 @@
// 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/.
//
// SPDX-License-Identifier: MPL-2.0
//
// love how i'm licensing this empty file

View file

@ -12,7 +12,7 @@ use crate::tag::TagId;
#[derive(Default)]
pub struct OutputState {
pub focused_tags: HashSet<TagId>,
pub tags: HashSet<TagId>,
}
impl OutputState {

View file

@ -136,7 +136,7 @@ impl<B: Backend> State<B> {
Msg::SetWindowSize { window_id, size } => {
let Some(window) = self.space.elements().find(|&win| {
WindowState::with_state(win, |state| state.id == window_id)
WindowState::with(win, |state| state.id == window_id)
}) else { return; };
// TODO: tiled vs floating
@ -149,9 +149,9 @@ impl<B: Backend> State<B> {
if let Some(window) = self
.windows
.iter()
.find(|&win| WindowState::with_state(win, |state| state.id == window_id))
.find(|&win| WindowState::with(win, |state| state.id == window_id))
{
WindowState::with_state(window, |state| {
WindowState::with(window, |state| {
state.tags = vec![tag_id.clone()];
});
}
@ -162,9 +162,9 @@ impl<B: Backend> State<B> {
if let Some(window) = self
.windows
.iter()
.find(|&win| WindowState::with_state(win, |state| state.id == window_id))
.find(|&win| WindowState::with(win, |state| state.id == window_id))
{
WindowState::with_state(window, |state| {
WindowState::with(window, |state| {
if state.tags.contains(&tag_id) {
state.tags.retain(|id| id != &tag_id);
} else {
@ -179,12 +179,12 @@ impl<B: Backend> State<B> {
OutputState::with(
self.focus_state.focused_output.as_ref().unwrap(), // TODO: handle error
|state| {
let should_remove = state.focused_tags.get(&tag_id).is_some();
let should_remove = state.tags.get(&tag_id).is_some();
if should_remove {
state.focused_tags.remove(&tag_id);
state.tags.remove(&tag_id);
tracing::debug!("toggled tag {tag_id:?} off");
} else {
state.focused_tags.insert(tag_id.clone());
state.tags.insert(tag_id.clone());
tracing::debug!("toggled tag {tag_id:?} on");
}
},
@ -194,9 +194,9 @@ impl<B: Backend> State<B> {
}
Msg::SwitchToTag { tag_id } => {
OutputState::with(self.focus_state.focused_output.as_ref().unwrap(), |state| {
state.focused_tags.clear();
state.focused_tags.insert(tag_id.clone());
tracing::debug!("focused tags: {:?}", state.focused_tags);
state.tags.clear();
state.tags.insert(tag_id.clone());
tracing::debug!("focused tags: {:?}", state.tags);
});
self.re_layout();
@ -238,7 +238,7 @@ impl<B: Backend> State<B> {
.expect("Couldn't lock XdgToplevelSurfaceData");
(lock.app_id.clone(), lock.title.clone())
});
let (window_id, floating) = WindowState::with_state(&current_focus, |state| {
let (window_id, floating) = WindowState::with(&current_focus, |state| {
(state.id, state.floating.is_floating())
});
// TODO: unwrap
@ -281,7 +281,7 @@ impl<B: Backend> State<B> {
.expect("Couldn't lock XdgToplevelSurfaceData");
(lock.app_id.clone(), lock.title.clone())
});
let (window_id, floating) = WindowState::with_state(win, |state| {
let (window_id, floating) = WindowState::with(win, |state| {
(state.id, state.floating.is_floating())
});
// TODO: unwrap
@ -471,46 +471,38 @@ impl<B: Backend> State<B> {
}
pub fn re_layout(&mut self) {
let mut windows =
OutputState::with(self.focus_state.focused_output.as_ref().unwrap(), |state| {
for window in self.space.elements().cloned().collect::<Vec<_>>() {
let should_render = WindowState::with_state(&window, |win_state| {
for tag_id in win_state.tags.iter() {
if state.focused_tags.get(tag_id).is_some() {
return true;
}
let output = self.focus_state.focused_output.as_ref().unwrap();
OutputState::with(output, |state| {
for window in self.space.elements().cloned().collect::<Vec<_>>() {
let should_render = WindowState::with(&window, |win_state| {
for tag_id in win_state.tags.iter() {
if state.tags.get(tag_id).is_some() {
return true;
}
false
});
if !should_render {
self.space.unmap_elem(&window);
}
false
});
if !should_render {
self.space.unmap_elem(&window);
}
}
let mut tags = self
.tag_state
.tags
.iter_mut()
.filter(|tg| state.tags.contains(&tg.id));
if let Some(first) = tags.next() {
let mut layout = first.windows.as_master_stack();
for tg in tags {
layout = layout.chain_with(&mut tg.windows);
}
self.windows
.iter()
.filter(|&win| {
WindowState::with_state(win, |win_state| {
for tag_id in win_state.tags.iter() {
if state.focused_tags.get(tag_id).is_some() {
return true;
}
}
false
})
})
.cloned()
.collect::<Vec<_>>()
});
tracing::debug!("Laying out {} windows", windows.len());
windows.as_master_stack().layout(
&self.space,
self.focus_state.focused_output.as_ref().unwrap(),
);
// Layouts::master_stack(self, windows, crate::layout::Direction::Left);
layout.layout(&self.space, output);
}
});
}
}

View file

@ -12,9 +12,7 @@ use smithay::{
wayland::{compositor, seat::WaylandFocus},
};
use crate::{
backend::Backend, layout::Layouts, state::State, window::window_state::WindowResizeState,
};
use crate::{backend::Backend, state::State};
use self::window_state::{Float, WindowId, WindowState};
@ -57,43 +55,11 @@ impl<B: Backend> State<B> {
.cloned()
})
}
/// Swap the positions and sizes of two windows.
pub fn swap_window_positions(&mut self, win1: &Window, win2: &Window) {
// FIXME: moving the mouse quickly will break swapping
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();
// tracing::info!("win1: {:?}, {:?}", win1_loc, win1_geo);
// tracing::info!("win2: {:?}, {:?}", win2_loc, win2_geo);
win1.toplevel().with_pending_state(|state| {
state.size = Some(win2_geo.size);
});
win2.toplevel().with_pending_state(|state| {
state.size = Some(win1_geo.size);
});
let serial = win1.toplevel().send_configure();
WindowState::with_state(win1, |state| {
state.resize_state = WindowResizeState::WaitingForAck(serial, win2_loc);
});
let serial = win2.toplevel().send_configure();
WindowState::with_state(win2, |state| {
state.resize_state = WindowResizeState::WaitingForAck(serial, win1_loc);
});
// self.space.map_element(win1.clone(), win2_loc, false);
// self.space.map_element(win2.clone(), win1_loc, false);
}
}
/// Toggle a window's floating status.
pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
WindowState::with_state(window, |window_state| {
WindowState::with(window, |window_state| {
match window_state.floating {
Float::Tiled(prev_loc_and_size) => {
if let Some((prev_loc, prev_size)) = prev_loc_and_size {
@ -119,8 +85,7 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
}
});
let windows = state.space.elements().cloned().collect::<Vec<_>>();
Layouts::master_stack(state, windows, crate::layout::Direction::Left);
state.re_layout();
state.space.raise_element(window, true);
}

View file

@ -16,7 +16,7 @@ use smithay::{
use crate::tag::{Tag, TagId, TagState};
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct WindowId(u32);
// TODO: this probably doesn't need to be atomic
@ -44,7 +44,7 @@ pub fn tags<'a>(tag_state: &'a TagState, window: &Window) -> Vec<&'a Tag> {
tag_state
.tags
.iter()
.filter(|&tag| WindowState::with_state(window, |state| state.tags.contains(&tag.id)))
.filter(|&tag| WindowState::with(window, |state| state.tags.contains(&tag.id)))
.collect()
}
@ -118,7 +118,7 @@ impl WindowState {
}
/// Access a [Window]'s state, optionally returning something.
pub fn with_state<F, T>(window: &Window, mut func: F) -> T
pub fn with<F, T>(window: &Window, mut func: F) -> T
where
F: FnMut(&mut Self) -> T,
{