]> git.eshelyaron.com Git - emacs.git/commitdiff
Protect windows from garbage collection when a ClientMessage is pending
authorPo Lu <luangruo@yahoo.com>
Sat, 16 Apr 2022 08:48:02 +0000 (16:48 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 16 Apr 2022 08:50:02 +0000 (16:50 +0800)
* src/xterm.c (x_protect_window_for_callback)
(x_unprotect_window_for_callback): New functions.
(x_send_scroll_bar_event): Protect windows from garbage
collection before sending event containing pointer to window.
(handle_one_xevent): Unprotect after such a ClientMessage is
received and the window put in the keyboard buffer.
(x_term_init): Initialize protected windows list.
(x_delete_display): Free that list.
(mark_xterm): Mark the windows in that list.
* src/xterm.h (struct x_display_info): New fields for recording
a list of protected windows.

src/xterm.c
src/xterm.h

index c5b31553ae8d5520ee392a922a871cf8503fc7a3..ae3f2d75179f5b8fadf50d479d19b99032a98d14 100644 (file)
@@ -10846,6 +10846,35 @@ xt_horizontal_action_hook (Widget widget, XtPointer client_data, String action_n
 }
 #endif /* not USE_GTK */
 
+/* Protect WINDOW from garbage collection until a matching scroll bar
+   message is received.  Return whether or not protection
+   succeeded.  */
+static bool
+x_protect_window_for_callback (struct x_display_info *dpyinfo,
+                              Lisp_Object window)
+{
+  if (dpyinfo->n_protected_windows + 1
+      >= dpyinfo->protected_windows_max)
+    return false;
+
+  dpyinfo->protected_windows[dpyinfo->n_protected_windows++]
+    = window;
+  return true;
+}
+
+static void
+x_unprotect_window_for_callback (struct x_display_info *dpyinfo)
+{
+  if (!dpyinfo->n_protected_windows)
+    emacs_abort ();
+
+  dpyinfo->n_protected_windows--;
+
+  if (dpyinfo->n_protected_windows)
+    memmove (dpyinfo->protected_windows, &dpyinfo->protected_windows[1],
+            sizeof (Lisp_Object) * dpyinfo->n_protected_windows);
+}
+
 /* Send a client message with message type Xatom_Scrollbar for a
    scroll action to the frame of WINDOW.  PART is a value identifying
    the part of the scroll bar that was clicked on.  PORTION is the
@@ -10863,8 +10892,12 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
   verify (INTPTR_WIDTH <= 64);
   int sign_shift = INTPTR_WIDTH - 32;
 
-  block_input ();
+  /* Don't do anything if too many scroll bar events have been
+     sent but not received.  */
+  if (!x_protect_window_for_callback (FRAME_DISPLAY_INFO (f), window))
+    return;
 
+  block_input ();
   /* Construct a ClientMessage event to send to the frame.  */
   ev->type = ClientMessage;
   ev->message_type = (horizontal
@@ -18854,6 +18887,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       count++;
     }
 
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  if (event->xany.type == ClientMessage
+      && inev.ie.kind == SCROLL_BAR_CLICK_EVENT)
+    x_unprotect_window_for_callback (dpyinfo);
+#endif
+
   if (do_help
       && !(hold_quit && hold_quit->kind != NO_EVENT))
     {
@@ -23415,6 +23454,12 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
   x_extension_initialize (dpyinfo);
 #endif
 
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  dpyinfo->protected_windows = xmalloc (sizeof (Lisp_Object) * 256);
+  dpyinfo->n_protected_windows = 0;
+  dpyinfo->protected_windows_max = 256;
+#endif
+
   unblock_input ();
 
   return dpyinfo;
@@ -23469,12 +23514,14 @@ x_delete_display (struct x_display_info *dpyinfo)
   xfree (dpyinfo->x_id_name);
   xfree (dpyinfo->x_dnd_atoms);
   xfree (dpyinfo->color_cells);
-  xfree (dpyinfo);
-
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  xfree (dpyinfo->protected_windows);
+#endif
 #ifdef HAVE_XINPUT2
   if (dpyinfo->supports_xi2)
     x_free_xi_devices (dpyinfo);
 #endif
+  xfree (dpyinfo);
 }
 
 #ifdef USE_X_TOOLKIT
@@ -23817,11 +23864,17 @@ mark_xterm (void)
       mark_object (val);
     }
 
-#ifdef HAVE_XINPUT2
+#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS
   for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
     {
+#ifdef HAVE_XINPUT2
       for (i = 0; i < dpyinfo->num_devices; ++i)
        mark_object (dpyinfo->devices[i].name);
+#endif
+#ifdef USE_TOOLKIT_SCROLL_BARS
+      for (i = 0; i < dpyinfo->n_protected_windows; ++i)
+       mark_object (dpyinfo->protected_windows[i]);
+#endif
     }
 #endif
 }
index a04596cdb1a6049948d68ae8ab5720d069c18ff9..5d2b397874d7cf8d841349d02f20059ebd35d269 100644 (file)
@@ -672,6 +672,12 @@ struct x_display_info
   int xshape_event_base;
   int xshape_error_base;
 #endif
+
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  Lisp_Object *protected_windows;
+  int n_protected_windows;
+  int protected_windows_max;
+#endif
 };
 
 #ifdef HAVE_X_I18N