mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-29 20:34:46 +01:00
Restructure layout-ing
This commit is contained in:
parent
77695c666e
commit
275d968e77
11 changed files with 440 additions and 247 deletions
|
@ -228,7 +228,8 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
|
|||
None,
|
||||
);
|
||||
layer_map_for_output(&output).arrange();
|
||||
state.re_layout(&output);
|
||||
state.update_windows(&output);
|
||||
// state.re_layout(&output);
|
||||
}
|
||||
WinitEvent::Focus(_) => {}
|
||||
WinitEvent::Input(input_evt) => {
|
||||
|
@ -299,6 +300,7 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
|
|||
state
|
||||
.tags
|
||||
.iter()
|
||||
.filter(|tag| tag.active())
|
||||
.find(|tag| tag.fullscreen_window().is_some())
|
||||
.cloned()
|
||||
})
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::{
|
|||
backend::Backend,
|
||||
state::{State, WithState},
|
||||
window::{
|
||||
window_state::{Float, WindowResizeState},
|
||||
window_state::{LocationRequestState, Status},
|
||||
WindowElement,
|
||||
},
|
||||
};
|
||||
|
@ -35,21 +35,22 @@ pub struct MoveSurfaceGrab<S: SeatHandler> {
|
|||
impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
||||
fn motion(
|
||||
&mut self,
|
||||
data: &mut State<B>,
|
||||
state: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
_focus: Option<(<State<B> as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
event: &MotionEvent,
|
||||
) {
|
||||
handle.motion(data, None, event);
|
||||
handle.motion(state, None, event);
|
||||
|
||||
if !self.window.alive() {
|
||||
handle.unset_grab(data, event.serial, event.time);
|
||||
handle.unset_grab(state, event.serial, event.time);
|
||||
return;
|
||||
}
|
||||
|
||||
data.space.raise_element(&self.window, false);
|
||||
state.space.raise_element(&self.window, false);
|
||||
if let WindowElement::X11(surface) = &self.window {
|
||||
data.xwm
|
||||
state
|
||||
.xwm
|
||||
.as_mut()
|
||||
.expect("no xwm")
|
||||
.raise_window(surface)
|
||||
|
@ -59,17 +60,17 @@ 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 = self.window.with_state(|state| state.floating.is_tiled());
|
||||
let tiled = self.window.with_state(|state| state.status.is_tiled());
|
||||
|
||||
if tiled {
|
||||
// INFO: this is being used instead of space.element_under(event.location) because that
|
||||
// | uses the bounding box, which is different from the actual geometry
|
||||
let window_under = data
|
||||
let window_under = state
|
||||
.space
|
||||
.elements()
|
||||
.rev()
|
||||
.find(|&win| {
|
||||
if let Some(loc) = data.space.element_location(win) {
|
||||
if let Some(loc) = state.space.element_location(win) {
|
||||
let size = win.geometry().size;
|
||||
let rect = Rectangle { size, loc };
|
||||
rect.contains(event.location.to_i32_round())
|
||||
|
@ -84,28 +85,36 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
|||
return;
|
||||
}
|
||||
|
||||
let is_floating = window_under.with_state(|state| state.floating.is_floating());
|
||||
let is_floating = window_under.with_state(|state| state.status.is_floating());
|
||||
|
||||
if is_floating {
|
||||
return;
|
||||
}
|
||||
|
||||
let has_pending_resize = window_under
|
||||
.with_state(|state| !matches!(state.resize_state, WindowResizeState::Idle));
|
||||
let has_pending_resize = window_under.with_state(|state| {
|
||||
!matches!(state.loc_request_state, LocationRequestState::Idle)
|
||||
});
|
||||
|
||||
if has_pending_resize {
|
||||
return;
|
||||
}
|
||||
|
||||
data.swap_window_positions(&self.window, &window_under);
|
||||
state.swap_window_positions(&self.window, &window_under);
|
||||
}
|
||||
} else {
|
||||
let delta = event.location - self.start_data.location;
|
||||
let new_loc = (self.initial_window_loc.to_f64() + delta).to_i32_round();
|
||||
data.space.map_element(self.window.clone(), new_loc, true);
|
||||
state.space.map_element(self.window.clone(), new_loc, true);
|
||||
|
||||
let size = state
|
||||
.space
|
||||
.element_geometry(&self.window)
|
||||
.expect("window wasn't mapped")
|
||||
.size;
|
||||
|
||||
self.window.with_state(|state| {
|
||||
if state.floating.is_floating() {
|
||||
state.floating = Float::Floating(new_loc);
|
||||
if state.status.is_floating() {
|
||||
state.status = Status::Floating(Rectangle::from_loc_and_size(new_loc, size));
|
||||
}
|
||||
});
|
||||
if let WindowElement::X11(surface) = &self.window {
|
||||
|
|
|
@ -18,7 +18,7 @@ use smithay::{
|
|||
use crate::{
|
||||
backend::Backend,
|
||||
state::{State, WithState},
|
||||
window::{window_state::Float, WindowElement},
|
||||
window::{window_state::Status, WindowElement},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
@ -325,10 +325,15 @@ pub fn handle_commit<B: Backend>(state: &mut State<B>, surface: &WlSurface) -> O
|
|||
|
||||
if new_loc.x.is_some() || new_loc.y.is_some() {
|
||||
state.space.map_element(window.clone(), window_loc, false);
|
||||
let size = state
|
||||
.space
|
||||
.element_geometry(&window)
|
||||
.expect("called element_geometry on unmapped window")
|
||||
.size;
|
||||
|
||||
window.with_state(|state| {
|
||||
if state.floating.is_floating() {
|
||||
state.floating = Float::Floating(window_loc);
|
||||
if state.status.is_floating() {
|
||||
state.status = Status::Floating(Rectangle::from_loc_and_size(window_loc, size));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -360,7 +365,7 @@ pub fn resize_request_client<B: Backend>(
|
|||
return;
|
||||
};
|
||||
|
||||
if window.with_state(|state| state.floating.is_tiled()) {
|
||||
if window.with_state(|state| state.status.is_tiled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -407,7 +412,7 @@ pub fn resize_request_server<B: Backend>(
|
|||
return;
|
||||
};
|
||||
|
||||
if window.with_state(|state| state.floating.is_tiled()) {
|
||||
if window.with_state(|state| state.status.is_tiled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ use crate::{
|
|||
backend::Backend,
|
||||
focus::FocusTarget,
|
||||
state::{CalloopData, ClientState, State, WithState},
|
||||
window::{window_state::WindowResizeState, WindowElement},
|
||||
window::{window_state::LocationRequestState, WindowElement},
|
||||
};
|
||||
|
||||
impl<B: Backend> BufferHandler for State<B> {
|
||||
|
@ -120,8 +120,8 @@ impl<B: Backend> CompositorHandler for State<B> {
|
|||
|
||||
if let Some(window) = self.window_for_surface(surface) {
|
||||
window.with_state(|state| {
|
||||
if let WindowResizeState::Acknowledged(new_pos) = state.resize_state {
|
||||
state.resize_state = WindowResizeState::Idle;
|
||||
if let LocationRequestState::Acknowledged(new_pos) = state.loc_request_state {
|
||||
state.loc_request_state = LocationRequestState::Idle;
|
||||
if window.is_x11() {
|
||||
tracing::warn!("did something with X11 window here");
|
||||
}
|
||||
|
@ -443,7 +443,8 @@ impl<B: Backend> WlrLayerShellHandler for State<B> {
|
|||
// TODO: instead of deferring by 1 cycle, actually check if the surface has committed
|
||||
// | before re-layouting
|
||||
self.loop_handle.insert_idle(move |data| {
|
||||
data.state.re_layout(&output);
|
||||
data.state.update_windows(&output);
|
||||
// data.state.re_layout(&output);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -466,7 +467,8 @@ impl<B: Backend> WlrLayerShellHandler for State<B> {
|
|||
// | before re-layouting
|
||||
if let Some(output) = output {
|
||||
self.loop_handle.insert_idle(move |data| {
|
||||
data.state.re_layout(&output);
|
||||
data.state.update_windows(&output);
|
||||
// data.state.re_layout(&output);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ use crate::{
|
|||
backend::Backend,
|
||||
focus::FocusTarget,
|
||||
state::{State, WithState},
|
||||
window::{window_state::WindowResizeState, WindowBlocker, WindowElement, BLOCKER_COUNTER},
|
||||
window::{window_state::LocationRequestState, WindowBlocker, WindowElement, BLOCKER_COUNTER},
|
||||
};
|
||||
|
||||
impl<B: Backend> XdgShellHandler for State<B> {
|
||||
|
@ -95,17 +95,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
self.windows.push(window.clone());
|
||||
// self.space.map_element(window.clone(), (0, 0), true);
|
||||
if let Some(focused_output) = self.focus_state.focused_output.clone() {
|
||||
focused_output.with_state(|state| {
|
||||
let first_tag = state.focused_tags().next();
|
||||
if let Some(first_tag) = first_tag {
|
||||
first_tag.layout().layout(
|
||||
self.windows.clone(),
|
||||
state.focused_tags().cloned().collect(),
|
||||
&mut self.space,
|
||||
&focused_output,
|
||||
);
|
||||
}
|
||||
});
|
||||
self.update_windows(&focused_output);
|
||||
BLOCKER_COUNTER.store(1, std::sync::atomic::Ordering::SeqCst);
|
||||
tracing::debug!(
|
||||
"blocker {}",
|
||||
|
@ -277,12 +267,13 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
|
||||
if let Some(window) = self.window_for_surface(&surface) {
|
||||
window.with_state(|state| {
|
||||
if let WindowResizeState::Requested(serial, new_loc) = state.resize_state {
|
||||
if let LocationRequestState::Requested(serial, new_loc) = state.loc_request_state {
|
||||
match &configure {
|
||||
Configure::Toplevel(configure) => {
|
||||
if configure.serial >= serial {
|
||||
// tracing::debug!("acked configure, new loc is {:?}", new_loc);
|
||||
state.resize_state = WindowResizeState::Acknowledged(new_loc);
|
||||
state.loc_request_state =
|
||||
LocationRequestState::Acknowledged(new_loc);
|
||||
if let Some(focused_output) =
|
||||
self.focus_state.focused_output.clone()
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ use crate::{
|
|||
backend::Backend,
|
||||
focus::FocusTarget,
|
||||
state::{CalloopData, WithState},
|
||||
window::{window_state::Float, WindowBlocker, WindowElement, BLOCKER_COUNTER},
|
||||
window::{window_state::Status, WindowBlocker, WindowElement, BLOCKER_COUNTER},
|
||||
};
|
||||
|
||||
impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||
|
@ -128,7 +128,7 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
|||
|
||||
if should_float(surface) {
|
||||
window.with_state(|state| {
|
||||
state.floating = Float::Floating(loc);
|
||||
state.status = Status::Floating(bbox);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -276,9 +276,10 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
|||
self.state
|
||||
.windows
|
||||
.retain(|elem| win.wl_surface() != elem.wl_surface());
|
||||
if win.with_state(|state| state.floating.is_tiled()) {
|
||||
if win.with_state(|state| state.status.is_tiled()) {
|
||||
if let Some(output) = win.output(&self.state) {
|
||||
self.state.re_layout(&output);
|
||||
self.state.update_windows(&output);
|
||||
// self.state.re_layout(&output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ impl<B: Backend> State<B> {
|
|||
[output]
|
||||
.into_iter()
|
||||
.flat_map(|op| op.with_state(|state| state.tags.clone()))
|
||||
.filter(|tag| tag.active())
|
||||
.find(|tag| tag.fullscreen_window().is_some())
|
||||
.and_then(|tag| tag.fullscreen_window())
|
||||
.map(|window| (FocusTarget::from(window), output_geo.loc))
|
||||
|
|
288
src/layout.rs
288
src/layout.rs
|
@ -4,16 +4,133 @@ use itertools::{Either, Itertools};
|
|||
use smithay::{
|
||||
desktop::{layer_map_for_output, Space},
|
||||
output::Output,
|
||||
utils::{Logical, Rectangle, Size},
|
||||
utils::{Logical, Point, Rectangle, Size},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::Backend,
|
||||
state::{State, WithState},
|
||||
tag::Tag,
|
||||
window::WindowElement,
|
||||
window::{
|
||||
window_state::{LocationRequestState, Status},
|
||||
WindowElement,
|
||||
},
|
||||
};
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
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 };
|
||||
|
||||
let (windows_on_foc_tags, windows_not_on_foc_tags): (Vec<_>, _) =
|
||||
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)))
|
||||
})
|
||||
});
|
||||
|
||||
let tiled_windows = windows_on_foc_tags
|
||||
.iter()
|
||||
.filter(|win| win.with_state(|state| state.status.is_tiled()))
|
||||
.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() {
|
||||
match window.with_state(|state| state.status) {
|
||||
Status::Fullscreen(_) => {
|
||||
window.change_geometry(output_geo);
|
||||
}
|
||||
Status::Maximized(_) => {
|
||||
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);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
WindowElement::X11(_) => {
|
||||
// already configured, just need to map
|
||||
// maybe wait for all wayland windows to commit before mapping
|
||||
self.space.map_element(window.clone(), loc, false);
|
||||
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);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Layout {
|
||||
MasterStack,
|
||||
|
@ -57,22 +174,18 @@ impl Layout {
|
|||
tracing::debug!("Laying out with rect {rect:?}");
|
||||
|
||||
match self {
|
||||
Layout::MasterStack => master_stack(windows, space, rect),
|
||||
Layout::Dwindle => dwindle(windows, space, rect),
|
||||
Layout::Spiral => spiral(windows, space, rect),
|
||||
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, space, rect),
|
||||
| Layout::CornerBottomRight) => corner(layout, windows, rect),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn master_stack(
|
||||
windows: Vec<WindowElement>,
|
||||
space: &mut Space<WindowElement>,
|
||||
rect: Rectangle<i32, Logical>,
|
||||
) {
|
||||
fn master_stack(windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
||||
let size = rect.size;
|
||||
let loc = rect.loc;
|
||||
|
||||
|
@ -85,11 +198,11 @@ fn master_stack(
|
|||
|
||||
if stack_count == 0 {
|
||||
// one window
|
||||
master.request_size_change(space, loc, size);
|
||||
master.change_geometry(Rectangle::from_loc_and_size(loc, size));
|
||||
} else {
|
||||
let loc = (loc.x, loc.y).into();
|
||||
let loc: Point<i32, Logical> = (loc.x, loc.y).into();
|
||||
let new_master_size: Size<i32, Logical> = (size.w / 2, size.h).into();
|
||||
master.request_size_change(space, loc, new_master_size);
|
||||
master.change_geometry(Rectangle::from_loc_and_size(loc, new_master_size));
|
||||
|
||||
let stack_count = stack_count;
|
||||
|
||||
|
@ -105,20 +218,15 @@ fn master_stack(
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
for (i, win) in stack.enumerate() {
|
||||
win.request_size_change(
|
||||
space,
|
||||
(size.w / 2 + loc.x, y_s[i] + loc.y).into(),
|
||||
(size.w / 2, i32::max(heights[i], 40)).into(),
|
||||
);
|
||||
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))),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dwindle(
|
||||
windows: Vec<WindowElement>,
|
||||
space: &mut Space<WindowElement>,
|
||||
rect: Rectangle<i32, Logical>,
|
||||
) {
|
||||
fn dwindle(windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
||||
let size = rect.size;
|
||||
let loc = rect.loc;
|
||||
|
||||
|
@ -126,7 +234,7 @@ fn dwindle(
|
|||
|
||||
if iter.peek().is_none() {
|
||||
if let Some(window) = windows.first() {
|
||||
window.request_size_change(space, loc, size);
|
||||
window.change_geometry(Rectangle::from_loc_and_size(loc, size));
|
||||
}
|
||||
} else {
|
||||
let mut win1_size = size;
|
||||
|
@ -146,41 +254,35 @@ fn dwindle(
|
|||
Slice::Right => {
|
||||
let width_partition = win1_size.w / 2;
|
||||
|
||||
win1.request_size_change(
|
||||
space,
|
||||
win1.change_geometry(Rectangle::from_loc_and_size(
|
||||
win1_loc,
|
||||
(win1_size.w - width_partition, i32::max(win1_size.h, 40)).into(),
|
||||
);
|
||||
Size::from((win1_size.w - width_partition, i32::max(win1_size.h, 40))),
|
||||
));
|
||||
|
||||
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();
|
||||
|
||||
win2.request_size_change(space, win1_loc, win1_size);
|
||||
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
||||
}
|
||||
Slice::Below => {
|
||||
let height_partition = win1_size.h / 2;
|
||||
|
||||
win1.request_size_change(
|
||||
space,
|
||||
win1.change_geometry(Rectangle::from_loc_and_size(
|
||||
win1_loc,
|
||||
(win1_size.w, i32::max(win1_size.h - height_partition, 40)).into(),
|
||||
);
|
||||
Size::from((win1_size.w, i32::max(win1_size.h - height_partition, 40))),
|
||||
));
|
||||
|
||||
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();
|
||||
|
||||
win2.request_size_change(space, win1_loc, win1_size);
|
||||
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spiral(
|
||||
windows: Vec<WindowElement>,
|
||||
space: &mut Space<WindowElement>,
|
||||
rect: Rectangle<i32, Logical>,
|
||||
) {
|
||||
fn spiral(windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
||||
let size = rect.size;
|
||||
let loc = rect.loc;
|
||||
|
||||
|
@ -188,7 +290,7 @@ fn spiral(
|
|||
|
||||
if iter.peek().is_none() {
|
||||
if let Some(window) = windows.first() {
|
||||
window.request_size_change(space, loc, size);
|
||||
window.change_geometry(Rectangle::from_loc_and_size(loc, size));
|
||||
}
|
||||
} else {
|
||||
let mut win1_loc = loc;
|
||||
|
@ -217,80 +319,73 @@ fn spiral(
|
|||
Slice::Above => {
|
||||
let height_partition = win1_size.h / 2;
|
||||
|
||||
win1.request_size_change(
|
||||
space,
|
||||
(win1_loc.x, win1_loc.y + height_partition).into(),
|
||||
(win1_size.w, i32::max(win1_size.h - height_partition, 40)).into(),
|
||||
);
|
||||
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))),
|
||||
));
|
||||
|
||||
win1_size = (win1_size.w, i32::max(height_partition, 40)).into();
|
||||
win2.request_size_change(space, win1_loc, win1_size);
|
||||
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
||||
}
|
||||
Slice::Below => {
|
||||
let height_partition = win1_size.h / 2;
|
||||
|
||||
win1.request_size_change(
|
||||
space,
|
||||
win1.change_geometry(Rectangle::from_loc_and_size(
|
||||
win1_loc,
|
||||
(win1_size.w, win1_size.h - i32::max(height_partition, 40)).into(),
|
||||
);
|
||||
Size::from((win1_size.w, win1_size.h - i32::max(height_partition, 40))),
|
||||
));
|
||||
|
||||
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();
|
||||
win2.request_size_change(space, win1_loc, win1_size);
|
||||
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
||||
}
|
||||
Slice::Left => {
|
||||
let width_partition = win1_size.w / 2;
|
||||
|
||||
win1.request_size_change(
|
||||
space,
|
||||
(win1_loc.x + width_partition, win1_loc.y).into(),
|
||||
(win1_size.w - width_partition, i32::max(win1_size.h, 40)).into(),
|
||||
);
|
||||
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))),
|
||||
));
|
||||
|
||||
win1_size = (width_partition, i32::max(win1_size.h, 40)).into();
|
||||
win2.request_size_change(space, win1_loc, win1_size);
|
||||
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
||||
}
|
||||
Slice::Right => {
|
||||
let width_partition = win1_size.w / 2;
|
||||
|
||||
win1.request_size_change(
|
||||
space,
|
||||
win1.change_geometry(Rectangle::from_loc_and_size(
|
||||
win1_loc,
|
||||
(win1_size.w - width_partition, i32::max(win1_size.h, 40)).into(),
|
||||
);
|
||||
Size::from((win1_size.w - width_partition, i32::max(win1_size.h, 40))),
|
||||
));
|
||||
|
||||
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();
|
||||
win2.request_size_change(space, win1_loc, win1_size);
|
||||
win2.change_geometry(Rectangle::from_loc_and_size(win1_loc, win1_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn corner(
|
||||
layout: &Layout,
|
||||
windows: Vec<WindowElement>,
|
||||
space: &mut Space<WindowElement>,
|
||||
rect: Rectangle<i32, Logical>,
|
||||
) {
|
||||
fn corner(layout: &Layout, windows: Vec<WindowElement>, rect: Rectangle<i32, Logical>) {
|
||||
let size = rect.size;
|
||||
let loc = rect.loc;
|
||||
|
||||
match windows.len() {
|
||||
0 => (),
|
||||
1 => {
|
||||
windows[0].request_size_change(space, loc, size);
|
||||
windows[0].change_geometry(rect);
|
||||
}
|
||||
2 => {
|
||||
windows[0].request_size_change(space, loc, (size.w / 2, size.h).into());
|
||||
windows[0].change_geometry(Rectangle::from_loc_and_size(
|
||||
loc,
|
||||
Size::from((size.w / 2, size.h)),
|
||||
));
|
||||
|
||||
windows[1].request_size_change(
|
||||
space,
|
||||
(loc.x + size.w / 2, loc.y).into(),
|
||||
(size.w / 2, size.h).into(),
|
||||
);
|
||||
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)),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
let mut windows = windows.into_iter();
|
||||
|
@ -306,9 +401,8 @@ fn corner(
|
|||
|
||||
let div_factor = 2;
|
||||
|
||||
corner.request_size_change(
|
||||
space,
|
||||
match layout {
|
||||
corner.change_geometry(Rectangle::from_loc_and_size(
|
||||
Point::from(match layout {
|
||||
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),
|
||||
|
@ -317,10 +411,9 @@ fn corner(
|
|||
loc.y + size.h - size.h / div_factor,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.into(),
|
||||
(size.w / div_factor, size.h / div_factor).into(),
|
||||
);
|
||||
}),
|
||||
Size::from((size.w / div_factor, size.h / div_factor)),
|
||||
));
|
||||
|
||||
let vert_stack_count = vert_stack.len();
|
||||
|
||||
|
@ -336,19 +429,17 @@ fn corner(
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
for (i, win) in vert_stack.iter().enumerate() {
|
||||
win.request_size_change(
|
||||
space,
|
||||
(
|
||||
win.change_geometry(Rectangle::from_loc_and_size(
|
||||
Point::from((
|
||||
match layout {
|
||||
Layout::CornerTopLeft | Layout::CornerBottomLeft => size.w / 2 + loc.x,
|
||||
Layout::CornerTopRight | Layout::CornerBottomRight => loc.x,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
y_s[i] + loc.y,
|
||||
)
|
||||
.into(),
|
||||
(size.w / 2, i32::max(heights[i], 40)).into(),
|
||||
);
|
||||
)),
|
||||
Size::from((size.w / 2, i32::max(heights[i], 40))),
|
||||
));
|
||||
}
|
||||
|
||||
let horiz_stack_count = horiz_stack.len();
|
||||
|
@ -365,18 +456,16 @@ fn corner(
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
for (i, win) in horiz_stack.iter().enumerate() {
|
||||
win.request_size_change(
|
||||
space,
|
||||
match layout {
|
||||
win.change_geometry(Rectangle::from_loc_and_size(
|
||||
Point::from(match layout {
|
||||
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),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.into(),
|
||||
(i32::max(widths[i], 1), size.h / 2).into(),
|
||||
);
|
||||
}),
|
||||
Size::from((i32::max(widths[i], 1), size.h / 2)),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +474,7 @@ fn corner(
|
|||
fn filter_windows(windows: &[WindowElement], tags: Vec<Tag>) -> Vec<WindowElement> {
|
||||
windows
|
||||
.iter()
|
||||
.filter(|window| window.with_state(|state| state.floating.is_tiled()))
|
||||
.filter(|window| window.with_state(|state| state.status.is_tiled()))
|
||||
.filter(|window| {
|
||||
window.with_state(|state| {
|
||||
for tag in state.tags.iter() {
|
||||
|
@ -421,6 +510,7 @@ impl<B: Backend> State<B> {
|
|||
.focused_output
|
||||
.clone()
|
||||
.expect("no focused output");
|
||||
self.re_layout(&output);
|
||||
self.update_windows(&output);
|
||||
// self.re_layout(&output);
|
||||
}
|
||||
}
|
||||
|
|
53
src/state.rs
53
src/state.rs
|
@ -21,7 +21,7 @@ use crate::{
|
|||
grab::resize_grab::ResizeSurfaceState,
|
||||
tag::Tag,
|
||||
window::{
|
||||
window_state::{Float, WindowResizeState},
|
||||
window_state::{LocationRequestState, Status},
|
||||
WindowElement,
|
||||
},
|
||||
};
|
||||
|
@ -187,7 +187,8 @@ impl<B: Backend> State<B> {
|
|||
state.tags = vec![tag.clone()];
|
||||
});
|
||||
let Some(output) = tag.output(self) else { return };
|
||||
self.re_layout(&output);
|
||||
self.update_windows(&output);
|
||||
// self.re_layout(&output);
|
||||
}
|
||||
Msg::ToggleTagOnWindow { window_id, tag_id } => {
|
||||
let Some(window) = window_id.window(self) else { return };
|
||||
|
@ -202,14 +203,16 @@ impl<B: Backend> State<B> {
|
|||
});
|
||||
|
||||
let Some(output) = tag.output(self) else { return };
|
||||
self.re_layout(&output);
|
||||
self.update_windows(&output);
|
||||
// self.re_layout(&output);
|
||||
}
|
||||
Msg::ToggleTag { tag_id } => {
|
||||
tracing::debug!("ToggleTag");
|
||||
if let Some(tag) = tag_id.tag(self) {
|
||||
tag.set_active(!tag.active());
|
||||
if let Some(output) = tag.output(self) {
|
||||
self.re_layout(&output);
|
||||
self.update_windows(&output);
|
||||
// self.re_layout(&output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +225,8 @@ impl<B: Backend> State<B> {
|
|||
}
|
||||
tag.set_active(true);
|
||||
});
|
||||
self.re_layout(&output);
|
||||
self.update_windows(&output);
|
||||
// self.re_layout(&output);
|
||||
}
|
||||
Msg::AddTags {
|
||||
output_name,
|
||||
|
@ -252,7 +256,8 @@ impl<B: Backend> State<B> {
|
|||
let Some(tag) = tag_id.tag(self) else { return };
|
||||
tag.set_layout(layout);
|
||||
let Some(output) = tag.output(self) else { return };
|
||||
self.re_layout(&output);
|
||||
self.update_windows(&output);
|
||||
// self.re_layout(&output);
|
||||
}
|
||||
|
||||
Msg::ConnectForAllOutputs { callback_id } => {
|
||||
|
@ -288,7 +293,8 @@ impl<B: Backend> State<B> {
|
|||
output.change_current_state(None, None, None, Some(loc));
|
||||
self.space.map_output(&output, loc);
|
||||
tracing::debug!("mapping output {} to {loc:?}", output.name());
|
||||
self.re_layout(&output);
|
||||
self.update_windows(&output);
|
||||
// self.re_layout(&output);
|
||||
}
|
||||
|
||||
Msg::Quit => {
|
||||
|
@ -358,7 +364,7 @@ impl<B: Backend> State<B> {
|
|||
});
|
||||
let floating = window
|
||||
.as_ref()
|
||||
.map(|win| win.with_state(|state| state.floating.is_floating()));
|
||||
.map(|win| win.with_state(|state| state.status.is_floating()));
|
||||
let focused = window.as_ref().and_then(|win| {
|
||||
self.focus_state
|
||||
.current_focus() // TODO: actual focus
|
||||
|
@ -645,14 +651,6 @@ impl<B: Backend> State<B> {
|
|||
}
|
||||
|
||||
pub fn re_layout(&mut self, output: &Output) {
|
||||
for win in self.windows.iter() {
|
||||
if win.is_wayland() {
|
||||
win.with_state(|state| {
|
||||
tracing::debug!("{:?}", state.resize_state);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let windows = self
|
||||
.windows
|
||||
.iter()
|
||||
|
@ -705,16 +703,20 @@ impl<B: Backend> State<B> {
|
|||
}
|
||||
}
|
||||
|
||||
for (win, loc) in clone.into_iter().filter_map(|win| {
|
||||
match win.with_state(|state| state.floating.clone()) {
|
||||
Float::Tiled(_) => None,
|
||||
Float::Floating(loc) => Some((win, loc)),
|
||||
}
|
||||
}) {
|
||||
for (win, rect) in
|
||||
clone
|
||||
.into_iter()
|
||||
.filter_map(|win| match win.with_state(|state| state.status) {
|
||||
Status::Floating(loc) => Some((win, loc)),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
if let WindowElement::X11(surface) = &win {
|
||||
surface.set_mapped(true).expect("failed to map x11 win");
|
||||
if !surface.is_override_redirect() {
|
||||
surface.set_mapped(true).expect("failed to map x11 win");
|
||||
}
|
||||
}
|
||||
dt.state.space.map_element(win, loc, false);
|
||||
dt.state.space.map_element(win, rect.loc, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -731,7 +733,8 @@ pub fn schedule_on_commit<F, B: Backend>(
|
|||
F: FnOnce(&mut CalloopData<B>) + 'static,
|
||||
{
|
||||
for window in windows.iter().filter(|win| win.alive()) {
|
||||
if window.with_state(|state| !matches!(state.resize_state, WindowResizeState::Idle)) {
|
||||
if window.with_state(|state| !matches!(state.loc_request_state, LocationRequestState::Idle))
|
||||
{
|
||||
data.state.loop_handle.insert_idle(|data| {
|
||||
schedule_on_commit(data, windows, on_commit);
|
||||
});
|
||||
|
|
187
src/window.rs
187
src/window.rs
|
@ -40,7 +40,7 @@ use crate::{
|
|||
state::{State, WithState},
|
||||
};
|
||||
|
||||
use self::window_state::{Float, WindowElementState, WindowResizeState};
|
||||
use self::window_state::{LocationRequestState, Status, WindowElementState};
|
||||
|
||||
pub mod window_state;
|
||||
|
||||
|
@ -180,6 +180,29 @@ impl WindowElement {
|
|||
}
|
||||
}
|
||||
|
||||
/// Send a geometry change without mapping windows or sending
|
||||
/// configures to Wayland windows.
|
||||
///
|
||||
/// Xwayland windows will still receive a configure.
|
||||
// TODO: ^ does that make things flicker?
|
||||
pub fn change_geometry(&self, new_geo: Rectangle<i32, Logical>) {
|
||||
match self {
|
||||
WindowElement::Wayland(window) => {
|
||||
window.toplevel().with_pending_state(|state| {
|
||||
state.size = Some(new_geo.size);
|
||||
});
|
||||
}
|
||||
WindowElement::X11(surface) => {
|
||||
surface
|
||||
.configure(new_geo)
|
||||
.expect("failed to configure x11 win");
|
||||
}
|
||||
}
|
||||
self.with_state(|state| {
|
||||
state.loc_request_state = LocationRequestState::Sent(new_geo.loc);
|
||||
});
|
||||
}
|
||||
|
||||
/// Request a size and loc change.
|
||||
pub fn request_size_change(
|
||||
&self,
|
||||
|
@ -193,8 +216,8 @@ impl WindowElement {
|
|||
state.size = Some(new_size);
|
||||
});
|
||||
self.with_state(|state| {
|
||||
state.resize_state =
|
||||
WindowResizeState::Requested(window.toplevel().send_configure(), new_loc)
|
||||
state.loc_request_state =
|
||||
LocationRequestState::Requested(window.toplevel().send_configure(), new_loc)
|
||||
});
|
||||
}
|
||||
WindowElement::X11(surface) => {
|
||||
|
@ -245,6 +268,107 @@ impl WindowElement {
|
|||
pub fn is_x11(&self) -> bool {
|
||||
matches!(self, Self::X11(..))
|
||||
}
|
||||
|
||||
/// Set this window to floating.
|
||||
///
|
||||
/// This will change the size of the window only.
|
||||
/// Call `State.update_windows` to perform mapping.
|
||||
pub fn set_floating(&self) {
|
||||
let status = self.with_state(|state| state.status);
|
||||
match status {
|
||||
Status::Floating(_) => (),
|
||||
Status::Tiled(rect) | Status::Fullscreen(rect) | Status::Maximized(rect) => {
|
||||
if let Some(rect) = rect {
|
||||
self.change_geometry(rect);
|
||||
self.with_state(|state| state.status = Status::Floating(rect));
|
||||
} else {
|
||||
// TODO: is this the same as from the space? prolly not
|
||||
let geo = self.geometry();
|
||||
self.with_state(|state| state.status = Status::Floating(geo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let WindowElement::Wayland(window) = self {
|
||||
window.toplevel().with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Maximized);
|
||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||
state.states.unset(xdg_toplevel::State::TiledTop);
|
||||
state.states.unset(xdg_toplevel::State::TiledBottom);
|
||||
state.states.unset(xdg_toplevel::State::TiledLeft);
|
||||
state.states.unset(xdg_toplevel::State::TiledRight);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Call compute_tiled_windows after this
|
||||
pub fn set_tiled(&self) {
|
||||
let geo = match self.with_state(|state| state.status) {
|
||||
Status::Floating(rect)
|
||||
| Status::Tiled(Some(rect))
|
||||
| Status::Fullscreen(Some(rect))
|
||||
| Status::Maximized(Some(rect)) => rect,
|
||||
_ => self.geometry(),
|
||||
};
|
||||
self.with_state(|state| state.status = Status::Tiled(Some(geo)));
|
||||
|
||||
if let WindowElement::Wayland(window) = self {
|
||||
window.toplevel().with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Maximized);
|
||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||
state.states.set(xdg_toplevel::State::TiledTop);
|
||||
state.states.set(xdg_toplevel::State::TiledBottom);
|
||||
state.states.set(xdg_toplevel::State::TiledLeft);
|
||||
state.states.set(xdg_toplevel::State::TiledRight);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_fullscreen(&self) {
|
||||
let geo = match self.with_state(|state| state.status) {
|
||||
Status::Floating(rect)
|
||||
| Status::Tiled(Some(rect))
|
||||
| Status::Fullscreen(Some(rect))
|
||||
| Status::Maximized(Some(rect)) => rect,
|
||||
_ => self.geometry(),
|
||||
};
|
||||
|
||||
self.with_state(|state| state.status = Status::Fullscreen(Some(geo)));
|
||||
|
||||
if let WindowElement::Wayland(window) = self {
|
||||
window.toplevel().with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Maximized);
|
||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||
state.states.set(xdg_toplevel::State::TiledTop);
|
||||
state.states.set(xdg_toplevel::State::TiledBottom);
|
||||
state.states.set(xdg_toplevel::State::TiledLeft);
|
||||
state.states.set(xdg_toplevel::State::TiledRight);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_maximized(&self) {
|
||||
let geo = match self.with_state(|state| state.status) {
|
||||
Status::Floating(rect)
|
||||
| Status::Tiled(Some(rect))
|
||||
| Status::Fullscreen(Some(rect))
|
||||
| Status::Maximized(Some(rect)) => rect,
|
||||
_ => self.geometry(),
|
||||
};
|
||||
|
||||
self.with_state(|state| state.status = Status::Maximized(Some(geo)));
|
||||
|
||||
if let WindowElement::Wayland(window) = self {
|
||||
window.toplevel().with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||
state.states.set(xdg_toplevel::State::Maximized);
|
||||
state.states.set(xdg_toplevel::State::TiledTop);
|
||||
state.states.set(xdg_toplevel::State::TiledBottom);
|
||||
state.states.set(xdg_toplevel::State::TiledLeft);
|
||||
state.states.set(xdg_toplevel::State::TiledRight);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsAlive for WindowElement {
|
||||
|
@ -480,54 +604,10 @@ impl<B: Backend> State<B> {
|
|||
|
||||
/// Toggle a window's floating status.
|
||||
pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &WindowElement) {
|
||||
let mut resize: Option<_> = None;
|
||||
window.with_state(|window_state| {
|
||||
match window_state.floating {
|
||||
Float::Tiled(prev_loc_and_size) => {
|
||||
if let Some((prev_loc, prev_size)) = prev_loc_and_size {
|
||||
resize = Some((prev_loc, prev_size));
|
||||
}
|
||||
|
||||
window_state.floating =
|
||||
Float::Floating(resize.map(|(point, _)| point).unwrap_or_else(|| {
|
||||
state
|
||||
.space
|
||||
.element_location(window)
|
||||
.unwrap_or((0, 0).into())
|
||||
}));
|
||||
if let WindowElement::Wayland(window) = window {
|
||||
window.toplevel().with_pending_state(|tl_state| {
|
||||
tl_state.states.unset(xdg_toplevel::State::TiledTop);
|
||||
tl_state.states.unset(xdg_toplevel::State::TiledBottom);
|
||||
tl_state.states.unset(xdg_toplevel::State::TiledLeft);
|
||||
tl_state.states.unset(xdg_toplevel::State::TiledRight);
|
||||
});
|
||||
} // TODO: tiled states for x11
|
||||
}
|
||||
Float::Floating(current_loc) => {
|
||||
window_state.floating = Float::Tiled(Some((
|
||||
// We get the location this way because window.geometry().loc
|
||||
// doesn't seem to be the actual location
|
||||
|
||||
// TODO: maybe store the location in state
|
||||
current_loc,
|
||||
window.geometry().size,
|
||||
)));
|
||||
|
||||
if let WindowElement::Wayland(window) = window {
|
||||
window.toplevel().with_pending_state(|tl_state| {
|
||||
tl_state.states.set(xdg_toplevel::State::TiledTop);
|
||||
tl_state.states.set(xdg_toplevel::State::TiledBottom);
|
||||
tl_state.states.set(xdg_toplevel::State::TiledLeft);
|
||||
tl_state.states.set(xdg_toplevel::State::TiledRight);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Some((prev_loc, prev_size)) = resize {
|
||||
window.request_size_change(&mut state.space, prev_loc, prev_size);
|
||||
if window.with_state(|state| state.status.is_floating()) {
|
||||
window.set_tiled();
|
||||
} else {
|
||||
window.set_floating();
|
||||
}
|
||||
|
||||
// TODO: don't use the focused output, use the one the window is on
|
||||
|
@ -536,8 +616,9 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &WindowElement)
|
|||
.focused_output
|
||||
.clone()
|
||||
.expect("no focused output");
|
||||
state.re_layout(&output);
|
||||
// state.re_layout(&output);
|
||||
|
||||
state.update_windows(&output);
|
||||
let render = output.with_state(|op_state| {
|
||||
state
|
||||
.windows
|
||||
|
@ -545,7 +626,7 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &WindowElement)
|
|||
.cloned()
|
||||
.filter(|win| {
|
||||
win.with_state(|win_state| {
|
||||
if win_state.floating.is_floating() {
|
||||
if win_state.status.is_floating() {
|
||||
return true;
|
||||
}
|
||||
for tag in win_state.tags.iter() {
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fmt,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use smithay::{
|
||||
desktop::Window,
|
||||
utils::{Logical, Point, Serial, Size},
|
||||
utils::{Logical, Point, Rectangle, Serial},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -67,10 +66,10 @@ impl WithState for Window {
|
|||
pub struct WindowElementState {
|
||||
/// The id of this window.
|
||||
pub id: WindowId,
|
||||
/// Whether the window is floating or tiled.
|
||||
pub floating: Float,
|
||||
/// Whether the window is floating, tiled, fullscreen, or maximized.
|
||||
pub status: Status,
|
||||
/// The window's resize state. See [WindowResizeState] for more.
|
||||
pub resize_state: WindowResizeState,
|
||||
pub loc_request_state: LocationRequestState,
|
||||
/// What tags the window is currently on.
|
||||
pub tags: Vec<Tag>,
|
||||
}
|
||||
|
@ -99,11 +98,12 @@ pub struct WindowElementState {
|
|||
/// [`resize_state`]: WindowState#structfield.resize_state
|
||||
/// [`XdgShellHandler.ack_configure()`]: smithay::wayland::shell::xdg::XdgShellHandler#method.ack_configure
|
||||
/// [`CompositorHandler.commit()`]: smithay::wayland::compositor::CompositorHandler#tymethod.commit
|
||||
#[derive(Default, Clone)]
|
||||
pub enum WindowResizeState {
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub enum LocationRequestState {
|
||||
/// The window doesn't need to be moved.
|
||||
#[default]
|
||||
Idle,
|
||||
Sent(Point<i32, Logical>),
|
||||
/// The window has received a configure request with a new size. The desired location and the
|
||||
/// configure request's serial should be provided here.
|
||||
Requested(Serial, Point<i32, Logical>),
|
||||
|
@ -114,24 +114,16 @@ pub enum WindowResizeState {
|
|||
Acknowledged(Point<i32, Logical>),
|
||||
}
|
||||
|
||||
impl fmt::Debug for WindowResizeState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Idle => write!(f, "Idle"),
|
||||
Self::Requested(_arg0, _arg1) => write!(f, "Requested"),
|
||||
Self::Acknowledged(_arg0) => write!(f, "Acknowledged"),
|
||||
}
|
||||
}
|
||||
/// Whether the window is floating, tiled, fullscreen, or maximized.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Status {
|
||||
Floating(Rectangle<i32, Logical>),
|
||||
Tiled(Option<Rectangle<i32, Logical>>),
|
||||
Fullscreen(Option<Rectangle<i32, Logical>>),
|
||||
Maximized(Option<Rectangle<i32, Logical>>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Float {
|
||||
/// The previous location and size of the window when it was floating, if any.
|
||||
Tiled(Option<(Point<i32, Logical>, Size<i32, Logical>)>),
|
||||
Floating(Point<i32, Logical>),
|
||||
}
|
||||
|
||||
impl Float {
|
||||
impl Status {
|
||||
/// Returns `true` if the float is [`Tiled`].
|
||||
///
|
||||
/// [`Tiled`]: Float::Tiled
|
||||
|
@ -147,6 +139,22 @@ impl Float {
|
|||
pub fn is_floating(&self) -> bool {
|
||||
matches!(self, Self::Floating(_))
|
||||
}
|
||||
|
||||
/// Returns `true` if the status is [`Fullscreen`].
|
||||
///
|
||||
/// [`Fullscreen`]: Status::Fullscreen
|
||||
#[must_use]
|
||||
pub fn is_fullscreen(&self) -> bool {
|
||||
matches!(self, Self::Fullscreen(..))
|
||||
}
|
||||
|
||||
/// Returns `true` if the status is [`Maximized`].
|
||||
///
|
||||
/// [`Maximized`]: Status::Maximized
|
||||
#[must_use]
|
||||
pub fn is_maximized(&self) -> bool {
|
||||
matches!(self, Self::Maximized(..))
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowElementState {
|
||||
|
@ -161,8 +169,8 @@ impl Default for WindowElementState {
|
|||
Self {
|
||||
// INFO: I think this will assign the id on use of the state, not on window spawn.
|
||||
id: WindowId::next(),
|
||||
floating: Float::Tiled(None),
|
||||
resize_state: WindowResizeState::Idle,
|
||||
status: Status::Tiled(None),
|
||||
loc_request_state: LocationRequestState::Idle,
|
||||
tags: vec![],
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue