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/layout.rs | |
| 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/layout.rs')
| -rw-r--r-- | src/layout.rs | 1026 |
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 { |
