diff --git a/src/it/test_backend.rs b/src/it/test_backend.rs index 17ff055f..cab5267e 100644 --- a/src/it/test_backend.rs +++ b/src/it/test_backend.rs @@ -319,13 +319,17 @@ impl TestBackendMouse { } pub fn scroll_px(&self, dy: i32) { + self.scroll_px2(dy, false); + } + + pub fn scroll_px2(&self, dy: i32, inverted: bool) { self.common.event(InputEvent::AxisSource { source: AxisSource::Finger, }); self.common.event(InputEvent::AxisPx { dist: Fixed::from_int(dy), axis: ScrollAxis::Vertical, - inverted: false, + inverted, }); self.common.event(InputEvent::AxisFrame { time_usec: now_usec(), diff --git a/src/it/test_client.rs b/src/it/test_client.rs index 31580baf..3f8b5e46 100644 --- a/src/it/test_client.rs +++ b/src/it/test_client.rs @@ -67,7 +67,7 @@ impl TestClient { caps: Cell::new(0), name: Default::default(), }); - self.registry.bind(&tseat, seat.name().raw(), 7)?; + self.registry.bind(&tseat, seat.name().raw(), 9)?; self.tran.sync().await; let server = self.tran.get_server_obj(tseat.id)?; tseat.server.set(Some(server)); diff --git a/src/it/test_ifs/test_pointer.rs b/src/it/test_ifs/test_pointer.rs index 05249f84..f858c743 100644 --- a/src/it/test_ifs/test_pointer.rs +++ b/src/it/test_ifs/test_pointer.rs @@ -19,6 +19,7 @@ pub struct TestPointer { pub leave: TEEH, pub enter: TEEH, pub motion: TEEH, + pub axis_relative_direction: TEEH, } impl TestPointer { @@ -76,6 +77,12 @@ impl TestPointer { let _ev = AxisDiscrete::parse_full(parser)?; Ok(()) } + + fn handle_axis_relative_direction(&self, parser: MsgParser<'_, '_>) -> TestResult { + let ev = AxisRelativeDirection::parse_full(parser)?; + self.axis_relative_direction.push(ev); + Ok(()) + } } impl Drop for TestPointer { @@ -96,6 +103,7 @@ test_object! { AXIS_SOURCE => handle_axis_source, AXIS_STOP => handle_axis_stop, AXIS_DISCRETE => handle_axis_discrete, + AXIS_RELATIVE_DIRECTION => handle_axis_relative_direction, } impl TestObject for TestPointer {} diff --git a/src/it/test_ifs/test_seat.rs b/src/it/test_ifs/test_seat.rs index 9e65b876..9d40b2d7 100644 --- a/src/it/test_ifs/test_seat.rs +++ b/src/it/test_ifs/test_seat.rs @@ -66,6 +66,7 @@ impl TestSeat { leave: Rc::new(Default::default()), enter: Rc::new(Default::default()), motion: Rc::new(Default::default()), + axis_relative_direction: Rc::new(Default::default()), }); self.tran.add_obj(pointer.clone())?; self.tran.sync().await; diff --git a/src/it/test_utils.rs b/src/it/test_utils.rs index e3a3396b..74db15cd 100644 --- a/src/it/test_utils.rs +++ b/src/it/test_utils.rs @@ -1,3 +1,7 @@ +pub mod test_container_node_ext; pub mod test_expected_event; pub mod test_object_ext; +pub mod test_ouput_node_ext; +pub mod test_toplevel_node_ext; pub mod test_window; +pub mod test_workspace_node_ext; diff --git a/src/it/test_utils/test_container_node_ext.rs b/src/it/test_utils/test_container_node_ext.rs new file mode 100644 index 00000000..8c8f8150 --- /dev/null +++ b/src/it/test_utils/test_container_node_ext.rs @@ -0,0 +1,20 @@ +use { + crate::{ + it::test_error::TestResult, + tree::{ContainerNode, ToplevelNode}, + }, + std::rc::Rc, +}; + +pub trait TestContainerExt { + fn first_toplevel(&self) -> TestResult>; +} + +impl TestContainerExt for ContainerNode { + fn first_toplevel(&self) -> TestResult> { + match self.children.first() { + None => bail!("container does not have children"), + Some(c) => Ok(c.node.clone()), + } + } +} diff --git a/src/it/test_utils/test_ouput_node_ext.rs b/src/it/test_utils/test_ouput_node_ext.rs new file mode 100644 index 00000000..472b4f98 --- /dev/null +++ b/src/it/test_utils/test_ouput_node_ext.rs @@ -0,0 +1,20 @@ +use { + crate::{ + it::test_error::TestResult, + tree::{OutputNode, WorkspaceNode}, + }, + std::rc::Rc, +}; + +pub trait TestOutputNodeExt { + fn workspace(&self) -> TestResult>; +} + +impl TestOutputNodeExt for OutputNode { + fn workspace(&self) -> TestResult> { + match self.workspace.get() { + None => bail!("Output node does not have a container"), + Some(w) => Ok(w), + } + } +} diff --git a/src/it/test_utils/test_toplevel_node_ext.rs b/src/it/test_utils/test_toplevel_node_ext.rs new file mode 100644 index 00000000..ed299f75 --- /dev/null +++ b/src/it/test_utils/test_toplevel_node_ext.rs @@ -0,0 +1,12 @@ +use crate::tree::ToplevelNode; + +pub trait TestToplevelNodeExt { + fn center(&self) -> (i32, i32); +} + +impl TestToplevelNodeExt for dyn ToplevelNode { + fn center(&self) -> (i32, i32) { + let rect = self.node_absolute_position(); + ((rect.x1() + rect.x2()) / 2, (rect.y1() + rect.y2()) / 2) + } +} diff --git a/src/it/test_utils/test_workspace_node_ext.rs b/src/it/test_utils/test_workspace_node_ext.rs new file mode 100644 index 00000000..48f2200c --- /dev/null +++ b/src/it/test_utils/test_workspace_node_ext.rs @@ -0,0 +1,20 @@ +use { + crate::{ + it::test_error::TestResult, + tree::{ContainerNode, WorkspaceNode}, + }, + std::rc::Rc, +}; + +pub trait TestWorkspaceNodeExt { + fn container(&self) -> TestResult>; +} + +impl TestWorkspaceNodeExt for WorkspaceNode { + fn container(&self) -> TestResult> { + match self.container.get() { + None => bail!("workspace does not have a container"), + Some(c) => Ok(c), + } + } +} diff --git a/src/it/testrun.rs b/src/it/testrun.rs index 81b88db0..ee5751d9 100644 --- a/src/it/testrun.rs +++ b/src/it/testrun.rs @@ -1,6 +1,7 @@ use { crate::{ client::{ClientId, RequestParser}, + fixed::Fixed, ifs::wl_seat::WlSeatGlobal, it::{ test_backend::{TestBackend, TestBackendKb, TestBackendMouse, TestConnector}, @@ -146,3 +147,12 @@ pub struct DefaultSetup { pub mouse: Rc, pub seat: Rc, } + +impl DefaultSetup { + pub fn move_to(&self, x: i32, y: i32) { + let (ox, oy) = self.seat.position(); + let (nx, ny) = (Fixed::from_int(x), Fixed::from_int(y)); + let (dx, dy) = (nx - ox, ny - oy); + self.mouse.rel(dx.to_f64(), dy.to_f64()) + } +} diff --git a/src/it/tests.rs b/src/it/tests.rs index a67da9c3..f47ef0dc 100644 --- a/src/it/tests.rs +++ b/src/it/tests.rs @@ -44,6 +44,7 @@ mod t0015_scroll_partial; mod t0016_scroll_ws; mod t0017_remove_unused_ws; mod t0018_click_to_active_ws; +mod t0019_natural_scrolling; pub trait TestCase: Sync { fn name(&self) -> &'static str; @@ -80,5 +81,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> { t0016_scroll_ws, t0017_remove_unused_ws, t0018_click_to_active_ws, + t0019_natural_scrolling, } } diff --git a/src/it/tests/t0019_natural_scrolling.rs b/src/it/tests/t0019_natural_scrolling.rs new file mode 100644 index 00000000..cdfa66d5 --- /dev/null +++ b/src/it/tests/t0019_natural_scrolling.rs @@ -0,0 +1,46 @@ +use { + crate::{ + ifs::wl_seat::wl_pointer::{IDENTICAL, INVERTED}, + it::{ + test_error::TestResult, + test_utils::{ + test_container_node_ext::TestContainerExt, test_ouput_node_ext::TestOutputNodeExt, + test_toplevel_node_ext::TestToplevelNodeExt, + test_workspace_node_ext::TestWorkspaceNodeExt, + }, + testrun::TestRun, + }, + }, + std::rc::Rc, +}; + +testcase!(); + +async fn test(run: Rc) -> TestResult { + let ds = run.create_default_setup().await?; + + let client = run.create_client().await?; + let win1 = client.create_window().await?; + win1.map2().await?; + + let (x, y) = ds + .output + .workspace()? + .container()? + .first_toplevel()? + .center(); + ds.move_to(x, y); + + let seat = client.get_default_seat().await?; + let ard = seat.pointer.axis_relative_direction.expect()?; + + ds.mouse.scroll_px2(1, false); + client.sync().await; + tassert_eq!(ard.next()?.direction, IDENTICAL); + + ds.mouse.scroll_px2(1, true); + client.sync().await; + tassert_eq!(ard.next()?.direction, INVERTED); + + Ok(()) +}