server: scale tablet_tool motion events

Also add missing Distance event handler.
Closes #179, closes #123
This commit is contained in:
Shawn Wallace 2025-06-19 23:03:51 -04:00
parent 70f15d5085
commit 03cbb2ee3a
4 changed files with 141 additions and 17 deletions

View file

@ -264,6 +264,10 @@ where
}
}
pub fn get(&self) -> Entity {
self.key.get().copied().expect("Object key is not set")
}
fn new() -> Self {
Self {
key: OnceLock::new(),

View file

@ -19,7 +19,8 @@ use wayland_protocols::{
tablet::zv2::{
client::{
zwp_tablet_pad_group_v2, zwp_tablet_pad_ring_v2, zwp_tablet_pad_strip_v2,
zwp_tablet_pad_v2, zwp_tablet_seat_v2, zwp_tablet_tool_v2, zwp_tablet_v2,
zwp_tablet_pad_v2, zwp_tablet_seat_v2, zwp_tablet_tool_v2,
zwp_tablet_v2::{self, ZwpTabletV2 as TabletClient},
},
server::{
zwp_tablet_pad_group_v2::ZwpTabletPadGroupV2 as TabletPadGroupServer,
@ -739,7 +740,10 @@ impl Event for client::wl_touch::Event {
cmd.run_on(&mut state.world);
}
Self::Motion { time, id, x, y } => {
let (touch, scale) = state.world.query_one_mut::<(&WlTouch, &SurfaceScaleFactor)>(target).unwrap();
let (touch, scale) = state
.world
.query_one_mut::<(&WlTouch, &SurfaceScaleFactor)>(target)
.unwrap();
touch.motion(time, id, x * scale.0, y * scale.0);
}
_ => {
@ -1327,27 +1331,55 @@ impl Event for zwp_tablet_pad_v2::Event {
impl Event for zwp_tablet_tool_v2::Event {
fn handle<C: XConnection>(self, target: Entity, state: &mut ServerState<C>) {
let tool = state.world.get::<&TabletToolServer>(target).unwrap();
match self {
Self::ProximityIn {
serial,
tablet,
surface,
} => {
let (e_tab, s_tablet) = from_client::<TabletServer, _, _>(&tablet, state);
let Some(surface) = surface
.data()
.copied()
.and_then(|key| state.world.get::<&WlSurface>(key).ok())
else {
return;
};
tool.proximity_in(serial, &s_tablet, &surface);
drop(tool);
drop(surface);
state.world.spawn_at(e_tab, (tablet, s_tablet));
let mut cmd = CommandBuffer::new();
{
let Some(mut query) = surface.data().copied().and_then(|key| {
state
.world
.query_one::<(&WlSurface, &SurfaceScaleFactor)>(key)
.ok()
}) else {
warn!("tablet tool proximity_in failed: stale surface");
return;
};
let (surface, scale) = query.get().unwrap();
cmd.insert(target, (*scale,));
let Some(s_tablet) =
tablet
.data()
.and_then(|key: &LateInitObjectKey<TabletClient>| {
state.world.get::<&TabletServer>(key.get()).ok()
})
else {
warn!("tablet tool proximity_in failed: stale tablet");
return;
};
state
.world
.get::<&TabletToolServer>(target)
.unwrap()
.proximity_in(serial, &s_tablet, surface);
}
cmd.run_on(&mut state.world);
}
Self::Motion { x, y } => {
let (tool, scale) = state
.world
.query_one_mut::<(&TabletToolServer, Option<&SurfaceScaleFactor>)>(target)
.unwrap();
let scale = scale.map(|s| s.0).unwrap_or(1.0);
tool.motion(x * scale, y * scale);
}
_ => {
let tool = state.world.get::<&TabletToolServer>(target).unwrap();
simple_event_shunt! {
tool, self => [
Type { |tool_type| convert_wenum(tool_type) },
@ -1359,7 +1391,7 @@ impl Event for zwp_tablet_tool_v2::Event {
ProximityOut,
Down { serial },
Up,
Motion { x, y },
Distance { distance },
Pressure { pressure },
Tilt { tilt_x, tilt_y },
Rotation { degrees },

View file

@ -2290,6 +2290,75 @@ fn touch_fractional_scale() {
assert_eq!(y, 40.0 * 1.5);
}
#[test]
fn tablet_tool_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 toplevel = unsafe { Window::new(1) };
let (_, id) = f.create_toplevel(&comp, toplevel);
let surface_data = f.testwl.get_surface_data(id).unwrap();
let fractional = surface_data.fractional.as_ref().cloned().unwrap();
let server_surface = surface_data.surface.clone();
f.testwl.move_surface_to_output(id, &output);
let seat = TestObject::<ZwpTabletSeatV2>::from_request(
&comp.tablet_man.obj,
zwp_tablet_manager_v2::Request::GetTabletSeat {
seat: comp.seat.obj,
},
);
// Not sure why exactly this requires 4 runs but it works so idk
for _ in 0..4 {
f.run();
}
let mut tool = None;
for event in seat.data.events.lock().unwrap().drain(..) {
if let zwp_tablet_seat_v2::Event::ToolAdded { id } = event {
tool = Some(id.clone());
break;
}
}
let client_tool = tool.expect("Didn't get tool");
let client_data = f.object_data(&client_tool);
let server_tool = f.testwl.tablet_tool().clone();
let tablet = f.testwl.tablet().clone();
let get_motion = || {
let events = &mut *client_data.events.lock().unwrap();
let event = events.pop();
let Some(zwp_tablet_tool_v2::Event::Motion { x, y }) = event else {
panic!("Didn't get motion event: {event:?}");
};
(x, y)
};
server_tool.proximity_in(0, &tablet, &server_surface);
server_tool.motion(20.0, 40.0);
f.testwl.dispatch();
f.run();
f.run();
let (x, y) = get_motion();
assert_eq!(x, 20.0);
assert_eq!(y, 40.0);
fractional.preferred_scale(180); // 1.5 scale
server_tool.proximity_in(0, &tablet, &server_surface);
server_tool.motion(20.0, 40.0);
f.testwl.dispatch();
f.run();
f.run();
let (x, y) = get_motion();
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() {}