]> git.eshelyaron.com Git - emacs.git/commitdiff
Remove selection requests on the keyboard buffer when closing display
authorPo Lu <luangruo@yahoo.com>
Tue, 21 Jun 2022 01:52:47 +0000 (09:52 +0800)
committerPo Lu <luangruo@yahoo.com>
Tue, 21 Jun 2022 01:53:14 +0000 (09:53 +0800)
* src/xterm.c (X_NEXT_KBD_EVENT): New macro.
(x_defer_selection_requests): Set input_pending if the kbd
buffer was modified.
(x_delete_selection_requests): New function.
(x_delete_display): Call that.  Bug found when a display died
while the clipboard manager was sending an unreasonably high
number of requests.

src/xterm.c

index b5543b873ca957b1bd771c1b99495cd7da912527..ee78da085e2dc3d587defac6e22a762c04351ba9 100644 (file)
@@ -802,6 +802,10 @@ static struct input_event *current_hold_quit;
    than 0.  */
 static int x_use_pending_selection_requests;
 
+/* Like `next_kbd_event', but for use in X code.  */
+#define X_NEXT_KBD_EVENT(ptr) \
+  ((ptr) == kbd_buffer + KBD_BUFFER_SIZE - 1 ? kbd_buffer : (ptr) + 1)
+
 static void x_push_selection_request (struct selection_input_event *);
 
 /* Defer selection requests.  Between this and
@@ -838,14 +842,12 @@ x_defer_selection_requests (void)
                 avoids exhausting the keyboard buffer with some
                 over-enthusiastic clipboard managers.  */
              if (!between)
-               kbd_fetch_ptr = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
-                                ? kbd_buffer : event + 1);
+               kbd_fetch_ptr = X_NEXT_KBD_EVENT (event);
            }
          else
            between = true;
 
-         event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
-                  ? kbd_buffer : event + 1);
+         event = X_NEXT_KBD_EVENT (event);
        }
     }
 
@@ -26969,7 +26971,54 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
 
   return dpyinfo;
 }
+
 \f
+
+/* Remove all the selection input events on the keyboard buffer
+   intended for DPYINFO.  */
+
+static void
+x_delete_selection_requests (struct x_display_info *dpyinfo)
+{
+  union buffered_input_event *event;
+  int moved_events;
+
+  for (event = kbd_fetch_ptr; event != kbd_store_ptr;
+       event = X_NEXT_KBD_EVENT (event))
+    {
+      if (event->kind == SELECTION_REQUEST_EVENT
+         || event->kind == SELECTION_CLEAR_EVENT)
+       {
+         if (SELECTION_EVENT_DPYINFO (&event->sie) != dpyinfo)
+           continue;
+
+         /* Remove the event from the fifo buffer before processing;
+            otherwise swallow_events called recursively could see it
+            and process it again.  To do this, we move the events
+            between kbd_fetch_ptr and EVENT one slot to the right,
+            cyclically.  */
+
+         if (event < kbd_fetch_ptr)
+           {
+             memmove (kbd_buffer + 1, kbd_buffer,
+                      (event - kbd_buffer) * sizeof *kbd_buffer);
+             kbd_buffer[0] = kbd_buffer[KBD_BUFFER_SIZE - 1];
+             moved_events = kbd_buffer + KBD_BUFFER_SIZE - 1 - kbd_fetch_ptr;
+           }
+         else
+           moved_events = event - kbd_fetch_ptr;
+
+         memmove (kbd_fetch_ptr + 1, kbd_fetch_ptr,
+                  moved_events * sizeof *kbd_fetch_ptr);
+         kbd_fetch_ptr = X_NEXT_KBD_EVENT (kbd_fetch_ptr);
+
+         /* `detect_input_pending' will then recompute whether or not
+            pending input events exist.  */
+         input_pending = false;
+       }
+    }
+}
+
 /* Get rid of display DPYINFO, deleting all frames on it,
    and without sending any more commands to the X server.  */
 
@@ -27019,6 +27068,8 @@ x_delete_display (struct x_display_info *dpyinfo)
       last = ie;
     }
 
+  x_delete_selection_requests (dpyinfo);
+
   if (next_noop_dpyinfo == dpyinfo)
     next_noop_dpyinfo = dpyinfo->next;