diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-13 19:55:37 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-13 19:55:37 +0400 |
| commit | 8f71842e7cf0c2e77183e99b954c9b511dca3576 (patch) | |
| tree | d4c74a27e59b5af64f41c1394bc7e7de1adb9789 /src | |
| parent | 95c810c855a27a28f4dfa7dc6b949fef0901c7b2 (diff) | |
| download | niri-8f71842e7cf0c2e77183e99b954c9b511dca3576.tar.gz niri-8f71842e7cf0c2e77183e99b954c9b511dca3576.tar.bz2 niri-8f71842e7cf0c2e77183e99b954c9b511dca3576.zip | |
Refactor everything again, make more things work
Diffstat (limited to 'src')
| -rw-r--r-- | src/backend.rs | 6 | ||||
| -rw-r--r-- | src/handlers/compositor.rs | 15 | ||||
| -rw-r--r-- | src/handlers/xdg_shell.rs | 89 | ||||
| -rw-r--r-- | src/input.rs | 57 | ||||
| -rw-r--r-- | src/layout.rs | 1026 | ||||
| -rw-r--r-- | src/niri.rs | 110 | ||||
| -rw-r--r-- | src/tty.rs | 6 | ||||
| -rw-r--r-- | src/winit.rs | 6 |
8 files changed, 756 insertions, 559 deletions
diff --git a/src/backend.rs b/src/backend.rs index 55ddfaff..65c8a772 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -1,4 +1,3 @@ -use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; use smithay::backend::renderer::gles::GlesRenderer; use smithay::output::Output; @@ -12,9 +11,6 @@ pub trait Backend { &mut self, niri: &mut Niri, output: &Output, - elements: &[OutputRenderElements< - GlesRenderer, - WaylandSurfaceRenderElement<GlesRenderer>, - >], + elements: &[OutputRenderElements<GlesRenderer>], ); } diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs index d9e25b8f..7a8612e8 100644 --- a/src/handlers/compositor.rs +++ b/src/handlers/compositor.rs @@ -68,10 +68,8 @@ impl CompositorHandler for Niri { } // This is a commit of a previously-mapped root or a non-toplevel root. - if let Some((window, space)) = self.monitor_set.find_window_and_space(surface) { + if let Some((window, output)) = self.monitor_set.find_window_and_output(surface) { // This is a commit of a previously-mapped toplevel. - let output = space.outputs().next().unwrap().clone(); - window.on_commit(); // This is a commit of a previously-mapped toplevel. @@ -80,7 +78,6 @@ impl CompositorHandler for Niri { if !is_mapped { // The toplevel got unmapped. - let window = window.clone(); self.monitor_set.remove_window(&window); self.unmapped_windows.insert(surface.clone(), window); self.update_focus(); @@ -101,9 +98,8 @@ impl CompositorHandler for Niri { } // This is a commit of a non-root or a non-toplevel root. - let root_window_space = self.monitor_set.find_window_and_space(&root_surface); - if let Some((window, space)) = root_window_space { - let output = space.outputs().next().unwrap().clone(); + let root_window_output = self.monitor_set.find_window_and_output(&root_surface); + if let Some((window, output)) = root_window_output { window.on_commit(); self.monitor_set.update_window(&window); self.queue_redraw(output); @@ -114,9 +110,8 @@ impl CompositorHandler for Niri { self.popups_handle_commit(surface); if let Some(popup) = self.popups.find_popup(surface) { if let Ok(root) = find_popup_root_surface(&popup) { - let root_window_space = self.monitor_set.find_window_and_space(&root); - if let Some((_window, space)) = root_window_space { - let output = space.outputs().next().unwrap().clone(); + let root_window_output = self.monitor_set.find_window_and_output(&root); + if let Some((_window, output)) = root_window_output { self.queue_redraw(output); } } diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index c7df18c7..00413451 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -1,5 +1,5 @@ use smithay::delegate_xdg_shell; -use smithay::desktop::{PopupKind, Window}; +use smithay::desktop::{find_popup_root_surface, PopupKind, Window}; use smithay::input::pointer::{Focus, GrabStartData as PointerGrabStartData}; use smithay::input::Seat; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; @@ -14,7 +14,7 @@ use smithay::wayland::shell::xdg::{ }; use crate::grabs::{MoveSurfaceGrab, ResizeSurfaceGrab}; -use crate::layout::MonitorSet; +use crate::layout::{configure_new_window, output_size}; use crate::Niri; impl XdgShellHandler for Niri { @@ -28,7 +28,7 @@ impl XdgShellHandler for Niri { // Tell the surface the preferred size and bounds for its likely output. let output = self.monitor_set.active_output().unwrap(); - MonitorSet::configure_new_window(output, &window); + configure_new_window(output_size(output), &window); // At the moment of creation, xdg toplevels must have no buffer. let existing = self.unmapped_windows.insert(wl_surface, window); @@ -49,24 +49,26 @@ impl XdgShellHandler for Niri { } fn move_request(&mut self, surface: ToplevelSurface, seat: wl_seat::WlSeat, serial: Serial) { - let seat = Seat::from_resource(&seat).unwrap(); + // FIXME - let wl_surface = surface.wl_surface(); + // let seat = Seat::from_resource(&seat).unwrap(); - if let Some(start_data) = check_grab(&seat, wl_surface, serial) { - let pointer = seat.get_pointer().unwrap(); + // let wl_surface = surface.wl_surface(); - let (window, space) = self.monitor_set.find_window_and_space(wl_surface).unwrap(); - let initial_window_location = space.element_location(&window).unwrap(); + // if let Some(start_data) = check_grab(&seat, wl_surface, serial) { + // let pointer = seat.get_pointer().unwrap(); - let grab = MoveSurfaceGrab { - start_data, - window: window.clone(), - initial_window_location, - }; + // let (window, space) = self.monitor_set.find_window_and_space(wl_surface).unwrap(); + // let initial_window_location = space.element_location(&window).unwrap(); - pointer.set_grab(self, grab, serial, Focus::Clear); - } + // let grab = MoveSurfaceGrab { + // start_data, + // window: window.clone(), + // initial_window_location, + // }; + + // pointer.set_grab(self, grab, serial, Focus::Clear); + // } } fn resize_request( @@ -76,32 +78,34 @@ impl XdgShellHandler for Niri { serial: Serial, edges: xdg_toplevel::ResizeEdge, ) { - let seat = Seat::from_resource(&seat).unwrap(); + // FIXME - let wl_surface = surface.wl_surface(); + // let seat = Seat::from_resource(&seat).unwrap(); - if let Some(start_data) = check_grab(&seat, wl_surface, serial) { - let pointer = seat.get_pointer().unwrap(); + // let wl_surface = surface.wl_surface(); - let (window, space) = self.monitor_set.find_window_and_space(wl_surface).unwrap(); - let initial_window_location = space.element_location(&window).unwrap(); - let initial_window_size = window.geometry().size; + // if let Some(start_data) = check_grab(&seat, wl_surface, serial) { + // let pointer = seat.get_pointer().unwrap(); - surface.with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Resizing); - }); + // let (window, space) = self.monitor_set.find_window_and_space(wl_surface).unwrap(); + // let initial_window_location = space.element_location(&window).unwrap(); + // let initial_window_size = window.geometry().size; - surface.send_pending_configure(); + // surface.with_pending_state(|state| { + // state.states.set(xdg_toplevel::State::Resizing); + // }); - let grab = ResizeSurfaceGrab::start( - start_data, - window.clone(), - edges.into(), - Rectangle::from_loc_and_size(initial_window_location, initial_window_size), - ); + // surface.send_pending_configure(); - pointer.set_grab(self, grab, serial, Focus::Clear); - } + // let grab = ResizeSurfaceGrab::start( + // start_data, + // window.clone(), + // edges.into(), + // Rectangle::from_loc_and_size(initial_window_location, initial_window_size), + // ); + + // pointer.set_grab(self, grab, serial, Focus::Clear); + // } } fn reposition_request( @@ -232,19 +236,22 @@ impl XdgShellHandler for Niri { return; } - let (window, space) = self + let (window, output) = self .monitor_set - .find_window_and_space(surface.wl_surface()) + .find_window_and_output(surface.wl_surface()) .unwrap(); - let output = space.outputs().next().unwrap().clone(); self.monitor_set.remove_window(&window); self.update_focus(); self.queue_redraw(output); } - fn popup_destroyed(&mut self, _surface: PopupSurface) { - // FIXME granular - self.queue_redraw_all(); + fn popup_destroyed(&mut self, surface: PopupSurface) { + if let Ok(root) = find_popup_root_surface(&surface.into()) { + let root_window_output = self.monitor_set.find_window_and_output(&root); + if let Some((_window, output)) = root_window_output { + self.queue_redraw(output); + } + } } } diff --git a/src/input.rs b/src/input.rs index 0c7c3e62..9e7267a9 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,4 +1,3 @@ -use std::cell::Cell; use std::process::Command; use smithay::backend::input::{ @@ -7,9 +6,7 @@ use smithay::backend::input::{ }; use smithay::input::keyboard::{keysyms, FilterResult, KeysymHandle, ModifiersState}; use smithay::input::pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent}; -use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::utils::SERIAL_COUNTER; -use smithay::wayland::shell::xdg::XdgShellHandler; use crate::niri::Niri; @@ -140,54 +137,13 @@ impl Niri { } } Action::CloseWindow => { - if let Some(focus) = self.seat.get_keyboard().unwrap().current_focus() { - // FIXME: is there a better way of doing this? - for window in self - .monitor_set - .workspaces() - .flat_map(|workspace| workspace.space.elements()) - { - let found = Cell::new(false); - window.with_surfaces(|surface, _| { - if surface == &focus { - found.set(true); - } - }); - if found.get() { - window.toplevel().send_close(); - break; - } - } + if let Some(window) = self.monitor_set.focus() { + window.toplevel().send_close(); } } Action::ToggleFullscreen => { - if let Some(focus) = self.seat.get_keyboard().unwrap().current_focus() { - // FIXME: is there a better way of doing this? - let window = self - .monitor_set - .workspaces() - .flat_map(|workspace| workspace.space.elements()) - .find(|window| { - let found = Cell::new(false); - window.with_surfaces(|surface, _| { - if surface == &focus { - found.set(true); - } - }); - found.get() - }); - if let Some(window) = window { - let toplevel = window.toplevel().clone(); - if toplevel - .current_state() - .states - .contains(xdg_toplevel::State::Fullscreen) - { - self.unfullscreen_request(toplevel); - } else { - self.fullscreen_request(toplevel, None); - } - } + if let Some(window) = self.monitor_set.focus() { + // FIXME } } Action::MoveLeft => { @@ -353,9 +309,8 @@ impl Niri { let button_state = event.state(); if ButtonState::Pressed == button_state && !pointer.is_grabbed() { - if let Some((_space, window, _loc)) = - self.window_under(pointer.current_location()) - { + if let Some(window) = self.window_under_cursor() { + let window = window.clone(); self.monitor_set.activate_window(&window); } else { let output = self.output_under_cursor().unwrap(); diff --git a/src/layout.rs b/src/layout.rs index 62a0423d..25c8edeb 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -31,69 +31,113 @@ use std::cmp::{max, min}; use std::mem; +use std::time::Duration; -use smithay::desktop::{Space, Window}; +use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; +use smithay::backend::renderer::element::AsRenderElements; +use smithay::backend::renderer::gles::GlesRenderer; +use smithay::desktop::space::SpaceElement; +use smithay::desktop::Window; use smithay::output::Output; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; -use smithay::utils::{Logical, Size}; +use smithay::utils::{Logical, Point, Rectangle, Scale, Size}; +use smithay::wayland::compositor::{with_states, SurfaceData}; +use smithay::wayland::shell::xdg::XdgToplevelSurfaceData; const PADDING: i32 = 16; #[derive(Debug, Clone, PartialEq, Eq)] pub struct OutputId(String); +pub trait LayoutElement: SpaceElement + PartialEq + Clone { + fn request_size(&self, size: Size<i32, Logical>); + fn send_pending_configure(&self); + fn min_size(&self) -> Size<i32, Logical>; + fn is_wl_surface(&self, wl_surface: &WlSurface) -> bool; + fn send_frame<T, F>( + &self, + output: &Output, + time: T, + throttle: Option<Duration>, + primary_scan_out_output: F, + ) where + T: Into<Duration>, + F: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy; +} + #[derive(Debug)] -pub enum MonitorSet { +pub enum MonitorSet<W: LayoutElement> { /// At least one output is connected. Normal { - monitors: Vec<Monitor>, + /// Connected monitors. + monitors: Vec<Monitor<W>>, /// Index of the primary monitor. primary_idx: usize, /// Index of the active monitor. active_monitor_idx: usize, }, /// No outputs are connected, and these are the workspaces. - // FIXME: preserve active output id? - NoOutputs(Vec<Workspace>), + NoOutputs(Vec<Workspace<W>>), } #[derive(Debug)] -pub struct Monitor { +pub struct Monitor<W: LayoutElement> { + /// Output for this monitor. output: Output, // Must always contain at least one. - workspaces: Vec<Workspace>, + workspaces: Vec<Workspace<W>>, /// Index of the currently active workspace. active_workspace_idx: usize, } #[derive(Debug)] -pub struct Workspace { +pub struct Workspace<W: LayoutElement> { /// The original output of this workspace. /// /// Most of the time this will be the workspace's current output, however, after an output /// disconnection, it may remain pointing to the disconnected output. original_output: OutputId, - layout: Layout, + /// Current output of this workspace. + output: Option<Output>, - // The actual Space with windows in this workspace. Should be synchronized to the layout except - // for a brief period during surface commit handling. - pub space: Space<Window>, -} + /// Latest known view size for this workspace. + /// + /// This should be computed from the current workspace output size, or, if all outputs have + /// been disconnected, preserved until a new output is connected. + view_size: Size<i32, Logical>, + + /// Columns of windows on this workspace. + columns: Vec<Column<W>>, -#[derive(Debug)] -pub struct Layout { - columns: Vec<Column>, /// Index of the currently active column, if any. active_column_idx: usize, + + /// Offset of the view computed from the active column. + view_offset: i32, +} + +/// Width of a column. +#[derive(Debug, Clone, Copy)] +enum ColumnWidth { + /// Proportion of the current view width. + Proportion(f64), + /// Fixed width in logical pixels. + Fixed(i32), } #[derive(Debug)] -pub struct Column { - // Must be non-empty. - windows: Vec<Window>, +struct Column<W: LayoutElement> { + /// Windows in this column. + /// + /// Must be non-empty. + windows: Vec<W>, + /// Index of the currently active window. active_window_idx: usize, + + /// Desired width of this column. + width: ColumnWidth, } impl OutputId { @@ -102,7 +146,65 @@ impl OutputId { } } -impl MonitorSet { +impl LayoutElement for Window { + fn request_size(&self, size: Size<i32, Logical>) { + let toplevel = &self.toplevel(); + toplevel.with_pending_state(|state| { + state.size = Some(size); + }); + toplevel.send_pending_configure(); + } + + fn send_pending_configure(&self) { + self.toplevel().send_pending_configure(); + } + + fn min_size(&self) -> Size<i32, Logical> { + with_states(self.toplevel().wl_surface(), |state| { + state + .data_map + .get::<XdgToplevelSurfaceData>() + .unwrap() + .lock() + .unwrap() + .min_size + }) + } + + fn is_wl_surface(&self, wl_surface: &WlSurface) -> bool { + self.toplevel().wl_surface() == wl_surface + } + + fn send_frame<T, F>( + &self, + output: &Output, + time: T, + throttle: Option<Duration>, + primary_scan_out_output: F, + ) where + T: Into<Duration>, + F: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy, + { + self.send_frame(output, time, throttle, primary_scan_out_output); + } +} + +impl ColumnWidth { + fn resolve(self, view_width: i32) -> i32 { + match self { + ColumnWidth::Proportion(proportion) => (view_width as f64 * proportion).floor() as i32, + ColumnWidth::Fixed(width) => width, + } + } +} + +impl Default for ColumnWidth { + fn default() -> Self { + Self::Proportion(0.5) + } +} + +impl<W: LayoutElement> MonitorSet<W> { pub fn new() -> Self { Self::NoOutputs(vec![]) } @@ -121,26 +223,18 @@ impl MonitorSet { let mut workspaces = vec![]; for i in (0..primary.workspaces.len()).rev() { if primary.workspaces[i].original_output == id { - let mut ws = primary.workspaces.remove(i); - ws.space.unmap_output(&primary.output); + let ws = primary.workspaces.remove(i); workspaces.push(ws); } } workspaces.reverse(); - if workspaces - .iter() - .all(|ws| ws.space.elements().next().is_some()) - { + if workspaces.iter().all(|ws| ws.has_windows()) { // Make sure there's always an empty workspace. - workspaces.push(Workspace { - original_output: id, - layout: Layout::new(), - space: Space::default(), - }); + workspaces.push(Workspace::new(output.clone())); } for ws in &mut workspaces { - ws.space.map_output(&output, (0, 0)); + ws.set_output(Some(output.clone())); } monitors.push(Monitor { @@ -155,19 +249,11 @@ impl MonitorSet { } } MonitorSet::NoOutputs(mut workspaces) => { - if workspaces.iter().all(|ws| ws.original_output != id) { - workspaces.insert( - 0, - Workspace { - original_output: id.clone(), - layout: Layout::new(), - space: Space::default(), - }, - ); - } + // We know there are no empty workspaces there, so add one. + workspaces.push(Workspace::new(output.clone())); for workspace in &mut workspaces { - workspace.space.map_output(&output, (0, 0)); + workspace.set_output(Some(output.clone())); } let monitor = Monitor { @@ -199,11 +285,11 @@ impl MonitorSet { let mut workspaces = monitor.workspaces; for ws in &mut workspaces { - ws.space.unmap_output(output); + ws.set_output(None); } // Get rid of empty workspaces. - workspaces.retain(|ws| ws.space.elements().next().is_some()); + workspaces.retain(|ws| ws.has_windows()); if monitors.is_empty() { // Removed the last monitor. @@ -223,9 +309,12 @@ impl MonitorSet { let primary = &mut monitors[primary_idx]; for ws in &mut workspaces { - ws.space.map_output(&primary.output, (0, 0)); + ws.set_output(Some(primary.output.clone())); } + + let empty = primary.workspaces.remove(primary.workspaces.len() - 1); primary.workspaces.extend(workspaces); + primary.workspaces.push(empty); MonitorSet::Normal { monitors, @@ -240,25 +329,11 @@ impl MonitorSet { } } - pub fn configure_new_window(output: &Output, window: &Window) { - let output_size = output_size(output); - let size = Size::from(( - (output_size.w - PADDING * 3) / 2, - output_size.h - PADDING * 2, - )); - let bounds = Size::from((output_size.w - PADDING * 2, output_size.h - PADDING * 2)); - - window.toplevel().with_pending_state(|state| { - state.size = Some(size); - state.bounds = Some(bounds); - }); - } - pub fn add_window( &mut self, monitor_idx: usize, workspace_idx: usize, - window: Window, + window: W, activate: bool, ) { let MonitorSet::Normal { @@ -272,31 +347,24 @@ impl MonitorSet { let monitor = &mut monitors[monitor_idx]; let workspace = &mut monitor.workspaces[workspace_idx]; - workspace.layout.add_window(window.clone(), activate); - workspace.space.map_element(window.clone(), (0, 0), false); - workspace.layout.sync_space(&mut workspace.space); - - MonitorSet::configure_new_window(&monitor.output, &window); - window.toplevel().send_pending_configure(); if activate { *active_monitor_idx = monitor_idx; monitor.active_workspace_idx = workspace_idx; + // Configure will be sent in add_window(). + window.set_activate(true); } + workspace.add_window(window.clone(), activate); + if workspace_idx == monitor.workspaces.len() - 1 { // Insert a new empty workspace. - let mut ws = Workspace { - original_output: OutputId::new(&monitor.output), - layout: Layout::new(), - space: Space::default(), - }; - ws.space.map_output(&monitor.output, (0, 0)); + let ws = Workspace::new(monitor.output.clone()); monitor.workspaces.push(ws); } } - pub fn add_window_to_output(&mut self, output: &Output, window: Window, activate: bool) { + pub fn add_window_to_output(&mut self, output: &Output, window: W, activate: bool) { let MonitorSet::Normal { monitors, .. } = self else { panic!() }; @@ -308,38 +376,110 @@ impl MonitorSet { .unwrap(); let workspace_idx = monitor.active_workspace_idx; - self.add_window(monitor_idx, workspace_idx, window, activate) + self.add_window(monitor_idx, workspace_idx, window, activate); } - pub fn remove_window(&mut self, window: &Window) { - let MonitorSet::Normal { monitors, .. } = self else { - panic!() - }; + pub fn remove_window(&mut self, window: &W) { + match self { + MonitorSet::Normal { monitors, .. } => { + for mon in monitors { + for (idx, ws) in mon.workspaces.iter_mut().enumerate() { + if ws.has_window(window) { + ws.remove_window(window); + + // Clean up empty workspaces that are not active and not last. + if !ws.has_windows() + && idx != mon.active_workspace_idx + && idx != mon.workspaces.len() - 1 + { + mon.workspaces.remove(idx); + } + + break; + } + } + } + } + MonitorSet::NoOutputs(workspaces) => { + for (idx, ws) in workspaces.iter_mut().enumerate() { + if ws.has_window(window) { + ws.remove_window(window); - let (output, workspace) = monitors - .iter_mut() - .flat_map(|mon| mon.workspaces.iter_mut().map(|ws| (&mon.output, ws))) - .find(|(_, ws)| ws.space.elements().any(|win| win == window)) - .unwrap(); + // Clean up empty workspaces. + if !ws.has_windows() { + workspaces.remove(idx); + } - workspace - .layout - .remove_window(window, output_size(output).h); - workspace.space.unmap_elem(window); - workspace.layout.sync_space(&mut workspace.space); + break; + } + } + } + } + } - // FIXME: remove empty unfocused workspaces. + pub fn update_window(&mut self, window: &W) { + match self { + MonitorSet::Normal { monitors, .. } => { + for mon in monitors { + for ws in &mut mon.workspaces { + if ws.has_window(window) { + ws.update_window(window); + break; + } + } + } + } + MonitorSet::NoOutputs(workspaces) => { + for ws in workspaces { + if ws.has_window(window) { + ws.update_window(window); + break; + } + } + } + } } - pub fn update_window(&mut self, window: &Window) { - let workspace = self - .workspaces() - .find(|ws| ws.space.elements().any(|w| w == window)) - .unwrap(); - workspace.layout.sync_space(&mut workspace.space); + pub fn send_frame(&self, output: &Output, time: Duration) { + if let MonitorSet::Normal { monitors, .. } = self { + for mon in monitors { + if &mon.output == output { + mon.workspaces[mon.active_workspace_idx].send_frame(time); + } + } + } } - pub fn activate_window(&mut self, window: &Window) { + pub fn find_window_and_output(&mut self, wl_surface: &WlSurface) -> Option<(W, Output)> { + if let MonitorSet::Normal { monitors, .. } = self { + for mon in monitors { + for ws in &mut mon.workspaces { + if let Some(window) = ws.find_wl_surface(wl_surface) { + return Some((window.clone(), mon.output.clone())); + } + } + } + } + + None + } + + pub fn update_output(&mut self, output: &Output) { + let MonitorSet::Normal { monitors, .. } = self else { + panic!() + }; + + for mon in monitors { + if &mon.output == output { + for ws in &mut mon.workspaces { + ws.set_view_size(output_size(output)); + } + break; + } + } + } + + pub fn activate_window(&mut self, window: &W) { let MonitorSet::Normal { monitors, active_monitor_idx, @@ -351,15 +491,10 @@ impl MonitorSet { for (monitor_idx, mon) in monitors.iter_mut().enumerate() { for (workspace_idx, ws) in mon.workspaces.iter_mut().enumerate() { - if ws.space.elements().any(|win| win == window) { + if ws.has_window(window) { *active_monitor_idx = monitor_idx; mon.active_workspace_idx = workspace_idx; - - let changed = ws.layout.activate_window(window); - if changed { - ws.layout.sync_space(&mut ws.space); - } - + ws.activate_window(window); break; } } @@ -396,12 +531,12 @@ impl MonitorSet { Some(&monitors[*active_monitor_idx].output) } - fn active_workspace(&mut self) -> Option<&mut Workspace> { + fn active_workspace(&mut self) -> Option<&mut Workspace<W>> { let monitor = self.active_monitor()?; Some(&mut monitor.workspaces[monitor.active_workspace_idx]) } - fn active_monitor(&mut self) -> Option<&mut Monitor> { + fn active_monitor(&mut self) -> Option<&mut Monitor<W>> { let MonitorSet::Normal { monitors, active_monitor_idx, @@ -418,68 +553,56 @@ impl MonitorSet { let Some(workspace) = self.active_workspace() else { return; }; - let changed = workspace.layout.move_left(); - if changed { - workspace.layout.sync_space(&mut workspace.space); - } + workspace.move_left(); } pub fn move_right(&mut self) { let Some(workspace) = self.active_workspace() else { return; }; - let changed = workspace.layout.move_right(); - if changed { - workspace.layout.sync_space(&mut workspace.space); - } + workspace.move_right(); } pub fn move_down(&mut self) { let Some(workspace) = self.active_workspace() else { return; }; - let changed = workspace.layout.move_down(); - if changed { - workspace.layout.sync_space(&mut workspace.space); - } + workspace.move_down(); } pub fn move_up(&mut self) { let Some(workspace) = self.active_workspace() else { return; }; - let changed = workspace.layout.move_up(); - if changed { - workspace.layout.sync_space(&mut workspace.space); - } + workspace.move_up(); } pub fn focus_left(&mut self) { let Some(workspace) = self.active_workspace() else { return; }; - workspace.layout.focus_left(); + workspace.focus_left(); } pub fn focus_right(&mut self) { let Some(workspace) = self.active_workspace() else { return; }; - workspace.layout.focus_right(); + workspace.focus_right(); } pub fn focus_down(&mut self) { let Some(workspace) = self.active_workspace() else { return; }; - workspace.layout.focus_down(); + workspace.focus_down(); } pub fn focus_up(&mut self) { let Some(workspace) = self.active_workspace() else { return; }; - workspace.layout.focus_up(); + workspace.focus_up(); } pub fn move_to_workspace_up(&mut self) { @@ -493,28 +616,27 @@ impl MonitorSet { }; let monitor = &mut monitors[*active_monitor_idx]; + let source_workspace_idx = monitor.active_workspace_idx; - let new_idx = monitor.active_workspace_idx.saturating_sub(1); - if new_idx == monitor.active_workspace_idx { + let new_idx = source_workspace_idx.saturating_sub(1); + if new_idx == source_workspace_idx { return; } - let workspace = &mut monitor.workspaces[monitor.active_workspace_idx]; - if workspace.layout.columns.is_empty() { |
