diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index f518d8a9..75959000 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -769,7 +769,7 @@ impl Node for WlSurface { seat.button_surface(&self, button, state, serial); } - fn node_on_axis_event(self: Rc, seat: &WlSeatGlobal, event: &PendingScroll) { + fn node_on_axis_event(self: Rc, seat: &Rc, event: &PendingScroll) { seat.scroll_surface(&*self, event); } diff --git a/src/it/test_backend.rs b/src/it/test_backend.rs index 25e28339..8cd4f227 100644 --- a/src/it/test_backend.rs +++ b/src/it/test_backend.rs @@ -2,9 +2,9 @@ use { crate::{ async_engine::SpawnedFuture, backend::{ - Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, - InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, - KeyState, Mode, MonitorInfo, TransformMatrix, + AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId, + ConnectorKernelId, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, + InputDeviceId, InputEvent, KeyState, Mode, MonitorInfo, ScrollAxis, TransformMatrix, }, compositor::TestFuture, fixed::Fixed, @@ -275,6 +275,14 @@ impl TestBackendMouse { }) } + pub fn abs(&self, connector: &TestConnector, x: f64, y: f64) { + self.common.event(InputEvent::ConnectorPosition { + 0: connector.id, + 1: Fixed::from_f64(x), + 2: Fixed::from_f64(y), + }) + } + pub fn click(self: &Rc, button: u32) -> TestMouseClick { self.common .event(InputEvent::Button(button, KeyState::Pressed)); @@ -283,6 +291,17 @@ impl TestBackendMouse { button, } } + + pub fn scroll(&self, dy: i32) { + self.common.event(InputEvent::AxisSource(AxisSource::Wheel)); + self.common + .event(InputEvent::AxisDiscrete(dy, ScrollAxis::Vertical)); + self.common.event(InputEvent::Axis( + Fixed::from_int(dy * 15), + ScrollAxis::Vertical, + )); + self.common.event(InputEvent::Frame); + } } pub struct TestBackendKb { diff --git a/src/it/test_config.rs b/src/it/test_config.rs index 92c9f5d3..c84d8853 100644 --- a/src/it/test_config.rs +++ b/src/it/test_config.rs @@ -14,7 +14,7 @@ use { }, input::{InputDevice, Seat}, keyboard::{keymap::Keymap, ModifiedKeySym}, - Direction, + Axis, Direction, }, std::{cell::Cell, ops::Deref, ptr, rc::Rc}, }; @@ -191,6 +191,20 @@ impl TestConfig { }) } + pub fn create_split(&self, seat: SeatId, axis: Axis) -> TestResult { + self.send(ClientMessage::CreateSplit { + seat: Seat(seat.raw() as _), + axis, + }) + } + + pub fn set_mono(&self, seat: SeatId, mono: bool) -> TestResult { + self.send(ClientMessage::SetMono { + seat: Seat(seat.raw() as _), + mono, + }) + } + pub fn add_shortcut>( &self, seat: SeatId, diff --git a/src/it/test_ifs/test_xdg_toplevel.rs b/src/it/test_ifs/test_xdg_toplevel.rs index 7f5b600e..184c56f6 100644 --- a/src/it/test_ifs/test_xdg_toplevel.rs +++ b/src/it/test_ifs/test_xdg_toplevel.rs @@ -2,9 +2,12 @@ use { crate::{ ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel, it::{ - test_error::TestError, test_object::TestObject, test_transport::TestTransport, + test_error::{TestError, TestResult}, + test_object::TestObject, + test_transport::TestTransport, testrun::ParseFull, }, + tree::{ContainerNode, ToplevelNode}, utils::buffd::MsgParser, wire::{xdg_toplevel::*, XdgToplevelId}, }, @@ -36,6 +39,17 @@ impl TestXdgToplevel { Ok(()) } + pub fn container_parent(&self) -> TestResult> { + let parent = match self.server.tl_data().parent.get() { + Some(p) => p, + _ => bail!("toplevel has no parent"), + }; + match parent.node_into_container() { + Some(p) => Ok(p), + _ => bail!("toplevel parent is not a container"), + } + } + fn handle_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> { let ev = Configure::parse_full(parser)?; self.width.set(ev.width); diff --git a/src/it/test_utils/test_window.rs b/src/it/test_utils/test_window.rs index 02405f83..3f78d3df 100644 --- a/src/it/test_utils/test_window.rs +++ b/src/it/test_utils/test_window.rs @@ -2,7 +2,7 @@ use { crate::{ format::ARGB8888, it::{ - test_error::TestError, + test_error::{TestError, TestResult}, test_ifs::{ test_shm_buffer::TestShmBuffer, test_shm_pool::TestShmPool, test_surface::TestSurface, test_xdg_surface::TestXdgSurface, @@ -41,6 +41,11 @@ impl TestWindow { Ok(()) } + pub async fn map2(&self) -> TestResult { + self.map().await?; + self.map().await + } + #[allow(dead_code)] pub fn set_color(&self, r: u8, g: u8, b: u8, a: u8) { self.color.set(Color::from_rgba_straight(r, g, b, a)); diff --git a/src/it/tests.rs b/src/it/tests.rs index 15861bc3..30895f79 100644 --- a/src/it/tests.rs +++ b/src/it/tests.rs @@ -39,6 +39,7 @@ mod t0010_fullscreen_focus; mod t0011_set_keymap; mod t0012_subsurface_focus; mod t0013_graphics_initialized; +mod t0014_container_scroll_focus; pub trait TestCase: Sync { fn name(&self) -> &'static str; @@ -70,5 +71,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> { t0011_set_keymap, t0012_subsurface_focus, t0013_graphics_initialized, + t0014_container_scroll_focus, } } diff --git a/src/it/tests/t0014_container_scroll_focus.rs b/src/it/tests/t0014_container_scroll_focus.rs new file mode 100644 index 00000000..e0c6a354 --- /dev/null +++ b/src/it/tests/t0014_container_scroll_focus.rs @@ -0,0 +1,72 @@ +use { + crate::{ + it::{ + test_error::{TestErrorExt, TestResult}, + testrun::TestRun, + }, + tree::ToplevelNode, + }, + jay_config::Axis, + std::rc::Rc, +}; + +testcase!(); + +/// Test that scrolling a mono container header activates the new window +async fn test(run: Rc) -> TestResult { + let ds = run.create_default_setup().await?; + ds.mouse.rel(1.0, 1.0); + + let client = run.create_client().await?; + let dss = client.get_default_seat().await?; + + let w_tiled = client.create_window().await?; + w_tiled.map2().await?; + let w_mono1 = client.create_window().await?; + w_mono1.map2().await?; + + run.cfg.create_split(ds.seat.id(), Axis::Horizontal)?; + run.cfg.set_mono(ds.seat.id(), true)?; + + let w_mono2 = client.create_window().await?; + w_mono2.map2().await?; + + // current state: + // | w_tiled | [ w_mono1 | w_mono2 ] | with w_mono2 visible and active + + client.sync().await; + tassert_eq!(w_tiled.tl.width.get(), w_mono2.tl.width.get()); + + let enters = dss.kb.enter.expect()?; + + ds.mouse.abs(&ds.connector, 0.0, 0.0); + ds.mouse.abs(&ds.connector, 10.0, 500.0); + client.sync().await; + + let enter = enters.next().with_context(|| "no enter event")?; + tassert_eq!(enter.surface, w_tiled.surface.id); + + let mono_container = w_mono2.tl.container_parent()?; + let container_pos = mono_container.tl_data().pos.get(); + log::info!("cp {:?}", container_pos); + let w_mono1_title = mono_container.render_data.borrow_mut().title_rects[0] + .move_(container_pos.x1(), container_pos.y1()); + ds.mouse.abs( + &ds.connector, + w_mono1_title.x1() as _, + w_mono1_title.y1() as _, + ); + + client.sync().await; + tassert!(enters.next().is_err()); + + ds.mouse.scroll(-1); + client.sync().await; + + client.save_screenshot("s2").await?; + + let enter = enters.next().with_context(|| "no enter event 2")?; + tassert_eq!(enter.surface, w_mono1.surface.id); + + Ok(()) +} diff --git a/src/tree.rs b/src/tree.rs index 8a55483f..7b472cf0 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -161,7 +161,7 @@ pub trait Node: 'static { let _ = serial; } - fn node_on_axis_event(self: Rc, seat: &WlSeatGlobal, event: &PendingScroll) { + fn node_on_axis_event(self: Rc, seat: &Rc, event: &PendingScroll) { let _ = seat; let _ = event; } diff --git a/src/tree/container.rs b/src/tree/container.rs index 3e58660d..61a2ff38 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1141,7 +1141,7 @@ impl Node for ContainerNode { } } - fn node_on_axis_event(self: Rc, seat: &WlSeatGlobal, event: &PendingScroll) { + fn node_on_axis_event(self: Rc, seat: &Rc, event: &PendingScroll) { let mut seat_datas = self.seats.borrow_mut(); let seat_data = match seat_datas.get_mut(&seat.id()) { Some(s) => s, @@ -1176,6 +1176,10 @@ impl Node for ContainerNode { }; } self.activate_child(&new_mc); + new_mc + .node + .clone() + .node_do_focus(seat, Direction::Unspecified); } fn node_on_pointer_enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { @@ -1347,6 +1351,7 @@ impl ToplevelNode for ContainerNode { } fn tl_change_extents(self: Rc, rect: &Rect) { + self.toplevel_data.pos.set(*rect); self.abs_x1.set(rect.x1()); self.abs_y1.set(rect.y1()); let mut size_changed = false;