aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-05-14 15:00:11 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-05-14 15:35:43 +0400
commit5f402210510aff0051abd080d664581c26e77c2b (patch)
treef75918a6a30295b4f571846d09cc12ee75397f12 /src
parentb14405904a8309fdcebc938f59584832ffe27fd6 (diff)
downloadniri-5f402210510aff0051abd080d664581c26e77c2b.tar.gz
niri-5f402210510aff0051abd080d664581c26e77c2b.tar.bz2
niri-5f402210510aff0051abd080d664581c26e77c2b.zip
Refactor column and tile offsets, fix a few issues
Diffstat (limited to 'src')
-rw-r--r--src/handlers/xdg_shell.rs4
-rw-r--r--src/layout/mod.rs31
-rw-r--r--src/layout/tile.rs15
-rw-r--r--src/layout/workspace.rs776
4 files changed, 459 insertions, 367 deletions
diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs
index 1b8194aa..44f07839 100644
--- a/src/handlers/xdg_shell.rs
+++ b/src/handlers/xdg_shell.rs
@@ -759,7 +759,7 @@ impl State {
// height.
let mut target =
Rectangle::from_loc_and_size((0, 0), (window_geo.size.w, output_geo.size.h));
- target.loc.y -= self.niri.layout.window_y(window).unwrap();
+ target.loc -= self.niri.layout.window_loc(window).unwrap();
target.loc -= get_popup_toplevel_coords(popup);
self.position_popup_within_rect(popup, target);
@@ -953,8 +953,6 @@ pub fn add_mapped_toplevel_pre_commit_hook(toplevel: &ToplevelSurface) -> HookId
state.backend.with_primary_renderer(|renderer| {
mapped.store_animation_snapshot(renderer);
});
-
- state.niri.layout.prepare_for_resize_animation(&window);
}
// The toplevel remains mapped; clear any stored unmap snapshot.
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 1442dfd0..88b9b3ec 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -745,14 +745,14 @@ impl<W: LayoutElement> Layout<W> {
None
}
- pub fn window_y(&self, window: &W::Id) -> Option<i32> {
+ pub fn window_loc(&self, window: &W::Id) -> Option<Point<i32, Logical>> {
match &self.monitor_set {
MonitorSet::Normal { monitors, .. } => {
for mon in monitors {
for ws in &mon.workspaces {
for col in &ws.columns {
if let Some(idx) = col.position(window) {
- return Some(col.window_y(idx));
+ return Some(col.window_loc(idx));
}
}
}
@@ -762,7 +762,7 @@ impl<W: LayoutElement> Layout<W> {
for ws in workspaces {
for col in &ws.columns {
if let Some(idx) = col.position(window) {
- return Some(col.window_y(idx));
+ return Some(col.window_loc(idx));
}
}
}
@@ -1995,31 +1995,6 @@ impl<W: LayoutElement> Layout<W> {
}
}
- pub fn prepare_for_resize_animation(&mut self, window: &W::Id) {
- let _span = tracy_client::span!("Layout::prepare_for_resize_animation");
-
- match &mut self.monitor_set {
- MonitorSet::Normal { monitors, .. } => {
- for mon in monitors {
- for ws in &mut mon.workspaces {
- if ws.has_window(window) {
- ws.prepare_for_resize_animation(window);
- return;
- }
- }
- }
- }
- MonitorSet::NoOutputs { workspaces, .. } => {
- for ws in workspaces {
- if ws.has_window(window) {
- ws.prepare_for_resize_animation(window);
- return;
- }
- }
- }
- }
- }
-
pub fn refresh(&mut self) {
let _span = tracy_client::span!("Layout::refresh");
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index 7f9c6e75..d53eb2b1 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -1,4 +1,3 @@
-use std::cell::RefCell;
use std::cmp::max;
use std::rc::Rc;
use std::time::Duration;
@@ -67,7 +66,7 @@ pub struct Tile<W: LayoutElement> {
move_y_animation: Option<MoveAnimation>,
/// Snapshot of the last render for use in the close animation.
- unmap_snapshot: RefCell<Option<TileRenderSnapshot>>,
+ unmap_snapshot: Option<TileRenderSnapshot>,
/// Extra damage for clipped surface corner radius changes.
rounded_corner_damage: RoundedCornerDamage,
@@ -122,7 +121,7 @@ impl<W: LayoutElement> Tile<W> {
resize_animation: None,
move_x_animation: None,
move_y_animation: None,
- unmap_snapshot: RefCell::new(None),
+ unmap_snapshot: None,
rounded_corner_damage: Default::default(),
options,
}
@@ -237,9 +236,7 @@ impl<W: LayoutElement> Tile<W> {
|| self.move_y_animation.is_some()
}
- pub fn update(&mut self, is_active: bool, mut view_rect: Rectangle<i32, Logical>) {
- view_rect.loc -= self.render_offset();
-
+ pub fn update(&mut self, is_active: bool, view_rect: Rectangle<i32, Logical>) {
let rules = self.window.rules();
let draw_border_with_background = rules
@@ -840,11 +837,11 @@ impl<W: LayoutElement> Tile<W> {
renderer: &mut GlesRenderer,
scale: Scale<f64>,
) {
- if self.unmap_snapshot.get_mut().is_some() {
+ if self.unmap_snapshot.is_some() {
return;
}
- *self.unmap_snapshot.get_mut() = Some(self.render_snapshot(renderer, scale));
+ self.unmap_snapshot = Some(self.render_snapshot(renderer, scale));
}
fn render_snapshot(
@@ -881,7 +878,7 @@ impl<W: LayoutElement> Tile<W> {
}
}
- pub fn take_unmap_snapshot(&self) -> Option<TileRenderSnapshot> {
+ pub fn take_unmap_snapshot(&mut self) -> Option<TileRenderSnapshot> {
self.unmap_snapshot.take()
}
}
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index fdcd7cb0..5aa78f2b 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -54,6 +54,9 @@ pub struct Workspace<W: LayoutElement> {
/// Columns of windows on this workspace.
pub columns: Vec<Column<W>>,
+ /// Extra per-column data.
+ data: Vec<ColumnData>,
+
/// Index of the currently active column, if any.
pub active_column_idx: usize,
@@ -116,6 +119,13 @@ niri_render_elements! {
}
}
+/// Extra per-column data.
+#[derive(Debug, Clone, Copy, PartialEq)]
+struct ColumnData {
+ /// Cached actual column width.
+ width: i32,
+}
+
#[derive(Debug)]
enum ViewOffsetAdjustment {
Animation(Animation),
@@ -181,12 +191,10 @@ pub struct Column<W: LayoutElement> {
/// Must be non-empty.
pub tiles: Vec<Tile<W>>,
- /// Heights of the windows.
+ /// Extra per-tile data.
///
/// Must have the same number of elements as `tiles`.
- ///
- /// These heights are window heights, not tile heights, so they exclude tile decorations.
- heights: Vec<WindowHeight>,
+ data: Vec<TileData>,
/// Index of the currently active tile.
pub active_tile_idx: usize,
@@ -206,9 +214,6 @@ pub struct Column<W: LayoutElement> {
/// Animation of the render offset during window swapping.
move_animation: Option<Animation>,
- /// Width right before a resize animation on one of the windows of the column.
- pub width_before_resize: Option<i32>,
-
/// Latest known view size for this column's workspace.
view_size: Size<i32, Logical>,
@@ -219,6 +224,21 @@ pub struct Column<W: LayoutElement> {
options: Rc<Options>,
}
+/// Extra per-tile data.
+#[derive(Debug, Clone, Copy, PartialEq)]
+struct TileData {
+ /// Requested height of the window.
+ ///
+ /// This is window height, not tile height, so it excludes tile decorations.
+ height: WindowHeight,
+
+ /// Cached actual size of the tile.
+ size: Size<i32, Logical>,
+
+ /// Cached whether the tile is being interactively resized by its left edge.
+ interactively_resizing_by_left_edge: bool,
+}
+
impl OutputId {
pub fn new(output: &Output) -> Self {
Self(output.name())
@@ -238,6 +258,18 @@ impl ViewOffsetAdjustment {
}
}
+impl ColumnData {
+ pub fn new<W: LayoutElement>(column: &Column<W>) -> Self {
+ let mut rv = Self { width: 0 };
+ rv.update(column);
+ rv
+ }
+
+ pub fn update<W: LayoutElement>(&mut self, column: &Column<W>) {
+ self.width = column.width();
+ }
+}
+
impl ColumnWidth {
fn resolve(self, options: &Options, view_width: i32) -> i32 {
match self {
@@ -259,6 +291,26 @@ impl From<PresetWidth> for ColumnWidth {
}
}
+impl TileData {
+ pub fn new<W: LayoutElement>(tile: &Tile<W>, height: WindowHeight) -> Self {
+ let mut rv = Self {
+ height,
+ size: Size::default(),
+ interactively_resizing_by_left_edge: false,
+ };
+ rv.update(tile);
+ rv
+ }
+
+ pub fn update<W: LayoutElement>(&mut self, tile: &Tile<W>) {
+ self.size = tile.tile_size();
+ self.interactively_resizing_by_left_edge = tile
+ .window()
+ .interactive_resize_data()
+ .map_or(false, |data| data.edges.contains(ResizeEdge::LEFT));
+ }
+}
+
impl<W: LayoutElement> Workspace<W> {
pub fn new(output: Output, options: Rc<Options>) -> Self {
let working_area = compute_working_area(&output, options.struts);
@@ -268,6 +320,7 @@ impl<W: LayoutElement> Workspace<W> {
working_area,
output: Some(output),
columns: vec![],
+ data: vec![],
active_column_idx: 0,
interactive_resize: None,
view_offset: 0,
@@ -287,6 +340,7 @@ impl<W: LayoutElement> Workspace<W> {
view_size: Size::from((1280, 720)),
working_area: Rectangle::from_loc_and_size((0, 0), (1280, 720)),
columns: vec![],
+ data: vec![],
active_column_idx: 0,
interactive_resize: None,
view_offset: 0,
@@ -339,12 +393,15 @@ impl<W: LayoutElement> Workspace<W> {
}
pub fn update_render_elements(&mut self, is_active: bool) {
- let mut view_rect = Rectangle::from_loc_and_size((self.view_pos(), 0), self.view_size);
-
- for (col_idx, col) in self.columns.iter_mut().enumerate() {
- let is_active = is_active && col_idx == self.active_column_idx;
+ let view_pos = Point::from((self.view_pos(), 0));
+ let view_size = self.view_size();
+ let active_idx = self.active_column_idx;
+ for (col_idx, (col, col_x)) in self.columns_mut().enumerate() {
+ let is_active = is_active && col_idx == active_idx;
+ let col_off = Point::from((col_x, 0));
+ let col_pos = view_pos - col_off - col.render_offset();
+ let view_rect = Rectangle::from_loc_and_size(col_pos, view_size);
col.update_render_elements(is_active, view_rect);
- view_rect.loc.x -= col.width() + self.options.gaps;
}
}
@@ -730,17 +787,6 @@ impl<W: LayoutElement> Workspace<W> {
self.windows_mut().find(|win| win.is_wl_surface(wl_surface))
}
- /// Computes the X position of the windows in the given column, in logical coordinates.
- pub fn column_x(&self, column_idx: usize) -> i32 {
- let mut x = 0;
-
- for column in self.columns.iter().take(column_idx) {
- x += column.width() + self.options.gaps;
- }
-
- x
- }
-
pub fn add_window_at(
&mut self,
col_idx: usize,
@@ -776,6 +822,7 @@ impl<W: LayoutElement> Workspace<W> {
true,
);
let width = column.width();
+ self.data.insert(col_idx, ColumnData::new(&column));
self.columns.insert(col_idx, column);
if activate {
@@ -874,6 +921,7 @@ impl<W: LayoutElement> Workspace<W> {
is_full_width,
true,
);
+ self.data.insert(idx, ColumnData::new(&column));
self.columns.insert(idx, column);
// Activate the new window if right_of was active.
@@ -913,6 +961,7 @@ impl<W: LayoutElement> Workspace<W> {
column.set_view_size(self.view_size, self.working_area);
let width = column.width();
+ self.data.insert(idx, ColumnData::new(&column));
self.columns.insert(idx, column);
if activate {
@@ -958,15 +1007,18 @@ impl<W: LayoutElement> Workspace<W> {
let offset = self.column_x(column_idx + 1) - self.column_x(column_idx);
let column = &mut self.columns[column_idx];
+ let prev_width = self.data[column_idx].width;
// Animate movement of other tiles.
- let offset_y = column.tile_y(window_idx + 1) - column.tile_y(window_idx);
+ // FIXME: tiles can move by X too, in a centered or resizing layout with one window smaller
+ // than the others.
+ let offset_y = column.tile_offset(window_idx + 1).y - column.tile_offset(window_idx).y;
for tile in &mut column.tiles[window_idx + 1..] {
tile.animate_move_y_from(offset_y);
}
let tile = column.tiles.remove(window_idx);
- column.heights.remove(window_idx);
+ column.data.remove(window_idx);
if let Some(output) = &self.output {
tile.window().output_leave(output);
@@ -979,7 +1031,30 @@ impl<W: LayoutElement> Workspace<W> {
}
}
- if column.tiles.is_empty() {
+ let became_empty = column.tiles.is_empty();
+ let offset = if became_empty {
+ offset
+ } else {
+ column.active_tile_idx = min(column.active_tile_idx, column.tiles.len() - 1);
+ column.update_tile_sizes(true);
+ self.data[column_idx].update(column);
+
+ prev_width - column.width()
+ };
+
+ // Animate movement of the other columns.
+ let movement_config = anim_config.unwrap_or(self.options.animations.window_movement.0);
+ if self.active_column_idx <= column_idx {
+ for col in &mut self.columns[column_idx + 1..] {
+ col.animate_move_from_with_config(offset, movement_config);
+ }
+ } else {
+ for col in &mut self.columns[..=column_idx] {
+ col.animate_move_from_with_config(-offset, movement_config);
+ }
+ }
+
+ if became_empty {
if column_idx + 1 == self.active_column_idx {
// The previous column, that we were going to activate upon removal of the active
// column, has just been itself removed.
@@ -990,19 +1065,8 @@ impl<W: LayoutElement> Workspace<W> {
self.view_offset_before_fullscreen = None;
}
- // Animate movement of the other columns.
- let movement_config = anim_config.unwrap_or(self.options.animations.window_movement.0);
- if self.active_column_idx <= column_idx {
- for col in &mut self.columns[column_idx + 1..] {
- col.animate_move_from_with_config(offset, movement_config);
- }
- } else {
- for col in &mut self.columns[..column_idx] {
- col.animate_move_from_with_config(-offset, movement_config);
- }
- }
-
self.columns.remove(column_idx);
+ self.data.remove(column_idx);
if self.columns.is_empty() {
return tile;
}
@@ -1050,9 +1114,6 @@ impl<W: LayoutElement> Workspace<W> {
return tile;
}
- column.active_tile_idx = min(column.active_tile_idx, column.tiles.len() - 1);
- column.update_tile_sizes(true);
-
tile
}
@@ -1070,6 +1131,7 @@ impl<W: LayoutElement> Workspace<W> {
}
let column = self.columns.remove(column_idx);
+ self.data.remove(column_idx);
if let Some(output) = &self.output {
for tile in &column.tiles {
@@ -1149,22 +1211,29 @@ impl<W: LayoutElement> Workspace<W> {
.enumerate()
.find(|(_, col)| col.contains(window))
.unwrap();
- let tile_idx = column
+ let (tile_idx, tile) = column
.tiles
- .iter()
- .position(|tile| tile.window().id() == window)
+ .iter_mut()
+ .enumerate()
+ .find(|(_, tile)| tile.window().id() == window)
.unwrap();
- let offset = column
- .width_before_resize
- .take()
- .map_or(0, |prev| prev - column.width());
+ let was_fullscreen = tile.is_fullscreen();
+ let resize = tile.window_mut().interactive_resize_data();
- let was_fullscreen = column.tiles[tile_idx].is_fullscreen();
+ // Do this before calling update_window() so it can get up-to-date info.
+ if let Some(serial) = serial {
+ tile.window_mut().update_interactive_resize(serial);
+ }
+
+ let prev_width = self.data[col_idx].width;
column.update_window(window);
+ self.data[col_idx].update(column);
column.update_tile_sizes(false);
+ let offset = prev_width - self.data[col_idx].width;
+
// Move other columns in tandem with resizing.
let started_resize_anim =
column.tiles[tile_idx].resize_animation().is_some() && offset != 0;
@@ -1190,12 +1259,6 @@ impl<W: LayoutElement> Workspace<W> {
let tile = &mut col.tiles[tile_idx];
let window = tile.window_mut();
- let resize = window.interactive_resize_data();
-
- if let Some(serial) = serial {
- window.update_interactive_resize(serial);
- }
-
// If this was the last resize commit, this function will now return None. This way we can
// animate the window into view after the last resize commit.
let resize_still_ongoing = window.interactive_resize_data().is_some();
@@ -1270,28 +1333,15 @@ impl<W: LayoutElement> Workspace<W> {
.map(|o| Scale::from(o.current_scale().fractional_scale()))
.unwrap_or(Scale::from(1.));
- let mut view_rect_ws = Rectangle::from_loc_and_size((self.view_pos(), 0), self.view_size);
- for col in &mut self.columns {
- let col_width = col.width();
-
- let mut view_rect = view_rect_ws;
- view_rect.loc -= col.render_offset();
- if !col.is_fullscreen {
- view_rect.loc.y -= self.working_area.loc.y + self.options.gaps;
- }
-
- for tile in &mut col.tiles {
- if tile.window().id() == window {
- view_rect.loc -= Column::render_offset_for_tile(tile, col_width, &self.options);
- tile.update(false, view_rect);
- tile.store_unmap_snapshot_if_empty(renderer, output_scale);
- return;
- }
-
- view_rect.loc.y -= tile.tile_size().h + self.options.gaps;
+ let view_size = self.view_size();
+ for (tile, tile_pos) in self.tiles_with_render_positions_mut() {
+ if tile.window().id() == window {
+ let view_pos = Point::from((-tile_pos.x, -tile_pos.y));
+ let view_rect = Rectangle::from_loc_and_size(view_pos, view_size);
+ tile.update(false, view_rect);
+ tile.store_unmap_snapshot_if_empty(renderer, output_scale);
+ return;
}
-
- view_rect_ws.loc.x -= col_width + self.options.gaps;
}
}
@@ -1311,11 +1361,6 @@ impl<W: LayoutElement> Workspace<W> {
renderer: &mut GlesRenderer,
window: &W::Id,
) {
- let (tile, mut tile_pos) = self
- .tiles_in_render_order()
- .find(|(tile, _)| tile.window().id() == window)
- .unwrap();
-
// FIXME: workspaces should probably cache their last used scale so they can be correctly
// rendered even with no outputs connected.
let output_scale = self
@@ -1324,36 +1369,53 @@ impl<W: LayoutElement> Workspace<W> {
.map(|o| Scale::from(o.current_scale().fractional_scale()))
.unwrap_or(Scale::from(1.));
+ let (tile, mut tile_pos) = self
+ .tiles_with_render_positions_mut()
+ .find(|(tile, _)| tile.window().id() == window)
+ .unwrap();
+
let Some(snapshot) = tile.take_unmap_snapshot() else {
return;
};
- let col_idx = self
+ let tile_size = tile.tile_size();
+
+ let (col_idx, tile_idx) = self
.columns
.iter()
- .position(|col| col.contains(window))
+ .enumerate()
+ .find_map(|(col_idx, col)| {
+ col.tiles
+ .iter()
+ .position(|tile| tile.window().id() == window)
+ .map(move |tile_idx| (col_idx, tile_idx))
+ })
.unwrap();
let col = &self.columns[col_idx];
let removing_last = col.tiles.len() == 1;
- let offset = self.column_x(col_idx + 1) - self.column_x(col_idx);
tile_pos.x += self.view_pos();
- if col_idx < self.active_column_idx && removing_last {
+ if col_idx < self.active_column_idx {
+ let offset = if removing_last {
+ self.column_x(col_idx + 1) - self.column_x(col_idx)
+ } else {
+ self.data[col_idx].width
+ - col
+ .data
+ .iter()
+ .enumerate()
+ .filter_map(|(idx, data)| (idx != tile_idx).then_some(data.size.w))
+ .max()
+ .unwrap()
+ };
tile_pos.x -= offset;
}
let anim = Animation::new(0., 1., 0., self.options.animations.window_close.anim);
- let res = ClosingWindow::new(
- renderer,
- snapshot,
- output_scale,
- tile.tile_size(),
- tile_pos,
- anim,
- );
+ let res = ClosingWindow::new(renderer, snapshot, output_scale, tile_size, tile_pos, anim);
match res {
Ok(closing) => {
self.closing_windows.push(closing);
@@ -1364,27 +1426,22 @@ impl<W: LayoutElement> Workspace<W> {
}
}
- pub fn prepare_for_resize_animation(&mut self, window: &W::Id) {
- let column = self
- .columns
- .iter_mut()
- .find(|col| col.contains(window))
- .unwrap();
-
- column.width_before_resize = Some(column.width());
- }
-
#[cfg(test)]
pub fn verify_invariants(&self) {
assert!(self.view_size.w > 0);
assert!(self.view_size.h > 0);
+ assert_eq!(self.columns.len(), self.data.len());
if !self.columns.is_empty() {
assert!(self.active_column_idx < self.columns.len());
- for column in &self.columns {
+ for (column, data) in zip(&self.columns, &self.data) {
assert!(Rc::ptr_eq(&self.options, &column.options));
column.verify_invariants();
+
+ let mut data2 = *data;
+ data2.update(column);
+ assert_eq!(data, &data2, "column data must be up to date");
}
let col = &self.columns[self.active_column_idx];
@@ -1461,8 +1518,10 @@ impl<W: LayoutElement> Workspace<W> {
let next_col_x = self.column_x(self.active_column_idx + 1);
let mut column = self.columns.remove(self.active_column_idx);
+ let data = self.data.remove(self.active_column_idx);
cancel_resize_if_this_column(&mut self.interactive_resize, &mut column);
self.columns.insert(new_idx, column);
+ self.data.insert(new_idx, data);
// Preserve the camera position when moving to the left.
let view_offset_delta = -self.column_x(self.active_column_idx) + current_col_x;
@@ -1540,21 +1599,22 @@ impl<W: LayoutElement> Workspace<W> {
let source_col_idx = self.active_column_idx;
let source_column = &self.columns[source_col_idx];
- let prev_y = source_column.tile_y(source_column.active_tile_idx);
+ let prev_off = source_column.tile_offset(source_column.active_tile_idx);
if source_column.tiles.len() == 1 {
if self.active_column_idx == 0 {
return;
}
- let offset_x = self.column_x(source_col_idx) - self.column_x(source_col_idx - 1);
+ let offset = self.column_x(source_col_idx) - self.column_x(source_col_idx - 1);
+ let mut offset = Point::from((offset, 0));
// Move into adjacent column.
let target_column_idx = source_col_idx - 1;
// Make sure the previous (target) column is activated so the animation looks right.
- self.activate_prev_column_on_removal = Some(self.static_view_offset() + offset_x);
- let offset_x = offset_x + self.columns[source_col_idx].render_offset().x;
+ self.activate_prev_column_on_removal = Some(self.static_view_offset() + offset.x);
+ offset.x += self.columns[source_col_idx].render_offset().x;
let tile = self.remove_tile_by_idx(
source_col_idx,
0,
@@ -1566,14 +1626,16 @@ impl<W: LayoutElement> Workspace<W> {
let prev_next_x = self.column_x(next_col_idx);
let target_column = &mut self.columns[target_column_idx];
- let offset_x = offset_x - target_column.render_offset().x;
- let offset_y = prev_y - target_column.tile_y(target_column.tiles.len());
+ offset.x -= target_column.render_offset().x;
target_column.add_tile(tile, true);
+ self.data[target_column_idx].update(target_column);
target_column.focus_last();
+ offset += prev_off - target_column.tile_offset(target_column.tiles.len() - 1);
+
let new_tile = target_column.tiles.last_mut().unwrap();
- new_tile.animate_move_from(Point::from((offset_x, offset_y)));
+ new_tile.animate_move_from(offset);
// Consuming a window into a column could've increased its width if the new window had a
// larger min width. Move the next columns to account for this.
@@ -1586,7 +1648,7 @@ impl<W: LayoutElement> Workspace<W> {
let width = source_column.width;
let is_full_width = source_column.is_full_width;
- let offset_x = source_column.render_offset().x;
+ let mut offset = Point::from((source_column.render_offset().x, 0));
let tile = self.remove_tile_by_idx(source_col_idx, source_column.active_tile_idx, None);
@@ -1603,8 +1665,8 @@ impl<W: LayoutElement> Workspace<W> {
self.activate_prev_column_on_removal = None;
let new_col = &mut self.columns[self.active_column_idx];
- let offset_y = prev_y - new_col.tile_y(0);
- new_col.tiles[0].animate_move_from(Point::from((offset_x, offset_y)));
+ offset += prev_off - new_col.tile_offset(0);
+ new_col.tiles[0].animate_move_from(offset);
}
}
@@ -1614,11 +1676,12 @@ impl<W: LayoutElement> Workspace<W> {
}
let source_col_idx = self.active_column_idx;
- let offset_x = self.column_x(source_col_idx) - self.column_x(source_col_idx + 1);
+ let offset = self.column_x(source_col_idx) - self.column_x(source_col_idx + 1);
+ let mut offset = Point::from((offset, 0));
let source_column = &self.columns[source_col_idx];
- let offset_x = offset_x + source_column.render_offset().x;
- let prev_y = source_column.tile_y(source_column.active_tile_idx);
+ offset.x += source_column.render_offset().x;
+ let prev_off = source_column.tile_offset(source_column.active_tile_idx);
if source_column.tiles.len() == 1 {
if self.active_column_idx + 1 == self.columns.len() {
@@ -1628,7 +1691,7 @@ impl<W: LayoutElement> Workspace<W> {
// Move into adjacent column.
let target_column_idx = source_col_idx;
- let offset_x = offset_x - self.columns[source_col_idx + 1].render_offset().x;
+ offset.x -= self.columns[source_col_idx + 1].render_offset().x;
// Make sure the target column gets activated.
self.activate_prev_column_on_removal = None;
@@ -1642,13 +1705,14 @@ impl<W: LayoutElement> Workspace<W> {
let prev_next_x = self.column_x(target_column_idx + 1);
let target_column = &mut self.columns[target_column_idx];
- let offset_y = prev_y - target_column.tile_y(target_column.tiles.len());
-
target_column.add_tile(tile, true);
+ self.data[target_column_idx].update(target_column);
target_column.focus_last();
+ offset += prev_off - target_column.tile_offset(target_column.tiles.len() - 1);
+
let new_tile = target_column.tiles.last_mut().unwrap();
- new_tile.animate_move_from(Point::from((offset_x, offset_y)));
+ new_tile.animate_move_from(offset);
// Consuming a window into a column could've increased its width if the new window had a
// larger min width. Move the next columns to account for this.
@@ -1672,8 +1736,8 @@ impl<W: LayoutElement> Workspace<W> {
);
let new_col = &mut self.columns[self.active_column_idx];
- let offset_y = prev_y - new_col.tile_y(0);
- new_col.tiles[0].animate_move_from(Point::from((offset_x, offset_y)));
+ offset += prev_off - new_col.tile_offset(0);
+ new_col.tiles[0].animate_move_from(offset);
}
}
@@ -1688,10 +1752,11 @@ impl<W: LayoutElement> Workspace<W> {
let source_column_idx = self.active_column_idx + 1;
- let offset_x = self.column_x(source_column_idx)
+ let offset = self.column_x(source_column_idx)
+ self.columns[source_column_idx].render_offset().x
- self.column_x(self.active_column_idx);
- let prev_y = self.columns[source_column_idx].tile_y(0);
+ let mut offset = Point::from((offset, 0));
+ let prev_off = self.columns[source_column_idx].tile_offset(0);
let tile = self.remove_tile_by_idx(source_column_idx, 0, None);
self.enter_output_for_window(tile.window());
@@ -1700,18 +1765,20 @@ impl<W: LayoutElement> Workspace<W> {
let target_column = &mut self.columns[self.active_column_idx];
let was_fullscreen = target_column.tiles[target_column.active_tile_idx].is_fullscreen();
- let offset_y = prev_y - target_column.tile_y(target_column.tiles.len());
target_column.add_tile(tile, true);
+ self.data[self.active_column_idx].update(target_column);
+
+ offset += prev_off - target_column.tile_offset(target_column.tiles.len() - 1);
if !was_fullscreen {
self.view_offset_before_fullscreen = None;
}
- let offset_x = offset_x - target_column.render_offset().x;
+ offset.x -= target_column.render_offset().x;
let new_tile = target_column.tiles.last_mut().unwrap();
- new_tile.animate_move_from(Point::from((offset_x, offset_y)));
+ new_tile.animate_move_from(offset);
// Consuming a window into a column could've increased its width if the new window had a
// larger min width. Move the next columns to account for this.
@@ -1726,17 +1793,17 @@ impl<W: LayoutElement> Workspace<W> {
return;
}
- let offset_x =
+ let offset =
self.column_x(self.active_column_idx) - self.column_x(self.active_column_idx + 1);
+ let mut offset = Point::from((offset, 0));
let source_column = &self.columns[self.active_column_idx];
if source_column.tiles.len() == 1 {
return;
}
- let offset_x = offset_x + source_column.render_offset().x;
-
- let prev_y = source_column.tile_y(source_column.active_tile_idx);
+ offset.x += source_column.render_offset().x;
+ let prev_off = source_column.tile_offset(source_column.active_tile_idx);
let width = source_column.width;
let is_full_width = source_column.is_full_width;
@@ -1752,8 +1819,8 @@ impl<W: LayoutElement> Workspace<W> {
);
let new_col = &mut self.columns[self.active_column_idx];
- let offset_y = prev_y - new_col.tile_y(0);
- new_col.tiles[0].animate_move_from(Point::from((offset_x, offset_y)));
+ offset += prev_off - new_col.tile_offset(0);
+ new_col.tiles[0].animate_move_from(offset);
}
pub fn center_column(&mut self) {
@@ -1786,89 +1853,113 @@ impl<W: LayoutElement> Workspace<W> {
}
}
- fn tiles_in_render_order(&self) -> impl Iterator<Item = (&'_ Tile<W>, Point<i32, Logical>)> {
- let view_pos = self.view_pos();
-
- // Start with the active window since it's drawn on top.
- let col = &self.columns[self.active_column_idx];
- let col_width = col.width();
- let tile = &col.tiles[col.active_tile_idx];
- let tile_pos = Point::from((-self.view_offset, col.tile_y(col.active_tile_idx)))
- + col.render_offset()
- + Column::render_offset_for_tile(tile, col_width, &self.options)
- + tile.render_offset();
- let first = iter::once((tile, tile_pos));
-
- // Next, the rest of the tiles in the active column, since it should be drawn on top as a
- // whole during animations.
- let next =
- zip(&col.tiles, col.tile_ys())
- .enumerate()
- .filter_map(move |(tile_idx, (tile, y))| {
- if tile_idx == col.active_tile_idx {
- // Active tile comes first.
- return None;
- }
+ // HACK: pass a self.data iterator in manually as a workaround for the lack of method partial
+ // borrowing. Note that this method's return value does not borrow the entire &Self!
+ fn column_xs(&self, data: impl Iterator<Item = ColumnData>) -> impl Iterator<Item = i32> {
+ let gaps = self.options.gaps;
+ let mut x = 0;
- let tile_pos = Point::from((-self.view_offset, y))
- + col.render_offset()
- + Column::render_offset_for_tile(tile, col_width, &self.options)
- + tile.render_offset();
- Some((tile, tile_pos))
- });
+ // Chain with a dummy value to be able to get one past all columns' X.
+ let dummy = ColumnData { width: 0 };
+ let data = data.chain(iter::once(dummy));
- let mut x = -view_pos;
- let rest = self
- .columns
- .iter()
+ data.map(move |data| {
+ let rv = x;
+ x += data.width + gaps;
+ rv
+ })
+ }
+
+ fn column_x(&self, column_idx: usize) -> i32 {
+ self.column_xs(self.data.iter().copied())
+ .nth(column_idx)
+ .unwrap()
+ }
+
+ fn column_xs_in_render_order(
+ &self,
+ data: impl Iterator<Item = ColumnData>,
+ ) -> impl Iterator<Item = i32> {
+ let active_idx = self.active_column_idx;
+ let active_pos = self.column_x(active_idx);
+ let offsets = self
+ .column_xs(data)
.enumerate()
- // Keep track of column X position.
- .map(move |(col_idx, col)| {
- let col_width = col.width();
- let rv = (col_idx, col, col_width, x);
- x += col_width + self.options.gaps;