aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-08-13 19:55:37 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-08-13 19:55:37 +0400
commit8f71842e7cf0c2e77183e99b954c9b511dca3576 (patch)
treed4c74a27e59b5af64f41c1394bc7e7de1adb9789 /src
parent95c810c855a27a28f4dfa7dc6b949fef0901c7b2 (diff)
downloadniri-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.rs6
-rw-r--r--src/handlers/compositor.rs15
-rw-r--r--src/handlers/xdg_shell.rs89
-rw-r--r--src/input.rs57
-rw-r--r--src/layout.rs1026
-rw-r--r--src/niri.rs110
-rw-r--r--src/tty.rs6
-rw-r--r--src/winit.rs6
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() {