aboutsummaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-05-11 14:01:48 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-05-11 14:02:37 +0400
commitbc29256b9d95f265c8f6508e7949c57497835430 (patch)
treee8d7dd9c3a43e383fdc9f5fb6850f31e3e3078e6 /src/layout
parentbeba87354a1fd30a95eaaf6c98eec72797e4baa7 (diff)
downloadniri-bc29256b9d95f265c8f6508e7949c57497835430.tar.gz
niri-bc29256b9d95f265c8f6508e7949c57497835430.tar.bz2
niri-bc29256b9d95f265c8f6508e7949c57497835430.zip
Implement Mod+MMB view offset gesture
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/mod.rs57
-rw-r--r--src/layout/workspace.rs28
2 files changed, 64 insertions, 21 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 0cb8e493..1442dfd0 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -1732,7 +1732,7 @@ impl<W: LayoutElement> Layout<W> {
None
}
- pub fn view_offset_gesture_begin(&mut self, output: &Output) {
+ pub fn view_offset_gesture_begin(&mut self, output: &Output, is_touchpad: bool) {
let monitors = match &mut self.monitor_set {
MonitorSet::Normal { monitors, .. } => monitors,
MonitorSet::NoOutputs { .. } => unreachable!(),
@@ -1742,11 +1742,11 @@ impl<W: LayoutElement> Layout<W> {
for (idx, ws) in monitor.workspaces.iter_mut().enumerate() {
// Cancel the gesture on other workspaces.
if &monitor.output != output || idx != monitor.active_workspace_idx {
- ws.view_offset_gesture_end(true);
+ ws.view_offset_gesture_end(true, None);
continue;
}
- ws.view_offset_gesture_begin();
+ ws.view_offset_gesture_begin(is_touchpad);
}
}
}
@@ -1755,6 +1755,7 @@ impl<W: LayoutElement> Layout<W> {
&mut self,
delta_x: f64,
timestamp: Duration,
+ is_touchpad: bool,
) -> Option<Option<Output>> {
let monitors = match &mut self.monitor_set {
MonitorSet::Normal { monitors, .. } => monitors,
@@ -1763,7 +1764,9 @@ 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, timestamp) {
+ if let Some(refresh) =
+ ws.view_offset_gesture_update(delta_x, timestamp, is_touchpad)
+ {
if refresh {
return Some(Some(monitor.output.clone()));
} else {
@@ -1776,7 +1779,11 @@ impl<W: LayoutElement> Layout<W> {
None
}
- pub fn view_offset_gesture_end(&mut self, cancelled: bool) -> Option<Output> {
+ pub fn view_offset_gesture_end(
+ &mut self,
+ cancelled: bool,
+ is_touchpad: Option<bool>,
+ ) -> Option<Output> {
let monitors = match &mut self.monitor_set {
MonitorSet::Normal { monitors, .. } => monitors,
MonitorSet::NoOutputs { .. } => return None,
@@ -1784,7 +1791,7 @@ impl<W: LayoutElement> Layout<W> {
for monitor in monitors {
for ws in &mut monitor.workspaces {
- if ws.view_offset_gesture_end(cancelled) {
+ if ws.view_offset_gesture_end(cancelled, is_touchpad) {
return Some(monitor.output.clone());
}
}
@@ -2029,7 +2036,7 @@ impl<W: LayoutElement> Layout<W> {
// Cancel the view offset gesture after workspace switches, moves, etc.
if ws_idx != mon.active_workspace_idx {
- ws.view_offset_gesture_end(false);
+ ws.view_offset_gesture_end(false, None);
}
}
}
@@ -2037,7 +2044,7 @@ impl<W: LayoutElement> Layout<W> {
MonitorSet::NoOutputs { workspaces, .. } => {
for ws in workspaces {
ws.refresh(false);
- ws.view_offset_gesture_end(false);
+ ws.view_offset_gesture_end(false, None);
}
}
}
@@ -2351,13 +2358,17 @@ mod tests {
ViewOffsetGestureBegin {
#[proptest(strategy = "1..=5usize")]
output_idx: usize,
+ is_touchpad: bool,
},
ViewOffsetGestureUpdate {
#[proptest(strategy = "arbitrary_view_offset_gesture_delta()")]
delta: f64,
timestamp: Duration,
+ is_touchpad: bool,
+ },
+ ViewOffsetGestureEnd {
+ is_touchpad: Option<bool>,
},
- ViewOffsetGestureEnd,
WorkspaceSwitchGestureBegin {
#[proptest(strategy = "1..=5usize")]
output_idx: usize,
@@ -2619,20 +2630,27 @@ mod tests {
layout.move_workspace_to_output(&output);
}
- Op::ViewOffsetGestureBegin { output_idx: id } => {
+ Op::ViewOffsetGestureBegin {
+ output_idx: id,
+ is_touchpad: normalize,
+ } => {
let name = format!("output{id}");
let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
return;
};
- layout.view_offset_gesture_begin(&output);
+ layout.view_offset_gesture_begin(&output, normalize);
}
- Op::ViewOffsetGestureUpdate { delta, timestamp } => {
- layout.view_offset_gesture_update(delta, timestamp);
+ Op::ViewOffsetGestureUpdate {
+ delta,
+ timestamp,
+ is_touchpad,
+ } => {
+ layout.view_offset_gesture_update(delta, timestamp, is_touchpad);
}
- Op::ViewOffsetGestureEnd => {
+ Op::ViewOffsetGestureEnd { is_touchpad } => {
// We don't handle cancels in this gesture.
- layout.view_offset_gesture_end(false);
+ layout.view_offset_gesture_end(false, is_touchpad);
}
Op::WorkspaceSwitchGestureBegin { output_idx: id } => {
let name = format!("output{id}");
@@ -3377,8 +3395,13 @@ mod tests {
min_max_size: Default::default(),
},
Op::FullscreenWindow(1),
- Op::ViewOffsetGestureBegin { output_idx: 1 },
- Op::ViewOffsetGestureEnd,
+ Op::ViewOffsetGestureBegin {
+ output_idx: 1,
+ is_touchpad: true,
+ },
+ Op::ViewOffsetGestureEnd {
+ is_touchpad: Some(true),
+ },
];
check_ops(&ops);
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 77f10919..6005d448 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -129,6 +129,8 @@ struct ViewGesture {
delta_from_tracker: f64,
// The view offset we'll use if needed for activate_prev_column_on_removal.
static_view_offset: i32,
+ /// Whether the gesture is controlled by the touchpad.
+ is_touchpad: bool,
}
#[derive(Debug)]
@@ -2131,7 +2133,7 @@ impl<W: LayoutElement> Workspace<W> {
rv
}
- pub fn view_offset_gesture_begin(&mut self) {
+ pub fn view_offset_gesture_begin(&mut self, is_touchpad: bool) {
if self.columns.is_empty() {
return;
}
@@ -2141,6 +2143,7 @@ impl<W: LayoutElement> Workspace<W> {
tracker: SwipeTracker::new(),
delta_from_tracker: self.view_offset as f64,
static_view_offset: self.static_view_offset(),
+ is_touchpad,
};
self.view_offset_adj = Some(ViewOffsetAdjustment::Gesture(gesture));
}
@@ -2149,14 +2152,23 @@ impl<W: LayoutElement> Workspace<W> {
&mut self,
delta_x: f64,
timestamp: Duration,
+ is_touchpad: bool,
) -> Option<bool> {
let Some(ViewOffsetAdjustment::Gesture(gesture)) = &mut self.view_offset_adj else {
return None;
};
+ if gesture.is_touchpad != is_touchpad {
+ return None;
+ }
+
gesture.tracker.push(delta_x, timestamp);
- let norm_factor = self.working_area.size.w as f64 / VIEW_GESTURE_WORKING_AREA_MOVEMENT;
+ let norm_factor = if gesture.is_touchpad {
+ self.working_area.size.w as f64 / VIEW_GESTURE_WORKING_AREA_MOVEMENT
+ } else {
+ 1.
+ };
let pos = gesture.tracker.pos() * norm_factor;
let view_offset = pos + gesture.delta_from_tracker;
gesture.current_view_offset = view_offset;
@@ -2164,17 +2176,25 @@ impl<W: LayoutElement> Workspace<W> {
Some(true)
}
- pub fn view_offset_gesture_end(&mut self, _cancelled: bool) -> bool {
+ pub fn view_offset_gesture_end(&mut self, _cancelled: bool, is_touchpad: Option<bool>) -> bool {
let Some(ViewOffsetAdjustment::Gesture(gesture)) = &self.view_offset_adj else {
return false;
};
+ if is_touchpad.map_or(false, |x| gesture.is_touchpad != x) {
+ return false;
+ }
+
// We do not handle cancelling, just like GNOME Shell doesn't. For this gesture, proper
// cancelling would require keeping track of the original active column, and then updating
// it in all the right places (adding columns, removing columns, etc.) -- quite a bit of
// effort and bug potential.
- let norm_factor = self.working_area.size.w as f64 / VIEW_GESTURE_WORKING_AREA_MOVEMENT;
+ let norm_factor = if gesture.is_touchpad {
+ self.working_area.size.w as f64 / VIEW_GESTURE_WORKING_AREA_MOVEMENT
+ } else {
+ 1.
+ };
let velocity = gesture.tracker.velocity() * norm_factor;
let pos = gesture.tracker.pos() * norm_factor;
let current_view_offset = pos + gesture.delta_from_tracker;