diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-04-04 11:46:22 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-04-25 02:00:18 -0700 |
| commit | 21630ddb5ebd078c5a6400d6d56c44f0903f1d44 (patch) | |
| tree | 4d65b2b45f43ceba7653b5189d95f877dd55f302 /src | |
| parent | 9e5e0c85bb3c50d00108a4a2de0fe45bfc4ebb8d (diff) | |
| download | niri-21630ddb5ebd078c5a6400d6d56c44f0903f1d44.tar.gz niri-21630ddb5ebd078c5a6400d6d56c44f0903f1d44.tar.bz2 niri-21630ddb5ebd078c5a6400d6d56c44f0903f1d44.zip | |
layout/monitor: Extract workspaces_render_geo()
Diffstat (limited to 'src')
| -rw-r--r-- | src/layout/mod.rs | 47 | ||||
| -rw-r--r-- | src/layout/monitor.rs | 146 |
2 files changed, 94 insertions, 99 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 6c2ba2ae..3cdcdc82 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -2601,6 +2601,17 @@ impl<W: LayoutElement> Layout<W> { } saw_view_offset_gesture = has_view_offset_gesture; } + + let scale = monitor.output.current_scale().fractional_scale(); + let iter = monitor.workspaces_with_render_geo(); + for (_ws, ws_geo) in iter { + let pos = ws_geo.loc; + let rounded_pos = pos.to_physical_precise_round(scale).to_logical(scale); + + // Workspace positions must be rounded to physical pixels. + assert_abs_diff_eq!(pos.x, rounded_pos.x, epsilon = 1e-5); + assert_abs_diff_eq!(pos.y, rounded_pos.y, epsilon = 1e-5); + } } } @@ -2623,14 +2634,14 @@ impl<W: LayoutElement> Layout<W> { // Scroll the view if needed. if let Some((output, pos_within_output)) = dnd_scroll { if let Some(mon) = self.monitor_for_output_mut(&output) { - if let Some((ws, offset)) = mon.workspace_under(pos_within_output) { + if let Some((ws, geo)) = mon.workspace_under(pos_within_output) { let ws_id = ws.id(); let ws = mon .workspaces .iter_mut() .find(|ws| ws.id() == ws_id) .unwrap(); - ws.dnd_scroll_gesture_scroll(pos_within_output - offset); + ws.dnd_scroll_gesture_scroll(pos_within_output - geo.loc); } } } @@ -2770,7 +2781,7 @@ impl<W: LayoutElement> Layout<W> { let _span = tracy_client::span!("Layout::update_insert_hint::update"); if let Some(mon) = self.monitor_for_output_mut(&move_.output) { - if let Some((ws, offset)) = mon.workspace_under(move_.pointer_pos_within_output) { + if let Some((ws, geo)) = mon.workspace_under(move_.pointer_pos_within_output) { let ws_id = ws.id(); let ws = mon .workspaces @@ -2778,7 +2789,7 @@ impl<W: LayoutElement> Layout<W> { .find(|ws| ws.id() == ws_id) .unwrap(); - let position = ws.get_insert_position(move_.pointer_pos_within_output - offset); + let position = ws.get_insert_position(move_.pointer_pos_within_output - geo.loc); let rules = move_.tile.window().rules(); let border_width = move_.tile.effective_border_width().unwrap_or(0.); @@ -3661,8 +3672,8 @@ impl<W: LayoutElement> Layout<W> { return false; }; - let Some((mon, (ws, ws_offset))) = monitors.iter().find_map(|mon| { - mon.workspaces_with_render_positions() + let Some((mon, (ws, ws_geo))) = monitors.iter().find_map(|mon| { + mon.workspaces_with_render_geo() .find(|(ws, _)| ws.has_window(&window_id)) .map(|rv| (mon, rv)) }) else { @@ -3680,7 +3691,7 @@ impl<W: LayoutElement> Layout<W> { .unwrap(); let window_offset = tile.window_loc(); - let tile_pos = ws_offset + tile_offset; + let tile_pos = ws_geo.loc + tile_offset; let pointer_offset_within_window = start_pos_within_output - tile_pos - window_offset; let window_size = tile.window_size(); @@ -3776,8 +3787,8 @@ impl<W: LayoutElement> Layout<W> { // potentially animatable. let mut tile_pos = None; if let MonitorSet::Normal { monitors, .. } = &self.monitor_set { - if let Some((mon, (ws, ws_offset))) = monitors.iter().find_map(|mon| { - mon.workspaces_with_render_positions() + if let Some((mon, (ws, ws_geo))) = monitors.iter().find_map(|mon| { + mon.workspaces_with_render_geo() .find(|(ws, _)| ws.has_window(window)) .map(|rv| (mon, rv)) }) { @@ -3787,7 +3798,7 @@ impl<W: LayoutElement> Layout<W> { .find(|(tile, _, _)| tile.window().id() == window) .unwrap(); - tile_pos = Some(ws_offset + tile_offset); + tile_pos = Some(ws_geo.loc + tile_offset); } } } @@ -3979,12 +3990,12 @@ impl<W: LayoutElement> Layout<W> { let (mon, ws_idx, position, offset) = if let Some(mon) = monitors.iter_mut().find(|mon| mon.output == move_.output) { - let (ws, offset) = mon + let (ws, ws_geo) = mon .workspace_under(move_.pointer_pos_within_output) // If the pointer is somehow outside the move output and a workspace switch // is in progress, this won't necessarily do the expected thing, but also // that is not really supposed to happen so eh? - .unwrap_or_else(|| mon.workspaces_with_render_positions().next().unwrap()); + .unwrap_or_else(|| mon.workspaces_with_render_geo().next().unwrap()); let ws_id = ws.id(); let ws_idx = mon @@ -3997,14 +4008,14 @@ impl<W: LayoutElement> Layout<W> { InsertPosition::Floating } else { let ws = &mut mon.workspaces[ws_idx]; - ws.get_insert_position(move_.pointer_pos_within_output - offset) + ws.get_insert_position(move_.pointer_pos_within_output - ws_geo.loc) }; - (mon, ws_idx, position, offset) + (mon, ws_idx, position, ws_geo.loc) } else { let mon = &mut monitors[*active_monitor_idx]; // No point in trying to use the pointer position on the wrong output. - let (ws, offset) = mon.workspaces_with_render_positions().next().unwrap(); + let (ws, ws_geo) = mon.workspaces_with_render_geo().next().unwrap(); let position = if move_.is_floating { InsertPosition::Floating @@ -4018,7 +4029,7 @@ impl<W: LayoutElement> Layout<W> { .iter_mut() .position(|ws| ws.id() == ws_id) .unwrap(); - (mon, ws_idx, position, offset) + (mon, ws_idx, position, ws_geo.loc) }; let win_id = move_.tile.window().id().clone(); @@ -4435,7 +4446,7 @@ impl<W: LayoutElement> Layout<W> { let Some(mon) = self.monitor_for_output_mut(&output) else { return; }; - let Some((ws, offset)) = mon.workspace_under(pointer_pos_within_output) else { + let Some((ws, ws_geo)) = mon.workspace_under(pointer_pos_within_output) else { return; }; let ws_id = ws.id(); @@ -4445,7 +4456,7 @@ impl<W: LayoutElement> Layout<W> { .find(|ws| ws.id() == ws_id) .unwrap(); - let tile_pos = tile_pos - offset; + let tile_pos = tile_pos - ws_geo.loc; ws.start_close_animation_for_tile(renderer, snapshot, tile_size, tile_pos, blocker); return; } diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index 2c2ea0f8..8f300812 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -1,4 +1,5 @@ use std::cmp::min; +use std::iter::zip; use std::rc::Rc; use std::time::Duration; @@ -20,7 +21,7 @@ use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::RenderTarget; use crate::rubber_band::RubberBand; use crate::utils::transaction::Transaction; -use crate::utils::{output_size, round_logical_in_physical, ResizeEdge}; +use crate::utils::{output_size, ResizeEdge}; /// Amount of touchpad movement to scroll the height of one workspace. const WORKSPACE_GESTURE_MOVEMENT: f64 = 300.; @@ -680,31 +681,8 @@ impl<W: LayoutElement> Monitor<W> { } pub fn update_render_elements(&mut self, is_active: bool) { - match &self.workspace_switch { - Some(switch) => { - let render_idx = switch.current_idx(); - let before_idx = render_idx.floor(); - let after_idx = render_idx.ceil(); - - if after_idx < 0. || before_idx as usize >= self.workspaces.len() { - return; - } - - let after_idx = after_idx as usize; - if after_idx < self.workspaces.len() { - self.workspaces[after_idx].update_render_elements(is_active); - - if before_idx < 0. { - return; - } - } - - let before_idx = before_idx as usize; - self.workspaces[before_idx].update_render_elements(is_active); - } - None => { - self.workspaces[self.active_workspace_idx].update_render_elements(is_active); - } + for (ws, _) in self.workspaces_with_render_geo_mut() { + ws.update_render_elements(is_active); } } @@ -855,72 +833,78 @@ impl<W: LayoutElement> Monitor<W> { Some(rect) } - pub fn workspaces_with_render_positions( + pub fn workspaces_render_geo(&self) -> impl Iterator<Item = Rectangle<f64, Logical>> { + let scale = self.output.current_scale().fractional_scale(); + let size = output_size(&self.output); + + // Ceil the workspace size in physical pixels. + let ws_size = size.to_physical_precise_ceil(scale).to_logical(scale); + + let render_idx = if let Some(switch) = &self.workspace_switch { + switch.current_idx() + } else { + self.active_workspace_idx as f64 + }; + + let first_ws_y = -render_idx * ws_size.h; + + (0..self.workspaces.len()).map(move |idx| { + let y = first_ws_y + idx as f64 * ws_size.h; + let loc = Point::from((0., y)); + let loc = loc.to_physical_precise_round(scale).to_logical(scale); + Rectangle::new(loc, ws_size) + }) + } + + pub fn workspaces_with_render_geo( &self, - ) -> impl Iterator<Item = (&Workspace<W>, Point<f64, Logical>)> { - let mut first = None; - let mut second = None; - - match &self.workspace_switch { - Some(switch) => { - let render_idx = switch.current_idx(); - let before_idx = render_idx.floor(); - let after_idx = render_idx.ceil(); - - if after_idx >= 0. && before_idx < self.workspaces.len() as f64 { - let scale = self.output.current_scale().fractional_scale(); - let size = output_size(&self.output); - let offset = - round_logical_in_physical(scale, (render_idx - before_idx) * size.h); - - // Ceil the height in physical pixels. - let height = (size.h * scale).ceil() / scale; - - if before_idx >= 0. { - let before_idx = before_idx as usize; - let before_offset = Point::from((0., -offset)); - first = Some((&self.workspaces[before_idx], before_offset)); - } - - let after_idx = after_idx as usize; - if after_idx < self.workspaces.len() { - let after_offset = Point::from((0., -offset + height)); - second = Some((&self.workspaces[after_idx], after_offset)); - } - } - } - None => { - first = Some(( - &self.workspaces[self.active_workspace_idx], - Point::from((0., 0.)), - )); - } - } + ) -> impl Iterator<Item = (&Workspace<W>, Rectangle<f64, Logical>)> { + let output_size = output_size(&self.output); + let output_geo = Rectangle::new(Point::from((0., 0.)), output_size); + + let geo = self.workspaces_render_geo(); + zip(self.workspaces.iter(), geo) + // Cull out workspaces outside the output. + .filter(move |(_ws, geo)| geo.intersection(output_geo).is_some()) + } - first.into_iter().chain(second) + pub fn workspaces_with_render_geo_mut( + &mut self, + ) -> impl Iterator<Item = (&mut Workspace<W>, Rectangle<f64, Logical>)> { + let output_size = output_size(&self.output); + let output_geo = Rectangle::new(Point::from((0., 0.)), output_size); + + let geo = self.workspaces_render_geo(); + zip(self.workspaces.iter_mut(), geo) + // Cull out workspaces outside the output. + .filter(move |(_ws, geo)| geo.intersection(output_geo).is_some()) } pub fn workspace_under( &self, pos_within_output: Point<f64, Logical>, - ) -> Option<(&Workspace<W>, Point<f64, Logical>)> { + ) -> Option<(&Workspace<W>, Rectangle<f64, Logical>)> { let size = output_size(&self.output); - let (ws, bounds) = self - .workspaces_with_render_positions() - .map(|(ws, offset)| (ws, Rectangle::new(offset, size))) - .find(|(_, bounds)| bounds.contains(pos_within_output))?; - Some((ws, bounds.loc)) + let (ws, geo) = self.workspaces_with_render_geo().find_map(|(ws, geo)| { + // Extend width to entire output. + let loc = Point::from((0., geo.loc.y)); + let size = Size::from((size.w, geo.size.h)); + let bounds = Rectangle::new(loc, size); + + bounds.contains(pos_within_output).then_some((ws, geo)) + })?; + Some((ws, geo)) } pub fn window_under(&self, pos_within_output: Point<f64, Logical>) -> Option<(&W, HitType)> { - let (ws, offset) = self.workspace_under(pos_within_output)?; - let (win, hit) = ws.window_under(pos_within_output - offset)?; - Some((win, hit.offset_win_pos(offset))) + let (ws, geo) = self.workspace_under(pos_within_output)?; + let (win, hit) = ws.window_under(pos_within_output - geo.loc)?; + Some((win, hit.offset_win_pos(geo.loc))) } pub fn resize_edges_under(&self, pos_within_output: Point<f64, Logical>) -> Option<ResizeEdge> { - let (ws, offset) = self.workspace_under(pos_within_output)?; - ws.resize_edges_under(pos_within_output - offset) + let (ws, geo) = self.workspace_under(pos_within_output)?; + ws.resize_edges_under(pos_within_output - geo.loc) } pub fn render_above_top_layer(&self) -> bool { @@ -968,8 +952,8 @@ impl<W: LayoutElement> Monitor<W> { ) }; - self.workspaces_with_render_positions() - .flat_map(move |(ws, offset)| { + self.workspaces_with_render_geo() + .flat_map(move |(ws, geo)| { ws.render_elements(renderer, target, focus_ring) .filter_map(move |elem| { CropRenderElement::from_element(elem, scale, crop_bounds) @@ -980,7 +964,7 @@ impl<W: LayoutElement> Monitor<W> { // The offset we get from workspaces_with_render_positions() is already // rounded to physical pixels, but it's in the logical coordinate // space, so we need to convert it to physical. - offset.to_physical_precise_round(scale), + geo.loc.to_physical_precise_round(scale), Relocate::Relative, ) }) |
