mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-27 21:58:18 +01:00
Clean up old layouts
This commit is contained in:
parent
170addbad1
commit
d860172334
10 changed files with 160 additions and 304 deletions
|
@ -47,7 +47,6 @@ use smithay::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{Direction, Layouts},
|
|
||||||
render::{pointer::PointerElement, CustomRenderElements, OutputRenderElements},
|
render::{pointer::PointerElement, CustomRenderElements, OutputRenderElements},
|
||||||
state::{CalloopData, State},
|
state::{CalloopData, State},
|
||||||
};
|
};
|
||||||
|
@ -220,11 +219,7 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
Layouts::master_stack(
|
state.re_layout();
|
||||||
state,
|
|
||||||
state.space.elements().cloned().collect(),
|
|
||||||
Direction::Left,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
WinitEvent::Focus(_) => {}
|
WinitEvent::Focus(_) => {}
|
||||||
WinitEvent::Input(input_evt) => {
|
WinitEvent::Input(input_evt) => {
|
||||||
|
|
|
@ -19,7 +19,13 @@ use smithay::{
|
||||||
utils::{IsAlive, Logical, Point, Rectangle},
|
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 struct MoveSurfaceGrab<S: SeatHandler> {
|
||||||
pub start_data: GrabStartData<S>,
|
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!("window geo is: {:?}", self.window.geometry());
|
||||||
// tracing::info!("loc is: {:?}", data.space.element_location(&self.window));
|
// 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 {
|
if tiled {
|
||||||
// INFO: this is being used instead of space.element_under(event.location) because that
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let window_under_floating =
|
let is_floating =
|
||||||
WindowState::with_state(&window_under, |state| state.floating.is_floating());
|
WindowState::with(&window_under, |state| state.floating.is_floating());
|
||||||
|
|
||||||
if window_under_floating {
|
if is_floating {
|
||||||
return;
|
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 {
|
} else {
|
||||||
let delta = event.location - self.start_data.location;
|
let delta = event.location - self.start_data.location;
|
||||||
let new_loc = self.initial_window_loc.to_f64() + delta;
|
let new_loc = self.initial_window_loc.to_f64() + delta;
|
||||||
data.space
|
data.space
|
||||||
.map_element(self.window.clone(), new_loc.to_i32_round(), true);
|
.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ impl<B: Backend> CompositorHandler for State<B> {
|
||||||
crate::grab::resize_grab::handle_commit(self, surface);
|
crate::grab::resize_grab::handle_commit(self, surface);
|
||||||
|
|
||||||
if let Some(window) = self.window_for_surface(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 {
|
if let WindowResizeState::WaitingForCommit(new_pos) = state.resize_state {
|
||||||
state.resize_state = WindowResizeState::Idle;
|
state.resize_state = WindowResizeState::Idle;
|
||||||
self.space.map_element(window.clone(), new_pos, false);
|
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) {
|
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||||
let window = Window::new(surface);
|
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 {
|
state.tags = if let Some(focused_output) = &self.focus_state.focused_output {
|
||||||
OutputState::with(focused_output, |state| {
|
OutputState::with(focused_output, |state| {
|
||||||
let output_tags: Vec<crate::tag::TagId> =
|
let output_tags: Vec<crate::tag::TagId> = state.tags.iter().cloned().collect();
|
||||||
state.focused_tags.iter().cloned().collect();
|
|
||||||
if !output_tags.is_empty() {
|
if !output_tags.is_empty() {
|
||||||
output_tags
|
output_tags
|
||||||
} else if let Some(first_tag) = self.tag_state.tags.first() {
|
} else if let Some(first_tag) = self.tag_state.tags.first() {
|
||||||
|
@ -270,7 +269,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
.tag_state
|
.tag_state
|
||||||
.tags
|
.tags
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter(|tg| state.focused_tags.contains(&tg.id));
|
.filter(|tg| state.tags.contains(&tg.id));
|
||||||
|
|
||||||
if let Some(first) = tags.next() {
|
if let Some(first) = tags.next() {
|
||||||
let mut layout = first.windows.as_master_stack();
|
let mut layout = first.windows.as_master_stack();
|
||||||
|
@ -302,7 +301,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
.tag_state
|
.tag_state
|
||||||
.tags
|
.tags
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter(|tg| state.focused_tags.contains(&tg.id));
|
.filter(|tg| state.tags.contains(&tg.id));
|
||||||
|
|
||||||
if let Some(first) = tags.next() {
|
if let Some(first) = tags.next() {
|
||||||
tracing::debug!("first tag: {:?}", first.id);
|
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) {
|
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) {
|
if let Some(window) = self.window_for_surface(&surface) {
|
||||||
tracing::debug!("found window for surface");
|
// tracing::debug!("found window for surface");
|
||||||
WindowState::with_state(&window, |state| {
|
WindowState::with(&window, |state| {
|
||||||
if let WindowResizeState::WaitingForAck(serial, new_loc) = state.resize_state {
|
if let WindowResizeState::WaitingForAck(serial, new_loc) = state.resize_state {
|
||||||
match &configure {
|
match &configure {
|
||||||
Configure::Toplevel(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
|
// | 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.
|
// | change. The code below is a workaround until I can figure it out.
|
||||||
if !self.space.elements().any(|win| win == &window) {
|
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 {
|
if let WindowResizeState::WaitingForCommit(new_loc) = state.resize_state {
|
||||||
tracing::debug!("remapping window");
|
tracing::debug!("remapping window");
|
||||||
let win = window.clone();
|
let win = window.clone();
|
||||||
|
|
|
@ -9,15 +9,11 @@ use smithay::{
|
||||||
desktop::{space::SpaceElement, Space, Window},
|
desktop::{space::SpaceElement, Space, Window},
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{Logical, Size},
|
utils::{Logical, Size},
|
||||||
|
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::window::window_state::{WindowResizeState, WindowState};
|
use crate::window::window_state::{WindowResizeState, WindowState};
|
||||||
|
|
||||||
pub mod automatic;
|
|
||||||
pub mod manual;
|
|
||||||
|
|
||||||
pub struct Layouts;
|
|
||||||
|
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
|
@ -75,7 +71,7 @@ impl MasterStack<'_, Window> {
|
||||||
state.size = Some((output_geo.size.w / 2, height).into());
|
state.size = Some((output_geo.size.w / 2, height).into());
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowState::with_state(win, |state| {
|
WindowState::with(win, |state| {
|
||||||
state.resize_state = WindowResizeState::WaitingForAck(
|
state.resize_state = WindowResizeState::WaitingForAck(
|
||||||
win.toplevel().send_configure(),
|
win.toplevel().send_configure(),
|
||||||
(output_geo.size.w / 2, i as i32 * height).into(),
|
(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();
|
let serial = win1.toplevel().send_configure();
|
||||||
WindowState::with_state(win1, |state| {
|
WindowState::with(win1, |state| {
|
||||||
state.resize_state = WindowResizeState::WaitingForAck(serial, win2_loc);
|
state.resize_state = WindowResizeState::WaitingForAck(serial, win2_loc);
|
||||||
});
|
});
|
||||||
|
|
||||||
let serial = win2.toplevel().send_configure();
|
let serial = win2.toplevel().send_configure();
|
||||||
WindowState::with_state(win2, |state| {
|
WindowState::with(win2, |state| {
|
||||||
state.resize_state = WindowResizeState::WaitingForAck(serial, win1_loc);
|
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);
|
state.size = Some(output_geo.size);
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowState::with_state(master, |state| {
|
WindowState::with(master, |state| {
|
||||||
state.resize_state = WindowResizeState::WaitingForAck(
|
state.resize_state = WindowResizeState::WaitingForAck(
|
||||||
master.toplevel().send_configure(),
|
master.toplevel().send_configure(),
|
||||||
(0, 0).into(),
|
(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());
|
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(
|
state.resize_state = WindowResizeState::WaitingForAck(
|
||||||
master.toplevel().send_configure(),
|
master.toplevel().send_configure(),
|
||||||
(0, 0).into(),
|
(0, 0).into(),
|
||||||
|
@ -172,7 +168,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
|
||||||
state.size = Some(output_geo.size);
|
state.size = Some(output_geo.size);
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowState::with_state(master, |state| {
|
WindowState::with(master, |state| {
|
||||||
state.resize_state = WindowResizeState::WaitingForAck(
|
state.resize_state = WindowResizeState::WaitingForAck(
|
||||||
master.toplevel().send_configure(),
|
master.toplevel().send_configure(),
|
||||||
(0, 0).into(),
|
(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) {
|
fn swap(&mut self, space: &Space<Window>, elem1: &Window, elem2: &Window) {
|
||||||
let mut elems = self.inner.iter_mut().flat_map(|vec| vec.iter_mut());
|
tracing::debug!("top of swap");
|
||||||
let first = elems.find(|elem| *elem == elem1);
|
|
||||||
let second = elems.find(|elem| *elem == elem2);
|
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(first) = first {
|
||||||
if let Some(second) = second {
|
if let Some(second) = second {
|
||||||
std::mem::swap(first, 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);
|
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");
|
tracing::error!("could not get output geometry");
|
||||||
return;
|
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 {
|
if self.stack().count() == 0 {
|
||||||
// one window
|
// one window
|
||||||
|
@ -212,7 +260,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
|
||||||
state.size = Some(output_geo.size);
|
state.size = Some(output_geo.size);
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowState::with_state(master, |state| {
|
WindowState::with(master, |state| {
|
||||||
state.resize_state = WindowResizeState::WaitingForAck(
|
state.resize_state = WindowResizeState::WaitingForAck(
|
||||||
master.toplevel().send_configure(),
|
master.toplevel().send_configure(),
|
||||||
(0, 0).into(),
|
(0, 0).into(),
|
||||||
|
@ -224,7 +272,7 @@ impl<'a> Layout<'a, Window> for MasterStack<'a, Window> {
|
||||||
master.toplevel().with_pending_state(|state| {
|
master.toplevel().with_pending_state(|state| {
|
||||||
state.size = Some(new_master_size);
|
state.size = Some(new_master_size);
|
||||||
});
|
});
|
||||||
WindowState::with_state(master, |state| {
|
WindowState::with(master, |state| {
|
||||||
state.resize_state = WindowResizeState::WaitingForAck(
|
state.resize_state = WindowResizeState::WaitingForAck(
|
||||||
master.toplevel().send_configure(),
|
master.toplevel().send_configure(),
|
||||||
(0, 0).into(),
|
(0, 0).into(),
|
||||||
|
|
|
@ -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!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -12,7 +12,7 @@ use crate::tag::TagId;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct OutputState {
|
pub struct OutputState {
|
||||||
pub focused_tags: HashSet<TagId>,
|
pub tags: HashSet<TagId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputState {
|
impl OutputState {
|
||||||
|
|
90
src/state.rs
90
src/state.rs
|
@ -136,7 +136,7 @@ impl<B: Backend> State<B> {
|
||||||
|
|
||||||
Msg::SetWindowSize { window_id, size } => {
|
Msg::SetWindowSize { window_id, size } => {
|
||||||
let Some(window) = self.space.elements().find(|&win| {
|
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; };
|
}) else { return; };
|
||||||
|
|
||||||
// TODO: tiled vs floating
|
// TODO: tiled vs floating
|
||||||
|
@ -149,9 +149,9 @@ impl<B: Backend> State<B> {
|
||||||
if let Some(window) = self
|
if let Some(window) = self
|
||||||
.windows
|
.windows
|
||||||
.iter()
|
.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()];
|
state.tags = vec![tag_id.clone()];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -162,9 +162,9 @@ impl<B: Backend> State<B> {
|
||||||
if let Some(window) = self
|
if let Some(window) = self
|
||||||
.windows
|
.windows
|
||||||
.iter()
|
.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) {
|
if state.tags.contains(&tag_id) {
|
||||||
state.tags.retain(|id| id != &tag_id);
|
state.tags.retain(|id| id != &tag_id);
|
||||||
} else {
|
} else {
|
||||||
|
@ -179,12 +179,12 @@ impl<B: Backend> State<B> {
|
||||||
OutputState::with(
|
OutputState::with(
|
||||||
self.focus_state.focused_output.as_ref().unwrap(), // TODO: handle error
|
self.focus_state.focused_output.as_ref().unwrap(), // TODO: handle error
|
||||||
|state| {
|
|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 {
|
if should_remove {
|
||||||
state.focused_tags.remove(&tag_id);
|
state.tags.remove(&tag_id);
|
||||||
tracing::debug!("toggled tag {tag_id:?} off");
|
tracing::debug!("toggled tag {tag_id:?} off");
|
||||||
} else {
|
} else {
|
||||||
state.focused_tags.insert(tag_id.clone());
|
state.tags.insert(tag_id.clone());
|
||||||
tracing::debug!("toggled tag {tag_id:?} on");
|
tracing::debug!("toggled tag {tag_id:?} on");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -194,9 +194,9 @@ impl<B: Backend> State<B> {
|
||||||
}
|
}
|
||||||
Msg::SwitchToTag { tag_id } => {
|
Msg::SwitchToTag { tag_id } => {
|
||||||
OutputState::with(self.focus_state.focused_output.as_ref().unwrap(), |state| {
|
OutputState::with(self.focus_state.focused_output.as_ref().unwrap(), |state| {
|
||||||
state.focused_tags.clear();
|
state.tags.clear();
|
||||||
state.focused_tags.insert(tag_id.clone());
|
state.tags.insert(tag_id.clone());
|
||||||
tracing::debug!("focused tags: {:?}", state.focused_tags);
|
tracing::debug!("focused tags: {:?}", state.tags);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.re_layout();
|
self.re_layout();
|
||||||
|
@ -238,7 +238,7 @@ impl<B: Backend> State<B> {
|
||||||
.expect("Couldn't lock XdgToplevelSurfaceData");
|
.expect("Couldn't lock XdgToplevelSurfaceData");
|
||||||
(lock.app_id.clone(), lock.title.clone())
|
(lock.app_id.clone(), lock.title.clone())
|
||||||
});
|
});
|
||||||
let (window_id, floating) = WindowState::with_state(¤t_focus, |state| {
|
let (window_id, floating) = WindowState::with(¤t_focus, |state| {
|
||||||
(state.id, state.floating.is_floating())
|
(state.id, state.floating.is_floating())
|
||||||
});
|
});
|
||||||
// TODO: unwrap
|
// TODO: unwrap
|
||||||
|
@ -281,7 +281,7 @@ impl<B: Backend> State<B> {
|
||||||
.expect("Couldn't lock XdgToplevelSurfaceData");
|
.expect("Couldn't lock XdgToplevelSurfaceData");
|
||||||
(lock.app_id.clone(), lock.title.clone())
|
(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())
|
(state.id, state.floating.is_floating())
|
||||||
});
|
});
|
||||||
// TODO: unwrap
|
// TODO: unwrap
|
||||||
|
@ -471,46 +471,38 @@ impl<B: Backend> State<B> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn re_layout(&mut self) {
|
pub fn re_layout(&mut self) {
|
||||||
let mut windows =
|
let output = self.focus_state.focused_output.as_ref().unwrap();
|
||||||
OutputState::with(self.focus_state.focused_output.as_ref().unwrap(), |state| {
|
OutputState::with(output, |state| {
|
||||||
for window in self.space.elements().cloned().collect::<Vec<_>>() {
|
for window in self.space.elements().cloned().collect::<Vec<_>>() {
|
||||||
let should_render = WindowState::with_state(&window, |win_state| {
|
let should_render = WindowState::with(&window, |win_state| {
|
||||||
for tag_id in win_state.tags.iter() {
|
for tag_id in win_state.tags.iter() {
|
||||||
if state.focused_tags.get(tag_id).is_some() {
|
if state.tags.get(tag_id).is_some() {
|
||||||
return true;
|
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
|
layout.layout(&self.space, output);
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,7 @@ use smithay::{
|
||||||
wayland::{compositor, seat::WaylandFocus},
|
wayland::{compositor, seat::WaylandFocus},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{backend::Backend, state::State};
|
||||||
backend::Backend, layout::Layouts, state::State, window::window_state::WindowResizeState,
|
|
||||||
};
|
|
||||||
|
|
||||||
use self::window_state::{Float, WindowId, WindowState};
|
use self::window_state::{Float, WindowId, WindowState};
|
||||||
|
|
||||||
|
@ -57,43 +55,11 @@ impl<B: Backend> State<B> {
|
||||||
.cloned()
|
.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.
|
/// Toggle a window's floating status.
|
||||||
pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
|
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 {
|
match window_state.floating {
|
||||||
Float::Tiled(prev_loc_and_size) => {
|
Float::Tiled(prev_loc_and_size) => {
|
||||||
if let Some((prev_loc, prev_size)) = 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<_>>();
|
state.re_layout();
|
||||||
Layouts::master_stack(state, windows, crate::layout::Direction::Left);
|
|
||||||
state.space.raise_element(window, true);
|
state.space.raise_element(window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use smithay::{
|
||||||
|
|
||||||
use crate::tag::{Tag, TagId, TagState};
|
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);
|
pub struct WindowId(u32);
|
||||||
|
|
||||||
// TODO: this probably doesn't need to be atomic
|
// 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
|
tag_state
|
||||||
.tags
|
.tags
|
||||||
.iter()
|
.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()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access a [Window]'s state, optionally returning something.
|
/// 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
|
where
|
||||||
F: FnMut(&mut Self) -> T,
|
F: FnMut(&mut Self) -> T,
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue