diff --git a/src/server/event.rs b/src/server/event.rs index 5a4f684..de88c4b 100644 --- a/src/server/event.rs +++ b/src/server/event.rs @@ -711,29 +711,49 @@ impl Event for client::wl_keyboard::Event { impl Event for client::wl_touch::Event { fn handle(self, target: Entity, state: &mut ServerState) { - let touch = state.world.get::<&WlTouch>(target).unwrap(); + match self { + Self::Down { + serial, + time, + surface, + id, + x, + y, + } => { + let mut cmd = CommandBuffer::new(); + { + let Some(mut s_query) = surface.data().copied().and_then(|key| { + state + .world + .query_one::<(&WlSurface, &SurfaceScaleFactor)>(key) + .ok() + }) else { + return; + }; - let s_surf; - simple_event_shunt! { - touch, self => [ - Down { - serial, - time, - |surface| { - s_surf = surface.data().copied().and_then(|key| state.world.get::<&WlSurface>(key).ok()); - if let Some(s) = &s_surf { s } else { return; } - }, - id, - x, - y - }, - Up { serial, time, id }, - Motion { time, id, x, y }, - Frame, - Cancel, - Shape { id, major, minor }, - Orientation { id, orientation } - ] + let (s_surface, s_factor) = s_query.get().unwrap(); + cmd.insert(target, (*s_factor,)); + let touch = state.world.get::<&WlTouch>(target).unwrap(); + touch.down(serial, time, s_surface, id, x * s_factor.0, y * s_factor.0); + } + cmd.run_on(&mut state.world); + } + Self::Motion { time, id, x, y } => { + let (touch, scale) = state.world.query_one_mut::<(&WlTouch, &SurfaceScaleFactor)>(target).unwrap(); + touch.motion(time, id, x * scale.0, y * scale.0); + } + _ => { + let touch = state.world.get::<&WlTouch>(target).unwrap(); + simple_event_shunt! { + touch, self => [ + Up { serial, time, id }, + Frame, + Cancel, + Shape { id, major, minor }, + Orientation { id, orientation } + ] + } + } } } } diff --git a/src/server/tests.rs b/src/server/tests.rs index 428b105..d5c5927 100644 --- a/src/server/tests.rs +++ b/src/server/tests.rs @@ -20,6 +20,7 @@ use wayland_client::{ wl_shm::{Format, WlShm}, wl_shm_pool::WlShmPool, wl_surface::WlSurface, + wl_touch::{self, WlTouch}, }, Connection, Proxy, WEnum, }; @@ -2246,6 +2247,49 @@ fn transient_for_toplevel() { ); } +#[test] +fn touch_fractional_scale() { + let mut f = TestFixture::new_pre_connect(|testwl| { + testwl.enable_fractional_scale(); + }); + let comp = f.compositor(); + let (_, output) = f.new_output(0, 0); + let touch = TestObject::::from_request(&comp.seat.obj, wl_seat::Request::GetTouch {}); + f.run(); + + let toplevel = unsafe { Window::new(1) }; + let (_, id) = f.create_toplevel(&comp, toplevel); + f.testwl.move_surface_to_output(id, &output); + + let data = f.testwl.get_surface_data(id).unwrap(); + let server_surface = data.surface.clone(); + let fractional = data.fractional.as_ref().cloned().unwrap(); + + let do_touch = |f: &mut TestFixture, x, y| { + f.testwl.touch().down(0, 0, &server_surface, 0, x, y); + f.testwl.dispatch(); + f.run(); + f.run(); + let events = &mut touch.data.events.lock().unwrap(); + assert_eq!(events.len(), 1); + let event = events.pop().unwrap(); + let wl_touch::Event::Down { x, y, .. } = event else { + panic!("Got unexpected event: {event:?}"); + }; + (x, y) + }; + + let (x, y) = do_touch(&mut f, 20.0, 40.0); + assert_eq!(x, 20.0); + assert_eq!(y, 40.0); + + fractional.preferred_scale(180); // 1.5 scale + f.run(); + let (x, y) = do_touch(&mut f, 20.0, 40.0); + assert_eq!(x, 20.0 * 1.5); + assert_eq!(y, 40.0 * 1.5); +} + /// See Pointer::handle_event for an explanation. #[test] fn popup_pointer_motion_workaround() {} diff --git a/testwl/src/lib.rs b/testwl/src/lib.rs index f5ad426..d92cb11 100644 --- a/testwl/src/lib.rs +++ b/testwl/src/lib.rs @@ -72,6 +72,7 @@ use wayland_server::{ wl_shm::WlShm, wl_shm_pool::WlShmPool, wl_surface::WlSurface, + wl_touch::{self, WlTouch}, }, Client, Dispatch, Display, DisplayHandle, GlobalDispatch, Resource, WEnum, }; @@ -225,6 +226,7 @@ struct State { seat: Option, pointer: Option, keyboard: Option, + touch: Option, configure_serial: u32, selection: Option, data_device_man: Option, @@ -248,6 +250,7 @@ impl Default for State { seat: None, pointer: None, keyboard: None, + touch: None, configure_serial: 0, selection: None, data_device_man: None, @@ -752,6 +755,11 @@ impl Server { .create_global::(1, ()); self.display.flush_clients().unwrap(); } + + #[track_caller] + pub fn touch(&mut self) -> &WlTouch { + self.state.touch.as_ref().expect("No touch object created") + } } #[derive(Clone, Eq, PartialEq, Debug)] @@ -1067,6 +1075,9 @@ impl Dispatch for State { current_focus: None, }); } + wl_seat::Request::GetTouch { id } => { + state.touch = Some(data_init.init(id, ())); + } wl_seat::Request::Release => {} other => todo!("unhandled request {other:?}"), } @@ -1125,6 +1136,23 @@ impl Dispatch for State { } } +impl Dispatch for State { + fn request( + _: &mut Self, + _: &Client, + _: &WlTouch, + request: ::Request, + _: &(), + _: &DisplayHandle, + _: &mut wayland_server::DataInit<'_, Self>, + ) { + match request { + wl_touch::Request::Release => {} + other => todo!("unhandled request {other:?}"), + } + } +} + impl Dispatch for State { fn request( state: &mut Self,