diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-03-02 15:23:40 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-03-02 15:48:54 +0400 |
| commit | 5f416abcf9053cf61323921b6218d72a77e2dceb (patch) | |
| tree | 7ca9eb9b3d96ddc9da8e4b2a6dd6bc0f2de51fe3 /src | |
| parent | 66c1272420c9fab848ff6ccf68d96a09632bc796 (diff) | |
| download | niri-5f416abcf9053cf61323921b6218d72a77e2dceb.tar.gz niri-5f416abcf9053cf61323921b6218d72a77e2dceb.tar.bz2 niri-5f416abcf9053cf61323921b6218d72a77e2dceb.zip | |
Change horizontal gesture to focus furthest window
Diffstat (limited to 'src')
| -rw-r--r-- | src/input.rs | 5 | ||||
| -rw-r--r-- | src/layout/mod.rs | 13 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 112 |
3 files changed, 55 insertions, 75 deletions
diff --git a/src/input.rs b/src/input.rs index 0b930b20..db415a49 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1269,7 +1269,10 @@ impl State { handled = true; } - let res = self.niri.layout.view_offset_gesture_update(delta_x); + let res = self + .niri + .layout + .view_offset_gesture_update(delta_x, timestamp); if let Some(output) = res { if let Some(output) = output { self.niri.queue_redraw(output); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 6ec3ca8c..2985a29e 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1660,7 +1660,11 @@ impl<W: LayoutElement> Layout<W> { } } - pub fn view_offset_gesture_update(&mut self, delta_x: f64) -> Option<Option<Output>> { + pub fn view_offset_gesture_update( + &mut self, + delta_x: f64, + timestamp: Duration, + ) -> Option<Option<Output>> { let monitors = match &mut self.monitor_set { MonitorSet::Normal { monitors, .. } => monitors, MonitorSet::NoOutputs { .. } => return None, @@ -1668,7 +1672,7 @@ impl<W: LayoutElement> Layout<W> { for monitor in monitors { for ws in &mut monitor.workspaces { - if let Some(refresh) = ws.view_offset_gesture_update(delta_x) { + if let Some(refresh) = ws.view_offset_gesture_update(delta_x, timestamp) { if refresh { return Some(Some(monitor.output.clone())); } else { @@ -2036,6 +2040,7 @@ mod tests { ViewOffsetGestureUpdate { #[proptest(strategy = "arbitrary_view_offset_gesture_delta()")] delta: f64, + timestamp: Duration, }, ViewOffsetGestureEnd, WorkspaceSwitchGestureBegin { @@ -2293,8 +2298,8 @@ mod tests { layout.view_offset_gesture_begin(&output); } - Op::ViewOffsetGestureUpdate { delta } => { - layout.view_offset_gesture_update(delta); + Op::ViewOffsetGestureUpdate { delta, timestamp } => { + layout.view_offset_gesture_update(delta, timestamp); } Op::ViewOffsetGestureEnd => { // We don't handle cancels in this gesture. diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index c0b04896..ec53f887 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -17,6 +17,7 @@ use super::{LayoutElement, Options}; use crate::animation::Animation; use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; +use crate::swipe_tracker::SwipeTracker; use crate::utils::output_size; #[derive(Debug)] @@ -90,6 +91,8 @@ enum ViewOffsetAdjustment { #[derive(Debug)] struct ViewGesture { current_view_offset: f64, + tracker: SwipeTracker, + delta_from_tracker: f64, } /// Width of a column. @@ -1230,39 +1233,51 @@ impl<W: LayoutElement> Workspace<W> { let gesture = ViewGesture { current_view_offset: self.view_offset as f64, + tracker: SwipeTracker::new(), + delta_from_tracker: self.view_offset as f64, }; self.view_offset_adj = Some(ViewOffsetAdjustment::Gesture(gesture)); } - pub fn view_offset_gesture_update(&mut self, delta_x: f64) -> Option<bool> { + pub fn view_offset_gesture_update( + &mut self, + delta_x: f64, + timestamp: Duration, + ) -> Option<bool> { let Some(ViewOffsetAdjustment::Gesture(gesture)) = &mut self.view_offset_adj else { return None; }; - let mut new_offset = gesture.current_view_offset + delta_x; - gesture.current_view_offset = new_offset; + gesture.tracker.push(delta_x, timestamp); + + let view_offset = gesture.tracker.pos() + gesture.delta_from_tracker; + gesture.current_view_offset = view_offset; if self.columns.is_empty() { return Some(true); } - // Switch the next window to be active, if necessary. - // - // The logic here is similar to PaperWM. The idea is: make the next window (in the - // direction of the gesture) active when it becomes "more visible" than the current active - // window. - - // Make an iterator over column indices into the gesture direction. - let mut idxs_before = (0..=self.active_column_idx).rev(); - let mut idxs_after = self.active_column_idx..self.columns.len(); - let next_column_idxs = if delta_x < 0. { - &mut idxs_before as &mut dyn Iterator<Item = usize> + // Check if moving too slow to switch focus. + if delta_x.abs() < 1. { + return Some(true); + } + + // Switch focus to the furthest visible window towards the gesture direction. + + // Make an iterator over column indices towards the gesture direction. + let mut idxs_forward = 0..self.columns.len(); + let mut idxs_back = idxs_forward.clone().rev(); + let idxs = if delta_x < 0. { + &mut idxs_back as &mut dyn Iterator<Item = usize> } else { - &mut idxs_after as &mut dyn Iterator<Item = usize> + &mut idxs_forward as &mut dyn Iterator<Item = usize> }; - let mut last = None; - for col_idx in next_column_idxs { + let active_col_x = self.column_x(self.active_column_idx); + let mut new_col_idx = self.active_column_idx; + let mut new_col_x = active_col_x; + + for col_idx in idxs { let col = &self.columns[col_idx]; let col_x = self.column_x(col_idx); let col_w = col.width(); @@ -1273,24 +1288,7 @@ impl<W: LayoutElement> Workspace<W> { self.working_area }; - if let Some((last_col_x, _)) = last { - area_for_col.loc.x += last_col_x + new_offset.round() as i32; - } else { - // First iteration of the loop; col_idx == self.active_column_idx. - area_for_col.loc.x += col_x + new_offset.round() as i32; - } - - // Check if the column is fully visible. - if area_for_col.loc.x <= col_x - && col_x + col_w <= area_for_col.loc.x + area_for_col.size.w - { - // Make it the new active column. - if let Some((last_col_x, _)) = last { - new_offset += (last_col_x - col_x) as f64; - self.active_column_idx = col_idx; - } - break; - } + area_for_col.loc.x += active_col_x + view_offset.round() as i32; // Check if the column is already past the working area. if (delta_x >= 0. && area_for_col.loc.x + area_for_col.size.w <= col_x) @@ -1299,46 +1297,19 @@ impl<W: LayoutElement> Workspace<W> { break; } - // Compute the visible width (inside the working area). - let visible_width = col_w - - max(0, area_for_col.loc.x - col_x) - - max( - 0, - (col_x + col_w) - (area_for_col.loc.x + area_for_col.size.w), - ); - let visible_ratio = if col_w == 0 { - 1. - } else { - visible_width as f64 / col_w as f64 - }; - - if let Some((last_col_x, last_ratio)) = last { - // Check if we reached the first visible window. - if area_for_col.loc.x < col_x + col_w - && col_x < area_for_col.loc.x + area_for_col.size.w - { - // If it's more visible than the last one, make it active. - if visible_ratio >= last_ratio { - new_offset += (last_col_x - col_x) as f64; - self.active_column_idx = col_idx; - } - - break; - } - - // Still working through invisible windows. - new_offset += (last_col_x - col_x) as f64; - self.active_column_idx = col_idx; - } - - last = Some((col_x, visible_ratio)); + new_col_idx = col_idx; + new_col_x = col_x; } let Some(ViewOffsetAdjustment::Gesture(gesture)) = &mut self.view_offset_adj else { unreachable!(); }; - gesture.current_view_offset = new_offset; + let delta = (active_col_x - new_col_x) as f64; + gesture.delta_from_tracker += delta; + gesture.current_view_offset += delta; + self.active_column_idx = new_col_idx; + Some(true) } @@ -1354,7 +1325,8 @@ impl<W: LayoutElement> Workspace<W> { // FIXME: keep track of gesture velocity and use it to compute the final point and // to animate to it. - let offset = gesture.current_view_offset.round() as i32; + let offset = gesture.tracker.pos() + gesture.delta_from_tracker; + let offset = offset.round() as i32; self.view_offset = offset; self.view_offset_adj = None; |
