server: scale wl_touch events

Fixes #172
This commit is contained in:
Shawn Wallace 2025-06-19 20:54:57 -04:00
parent b98fa84524
commit 70f15d5085
3 changed files with 114 additions and 22 deletions

View file

@ -711,29 +711,49 @@ impl Event for client::wl_keyboard::Event {
impl Event for client::wl_touch::Event { impl Event for client::wl_touch::Event {
fn handle<C: XConnection>(self, target: Entity, state: &mut ServerState<C>) { fn handle<C: XConnection>(self, target: Entity, state: &mut ServerState<C>) {
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; let (s_surface, s_factor) = s_query.get().unwrap();
simple_event_shunt! { cmd.insert(target, (*s_factor,));
touch, self => [ let touch = state.world.get::<&WlTouch>(target).unwrap();
Down { touch.down(serial, time, s_surface, id, x * s_factor.0, y * s_factor.0);
serial, }
time, cmd.run_on(&mut state.world);
|surface| { }
s_surf = surface.data().copied().and_then(|key| state.world.get::<&WlSurface>(key).ok()); Self::Motion { time, id, x, y } => {
if let Some(s) = &s_surf { s } else { return; } let (touch, scale) = state.world.query_one_mut::<(&WlTouch, &SurfaceScaleFactor)>(target).unwrap();
}, touch.motion(time, id, x * scale.0, y * scale.0);
id, }
x, _ => {
y let touch = state.world.get::<&WlTouch>(target).unwrap();
}, simple_event_shunt! {
Up { serial, time, id }, touch, self => [
Motion { time, id, x, y }, Up { serial, time, id },
Frame, Frame,
Cancel, Cancel,
Shape { id, major, minor }, Shape { id, major, minor },
Orientation { id, orientation } Orientation { id, orientation }
] ]
}
}
} }
} }
} }

View file

@ -20,6 +20,7 @@ use wayland_client::{
wl_shm::{Format, WlShm}, wl_shm::{Format, WlShm},
wl_shm_pool::WlShmPool, wl_shm_pool::WlShmPool,
wl_surface::WlSurface, wl_surface::WlSurface,
wl_touch::{self, WlTouch},
}, },
Connection, Proxy, WEnum, 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::<WlTouch>::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. /// See Pointer::handle_event for an explanation.
#[test] #[test]
fn popup_pointer_motion_workaround() {} fn popup_pointer_motion_workaround() {}

View file

@ -72,6 +72,7 @@ use wayland_server::{
wl_shm::WlShm, wl_shm::WlShm,
wl_shm_pool::WlShmPool, wl_shm_pool::WlShmPool,
wl_surface::WlSurface, wl_surface::WlSurface,
wl_touch::{self, WlTouch},
}, },
Client, Dispatch, Display, DisplayHandle, GlobalDispatch, Resource, WEnum, Client, Dispatch, Display, DisplayHandle, GlobalDispatch, Resource, WEnum,
}; };
@ -225,6 +226,7 @@ struct State {
seat: Option<WlSeat>, seat: Option<WlSeat>,
pointer: Option<WlPointer>, pointer: Option<WlPointer>,
keyboard: Option<KeyboardState>, keyboard: Option<KeyboardState>,
touch: Option<WlTouch>,
configure_serial: u32, configure_serial: u32,
selection: Option<WlDataSource>, selection: Option<WlDataSource>,
data_device_man: Option<WlDataDeviceManager>, data_device_man: Option<WlDataDeviceManager>,
@ -248,6 +250,7 @@ impl Default for State {
seat: None, seat: None,
pointer: None, pointer: None,
keyboard: None, keyboard: None,
touch: None,
configure_serial: 0, configure_serial: 0,
selection: None, selection: None,
data_device_man: None, data_device_man: None,
@ -752,6 +755,11 @@ impl Server {
.create_global::<State, WpFractionalScaleManagerV1, _>(1, ()); .create_global::<State, WpFractionalScaleManagerV1, _>(1, ());
self.display.flush_clients().unwrap(); 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)] #[derive(Clone, Eq, PartialEq, Debug)]
@ -1067,6 +1075,9 @@ impl Dispatch<WlSeat, ()> for State {
current_focus: None, current_focus: None,
}); });
} }
wl_seat::Request::GetTouch { id } => {
state.touch = Some(data_init.init(id, ()));
}
wl_seat::Request::Release => {} wl_seat::Request::Release => {}
other => todo!("unhandled request {other:?}"), other => todo!("unhandled request {other:?}"),
} }
@ -1125,6 +1136,23 @@ impl Dispatch<WlKeyboard, ()> for State {
} }
} }
impl Dispatch<WlTouch, ()> for State {
fn request(
_: &mut Self,
_: &Client,
_: &WlTouch,
request: <WlTouch as Resource>::Request,
_: &(),
_: &DisplayHandle,
_: &mut wayland_server::DataInit<'_, Self>,
) {
match request {
wl_touch::Request::Release => {}
other => todo!("unhandled request {other:?}"),
}
}
}
impl Dispatch<XdgPopup, SurfaceId> for State { impl Dispatch<XdgPopup, SurfaceId> for State {
fn request( fn request(
state: &mut Self, state: &mut Self,