diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-02-07 10:49:01 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-02-07 10:49:01 +0400 |
| commit | 9896fd67a0dcdade5f05568aa7b12fa17605976b (patch) | |
| tree | d61647ec4c805629976f7c7c8b271bce2403b882 | |
| parent | 15ec699fbbc9fc7fe1c865aa96584bec15fd2831 (diff) | |
| download | niri-9896fd67a0dcdade5f05568aa7b12fa17605976b.tar.gz niri-9896fd67a0dcdade5f05568aa7b12fa17605976b.tar.bz2 niri-9896fd67a0dcdade5f05568aa7b12fa17605976b.zip | |
Open dialogs to the right of their parent, don't steal focus
| -rw-r--r-- | src/handlers/compositor.rs | 18 | ||||
| -rw-r--r-- | src/layout/mod.rs | 138 | ||||
| -rw-r--r-- | src/layout/monitor.rs | 25 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 37 |
4 files changed, 216 insertions, 2 deletions
diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs index 517c8942..79ad5d12 100644 --- a/src/handlers/compositor.rs +++ b/src/handlers/compositor.rs @@ -104,8 +104,22 @@ impl CompositorHandler for State { let window = entry.remove(); window.on_commit(); - if let Some(output) = self.niri.layout.add_window(window, None, false).cloned() - { + let parent = window + .toplevel() + .parent() + .and_then(|parent| self.niri.layout.find_window_and_output(&parent)) + .map(|(win, _)| win.clone()); + + let win = window.clone(); + + // Open dialogs immediately to the right of their parent window. + let output = if let Some(p) = parent { + self.niri.layout.add_window_right_of(&p, win, None, false) + } else { + self.niri.layout.add_window(win, None, false) + }; + + if let Some(output) = output.cloned() { self.niri.queue_redraw(output); } return; diff --git a/src/layout/mod.rs b/src/layout/mod.rs index acd26348..dff5c0d0 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -564,6 +564,58 @@ impl<W: LayoutElement> Layout<W> { } } + /// Adds a new window to the layout immediately to the right of another window. + /// + /// If that another window was active, activates the new window. + /// + /// Returns an output that the window was added to, if there were any outputs. + pub fn add_window_right_of( + &mut self, + right_of: &W, + window: W, + width: Option<ColumnWidth>, + is_full_width: bool, + ) -> Option<&Output> { + let width = width + .or(self.options.default_width) + .unwrap_or_else(|| ColumnWidth::Fixed(window.size().w)); + + match &mut self.monitor_set { + MonitorSet::Normal { + monitors, + active_monitor_idx, + .. + } => { + let mon_idx = monitors + .iter() + .position(|mon| mon.workspaces.iter().any(|ws| ws.has_window(right_of))) + .unwrap(); + let mon = &mut monitors[mon_idx]; + + let mut activate = false; + if mon_idx == *active_monitor_idx { + let active_ws = &mon.workspaces[mon.active_workspace_idx]; + if !active_ws.columns.is_empty() { + let active_col = &active_ws.columns[active_ws.active_column_idx]; + let active_tile = &active_col.tiles[active_col.active_tile_idx]; + activate = active_tile.window() == right_of; + } + } + + mon.add_window_right_of(right_of, window, activate, width, is_full_width); + Some(&mon.output) + } + MonitorSet::NoOutputs { workspaces } => { + let ws = workspaces + .iter_mut() + .find(|ws| ws.has_window(right_of)) + .unwrap(); + ws.add_window_right_of(right_of, window, true, width, is_full_width); + None + } + } + } + pub fn remove_window(&mut self, window: &W) { match &mut self.monitor_set { MonitorSet::Normal { monitors, .. } => { @@ -1777,6 +1829,16 @@ mod tests { #[proptest(strategy = "arbitrary_min_max_size()")] min_max_size: (Size<i32, Logical>, Size<i32, Logical>), }, + AddWindowRightOf { + #[proptest(strategy = "1..=5usize")] + id: usize, + #[proptest(strategy = "1..=5usize")] + right_of_id: usize, + #[proptest(strategy = "arbitrary_bbox()")] + bbox: Rectangle<i32, Logical>, + #[proptest(strategy = "arbitrary_min_max_size()")] + min_max_size: (Size<i32, Logical>, Size<i32, Logical>), + }, CloseWindow(#[proptest(strategy = "1..=5usize")] usize), FullscreenWindow(#[proptest(strategy = "1..=5usize")] usize), FocusColumnLeft, @@ -1897,6 +1959,58 @@ mod tests { let win = TestWindow::new(id, bbox, min_max_size.0, min_max_size.1); layout.add_window(win, None, false); } + Op::AddWindowRightOf { + id, + right_of_id, + bbox, + min_max_size, + } => { + let mut found_right_of = false; + + match &mut layout.monitor_set { + MonitorSet::Normal { monitors, .. } => { + for mon in monitors { + for ws in &mut mon.workspaces { + for win in ws.windows() { + if win.0.id == id { + return; + } + + if win.0.id == right_of_id { + found_right_of = true; + } + } + } + } + } + MonitorSet::NoOutputs { workspaces, .. } => { + for ws in workspaces { + for win in ws.windows() { + if win.0.id == id { + return; + } + + if win.0.id == right_of_id { + found_right_of = true; + } + } + } + } + } + + if !found_right_of { + return; + } + + let right_of_win = TestWindow::new( + right_of_id, + Rectangle::default(), + Size::default(), + Size::default(), + ); + let win = TestWindow::new(id, bbox, min_max_size.0, min_max_size.1); + layout.add_window_right_of(&right_of_win, win, None, false); + } Op::CloseWindow(id) => { let dummy = TestWindow::new(id, Rectangle::default(), Size::default(), Size::default()); @@ -2052,6 +2166,18 @@ mod tests { bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)), min_max_size: Default::default(), }, + Op::AddWindowRightOf { + id: 3, + right_of_id: 0, + bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)), + min_max_size: Default::default(), + }, + Op::AddWindowRightOf { + id: 4, + right_of_id: 1, + bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)), + min_max_size: Default::default(), + }, Op::CloseWindow(0), Op::CloseWindow(1), Op::CloseWindow(2), @@ -2185,6 +2311,18 @@ mod tests { bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)), min_max_size: Default::default(), }, + Op::AddWindowRightOf { + id: 6, + right_of_id: 0, + bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)), + min_max_size: Default::default(), + }, + Op::AddWindowRightOf { + id: 7, + right_of_id: 1, + bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)), + min_max_size: Default::default(), + }, Op::CloseWindow(0), Op::CloseWindow(1), Op::CloseWindow(2), diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index 0e5802cd..f5da804a 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -126,6 +126,31 @@ impl<W: LayoutElement> Monitor<W> { } } + pub fn add_window_right_of( + &mut self, + right_of: &W, + window: W, + activate: bool, + width: ColumnWidth, + is_full_width: bool, + ) { + let workspace_idx = self + .workspaces + .iter_mut() + .position(|ws| ws.has_window(right_of)) + .unwrap(); + let workspace = &mut self.workspaces[workspace_idx]; + + workspace.add_window_right_of(right_of, window, activate, width, is_full_width); + + // After adding a new window, workspace becomes this output's own. + workspace.original_output = OutputId::new(&self.output); + + if activate { + self.activate_workspace(workspace_idx); + } + } + pub fn add_column(&mut self, workspace_idx: usize, column: Column<W>, activate: bool) { let workspace = &mut self.workspaces[workspace_idx]; diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index 6e2a7c00..47be5877 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -555,6 +555,43 @@ impl<W: LayoutElement> Workspace<W> { } } + pub fn add_window_right_of( + &mut self, + right_of: &W, + window: W, + activate: bool, + width: ColumnWidth, + is_full_width: bool, + ) { + self.enter_output_for_window(&window); + + let idx = self + .columns + .iter() + .position(|col| col.contains(right_of)) + .unwrap() + + 1; + + let column = Column::new( + window, + self.view_size, + self.working_area, + self.options.clone(), + width, + is_full_width, + ); + self.columns.insert(idx, column); + + if self.active_column_idx >= idx { + self.active_column_idx += 1; + } + + if activate { + self.activate_column(idx); + self.activate_prev_column_on_removal = true; + } + } + pub fn add_column(&mut self, mut column: Column<W>, activate: bool) { for tile in &column.tiles { self.enter_output_for_window(tile.window()); |
