Fix focus=false for move-column-to-workspace*, add to move-window-to-workspace-up/down

This commit is contained in:
gibberish
2025-06-16 17:23:29 +07:00
committed by Ivan Molodetskikh
parent f6f4bf97c3
commit e038b8770a
8 changed files with 122 additions and 41 deletions
+8 -4
View File
@@ -1844,8 +1844,8 @@ pub enum Action {
FocusWorkspaceUpUnderMouse, FocusWorkspaceUpUnderMouse,
FocusWorkspace(#[knuffel(argument)] WorkspaceReference), FocusWorkspace(#[knuffel(argument)] WorkspaceReference),
FocusWorkspacePrevious, FocusWorkspacePrevious,
MoveWindowToWorkspaceDown, MoveWindowToWorkspaceDown(#[knuffel(property(name = "focus"), default = true)] bool),
MoveWindowToWorkspaceUp, MoveWindowToWorkspaceUp(#[knuffel(property(name = "focus"), default = true)] bool),
MoveWindowToWorkspace( MoveWindowToWorkspace(
#[knuffel(argument)] WorkspaceReference, #[knuffel(argument)] WorkspaceReference,
#[knuffel(property(name = "focus"), default = true)] bool, #[knuffel(property(name = "focus"), default = true)] bool,
@@ -2089,8 +2089,12 @@ impl From<niri_ipc::Action> for Action {
Self::FocusWorkspace(WorkspaceReference::from(reference)) Self::FocusWorkspace(WorkspaceReference::from(reference))
} }
niri_ipc::Action::FocusWorkspacePrevious {} => Self::FocusWorkspacePrevious, niri_ipc::Action::FocusWorkspacePrevious {} => Self::FocusWorkspacePrevious,
niri_ipc::Action::MoveWindowToWorkspaceDown {} => Self::MoveWindowToWorkspaceDown, niri_ipc::Action::MoveWindowToWorkspaceDown { focus } => {
niri_ipc::Action::MoveWindowToWorkspaceUp {} => Self::MoveWindowToWorkspaceUp, Self::MoveWindowToWorkspaceDown(focus)
}
niri_ipc::Action::MoveWindowToWorkspaceUp { focus } => {
Self::MoveWindowToWorkspaceUp(focus)
}
niri_ipc::Action::MoveWindowToWorkspace { niri_ipc::Action::MoveWindowToWorkspace {
window_id: None, window_id: None,
reference, reference,
+16 -2
View File
@@ -447,9 +447,23 @@ pub enum Action {
/// Focus the previous workspace. /// Focus the previous workspace.
FocusWorkspacePrevious {}, FocusWorkspacePrevious {},
/// Move the focused window to the workspace below. /// Move the focused window to the workspace below.
MoveWindowToWorkspaceDown {}, MoveWindowToWorkspaceDown {
/// Whether the focus should follow the target workspace.
///
/// If `true` (the default), the focus will follow the window to the new workspace. If
/// `false`, the focus will remain on the original workspace.
#[cfg_attr(feature = "clap", arg(long, action = clap::ArgAction::Set, default_value_t = true))]
focus: bool,
},
/// Move the focused window to the workspace above. /// Move the focused window to the workspace above.
MoveWindowToWorkspaceUp {}, MoveWindowToWorkspaceUp {
/// Whether the focus should follow the target workspace.
///
/// If `true` (the default), the focus will follow the window to the new workspace. If
/// `false`, the focus will remain on the original workspace.
#[cfg_attr(feature = "clap", arg(long, action = clap::ArgAction::Set, default_value_t = true))]
focus: bool,
},
/// Move a window to a workspace. /// Move a window to a workspace.
#[cfg_attr( #[cfg_attr(
feature = "clap", feature = "clap",
+4 -4
View File
@@ -1138,14 +1138,14 @@ impl State {
// FIXME: granular // FIXME: granular
self.niri.queue_redraw_all(); self.niri.queue_redraw_all();
} }
Action::MoveWindowToWorkspaceDown => { Action::MoveWindowToWorkspaceDown(focus) => {
self.niri.layout.move_to_workspace_down(); self.niri.layout.move_to_workspace_down(focus);
self.maybe_warp_cursor_to_focus(); self.maybe_warp_cursor_to_focus();
// FIXME: granular // FIXME: granular
self.niri.queue_redraw_all(); self.niri.queue_redraw_all();
} }
Action::MoveWindowToWorkspaceUp => { Action::MoveWindowToWorkspaceUp(focus) => {
self.niri.layout.move_to_workspace_up(); self.niri.layout.move_to_workspace_up(focus);
self.maybe_warp_cursor_to_focus(); self.maybe_warp_cursor_to_focus();
// FIXME: granular // FIXME: granular
self.niri.queue_redraw_all(); self.niri.queue_redraw_all();
+4 -4
View File
@@ -2178,18 +2178,18 @@ impl<W: LayoutElement> Layout<W> {
workspace.focus_window_up_or_bottom(); workspace.focus_window_up_or_bottom();
} }
pub fn move_to_workspace_up(&mut self) { pub fn move_to_workspace_up(&mut self, focus: bool) {
let Some(monitor) = self.active_monitor() else { let Some(monitor) = self.active_monitor() else {
return; return;
}; };
monitor.move_to_workspace_up(); monitor.move_to_workspace_up(focus);
} }
pub fn move_to_workspace_down(&mut self) { pub fn move_to_workspace_down(&mut self, focus: bool) {
let Some(monitor) = self.active_monitor() else { let Some(monitor) = self.active_monitor() else {
return; return;
}; };
monitor.move_to_workspace_down(); monitor.move_to_workspace_down(focus);
} }
pub fn move_to_workspace( pub fn move_to_workspace(
+26 -9
View File
@@ -601,13 +601,13 @@ impl<W: LayoutElement> Monitor<W> {
pub fn move_down_or_to_workspace_down(&mut self) { pub fn move_down_or_to_workspace_down(&mut self) {
if !self.active_workspace().move_down() { if !self.active_workspace().move_down() {
self.move_to_workspace_down(); self.move_to_workspace_down(true);
} }
} }
pub fn move_up_or_to_workspace_up(&mut self) { pub fn move_up_or_to_workspace_up(&mut self) {
if !self.active_workspace().move_up() { if !self.active_workspace().move_up() {
self.move_to_workspace_up(); self.move_to_workspace_up(true);
} }
} }
@@ -623,7 +623,7 @@ impl<W: LayoutElement> Monitor<W> {
} }
} }
pub fn move_to_workspace_up(&mut self) { pub fn move_to_workspace_up(&mut self, focus: bool) {
let source_workspace_idx = self.active_workspace_idx; let source_workspace_idx = self.active_workspace_idx;
let new_idx = source_workspace_idx.saturating_sub(1); let new_idx = source_workspace_idx.saturating_sub(1);
@@ -637,13 +637,19 @@ impl<W: LayoutElement> Monitor<W> {
return; return;
}; };
let activate = if focus {
ActivateWindow::Yes
} else {
ActivateWindow::Smart
};
self.add_tile( self.add_tile(
removed.tile, removed.tile,
MonitorAddWindowTarget::Workspace { MonitorAddWindowTarget::Workspace {
id: new_id, id: new_id,
column_idx: None, column_idx: None,
}, },
ActivateWindow::Yes, activate,
true, true,
removed.width, removed.width,
removed.is_full_width, removed.is_full_width,
@@ -651,7 +657,7 @@ impl<W: LayoutElement> Monitor<W> {
); );
} }
pub fn move_to_workspace_down(&mut self) { pub fn move_to_workspace_down(&mut self, focus: bool) {
let source_workspace_idx = self.active_workspace_idx; let source_workspace_idx = self.active_workspace_idx;
let new_idx = min(source_workspace_idx + 1, self.workspaces.len() - 1); let new_idx = min(source_workspace_idx + 1, self.workspaces.len() - 1);
@@ -665,13 +671,19 @@ impl<W: LayoutElement> Monitor<W> {
return; return;
}; };
let activate = if focus {
ActivateWindow::Yes
} else {
ActivateWindow::Smart
};
self.add_tile( self.add_tile(
removed.tile, removed.tile,
MonitorAddWindowTarget::Workspace { MonitorAddWindowTarget::Workspace {
id: new_id, id: new_id,
column_idx: None, column_idx: None,
}, },
ActivateWindow::Yes, activate,
true, true,
removed.width, removed.width,
removed.is_full_width, removed.is_full_width,
@@ -748,7 +760,7 @@ impl<W: LayoutElement> Monitor<W> {
let workspace = &mut self.workspaces[source_workspace_idx]; let workspace = &mut self.workspaces[source_workspace_idx];
if workspace.floating_is_active() { if workspace.floating_is_active() {
self.move_to_workspace_up(); self.move_to_workspace_up(activate);
return; return;
} }
@@ -769,7 +781,7 @@ impl<W: LayoutElement> Monitor<W> {
let workspace = &mut self.workspaces[source_workspace_idx]; let workspace = &mut self.workspaces[source_workspace_idx];
if workspace.floating_is_active() { if workspace.floating_is_active() {
self.move_to_workspace_down(); self.move_to_workspace_down(activate);
return; return;
} }
@@ -790,7 +802,12 @@ impl<W: LayoutElement> Monitor<W> {
let workspace = &mut self.workspaces[source_workspace_idx]; let workspace = &mut self.workspaces[source_workspace_idx];
if workspace.floating_is_active() { if workspace.floating_is_active() {
self.move_to_workspace(None, idx, ActivateWindow::Smart); let activate = if activate {
ActivateWindow::Smart
} else {
ActivateWindow::No
};
self.move_to_workspace(None, idx, activate);
return; return;
} }
+56 -10
View File
@@ -497,8 +497,8 @@ enum Op {
FocusWorkspace(#[proptest(strategy = "0..=4usize")] usize), FocusWorkspace(#[proptest(strategy = "0..=4usize")] usize),
FocusWorkspaceAutoBackAndForth(#[proptest(strategy = "0..=4usize")] usize), FocusWorkspaceAutoBackAndForth(#[proptest(strategy = "0..=4usize")] usize),
FocusWorkspacePrevious, FocusWorkspacePrevious,
MoveWindowToWorkspaceDown, MoveWindowToWorkspaceDown(bool),
MoveWindowToWorkspaceUp, MoveWindowToWorkspaceUp(bool),
MoveWindowToWorkspace { MoveWindowToWorkspace {
#[proptest(strategy = "proptest::option::of(1..=5usize)")] #[proptest(strategy = "proptest::option::of(1..=5usize)")]
window_id: Option<usize>, window_id: Option<usize>,
@@ -1113,8 +1113,8 @@ impl Op {
layout.switch_workspace_auto_back_and_forth(idx) layout.switch_workspace_auto_back_and_forth(idx)
} }
Op::FocusWorkspacePrevious => layout.switch_workspace_previous(), Op::FocusWorkspacePrevious => layout.switch_workspace_previous(),
Op::MoveWindowToWorkspaceDown => layout.move_to_workspace_down(), Op::MoveWindowToWorkspaceDown(focus) => layout.move_to_workspace_down(focus),
Op::MoveWindowToWorkspaceUp => layout.move_to_workspace_up(), Op::MoveWindowToWorkspaceUp(focus) => layout.move_to_workspace_up(focus),
Op::MoveWindowToWorkspace { Op::MoveWindowToWorkspace {
window_id, window_id,
workspace_idx, workspace_idx,
@@ -1615,8 +1615,8 @@ fn operations_dont_panic() {
Op::FocusWorkspaceUp, Op::FocusWorkspaceUp,
Op::FocusWorkspace(1), Op::FocusWorkspace(1),
Op::FocusWorkspace(2), Op::FocusWorkspace(2),
Op::MoveWindowToWorkspaceDown, Op::MoveWindowToWorkspaceDown(true),
Op::MoveWindowToWorkspaceUp, Op::MoveWindowToWorkspaceUp(true),
Op::MoveWindowToWorkspace { Op::MoveWindowToWorkspace {
window_id: None, window_id: None,
workspace_idx: 1, workspace_idx: 1,
@@ -1671,7 +1671,7 @@ fn operations_from_starting_state_dont_panic() {
Op::AddWindow { Op::AddWindow {
params: TestWindowParams::new(1), params: TestWindowParams::new(1),
}, },
Op::MoveWindowToWorkspaceDown, Op::MoveWindowToWorkspaceDown(true),
Op::AddWindow { Op::AddWindow {
params: TestWindowParams::new(2), params: TestWindowParams::new(2),
}, },
@@ -1786,8 +1786,8 @@ fn operations_from_starting_state_dont_panic() {
Op::FocusWorkspace(1), Op::FocusWorkspace(1),
Op::FocusWorkspace(2), Op::FocusWorkspace(2),
Op::FocusWorkspace(3), Op::FocusWorkspace(3),
Op::MoveWindowToWorkspaceDown, Op::MoveWindowToWorkspaceDown(true),
Op::MoveWindowToWorkspaceUp, Op::MoveWindowToWorkspaceUp(true),
Op::MoveWindowToWorkspace { Op::MoveWindowToWorkspace {
window_id: None, window_id: None,
workspace_idx: 1, workspace_idx: 1,
@@ -3366,7 +3366,7 @@ fn move_pending_unfullscreen_window_out_of_active_column() {
Op::ConsumeWindowIntoColumn, Op::ConsumeWindowIntoColumn,
// Window 1 is now pending unfullscreen. // Window 1 is now pending unfullscreen.
// Moving it out should reset view_offset_before_fullscreen. // Moving it out should reset view_offset_before_fullscreen.
Op::MoveWindowToWorkspaceDown, Op::MoveWindowToWorkspaceDown(true),
]; ];
check_ops(&ops); check_ops(&ops);
@@ -3583,6 +3583,52 @@ fn unfullscreen_view_offset_not_reset_during_ongoing_gesture() {
check_ops(&ops); check_ops(&ops);
} }
#[test]
fn move_column_to_workspace_down_focus_false_on_floating_window() {
let ops = [
Op::AddOutput(1),
Op::AddWindow {
params: TestWindowParams::new(1),
},
Op::AddWindow {
params: TestWindowParams::new(2),
},
Op::ToggleWindowFloating { id: None },
Op::MoveColumnToWorkspaceDown(false),
];
let layout = check_ops(&ops);
let MonitorSet::Normal { monitors, .. } = layout.monitor_set else {
unreachable!()
};
assert_eq!(monitors[0].active_workspace_idx, 0);
}
#[test]
fn move_column_to_workspace_focus_false_on_floating_window() {
let ops = [
Op::AddOutput(1),
Op::AddWindow {
params: TestWindowParams::new(1),
},
Op::AddWindow {
params: TestWindowParams::new(2),
},
Op::ToggleWindowFloating { id: None },
Op::MoveColumnToWorkspace(1, false),
];
let layout = check_ops(&ops);
let MonitorSet::Normal { monitors, .. } = layout.monitor_set else {
unreachable!()
};
assert_eq!(monitors[0].active_workspace_idx, 0);
}
fn parent_id_causes_loop(layout: &Layout<TestWindow>, id: usize, mut parent_id: usize) -> bool { fn parent_id_causes_loop(layout: &Layout<TestWindow>, id: usize, mut parent_id: usize) -> bool {
if parent_id == id { if parent_id == id {
return true; return true;
+2 -2
View File
@@ -349,7 +349,7 @@ fn moving_across_workspaces_doesnt_cancel_resize() {
// Move to a different workspace before the window has a chance to respond. This will remove it // Move to a different workspace before the window has a chance to respond. This will remove it
// from one floating layout and add into a different one, potentially causing a size request. // from one floating layout and add into a different one, potentially causing a size request.
f.niri().layout.move_to_workspace_down(); f.niri().layout.move_to_workspace_down(true);
// Drop the Activated state to force a configure. // Drop the Activated state to force a configure.
f.niri_focus_output(2); f.niri_focus_output(2);
f.double_roundtrip(id); f.double_roundtrip(id);
@@ -369,7 +369,7 @@ fn moving_across_workspaces_doesnt_cancel_resize() {
// Focus, adding Activated, and move to workspace down, causing removing and adding to a // Focus, adding Activated, and move to workspace down, causing removing and adding to a
// floating layout. // floating layout.
f.niri_focus_output(1); f.niri_focus_output(1);
f.niri().layout.move_to_workspace_down(); f.niri().layout.move_to_workspace_down(true);
f.double_roundtrip(id); f.double_roundtrip(id);
// This should request the current size (300 × 300) since the window responded to the change. // This should request the current size (300 × 300) since the window responded to the change.
+6 -6
View File
@@ -228,9 +228,9 @@ fn collect_actions(config: &Config) -> Vec<&Action> {
actions.push(&bind.action); actions.push(&bind.action);
} else if binds } else if binds
.iter() .iter()
.any(|bind| matches!(bind.action, Action::MoveWindowToWorkspaceDown)) .any(|bind| matches!(bind.action, Action::MoveWindowToWorkspaceDown(_)))
{ {
actions.push(&Action::MoveWindowToWorkspaceDown); actions.push(&Action::MoveWindowToWorkspaceDown(true));
} else { } else {
actions.push(&Action::MoveColumnToWorkspaceDown(true)); actions.push(&Action::MoveColumnToWorkspaceDown(true));
} }
@@ -243,9 +243,9 @@ fn collect_actions(config: &Config) -> Vec<&Action> {
actions.push(&bind.action); actions.push(&bind.action);
} else if binds } else if binds
.iter() .iter()
.any(|bind| matches!(bind.action, Action::MoveWindowToWorkspaceUp)) .any(|bind| matches!(bind.action, Action::MoveWindowToWorkspaceUp(_)))
{ {
actions.push(&Action::MoveWindowToWorkspaceUp); actions.push(&Action::MoveWindowToWorkspaceUp(true));
} else { } else {
actions.push(&Action::MoveColumnToWorkspaceUp(true)); actions.push(&Action::MoveColumnToWorkspaceUp(true));
} }
@@ -468,8 +468,8 @@ fn action_name(action: &Action) -> String {
Action::FocusWorkspaceUp => String::from("Switch Workspace Up"), Action::FocusWorkspaceUp => String::from("Switch Workspace Up"),
Action::MoveColumnToWorkspaceDown(_) => String::from("Move Column to Workspace Down"), Action::MoveColumnToWorkspaceDown(_) => String::from("Move Column to Workspace Down"),
Action::MoveColumnToWorkspaceUp(_) => String::from("Move Column to Workspace Up"), Action::MoveColumnToWorkspaceUp(_) => String::from("Move Column to Workspace Up"),
Action::MoveWindowToWorkspaceDown => String::from("Move Window to Workspace Down"), Action::MoveWindowToWorkspaceDown(_) => String::from("Move Window to Workspace Down"),
Action::MoveWindowToWorkspaceUp => String::from("Move Window to Workspace Up"), Action::MoveWindowToWorkspaceUp(_) => String::from("Move Window to Workspace Up"),
Action::SwitchPresetColumnWidth => String::from("Switch Preset Column Widths"), Action::SwitchPresetColumnWidth => String::from("Switch Preset Column Widths"),
Action::MaximizeColumn => String::from("Maximize Column"), Action::MaximizeColumn => String::from("Maximize Column"),
Action::ConsumeOrExpelWindowLeft => String::from("Consume or Expel Window Left"), Action::ConsumeOrExpelWindowLeft => String::from("Consume or Expel Window Left"),