aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-02-04 22:10:26 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-02-04 22:10:26 +0400
commitb824cf90ab10f4ba5e1e0b23e0b2cf840814c02a (patch)
tree9937888dc8edfa72b71c1f94a26909a467b73c83
parent7a4bb8ba8ae9022c572c5d4b66182f1af7fd3fb7 (diff)
downloadniri-b824cf90ab10f4ba5e1e0b23e0b2cf840814c02a.tar.gz
niri-b824cf90ab10f4ba5e1e0b23e0b2cf840814c02a.tar.bz2
niri-b824cf90ab10f4ba5e1e0b23e0b2cf840814c02a.zip
layout: Generalize traversal between rendering and input
-rw-r--r--src/layout/workspace.rs99
1 files changed, 48 insertions, 51 deletions
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 5ecd25e0..70237f06 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -1,5 +1,6 @@
use std::cmp::{max, min};
use std::iter::zip;
+use std::ops::ControlFlow;
use std::rc::Rc;
use std::time::Duration;
@@ -913,46 +914,36 @@ impl<W: LayoutElement> Workspace<W> {
self.column_x(self.active_column_idx) + self.view_offset
}
- pub fn window_under(
- &self,
- pos: Point<f64, Logical>,
- ) -> Option<(&W, Option<Point<i32, Logical>>)> {
- if self.columns.is_empty() {
- return None;
- }
-
+ fn with_tiles_in_render_order<'a, F, B>(&'a self, mut f: F) -> Option<B>
+ where
+ F: FnMut(&'a Tile<W>, Point<i32, Logical>) -> ControlFlow<B>,
+ {
let view_pos = self.view_pos();
- // Prefer the active window since it's drawn on top.
+ // Start with the active window since it's drawn on top.
let col = &self.columns[self.active_column_idx];
- let active_tile = &col.tiles[col.active_tile_idx];
+ let tile = &col.tiles[col.active_tile_idx];
let tile_pos = Point::from((
self.column_x(self.active_column_idx) - view_pos,
col.tile_y(col.active_tile_idx),
));
- let pos_within_tile = pos - tile_pos.to_f64();
- if active_tile.is_in_input_region(pos_within_tile) {
- let pos_within_surface = tile_pos + active_tile.buf_loc();
- return Some((active_tile.window(), Some(pos_within_surface)));
- } else if active_tile.is_in_activation_region(pos_within_tile) {
- return Some((active_tile.window(), None));
+
+ if let ControlFlow::Break(rv) = f(tile, tile_pos) {
+ return Some(rv);
}
let mut x = -view_pos;
- for col in &self.columns {
- for (tile, y) in zip(&col.tiles, col.tile_ys()) {
- if tile.window() == active_tile.window() {
+ for (col_idx, col) in self.columns.iter().enumerate() {
+ for (tile_idx, (tile, y)) in zip(&col.tiles, col.tile_ys()).enumerate() {
+ if col_idx == self.active_column_idx && tile_idx == col.active_tile_idx {
// Already handled it above.
continue;
}
let tile_pos = Point::from((x, y));
- let pos_within_tile = pos - tile_pos.to_f64();
- if tile.is_in_input_region(pos_within_tile) {
- let pos_within_surface = tile_pos + tile.buf_loc();
- return Some((tile.window(), Some(pos_within_surface)));
- } else if tile.is_in_activation_region(pos_within_tile) {
- return Some((tile.window(), None));
+
+ if let ControlFlow::Break(rv) = f(tile, tile_pos) {
+ return Some(rv);
}
}
@@ -962,6 +953,28 @@ impl<W: LayoutElement> Workspace<W> {
None
}
+ pub fn window_under(
+ &self,
+ pos: Point<f64, Logical>,
+ ) -> Option<(&W, Option<Point<i32, Logical>>)> {
+ if self.columns.is_empty() {
+ return None;
+ }
+
+ self.with_tiles_in_render_order(|tile, tile_pos| {
+ let pos_within_tile = pos - tile_pos.to_f64();
+
+ if tile.is_in_input_region(pos_within_tile) {
+ let pos_within_surface = tile_pos + tile.buf_loc();
+ return ControlFlow::Break((tile.window(), Some(pos_within_surface)));
+ } else if tile.is_in_activation_region(pos_within_tile) {
+ return ControlFlow::Break((tile.window(), None));
+ }
+
+ ControlFlow::Continue(())
+ })
+ }
+
pub fn toggle_width(&mut self) {
if self.columns.is_empty() {
return;
@@ -1079,36 +1092,20 @@ impl<W: LayoutElement> Workspace<W> {
.unwrap_or(Scale::from(1.));
let mut rv = vec![];
- let view_pos = self.view_pos();
-
- // Draw the active window on top.
- let col = &self.columns[self.active_column_idx];
- let active_tile = &col.tiles[col.active_tile_idx];
- let tile_pos = Point::from((
- self.column_x(self.active_column_idx) - view_pos,
- col.tile_y(col.active_tile_idx),
- ));
-
- // Draw the window itself.
- rv.extend(active_tile.render(renderer, tile_pos, output_scale));
+ let mut first = true;
- // Draw the focus ring.
- rv.extend(self.focus_ring.render(output_scale).map(Into::into));
+ self.with_tiles_in_render_order(|tile, tile_pos| {
+ // Draw the window itself.
+ rv.extend(tile.render(renderer, tile_pos, output_scale));
- let mut x = -view_pos;
- for col in &self.columns {
- for (tile, y) in zip(&col.tiles, col.tile_ys()) {
- if tile.window() == active_tile.window() {
- // Already handled it above.
- continue;
- }
-
- let tile_pos = Point::from((x, y));
- rv.extend(tile.render(renderer, tile_pos, output_scale));
+ // For the active tile (which comes first), draw the focus ring.
+ if first {
+ rv.extend(self.focus_ring.render(output_scale).map(Into::into));
+ first = false;
}
- x += col.width() + self.options.gaps;
- }
+ ControlFlow::<()>::Continue(())
+ });
rv
}