Fix scroll axis interpolation with the libinput driver

* atoms.c (names, XLInitAtoms): Intern "libinput Scrolling Pixel
Distance".
* compositor.h: Update atom.
* seat.c (struct _DeviceInfo): New field
`scroll_pixel_distance'.
(UpdateScrollPixelDistance): New function.
(RecordDeviceInformation, HandlePropertyChanged): Update that
field whenever necessary.
(InterpolateAxes, SendScrollAxis): Fix NULL pointer dereference
and always interpolate axes by the scroll pixel distance
whenever available.
(HandleValuatorMotion): Don't scale axis values by 10.
This commit is contained in:
hujianwei 2022-10-23 02:17:00 +00:00
parent b0db38043a
commit a220f29723
3 changed files with 76 additions and 18 deletions

View file

@ -111,6 +111,7 @@ static const char *names[] =
"CONNECTOR_ID", "CONNECTOR_ID",
"_NET_WM_PID", "_NET_WM_PID",
"_NET_WM_PING", "_NET_WM_PING",
"libinput Scrolling Pixel Distance",
/* These are automatically generated from mime.txt. */ /* These are automatically generated from mime.txt. */
DirectTransferAtomNames DirectTransferAtomNames
@ -133,7 +134,7 @@ Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE, _NET_WM_SYNC_REQUEST_COUNTER,
XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished,
_NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND,
CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING; CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING, libinput_Scrolling_Pixel_Distance;
XrmQuark resource_quark, app_quark, QString; XrmQuark resource_quark, app_quark, QString;
@ -290,9 +291,10 @@ XLInitAtoms (void)
CONNECTOR_ID = atoms[61]; CONNECTOR_ID = atoms[61];
_NET_WM_PID = atoms[62]; _NET_WM_PID = atoms[62];
_NET_WM_PING = atoms[63]; _NET_WM_PING = atoms[63];
libinput_Scrolling_Pixel_Distance = atoms[64];
/* This is automatically generated. */ /* This is automatically generated. */
DirectTransferAtomInit (atoms, 64); DirectTransferAtomInit (atoms, 65);
/* Now, initialize quarks. */ /* Now, initialize quarks. */
resource_quark = XrmPermStringToQuark (compositor.resource_name); resource_quark = XrmPermStringToQuark (compositor.resource_name);

View file

@ -1177,7 +1177,7 @@ extern Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE,
XdndProxy, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndProxy, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop,
XdndFinished, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE, XdndFinished, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND,
CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING; CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING, libinput_Scrolling_Pixel_Distance;
extern XrmQuark resource_quark, app_quark, QString; extern XrmQuark resource_quark, app_quark, QString;

86
seat.c
View file

@ -565,6 +565,9 @@ struct _DeviceInfo
{ {
/* Some flags associated with this device. */ /* Some flags associated with this device. */
int flags; int flags;
/* The libinput scroll pixel distance, if available. Else 15. */
int scroll_pixel_distance;
}; };
#define SetMask(ptr, event) \ #define SetMask(ptr, event) \
@ -1918,6 +1921,44 @@ UpdateScrollMethods (DeviceInfo *info, int deviceid)
XFree (data); XFree (data);
} }
static void
UpdateScrollPixelDistance (DeviceInfo *info, int deviceid)
{
unsigned char *data;
Status rc;
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
data = NULL;
/* This only works with the libinput driver. */
rc = XIGetProperty (compositor.display, deviceid,
libinput_Scrolling_Pixel_Distance,
0, 1, False, XIAnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &data);
/* If there aren't enough items in the data, or the format is wrong,
return. */
if (rc != Success || nitems < 1 || actual_format != 32 || !data)
{
if (data)
XFree (data);
/* Set the distance to the default, 15. */
info->scroll_pixel_distance = 15;
return;
}
/* Now set the scroll pixel distance. */
info->scroll_pixel_distance = ((long *) data)[0];
/* And free the data. */
XLFree (data);
}
static void static void
RecordDeviceInformation (XIDeviceInfo *deviceinfo) RecordDeviceInformation (XIDeviceInfo *deviceinfo)
{ {
@ -1946,6 +1987,10 @@ RecordDeviceInformation (XIDeviceInfo *deviceinfo)
only works with the libinput driver. */ only works with the libinput driver. */
UpdateScrollMethods (info, deviceinfo->deviceid); UpdateScrollMethods (info, deviceinfo->deviceid);
/* Obtain the "libinput Scrolling Pixel Distance" property and
use it if available. If not, default to 15. */
UpdateScrollPixelDistance (info, deviceinfo->deviceid);
/* Uncatch errors. */ /* Uncatch errors. */
UncatchXErrors (NULL); UncatchXErrors (NULL);
} }
@ -2602,6 +2647,9 @@ HandlePropertyChanged (XIPropertyEvent *event)
/* Update scroll methods for the device whose property /* Update scroll methods for the device whose property
changed. */ changed. */
UpdateScrollMethods (info, event->deviceid); UpdateScrollMethods (info, event->deviceid);
else if (event->property == libinput_Scrolling_Pixel_Distance)
/* Update the scroll pixel distance. */
UpdateScrollPixelDistance (info, event->deviceid);
} }
static Seat * static Seat *
@ -3705,15 +3753,21 @@ FindScrollValuator (Seat *seat, int number)
} }
static void static void
InterpolateAxes (Surface *surface, double movement_x, InterpolateAxes (Surface *surface, DeviceInfo *info,
double movement_y, double *x_out, double movement_x, double movement_y,
double *y_out) double *x_out, double *y_out)
{ {
/* This is the algorithm used by most programs. */ if (!info)
*x_out = movement_x * pow (ViewWidth (surface->view), {
2.0 / 3.0); /* Multiply the deltas by 15 if no device was found. */
*x_out = movement_y * pow (ViewHeight (surface->view), *x_out = movement_x * 15;
2.0 / 3.0); *y_out = movement_y * 15;
}
/* Multiply these deltas by the scrolling pixel distance to obtain
the original delta. */
*x_out = movement_x * info->scroll_pixel_distance;
*y_out = movement_y * info->scroll_pixel_distance;
} }
static void static void
@ -3749,12 +3803,14 @@ SendScrollAxis (Seat *seat, Surface *surface, Time time,
if (wl_resource_get_version (pointer->resource) < 8 if (wl_resource_get_version (pointer->resource) < 8
/* Send pixel-wise axis events from devices that are most /* Send pixel-wise axis events from devices that are most
likely touchpads. */ likely touchpads. */
|| (deviceinfo->flags & DeviceCanFingerScroll || (deviceinfo
|| deviceinfo->flags & DeviceCanEdgeScroll)) && (deviceinfo->flags & DeviceCanFingerScroll
|| deviceinfo->flags & DeviceCanEdgeScroll)))
{ {
/* Interpolate the increment-relative axis values to pixel /* Interpolate the increment-relative axis values to pixel
values. */ values. */
InterpolateAxes (surface, axis_x, axis_y, &axis_x, &axis_y); InterpolateAxes (surface, deviceinfo, axis_x, axis_y,
&axis_x, &axis_y);
if (axis_x != 0.0) if (axis_x != 0.0)
wl_pointer_send_axis (pointer->resource, time, wl_pointer_send_axis (pointer->resource, time,
@ -3774,12 +3830,12 @@ SendScrollAxis (Seat *seat, Surface *surface, Time time,
if (axis_x != 0.0) if (axis_x != 0.0)
wl_pointer_send_axis_value120 (pointer->resource, wl_pointer_send_axis_value120 (pointer->resource,
WL_POINTER_AXIS_HORIZONTAL_SCROLL, WL_POINTER_AXIS_HORIZONTAL_SCROLL,
axis_x * 12); axis_x * 120);
if (axis_y != 0.0) if (axis_y != 0.0)
wl_pointer_send_axis_value120 (pointer->resource, wl_pointer_send_axis_value120 (pointer->resource,
WL_POINTER_AXIS_VERTICAL_SCROLL, WL_POINTER_AXIS_VERTICAL_SCROLL,
axis_y * 12); axis_y * 120);
} }
if (axis_y == 0.0 && axis_x == 0.0) if (axis_y == 0.0 && axis_x == 0.0)
@ -3862,8 +3918,8 @@ HandleValuatorMotion (Seat *seat, Surface *dispatch, double x, double y,
} }
if (value && dispatch) if (value && dispatch)
SendScrollAxis (seat, dispatch, event->time, x, y, SendScrollAxis (seat, dispatch, event->time, x, y, total_x,
total_x * 10, total_y * 10, flags, total_y, flags,
/* Also pass the event source device ID, which is /* Also pass the event source device ID, which is
used in an attempt to determine the axis used in an attempt to determine the axis
source. */ source. */