Add center-window by-id action

This commit is contained in:
Ivan Molodetskikh
2024-12-29 22:44:19 +03:00
parent 6cb5135f34
commit 6c897d5201
7 changed files with 88 additions and 4 deletions
+5
View File
@@ -1225,6 +1225,9 @@ pub enum Action {
ConsumeWindowIntoColumn,
ExpelWindowFromColumn,
CenterColumn,
CenterWindow,
#[knuffel(skip)]
CenterWindowById(u64),
FocusWorkspaceDown,
FocusWorkspaceUp,
FocusWorkspace(#[knuffel(argument)] WorkspaceReference),
@@ -1368,6 +1371,8 @@ impl From<niri_ipc::Action> for Action {
niri_ipc::Action::ConsumeWindowIntoColumn {} => Self::ConsumeWindowIntoColumn,
niri_ipc::Action::ExpelWindowFromColumn {} => Self::ExpelWindowFromColumn,
niri_ipc::Action::CenterColumn {} => Self::CenterColumn,
niri_ipc::Action::CenterWindow { id: None } => Self::CenterWindow,
niri_ipc::Action::CenterWindow { id: Some(id) } => Self::CenterWindowById(id),
niri_ipc::Action::FocusWorkspaceDown {} => Self::FocusWorkspaceDown,
niri_ipc::Action::FocusWorkspaceUp {} => Self::FocusWorkspaceUp,
niri_ipc::Action::FocusWorkspace { reference } => {
+12
View File
@@ -292,6 +292,18 @@ pub enum Action {
ExpelWindowFromColumn {},
/// Center the focused column on the screen.
CenterColumn {},
/// Center a window on the screen.
#[cfg_attr(
feature = "clap",
clap(about = "Center the focused window on the screen")
)]
CenterWindow {
/// Id of the window to center.
///
/// If `None`, uses the focused window.
#[cfg_attr(feature = "clap", arg(long))]
id: Option<u64>,
},
/// Focus the workspace below.
FocusWorkspaceDown {},
/// Focus the workspace above.
+14
View File
@@ -1127,6 +1127,20 @@ impl State {
// FIXME: granular
self.niri.queue_redraw_all();
}
Action::CenterWindow => {
self.niri.layout.center_window(None);
// FIXME: granular
self.niri.queue_redraw_all();
}
Action::CenterWindowById(id) => {
let window = self.niri.layout.windows().find(|(_, m)| m.id().get() == id);
let window = window.map(|(_, m)| m.window.clone());
if let Some(window) = window {
self.niri.layout.center_window(Some(&window));
// FIXME: granular
self.niri.queue_redraw_all();
}
}
Action::MaximizeColumn => {
self.niri.layout.toggle_full_width();
}
+3 -3
View File
@@ -902,11 +902,11 @@ impl<W: LayoutElement> FloatingSpace<W> {
self.move_to(idx, new_pos, animate);
}
pub fn center_window(&mut self) {
let Some(active_id) = &self.active_window_id else {
pub fn center_window(&mut self, id: Option<&W::Id>) {
let Some(id) = id.or(self.active_window_id.as_ref()).cloned() else {
return;
};
let idx = self.idx_of(active_id).unwrap();
let idx = self.idx_of(&id).unwrap();
let new_pos = center_preferring_top_left_in_area(self.working_area, self.data[idx].size);
self.move_to(idx, new_pos, true);
+21
View File
@@ -1993,6 +1993,19 @@ impl<W: LayoutElement> Layout<W> {
monitor.center_column();
}
pub fn center_window(&mut self, id: Option<&W::Id>) {
let workspace = if let Some(id) = id {
Some(self.workspaces_mut().find(|ws| ws.has_window(id)).unwrap())
} else {
self.active_workspace_mut()
};
let Some(workspace) = workspace else {
return;
};
workspace.center_window(id);
}
pub fn focus(&self) -> Option<&W> {
self.focus_with_output().map(|(win, _out)| win)
}
@@ -4390,6 +4403,10 @@ mod tests {
ConsumeWindowIntoColumn,
ExpelWindowFromColumn,
CenterColumn,
CenterWindow {
#[proptest(strategy = "proptest::option::of(1..=5usize)")]
id: Option<usize>,
},
FocusWorkspaceDown,
FocusWorkspaceUp,
FocusWorkspace(#[proptest(strategy = "0..=4usize")] usize),
@@ -4901,6 +4918,10 @@ mod tests {
Op::ConsumeWindowIntoColumn => layout.consume_into_column(),
Op::ExpelWindowFromColumn => layout.expel_from_column(),
Op::CenterColumn => layout.center_column(),
Op::CenterWindow { id } => {
let id = id.filter(|id| layout.has_window(id));
layout.center_window(id.as_ref());
}
Op::FocusWorkspaceDown => layout.switch_workspace_down(),
Op::FocusWorkspaceUp => layout.switch_workspace_up(),
Op::FocusWorkspace(idx) => layout.switch_workspace(idx),
+22
View File
@@ -1747,6 +1747,28 @@ impl<W: LayoutElement> ScrollingSpace<W> {
cancel_resize_for_column(&mut self.interactive_resize, col);
}
pub fn center_window(&mut self, window: Option<&W::Id>) {
if self.columns.is_empty() {
return;
}
let col_idx = if let Some(window) = window {
self.columns
.iter()
.position(|col| col.contains(window))
.unwrap()
} else {
self.active_column_idx
};
// We can reasonably center only the active column.
if col_idx != self.active_column_idx {
return;
}
self.center_column();
}
pub fn view_pos(&self) -> f64 {
self.column_x(self.active_column_idx) + self.view_offset.current()
}
+11 -1
View File
@@ -971,12 +971,22 @@ impl<W: LayoutElement> Workspace<W> {
pub fn center_column(&mut self) {
if self.floating_is_active.get() {
self.floating.center_window();
self.floating.center_window(None);
} else {
self.scrolling.center_column();
}
}
pub fn center_window(&mut self, id: Option<&W::Id>) {
if id.map_or(self.floating_is_active.get(), |id| {
self.floating.has_window(id)
}) {
self.floating.center_window(id);
} else {
self.scrolling.center_window(id);
}
}
pub fn toggle_width(&mut self) {
if self.floating_is_active.get() {
self.floating.toggle_window_width(None);