From 01471b5fdff21fcb23b7718d9cd99bf5c08645ba Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 4 Nov 2022 19:21:22 +0800 Subject: [PATCH] Avoid using too up-to-date values when restoring valuators * src/xterm.c (xi_has_scroll_valuators): New function. (xi_handle_device_changed): If the device changed event provides scroll valuators, then use the values in there. (bug#58980) --- src/xterm.c | 145 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 28 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index 71ff69ece4c..4178526c318 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -13026,6 +13026,23 @@ xi_get_scroll_valuator (struct xi_device_t *device, int number) return NULL; } +/* Check if EVENT, a DeviceChanged event, contains any scroll + valuators. */ + +static bool +xi_has_scroll_valuators (XIDeviceChangedEvent *event) +{ + int i; + + for (i = 0; i < event->num_classes; ++i) + { + if (event->classes[i]->type == XIScrollClass) + return true; + } + + return false; +} + #endif /* Handle EVENT, a DeviceChanged event. Look up the device that @@ -13049,21 +13066,93 @@ xi_handle_device_changed (struct x_display_info *dpyinfo, #endif #ifdef HAVE_XINPUT2_1 - /* When a DeviceChange event is received for a master device, we - don't get any scroll valuators along with it. This is possibly - an X server bug but I really don't want to dig any further, so - fetch the scroll valuators manually. (bug#57020) */ + if (xi_has_scroll_valuators (event)) + { + /* Scroll valuators are provided by this event. Use the values + provided in this event to populate the device's new scroll + valuator list, as if this event's is a SlaveSwitch event + caused by wheel movement, querying for the device info will + probably return newer values, leading to a delta of 0 being + computed when handling the subsequent XI_Motion event. + (bug#58980) */ - x_catch_errors (dpyinfo->display); - info = XIQueryDevice (dpyinfo->display, event->deviceid, - /* ndevices is always 1 if a deviceid is - specified. If the request fails, NULL will - be returned. */ - &ndevices); - x_uncatch_errors (); + device->valuators = xrealloc (device->valuators, + (event->num_classes + * sizeof *device->valuators)); + device->scroll_valuator_count = 0; +#ifdef HAVE_XINPUT2_2 + device->direct_p = false; +#endif + + for (i = 0; i < event->num_classes; ++i) + { + switch (event->classes[i]->type) + { + case XIScrollClass: + scroll = (XIScrollClassInfo *) event->classes[i]; + + valuator = &device->valuators[device->scroll_valuator_count++]; + valuator->horizontal = (scroll->scroll_type + == XIScrollTypeHorizontal); + valuator->invalid_p = true; + valuator->emacs_value = 0; + valuator->increment = scroll->increment; + valuator->number = scroll->number; + break; + +#ifdef HAVE_XINPUT2_2 + case XITouchClass: + touch = (XITouchClassInfo *) event->classes[i]; + + if (touch->mode == XIDirectTouch) + device->direct_p = true; + break; +#endif + } + } + + /* Restore the values of any scroll valuators that we already + know about. */ + + for (i = 0; i < event->num_classes; ++i) + { + switch (event->classes[i]->type) + { + case XIValuatorClass: + valuator_info = (XIValuatorClassInfo *) event->classes[i]; + + valuator = xi_get_scroll_valuator (device, + valuator_info->number); + if (valuator) + { + valuator->invalid_p = false; + valuator->current_value = valuator_info->value; + valuator->emacs_value = 0; + } - if (info) + break; + } + } + } + else { + /* When a DeviceChange event is received for a master device, + the X server sometimes does not send any scroll valuators + along with it. This is possibly an X server bug but I really + don't want to dig any further, so fetch the scroll valuators + manually. (bug#57020) */ + + x_catch_errors (dpyinfo->display); + info = XIQueryDevice (dpyinfo->display, event->deviceid, + /* ndevices is always 1 if a deviceid is + specified. If the request fails, NULL will + be returned. */ + &ndevices); + x_uncatch_errors (); + + if (!info) + return; + device->valuators = xrealloc (device->valuators, (info->num_classes * sizeof *device->valuators)); @@ -13115,32 +13204,32 @@ xi_handle_device_changed (struct x_display_info *dpyinfo, { valuator->invalid_p = false; valuator->current_value = valuator_info->value; + valuator->emacs_value = 0; } break; } } -#ifdef HAVE_XINPUT2_2 - /* The device is no longer a DirectTouch device, so - remove any touchpoints that we might have - recorded. */ - if (!device->direct_p) - { - tem = device->touchpoints; + XIFreeDeviceInfo (info); + } +#endif - while (tem) - { - last = tem; - tem = tem->next; - xfree (last); - } +#ifdef HAVE_XINPUT2_2 + /* The device is no longer a DirectTouch device, so remove any + touchpoints that we might have recorded. */ + if (!device->direct_p) + { + tem = device->touchpoints; - device->touchpoints = NULL; + while (tem) + { + last = tem; + tem = tem->next; + xfree (last); } -#endif - XIFreeDeviceInfo (info); + device->touchpoints = NULL; } #endif } -- 2.39.2