aboutsummaryrefslogtreecommitdiff
path: root/src/layout.rs
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/layout.rs
parent95c810c855a27a28f4dfa7dc6b949fef0901c7b2 (diff)
downloadniri-8f71842e7cf0c2e77183e99b954c9b511dca3576.tar.gz
niri-8f71842e7cf0c2e77183e99b954c9b511dca3576.tar.bz2
niri-8f71842e7cf0c2e77183e99b954c9b511dca3576.zip
Refactor everything again, make more things work
Diffstat (limited to 'src/layout.rs')
-rw-r--r--src/layout.rs1026
1 files changed, 669 insertions, 357 deletions
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() {
+ let workspace = &mut monitor.workspaces[source_workspace_idx];
+ if workspace.columns.is_empty() {
return;
}
- let column = &mut workspace.layout.columns[workspace.layout.active_column_idx];
+ let column = &mut workspace.columns[workspace.active_column_idx];
let window = column.windows[column.active_window_idx].clone();
- workspace
- .layout
- .remove_window(&window, output_size(&monitor.output).h);
- workspace.space.unmap_elem(&window);
- workspace.layout.sync_space(&mut workspace.space);
+ workspace.remove_window(&window);
- self.add_window(*active_monitor_idx, new_idx, window, true);
+ if !workspace.has_windows() && source_workspace_idx != monitor.workspaces.len() - 1 {
+ monitor.workspaces.remove(source_workspace_idx);
+ }
- // FIXME: remove empty unfocused workspaces.
+ self.add_window(*active_monitor_idx, new_idx, window, true);
}
pub fn move_to_workspace_down(&mut self) {
@@ -528,32 +650,28 @@ impl MonitorSet {
};
let monitor = &mut monitors[*active_monitor_idx];
+ let source_workspace_idx = monitor.active_workspace_idx;
- let new_idx = min(
- monitor.active_workspace_idx + 1,
- monitor.workspaces.len() - 1,
- );
-
- if new_idx == monitor.active_workspace_idx {
+ let mut new_idx = min(source_workspace_idx + 1, monitor.workspaces.len() - 1);
+ if new_idx == source_workspace_idx {
return;
}
- let workspace = &mut monitor.workspaces[monitor.active_workspace_idx];
- if workspace.layout.columns.is_empty() {
+ let workspace = &mut monitor.workspaces[source_workspace_idx];
+ if workspace.columns.is_empty() {
return;
}
- let column = &mut workspace.layout.columns[workspace.layout.active_column_idx];
+ let column = &mut workspace.columns[workspace.active_column_idx];
let window = column.windows[column.active_window_idx].clone();
- workspace
- .layout
- .remove_window(&window, output_size(&monitor.output).h);
- workspace.space.unmap_elem(&window);
- workspace.layout.sync_space(&mut workspace.space);
+ workspace.remove_window(&window);
- self.add_window(*active_monitor_idx, new_idx, window, true);
+ if !workspace.has_windows() {
+ monitor.workspaces.remove(source_workspace_idx);
+ new_idx -= 1;
+ }
- // FIXME: remove empty unfocused workspaces.
+ self.add_window(*active_monitor_idx, new_idx, window, true);
}
pub fn switch_workspace_up(&mut self) {
@@ -561,21 +679,40 @@ impl MonitorSet {
return;
};
- monitor.active_workspace_idx = monitor.active_workspace_idx.saturating_sub(1);
+ let source_workspace_idx = monitor.active_workspace_idx;
+
+ let new_idx = source_workspace_idx.saturating_sub(1);
+ if new_idx == source_workspace_idx {
+ return;
+ }
- // FIXME: remove empty unfocused workspaces.
+ monitor.active_workspace_idx = new_idx;
+
+ if !monitor.workspaces[source_workspace_idx].has_windows()
+ && source_workspace_idx != monitor.workspaces.len() - 1
+ {
+ monitor.workspaces.remove(source_workspace_idx);
+ }
}
pub fn switch_workspace_down(&mut self) {
let Some(monitor) = self.active_monitor() else {
return;
};
- monitor.active_workspace_idx = min(
- monitor.active_workspace_idx + 1,
- monitor.workspaces.len() - 1,
- );
- // FIXME: remove empty unfocused workspaces.
+ let source_workspace_idx = monitor.active_workspace_idx;
+
+ let mut new_idx = min(source_workspace_idx + 1, monitor.workspaces.len() - 1);
+ if new_idx == source_workspace_idx {
+ return;
+ }
+
+ if !monitor.workspaces[source_workspace_idx].has_windows() {
+ monitor.workspaces.remove(source_workspace_idx);
+ new_idx -= 1;
+ }
+
+ monitor.active_workspace_idx = new_idx;
}
pub fn consume_into_column(&mut self) {
@@ -591,12 +728,7 @@ impl MonitorSet {
let monitor = &mut monitors[*active_monitor_idx];
let workspace = &mut monitor.workspaces[monitor.active_workspace_idx];
- let changed = workspace
- .layout
- .consume_into_column(output_size(&monitor.output).h);
- if changed {
- workspace.layout.sync_space(&mut workspace.space);
- }
+ workspace.consume_into_column();
}
pub fn expel_from_column(&mut self) {
@@ -610,22 +742,11 @@ impl MonitorSet {
};
let monitor = &mut monitors[*active_monitor_idx];
-
- let output_scale = monitor.output.current_scale().integer_scale();
- let output_transform = monitor.output.current_transform();
- let output_mode = monitor.output.current_mode().unwrap();
- let output_size = output_transform
- .transform_size(output_mode.size)
- .to_logical(output_scale);
-
let workspace = &mut monitor.workspaces[monitor.active_workspace_idx];
- let changed = workspace.layout.expel_from_column(output_size.h);
- if changed {
- workspace.layout.sync_space(&mut workspace.space);
- }
+ workspace.expel_from_column();
}
- pub fn focus(&self) -> Option<&Window> {
+ pub fn focus(&self) -> Option<&W> {
let MonitorSet::Normal {
monitors,
active_monitor_idx,
@@ -637,65 +758,40 @@ impl MonitorSet {
let monitor = &monitors[*active_monitor_idx];
let workspace = &monitor.workspaces[monitor.active_workspace_idx];
- if workspace.layout.columns.is_empty() {
+ if !workspace.has_windows() {
return None;
}
- let column = &workspace.layout.columns[workspace.layout.active_column_idx];
+ let column = &workspace.columns[workspace.active_column_idx];
Some(&column.windows[column.active_window_idx])
}
- pub fn workspace_for_output(&mut self, output: &Output) -> Option<&mut Workspace> {
+ pub fn workspace_for_output(&self, output: &Output) -> Option<&Workspace<W>> {
let MonitorSet::Normal { monitors, .. } = self else {
return None;
};
- monitors.iter_mut().find_map(|monitor| {
+ monitors.iter().find_map(|monitor| {
if &monitor.output == output {
- Some(&mut monitor.workspaces[monitor.active_workspace_idx])
+ Some(&monitor.workspaces[monitor.active_workspace_idx])
} else {
None
}
})
}
- pub fn workspaces(&mut self) -> impl Iterator<Item = &mut Workspace> + '_ {
- match self {
- MonitorSet::Normal { monitors, .. } => {
- monitors.iter_mut().flat_map(|mon| &mut mon.workspaces)
- }
- MonitorSet::NoOutputs(_workspaces) => todo!(),
- }
- }
-
- pub fn spaces(&mut self) -> impl Iterator<Item = &Space<Window>> + '_ {
- self.workspaces().map(|workspace| &workspace.space)
- }
-
- pub fn find_window(&mut self, wl_surface: &WlSurface) -> Option<&Window> {
- self.workspaces()
- .flat_map(|workspace| workspace.space.elements())
- .find(|window| window.toplevel().wl_surface() == wl_surface)
- }
-
- pub fn find_window_and_space(
- &mut self,
- wl_surface: &WlSurface,
- ) -> Option<(Window, &Space<Window>)> {
- self.spaces().find_map(|space| {
- let window = space
- .elements()
- .find(|window| window.toplevel().wl_surface() == wl_surface)
- .cloned();
- window.map(|window| (window, space))
- })
+ pub fn window_under(
+ &self,
+ output: &Output,
+ pos_within_output: Point<f64, Logical>,
+ ) -> Option<(&W, Point<i32, Logical>)> {
+ let ws = self.workspace_for_output(output).unwrap();
+ ws.window_under(pos_within_output)
}
- /// Refreshes the `Space`s.
+ /// Refreshes the `Workspace`s.
pub fn refresh(&mut self) {
- for workspace in self.workspaces() {
- workspace.space.refresh();
- }
+ // TODO
}
fn verify_invariants(&self) {
@@ -708,11 +804,11 @@ impl MonitorSet {
MonitorSet::NoOutputs(workspaces) => {
for workspace in workspaces {
assert!(
- !workspace.layout.has_windows(),
+ !workspace.has_windows(),
"with no outputs there cannot be empty workspaces"
);
- workspace.layout.verify_invariants();
+ workspace.verify_invariants();
}
return;
@@ -731,13 +827,6 @@ impl MonitorSet {
let monitor_id = OutputId::new(&monitor.output);
if idx == primary_idx {
- assert!(
- monitor
- .workspaces
- .iter()
- .any(|workspace| workspace.original_output == monitor_id),
- "primary monitor must have at least one own workspace"
- );
} else {
assert!(
monitor
@@ -752,76 +841,102 @@ impl MonitorSet {
// exists.
for workspace in &monitor.workspaces {
- workspace.layout.verify_invariants();
+ workspace.verify_invariants();
}
}
}
}
-fn output_size(output: &Output) -> Size<i32, Logical> {
- let output_scale = output.current_scale().integer_scale();
- let output_transform = output.current_transform();
- let output_mode = output.current_mode().unwrap();
- let output_size = output_transform
- .transform_size(output_mode.size)
- .to_logical(output_scale);
- output_size
+impl MonitorSet<Window> {
+ pub fn render_elements(
+ &self,
+ renderer: &mut GlesRenderer,
+ output: &Output,
+ ) -> Vec<WaylandSurfaceRenderElement<GlesRenderer>> {
+ let ws = self.workspace_for_output(output).unwrap();
+ ws.render_elements(renderer)
+ }
}
-impl Default for MonitorSet {
+impl<W: LayoutElement> Default for MonitorSet<W> {
fn default() -> Self {
Self::new()
}
}
-impl Layout {
- fn new() -> Self {
+impl<W: LayoutElement> Workspace<W> {
+ fn new(output: Output) -> Self {
Self {
+ original_output: OutputId::new(&output),
+ view_size: output_size(&output),
+ output: Some(output),
columns: vec![],
active_column_idx: 0,
+ view_offset: 0,
}
}
- fn sync_space(&self, space: &mut Space<Window>) {
- // FIXME: this is really inefficient
- let mut active_window = None;
+ fn refresh(&self) {
+ // FIXME: proper overlap.
+ }
- let mut x = PADDING;
- for (column_idx, column) in self.columns.iter().enumerate() {
- let mut y = PADDING;
- for (window_idx, window) in column.windows.iter().enumerate() {
- let active =
- column_idx == self.active_column_idx && window_idx == column.active_window_idx;
- if active {
- active_window = Some(window.clone());
- }
+ fn windows(&self) -> impl Iterator<Item = &W> + '_ {
+ self.columns.iter().flat_map(|col| col.windows.iter())
+ }
- window.set_activated(active);
- space.map_element(window.clone(), (x, y), false);
- window.toplevel().send_pending_configure();
- y += window.geometry().size.h + PADDING;
+ fn set_output(&mut self, output: Option<Output>) {
+ if self.output == output {
+ return;
+ }
+
+ if let Some(output) = self.output.take() {
+ for win in self.windows() {
+ win.output_leave(&output);
}
- x += column.size().w + PADDING;
}
- if let Some(window) = active_window {
- space.raise_element(&window, false);
+ if let Some(output) = output {
+ self.set_view_size(output_size(&output));
+
+ self.output = Some(output);
+
+ for win in self.windows() {
+ self.enter_output_for_window(win);
+ }
}
}
- fn has_windows(&self) -> bool {
- self.columns.is_empty()
+ fn enter_output_for_window(&self, window: &W) {
+ if let Some(output) = &self.output {
+ // FIXME: proper overlap.
+ window.output_enter(
+ output,
+ Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX)),
+ );
+ }
}
- /// Computes the width of the layout including left and right padding, in Logical coordinates.
- fn width(&self) -> i32 {
- let mut total = PADDING;
+ fn set_view_size(&mut self, size: Size<i32, Logical>) {
+ if self.view_size == size {
+ return;
+ }
- for column in &self.columns {
- total += column.size().w + PADDING;
+ self.view_size = size;
+ for col in &mut self.columns {
+ col.update_window_sizes(self.view_size);
}
+ }
- total
+ fn has_windows(&self) -> bool {
+ self.windows().next().is_some()
+ }
+
+ fn has_window(&self, window: &W) -> bool {
+ self.windows().any(|win| win == window)
+ }
+
+ fn find_wl_surface(&self, wl_surface: &WlSurface) -> Option<&W> {
+ self.windows().find(|win| win.is_wl_surface(wl_surface))
}
/// Computes the X position of the windows in the given column, in logical coordinates.
@@ -835,17 +950,25 @@ impl Layout {