aboutsummaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-10-11 19:52:03 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-10-12 09:58:03 +0300
commitd5cbc35811dc758753b4f74b05a8c439fd850d83 (patch)
tree76c1523953a23c5a623b6d4dcf237941a93cfab0 /src/layout
parenta038c5aaabd1cf4224268518f7c8840ae7b30078 (diff)
downloadniri-d5cbc35811dc758753b4f74b05a8c439fd850d83.tar.gz
niri-d5cbc35811dc758753b4f74b05a8c439fd850d83.tar.bz2
niri-d5cbc35811dc758753b4f74b05a8c439fd850d83.zip
Implement ConsumeOrExpelWindow{Left,Right} by id
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/mod.rs82
-rw-r--r--src/layout/monitor.rs8
-rw-r--r--src/layout/workspace.rs147
3 files changed, 164 insertions, 73 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 7fe0d230..0a1063fb 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -1340,18 +1340,38 @@ impl<W: LayoutElement> Layout<W> {
monitor.move_up_or_to_workspace_up();
}
- pub fn consume_or_expel_window_left(&mut self) {
- let Some(monitor) = self.active_monitor() else {
+ pub fn consume_or_expel_window_left(&mut self, window: Option<&W::Id>) {
+ let workspace = if let Some(window) = window {
+ Some(
+ self.workspaces_mut()
+ .find(|ws| ws.has_window(window))
+ .unwrap(),
+ )
+ } else {
+ self.active_workspace_mut()
+ };
+
+ let Some(workspace) = workspace else {
return;
};
- monitor.consume_or_expel_window_left();
+ workspace.consume_or_expel_window_left(window);
}
- pub fn consume_or_expel_window_right(&mut self) {
- let Some(monitor) = self.active_monitor() else {
+ pub fn consume_or_expel_window_right(&mut self, window: Option<&W::Id>) {
+ let workspace = if let Some(window) = window {
+ Some(
+ self.workspaces_mut()
+ .find(|ws| ws.has_window(window))
+ .unwrap(),
+ )
+ } else {
+ self.active_workspace_mut()
+ };
+
+ let Some(workspace) = workspace else {
return;
};
- monitor.consume_or_expel_window_right();
+ workspace.consume_or_expel_window_right(window);
}
pub fn focus_left(&mut self) {
@@ -3011,8 +3031,14 @@ mod tests {
MoveWindowUp,
MoveWindowDownOrToWorkspaceDown,
MoveWindowUpOrToWorkspaceUp,
- ConsumeOrExpelWindowLeft,
- ConsumeOrExpelWindowRight,
+ ConsumeOrExpelWindowLeft {
+ #[proptest(strategy = "proptest::option::of(1..=5usize)")]
+ id: Option<usize>,
+ },
+ ConsumeOrExpelWindowRight {
+ #[proptest(strategy = "proptest::option::of(1..=5usize)")]
+ id: Option<usize>,
+ },
ConsumeWindowIntoColumn,
ExpelWindowFromColumn,
CenterColumn,
@@ -3420,8 +3446,14 @@ mod tests {
Op::MoveWindowUp => layout.move_up(),
Op::MoveWindowDownOrToWorkspaceDown => layout.move_down_or_to_workspace_down(),
Op::MoveWindowUpOrToWorkspaceUp => layout.move_up_or_to_workspace_up(),
- Op::ConsumeOrExpelWindowLeft => layout.consume_or_expel_window_left(),
- Op::ConsumeOrExpelWindowRight => layout.consume_or_expel_window_right(),
+ Op::ConsumeOrExpelWindowLeft { id } => {
+ let id = id.filter(|id| layout.has_window(id));
+ layout.consume_or_expel_window_left(id.as_ref());
+ }
+ Op::ConsumeOrExpelWindowRight { id } => {
+ let id = id.filter(|id| layout.has_window(id));
+ layout.consume_or_expel_window_right(id.as_ref());
+ }
Op::ConsumeWindowIntoColumn => layout.consume_into_column(),
Op::ExpelWindowFromColumn => layout.expel_from_column(),
Op::CenterColumn => layout.center_column(),
@@ -3700,8 +3732,8 @@ mod tests {
Op::MoveWindowDownOrToWorkspaceDown,
Op::MoveWindowUp,
Op::MoveWindowUpOrToWorkspaceUp,
- Op::ConsumeOrExpelWindowLeft,
- Op::ConsumeOrExpelWindowRight,
+ Op::ConsumeOrExpelWindowLeft { id: None },
+ Op::ConsumeOrExpelWindowRight { id: None },
Op::MoveWorkspaceToOutput(1),
];
@@ -3897,8 +3929,8 @@ mod tests {
Op::MoveWindowDownOrToWorkspaceDown,
Op::MoveWindowUp,
Op::MoveWindowUpOrToWorkspaceUp,
- Op::ConsumeOrExpelWindowLeft,
- Op::ConsumeOrExpelWindowRight,
+ Op::ConsumeOrExpelWindowLeft { id: None },
+ Op::ConsumeOrExpelWindowRight { id: None },
];
for third in every_op {
@@ -4233,7 +4265,7 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: (Size::from((0, 0)), Size::from((i32::MAX, i32::MAX))),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::SetFullscreenWindow {
window: 2,
is_fullscreen: false,
@@ -4301,7 +4333,7 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowRight,
+ Op::ConsumeOrExpelWindowRight { id: None },
];
check_ops(&ops);
@@ -4358,7 +4390,7 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::FullscreenWindow(0),
];
@@ -4459,7 +4491,7 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (1280, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::SwitchPresetWindowHeight { id: None },
Op::SwitchPresetWindowHeight { id: None },
];
@@ -4554,13 +4586,13 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::AddWindow {
id: 2,
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::SetWindowHeight {
id: None,
change: SizeChange::SetFixed(100),
@@ -4589,13 +4621,13 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::AddWindow {
id: 2,
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::SetWindowHeight {
id: None,
change: SizeChange::SetFixed(100),
@@ -4628,13 +4660,13 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::AddWindow {
id: 2,
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
Op::SetWindowHeight {
id: None,
change: SizeChange::SetFixed(100),
@@ -4671,7 +4703,7 @@ mod tests {
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
min_max_size: Default::default(),
},
- Op::ConsumeOrExpelWindowLeft,
+ Op::ConsumeOrExpelWindowLeft { id: None },
];
let options = Options {
diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs
index 9e2c6e27..e1cfb512 100644
--- a/src/layout/monitor.rs
+++ b/src/layout/monitor.rs
@@ -325,14 +325,6 @@ impl<W: LayoutElement> Monitor<W> {
}
}
- pub fn consume_or_expel_window_left(&mut self) {
- self.active_workspace().consume_or_expel_window_left();
- }
-
- pub fn consume_or_expel_window_right(&mut self) {
- self.active_workspace().consume_or_expel_window_right();
- }
-
pub fn focus_left(&mut self) {
self.active_workspace().focus_left();
}
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 55d18a06..d115f07c 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -1798,28 +1798,59 @@ impl<W: LayoutElement> Workspace<W> {
self.columns[self.active_column_idx].move_up();
}
- pub fn consume_or_expel_window_left(&mut self) {
+ pub fn consume_or_expel_window_left(&mut self, window: Option<&W::Id>) {
if self.columns.is_empty() {
return;
}
- let source_col_idx = self.active_column_idx;
+ let (source_col_idx, source_tile_idx) = if let Some(window) = window {
+ self.columns
+ .iter_mut()
+ .enumerate()
+ .find_map(|(col_idx, col)| {
+ col.tiles
+ .iter()
+ .position(|tile| tile.window().id() == window)
+ .map(|tile_idx| (col_idx, tile_idx))
+ })
+ .unwrap()
+ } else {
+ let source_col_idx = self.active_column_idx;
+ let source_tile_idx = self.columns[self.active_column_idx].active_tile_idx;
+ (source_col_idx, source_tile_idx)
+ };
+
let source_column = &self.columns[source_col_idx];
- let prev_off = source_column.tile_offset(source_column.active_tile_idx);
+ let prev_off = source_column.tile_offset(source_tile_idx);
+
+ let source_tile_was_active = self.active_column_idx == source_col_idx
+ && source_column.active_tile_idx == source_tile_idx;
if source_column.tiles.len() == 1 {
- if self.active_column_idx == 0 {
+ if source_col_idx == 0 {
return;
}
- 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 = if self.active_column_idx <= source_col_idx {
+ // Tiles to the right animate from the following column.
+ self.column_x(source_col_idx) - self.column_x(target_column_idx)
+ } else {
+ // Tiles to the left animate to preserve their right edge position.
+ f64::max(
+ 0.,
+ self.data[target_column_idx].width - self.data[source_col_idx].width,
+ )
+ };
+ let mut offset = Point::from((offset, 0.));
+
+ if source_tile_was_active {
+ // 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);
+ }
+
offset.x += self.columns[source_col_idx].render_offset().x;
let tile = self.remove_tile_by_idx(
source_col_idx,
@@ -1827,7 +1858,7 @@ impl<W: LayoutElement> Workspace<W> {
Transaction::new(),
Some(self.options.animations.window_movement.0),
);
- self.add_tile_to_column(target_column_idx, None, tile, true);
+ self.add_tile_to_column(target_column_idx, None, tile, source_tile_was_active);
let target_column = &mut self.columns[target_column_idx];
offset.x -= target_column.render_offset().x;
@@ -1842,63 +1873,91 @@ impl<W: LayoutElement> Workspace<W> {
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,
- Transaction::new(),
- None,
- );
+ let tile =
+ self.remove_tile_by_idx(source_col_idx, source_tile_idx, Transaction::new(), None);
+
+ // We're inserting into the source column position.
+ let target_column_idx = source_col_idx;
self.add_tile(
- Some(self.active_column_idx),
+ Some(target_column_idx),
tile,
- true,
+ source_tile_was_active,
width,
is_full_width,
Some(self.options.animations.window_movement.0),
);
- // We added to the left, don't activate even further left on removal.
- self.activate_prev_column_on_removal = None;
+ if source_tile_was_active {
+ // We added to the left, don't activate even further left on removal.
+ self.activate_prev_column_on_removal = None;
+ }
- let new_col = &mut self.columns[self.active_column_idx];
+ if target_column_idx < self.active_column_idx {
+ // Tiles to the left animate from the following column.
+ offset.x += self.column_x(target_column_idx + 1) - self.column_x(target_column_idx);
+ }
+
+ let new_col = &mut self.columns[target_column_idx];
offset += prev_off - new_col.tile_offset(0);
new_col.tiles[0].animate_move_from(offset);
}
}
- pub fn consume_or_expel_window_right(&mut self) {
+ pub fn consume_or_expel_window_right(&mut self, window: Option<&W::Id>) {
if self.columns.is_empty() {
return;
}
- let source_col_idx = self.active_column_idx;
- let offset = self.column_x(source_col_idx) - self.column_x(source_col_idx + 1);
- let mut offset = Point::from((offset, 0.));
+ let (source_col_idx, source_tile_idx) = if let Some(window) = window {
+ self.columns
+ .iter_mut()
+ .enumerate()
+ .find_map(|(col_idx, col)| {
+ col.tiles
+ .iter()
+ .position(|tile| tile.window().id() == window)
+ .map(|tile_idx| (col_idx, tile_idx))
+ })
+ .unwrap()
+ } else {
+ let source_col_idx = self.active_column_idx;
+ let source_tile_idx = self.columns[self.active_column_idx].active_tile_idx;
+ (source_col_idx, source_tile_idx)
+ };
+
+ let cur_x = self.column_x(source_col_idx);
let source_column = &self.columns[source_col_idx];
- offset.x += source_column.render_offset().x;
- let prev_off = source_column.tile_offset(source_column.active_tile_idx);
+ let mut offset = Point::from((source_column.render_offset().x, 0.));
+ let prev_off = source_column.tile_offset(source_tile_idx);
+
+ let source_tile_was_active = self.active_column_idx == source_col_idx
+ && source_column.active_tile_idx == source_tile_idx;
if source_column.tiles.len() == 1 {
- if self.active_column_idx + 1 == self.columns.len() {
+ if source_col_idx + 1 == self.columns.len() {
return;
}
// Move into adjacent column.
let target_column_idx = source_col_idx;
+ offset.x += cur_x - self.column_x(source_col_idx + 1);
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;
+ if source_tile_was_active {
+ // Make sure the target column gets activated.
+ self.activate_prev_column_on_removal = None;
+ }
+
let tile = self.remove_tile_by_idx(
source_col_idx,
0,
Transaction::new(),
Some(self.options.animations.window_movement.0),
);
- self.add_tile_to_column(target_column_idx, None, tile, true);
+ self.add_tile_to_column(target_column_idx, None, tile, source_tile_was_active);
let target_column = &mut self.columns[target_column_idx];
offset += prev_off - target_column.tile_offset(target_column.tiles.len() - 1);
@@ -1910,23 +1969,31 @@ impl<W: LayoutElement> Workspace<W> {
let width = source_column.width;
let is_full_width = source_column.is_full_width;
- let tile = self.remove_tile_by_idx(
- source_col_idx,
- source_column.active_tile_idx,
- Transaction::new(),
- None,
- );
+ let prev_width = self.data[source_col_idx].width;
+
+ let tile =
+ self.remove_tile_by_idx(source_col_idx, source_tile_idx, Transaction::new(), None);
+
+ let target_column_idx = source_col_idx + 1;
self.add_tile(
- Some(self.active_column_idx + 1),
+ Some(target_column_idx),
tile,
- true,
+ source_tile_was_active,
width,
is_full_width,
Some(self.options.animations.window_movement.0),
);
- let new_col = &mut self.columns[self.active_column_idx];
+ offset.x += if self.active_column_idx <= target_column_idx {
+ // Tiles to the right animate to the following column.
+ cur_x - self.column_x(target_column_idx)
+ } else {
+ // Tiles to the left animate for a change in width.
+ -f64::max(0., prev_width - self.data[target_column_idx].width)
+ };
+
+ let new_col = &mut self.columns[target_column_idx];
offset += prev_off - new_col.tile_offset(0);
new_col.tiles[0].animate_move_from(offset);
}