mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
Add move-column-to-workspace* binds
As opposed to move-window-to-workspace*
This commit is contained in:
@@ -408,6 +408,9 @@ pub enum Action {
|
||||
MoveWindowToWorkspaceDown,
|
||||
MoveWindowToWorkspaceUp,
|
||||
MoveWindowToWorkspace(#[knuffel(argument)] u8),
|
||||
MoveColumnToWorkspaceDown,
|
||||
MoveColumnToWorkspaceUp,
|
||||
MoveColumnToWorkspace(#[knuffel(argument)] u8),
|
||||
MoveWorkspaceDown,
|
||||
MoveWorkspaceUp,
|
||||
FocusMonitorLeft,
|
||||
|
||||
@@ -458,6 +458,22 @@ impl State {
|
||||
// FIXME: granular
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
Action::MoveColumnToWorkspaceDown => {
|
||||
self.niri.layout.move_column_to_workspace_down();
|
||||
// FIXME: granular
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
Action::MoveColumnToWorkspaceUp => {
|
||||
self.niri.layout.move_column_to_workspace_up();
|
||||
// FIXME: granular
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
Action::MoveColumnToWorkspace(idx) => {
|
||||
let idx = idx.saturating_sub(1) as usize;
|
||||
self.niri.layout.move_column_to_workspace(idx);
|
||||
// FIXME: granular
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
Action::FocusWorkspaceDown => {
|
||||
self.niri.layout.switch_workspace_down();
|
||||
// FIXME: granular
|
||||
|
||||
@@ -897,6 +897,27 @@ impl<W: LayoutElement> Layout<W> {
|
||||
monitor.move_to_workspace(idx);
|
||||
}
|
||||
|
||||
pub fn move_column_to_workspace_up(&mut self) {
|
||||
let Some(monitor) = self.active_monitor() else {
|
||||
return;
|
||||
};
|
||||
monitor.move_column_to_workspace_up();
|
||||
}
|
||||
|
||||
pub fn move_column_to_workspace_down(&mut self) {
|
||||
let Some(monitor) = self.active_monitor() else {
|
||||
return;
|
||||
};
|
||||
monitor.move_column_to_workspace_down();
|
||||
}
|
||||
|
||||
pub fn move_column_to_workspace(&mut self, idx: usize) {
|
||||
let Some(monitor) = self.active_monitor() else {
|
||||
return;
|
||||
};
|
||||
monitor.move_column_to_workspace(idx);
|
||||
}
|
||||
|
||||
pub fn switch_workspace_up(&mut self) {
|
||||
let Some(monitor) = self.active_monitor() else {
|
||||
return;
|
||||
@@ -1608,6 +1629,9 @@ mod tests {
|
||||
MoveWindowToWorkspaceDown,
|
||||
MoveWindowToWorkspaceUp,
|
||||
MoveWindowToWorkspace(#[proptest(strategy = "0..=4usize")] usize),
|
||||
MoveColumnToWorkspaceDown,
|
||||
MoveColumnToWorkspaceUp,
|
||||
MoveColumnToWorkspace(#[proptest(strategy = "0..=4usize")] usize),
|
||||
MoveWorkspaceDown,
|
||||
MoveWorkspaceUp,
|
||||
MoveWindowToOutput(#[proptest(strategy = "1..=5u8")] u8),
|
||||
@@ -1729,6 +1753,9 @@ mod tests {
|
||||
Op::MoveWindowToWorkspaceDown => layout.move_to_workspace_down(),
|
||||
Op::MoveWindowToWorkspaceUp => layout.move_to_workspace_up(),
|
||||
Op::MoveWindowToWorkspace(idx) => layout.move_to_workspace(idx),
|
||||
Op::MoveColumnToWorkspaceDown => layout.move_column_to_workspace_down(),
|
||||
Op::MoveColumnToWorkspaceUp => layout.move_column_to_workspace_up(),
|
||||
Op::MoveColumnToWorkspace(idx) => layout.move_column_to_workspace(idx),
|
||||
Op::MoveWindowToOutput(id) => {
|
||||
let name = format!("output{id}");
|
||||
let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
|
||||
@@ -1855,6 +1882,11 @@ mod tests {
|
||||
Op::MoveWindowToWorkspace(1),
|
||||
Op::MoveWindowToWorkspace(2),
|
||||
Op::MoveWindowToWorkspace(3),
|
||||
Op::MoveColumnToWorkspaceDown,
|
||||
Op::MoveColumnToWorkspaceUp,
|
||||
Op::MoveColumnToWorkspace(1),
|
||||
Op::MoveColumnToWorkspace(2),
|
||||
Op::MoveColumnToWorkspace(3),
|
||||
Op::MoveWindowDown,
|
||||
Op::MoveWindowDownOrToWorkspaceDown,
|
||||
Op::MoveWindowUp,
|
||||
@@ -1977,6 +2009,11 @@ mod tests {
|
||||
Op::MoveWindowToWorkspace(1),
|
||||
Op::MoveWindowToWorkspace(2),
|
||||
Op::MoveWindowToWorkspace(3),
|
||||
Op::MoveColumnToWorkspaceDown,
|
||||
Op::MoveColumnToWorkspaceUp,
|
||||
Op::MoveColumnToWorkspace(1),
|
||||
Op::MoveColumnToWorkspace(2),
|
||||
Op::MoveColumnToWorkspace(3),
|
||||
Op::MoveWindowDown,
|
||||
Op::MoveWindowDownOrToWorkspaceDown,
|
||||
Op::MoveWindowUp,
|
||||
|
||||
+76
-1
@@ -12,7 +12,7 @@ use smithay::output::Output;
|
||||
use smithay::utils::{Logical, Point, Rectangle, Scale};
|
||||
|
||||
use super::workspace::{
|
||||
compute_working_area, ColumnWidth, OutputId, Workspace, WorkspaceRenderElement,
|
||||
compute_working_area, Column, ColumnWidth, OutputId, Workspace, WorkspaceRenderElement,
|
||||
};
|
||||
use super::{LayoutElement, Options};
|
||||
use crate::animation::Animation;
|
||||
@@ -127,6 +127,25 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_column(&mut self, workspace_idx: usize, column: Column<W>, activate: bool) {
|
||||
let workspace = &mut self.workspaces[workspace_idx];
|
||||
|
||||
workspace.add_column(column, activate);
|
||||
|
||||
// After adding a new window, workspace becomes this output's own.
|
||||
workspace.original_output = OutputId::new(&self.output);
|
||||
|
||||
if workspace_idx == self.workspaces.len() - 1 {
|
||||
// Insert a new empty workspace.
|
||||
let ws = Workspace::new(self.output.clone(), self.options.clone());
|
||||
self.workspaces.push(ws);
|
||||
}
|
||||
|
||||
if activate {
|
||||
self.activate_workspace(workspace_idx);
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_up_workspaces(&mut self) {
|
||||
assert!(self.workspace_switch.is_none());
|
||||
|
||||
@@ -323,6 +342,62 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
self.clean_up_workspaces();
|
||||
}
|
||||
|
||||
pub fn move_column_to_workspace_up(&mut self) {
|
||||
let source_workspace_idx = self.active_workspace_idx;
|
||||
|
||||
let new_idx = source_workspace_idx.saturating_sub(1);
|
||||
if new_idx == source_workspace_idx {
|
||||
return;
|
||||
}
|
||||
|
||||
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||
if workspace.columns.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let column = workspace.remove_column_by_idx(workspace.active_column_idx);
|
||||
self.add_column(new_idx, column, true);
|
||||
}
|
||||
|
||||
pub fn move_column_to_workspace_down(&mut self) {
|
||||
let source_workspace_idx = self.active_workspace_idx;
|
||||
|
||||
let new_idx = min(source_workspace_idx + 1, self.workspaces.len() - 1);
|
||||
if new_idx == source_workspace_idx {
|
||||
return;
|
||||
}
|
||||
|
||||
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||
if workspace.columns.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let column = workspace.remove_column_by_idx(workspace.active_column_idx);
|
||||
self.add_column(new_idx, column, true);
|
||||
}
|
||||
|
||||
pub fn move_column_to_workspace(&mut self, idx: usize) {
|
||||
let source_workspace_idx = self.active_workspace_idx;
|
||||
|
||||
let new_idx = min(idx, self.workspaces.len() - 1);
|
||||
if new_idx == source_workspace_idx {
|
||||
return;
|
||||
}
|
||||
|
||||
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||
if workspace.columns.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let column = workspace.remove_column_by_idx(workspace.active_column_idx);
|
||||
self.add_column(new_idx, column, true);
|
||||
|
||||
// Don't animate this action.
|
||||
self.workspace_switch = None;
|
||||
|
||||
self.clean_up_workspaces();
|
||||
}
|
||||
|
||||
pub fn switch_workspace_up(&mut self) {
|
||||
self.activate_workspace(self.active_workspace_idx.saturating_sub(1));
|
||||
}
|
||||
|
||||
@@ -574,6 +574,43 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_column(&mut self, mut column: Column<W>, activate: bool) {
|
||||
for tile in &column.tiles {
|
||||
self.enter_output_for_window(tile.window());
|
||||
}
|
||||
|
||||
let was_empty = self.columns.is_empty();
|
||||
|
||||
let idx = if self.columns.is_empty() {
|
||||
0
|
||||
} else {
|
||||
self.active_column_idx + 1
|
||||
};
|
||||
|
||||
column.set_view_size(self.view_size, self.working_area);
|
||||
let width = column.width();
|
||||
self.columns.insert(idx, column);
|
||||
|
||||
if activate {
|
||||
// If this is the first window on an empty workspace, skip the animation from whatever
|
||||
// view_offset was left over.
|
||||
if was_empty {
|
||||
if self.options.center_focused_column == CenterFocusedColumn::Always {
|
||||
self.view_offset =
|
||||
-(self.working_area.size.w - width) / 2 - self.working_area.loc.x;
|
||||
} else {
|
||||
// Try to make the code produce a left-aligned offset, even in presence of left
|
||||
// exclusive zones.
|
||||
self.view_offset = self.compute_new_view_offset_for_column(self.column_x(0), 0);
|
||||
}
|
||||
self.view_offset_anim = None;
|
||||
}
|
||||
|
||||
self.activate_column(idx);
|
||||
self.activate_prev_column_on_removal = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_window_by_idx(&mut self, column_idx: usize, window_idx: usize) -> W {
|
||||
let column = &mut self.columns[column_idx];
|
||||
let window = column.tiles.remove(window_idx).into_window();
|
||||
@@ -618,6 +655,42 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
window
|
||||
}
|
||||
|
||||
pub fn remove_column_by_idx(&mut self, column_idx: usize) -> Column<W> {
|
||||
let column = self.columns.remove(column_idx);
|
||||
|
||||
if let Some(output) = &self.output {
|
||||
for tile in &column.tiles {
|
||||
tile.window().output_leave(output);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
self.activate_prev_column_on_removal = false;
|
||||
}
|
||||
|
||||
// FIXME: activate_column below computes current view position to compute the new view
|
||||
// position, which can include the column we're removing here. This leads to unwanted
|
||||
// view jumps.
|
||||
if self.columns.is_empty() {
|
||||
return column;
|
||||
}
|
||||
|
||||
if self.active_column_idx > column_idx
|
||||
|| (self.active_column_idx == column_idx && self.activate_prev_column_on_removal)
|
||||
{
|
||||
// A column to the left was removed; preserve the current position.
|
||||
// FIXME: preserve activate_prev_column_on_removal.
|
||||
// Or, the active column was removed, and we needed to activate the previous column.
|
||||
self.activate_column(self.active_column_idx.saturating_sub(1));
|
||||
} else {
|
||||
self.activate_column(min(self.active_column_idx, self.columns.len() - 1));
|
||||
}
|
||||
|
||||
column
|
||||
}
|
||||
|
||||
pub fn remove_window(&mut self, window: &W) {
|
||||
let column_idx = self
|
||||
.columns
|
||||
|
||||
Reference in New Issue
Block a user