From 1bf30718dd1e4284af285e4a92c336f512564f01 Mon Sep 17 00:00:00 2001
From: Po Lu <luangruo@yahoo.com>
Date: Mon, 14 Feb 2022 11:16:38 +0800
Subject: [PATCH] Improve efficency of handling DeviceChanged events

* src/xterm.c (handle_one_xevent): Just update the device that
was changed on DeviceChanged and only do hierarchy recalculation
upon HierarchyChanged events.
---
 src/xterm.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 82 insertions(+), 7 deletions(-)

diff --git a/src/xterm.c b/src/xterm.c
index a17b445701b..198aaa69e5f 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10783,6 +10783,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 	XIEnterEvent *enter = (XIEnterEvent *) xi_event;
 	XIFocusInEvent *focusin = (XIFocusInEvent *) xi_event;
 	XIFocusOutEvent *focusout = (XIFocusOutEvent *) xi_event;
+	XIDeviceChangedEvent *device_changed = (XIDeviceChangedEvent *) xi_event;
 	XIValuatorState *states;
 	double *values;
 	bool found_valuator = false;
@@ -11861,17 +11862,91 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 	    goto XI_OTHER;
 
 	  case XI_PropertyEvent:
+	    goto XI_OTHER;
+
 	  case XI_HierarchyChanged:
-	  case XI_DeviceChanged:
-#ifdef XISlaveSwitch
-	    if (xi_event->evtype == XI_DeviceChanged
-		&& (((XIDeviceChangedEvent *) xi_event)->reason
-		    == XISlaveSwitch))
-	      goto XI_OTHER;
-#endif
 	    x_init_master_valuators (dpyinfo);
 	    goto XI_OTHER;
 
+	  case XI_DeviceChanged:
+	    {
+	      struct xi_device_t *device;
+	      struct xi_touch_point_t *tem, *last;
+	      int c;
+
+	      device = xi_device_from_id (dpyinfo, device_changed->sourceid);
+
+	      if (!device)
+		emacs_abort ();
+
+	      /* Free data that we will regenerate from new
+		 information.  */
+	      device->valuators = xrealloc (device->valuators,
+					    (device_changed->num_classes
+					     * sizeof *device->valuators));
+	      device->scroll_valuator_count = 0;
+	      device->direct_p = false;
+
+	      for (c = 0; c < device_changed->num_classes; ++c)
+		{
+		  switch (device_changed->classes[c]->type)
+		    {
+#ifdef XIScrollClass
+		    case XIScrollClass:
+		      {
+			XIScrollClassInfo *info =
+			  (XIScrollClassInfo *) device_changed->classes[c];
+			struct xi_scroll_valuator_t *valuator;
+
+			if (device->master_p)
+			  {
+			    valuator = &device->valuators[device->scroll_valuator_count++];
+			    valuator->horizontal
+			      = (info->scroll_type == XIScrollTypeHorizontal);
+			    valuator->invalid_p = true;
+			    valuator->emacs_value = DBL_MIN;
+			    valuator->increment = info->increment;
+			    valuator->number = info->number;
+			  }
+
+			break;
+		      }
+#endif
+
+#ifdef XITouchClass
+		    case XITouchClass:
+		      {
+			XITouchClassInfo *info;
+
+			info = (XITouchClassInfo *) device_changed->classes[c];
+			device->direct_p = info->mode == XIDirectTouch;
+		      }
+#endif
+		    default:
+		      break;
+		    }
+		}
+
+	      /* The device is no longer a DirectTouch device, so
+		 remove any touchpoints that we might have
+		 recorded.  */
+	      if (!device->direct_p)
+		{
+		  tem = device->touchpoints;
+
+		  while (tem)
+		    {
+		      last = tem;
+		      tem = tem->next;
+		      xfree (last);
+		    }
+
+		  device->touchpoints = NULL;
+		}
+
+	      goto XI_OTHER;
+	    }
+
 #ifdef XI_TouchBegin
 	  case XI_TouchBegin:
 	    {
-- 
2.39.5