From 154ecf61972fa7277bf9412f2bf34b496338b57d Mon Sep 17 00:00:00 2001
From: Po Lu <luangruo@yahoo.com>
Date: Sat, 5 Nov 2022 19:09:42 +0800
Subject: [PATCH] Simplify XI scroll class reporting code

* src/xterm.c (xi_populate_device_from_info): Use xnmalloc.
Avoid reading classes at all when the XI library only supports
2.0.
(xi_handle_new_classes): New function.
(xi_handle_device_changed): Move class parsing logic there to
avoid duplicating code.
---
 src/xterm.c | 224 ++++++++++++++++++++++------------------------------
 1 file changed, 94 insertions(+), 130 deletions(-)

diff --git a/src/xterm.c b/src/xterm.c
index 4178526c318..545a95f7b24 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5301,6 +5301,7 @@ x_free_xi_devices (struct x_display_info *dpyinfo)
 }
 
 #ifdef HAVE_XINPUT2_1
+
 struct xi_known_valuator
 {
   /* The current value of this valuator.  */
@@ -5312,6 +5313,7 @@ struct xi_known_valuator
   /* The next valuator whose value we already know.  */
   struct xi_known_valuator *next;
 };
+
 #endif
 
 static void
@@ -5321,11 +5323,10 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
 #ifdef HAVE_XINPUT2_1
   struct xi_scroll_valuator_t *valuator;
   struct xi_known_valuator *values, *tem;
-  int actual_valuator_count;
+  int actual_valuator_count, c;
   XIScrollClassInfo *info;
   XIValuatorClassInfo *val_info;
 #endif
-  int c;
 #ifdef HAVE_XINPUT2_2
   XITouchClassInfo *touch_info;
 #endif
@@ -5339,8 +5340,8 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
 
 #ifdef HAVE_XINPUT2_1
   actual_valuator_count = 0;
-  xi_device->valuators = xmalloc (sizeof *xi_device->valuators
-				  * device->num_classes);
+  xi_device->valuators = xnmalloc (device->num_classes,
+				   sizeof *xi_device->valuators);
   values = NULL;
 #endif
 
@@ -5353,11 +5354,11 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
   xi_device->direct_p = false;
 #endif
 
+#ifdef HAVE_XINPUT2_1
   for (c = 0; c < device->num_classes; ++c)
     {
       switch (device->classes[c]->type)
 	{
-#ifdef HAVE_XINPUT2_1
 	case XIScrollClass:
 	  {
 	    info = (XIScrollClassInfo *) device->classes[c];
@@ -5385,7 +5386,6 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
 	    values = tem;
 	    break;
 	  }
-#endif
 
 #ifdef HAVE_XINPUT2_2
 	case XITouchClass:
@@ -5399,7 +5399,6 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
 	}
     }
 
-#ifdef HAVE_XINPUT2_1
   xi_device->scroll_valuator_count = actual_valuator_count;
 
   /* Now look through all the valuators whose values are already known
@@ -13043,97 +13042,117 @@ xi_has_scroll_valuators (XIDeviceChangedEvent *event)
   return false;
 }
 
-#endif
+/* Repopulate the information (touchpoint tracking information, scroll
+   valuators, etc) in DEVICE with the device classes provided in
+   CLASSES.  This is called upon receiving a DeviceChanged event.
 
-/* Handle EVENT, a DeviceChanged event.  Look up the device that
-   changed, and update its information with the data in EVENT.  */
+   This function is not present on XI 2.0 as there are no worthwhile
+   classes there.  */
 
 static void
-xi_handle_device_changed (struct x_display_info *dpyinfo,
-			  struct xi_device_t *device,
-			  XIDeviceChangedEvent *event)
+xi_handle_new_classes (struct x_display_info *dpyinfo, struct xi_device_t *device,
+		       XIAnyClassInfo **classes, int num_classes)
 {
-#ifdef HAVE_XINPUT2_1
-  XIDeviceInfo *info;
   XIScrollClassInfo *scroll;
-  int i, ndevices;
   struct xi_scroll_valuator_t *valuator;
   XIValuatorClassInfo *valuator_info;
-#endif
+  int i;
 #ifdef HAVE_XINPUT2_2
-  struct xi_touch_point_t *tem, *last;
   XITouchClassInfo *touch;
 #endif
 
-#ifdef HAVE_XINPUT2_1
-  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) */
-
-      device->valuators = xrealloc (device->valuators,
-				    (event->num_classes
-				     * sizeof *device->valuators));
-      device->scroll_valuator_count = 0;
+  if (dpyinfo->xi2_version < 1)
+    /* Emacs is connected to an XI 2.0 server, which reports no
+       classes of interest.  */
+    return;
+
+  device->valuators = xnmalloc (num_classes,
+				sizeof *device->valuators);
+  device->scroll_valuator_count = 0;
 #ifdef HAVE_XINPUT2_2
-      device->direct_p = false;
+  device->direct_p = false;
 #endif
 
-      for (i = 0; i < event->num_classes; ++i)
+  for (i = 0; i < num_classes; ++i)
+    {
+      switch (classes[i]->type)
 	{
-	  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;
+	case XIScrollClass:
+	  scroll = (XIScrollClassInfo *) 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];
+	case XITouchClass:
+	  touch = (XITouchClassInfo *) classes[i];
 
-	      if (touch->mode == XIDirectTouch)
-		device->direct_p = true;
-	      break;
+	  if (touch->mode == XIDirectTouch)
+	    device->direct_p = true;
+	  break;
 #endif
-	    }
 	}
+    }
 
-      /* Restore the values of any scroll valuators that we already
-	 know about.  */
+  /* Restore the values of any scroll valuators that we already
+     know about.  */
 
-      for (i = 0; i < event->num_classes; ++i)
+  for (i = 0; i < num_classes; ++i)
+    {
+      switch (classes[i]->type)
 	{
-	  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;
-		}
+	case XIValuatorClass:
+	  valuator_info = (XIValuatorClassInfo *) classes[i];
 
-	      break;
+	  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;
 	    }
+
+	  break;
 	}
     }
+}
+
+#endif
+
+/* Handle EVENT, a DeviceChanged event.  Look up the device that
+   changed, and update its information with the data in EVENT.  */
+
+static void
+xi_handle_device_changed (struct x_display_info *dpyinfo,
+			  struct xi_device_t *device,
+			  XIDeviceChangedEvent *event)
+{
+#ifdef HAVE_XINPUT2_1
+  int ndevices;
+  XIDeviceInfo *info;
+#endif
+#ifdef HAVE_XINPUT2_2
+  struct xi_touch_point_t *tem, *last;
+#endif
+
+#ifdef HAVE_XINPUT2_1
+  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: if this event is a SlaveSwitch event caused by
+       wheel movement, then querying for the device info will probably
+       return the value after the wheel movement, leading to a delta
+       of 0 being computed upon handling the subsequent XI_Motion
+       event.  (bug#58980) */
+    xi_handle_new_classes (dpyinfo, device, event->classes,
+			   event->num_classes);
   else
     {
       /* When a DeviceChange event is received for a master device,
@@ -13153,65 +13172,10 @@ xi_handle_device_changed (struct x_display_info *dpyinfo,
       if (!info)
 	return;
 
-      device->valuators = xrealloc (device->valuators,
-				    (info->num_classes
-				     * sizeof *device->valuators));
-      device->scroll_valuator_count = 0;
-#ifdef HAVE_XINPUT2_2
-      device->direct_p = false;
-#endif
-
-      for (i = 0; i < info->num_classes; ++i)
-	{
-	  switch (info->classes[i]->type)
-	    {
-	    case XIScrollClass:
-	      scroll = (XIScrollClassInfo *) info->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 *) info->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 < info->num_classes; ++i)
-	{
-	  switch (info->classes[i]->type)
-	    {
-	    case XIValuatorClass:
-	      valuator_info = (XIValuatorClassInfo *) info->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;
-		}
-
-	      break;
-	    }
-	}
-
-      XIFreeDeviceInfo (info);
+      /* info contains the classes currently associated with the
+	 event.  Apply them.  */
+      xi_handle_new_classes (dpyinfo, device, info->classes,
+			     info->num_classes);
     }
 #endif
 
-- 
2.39.5