emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master d49ea6de2f: Fix leak of DND toplevels when return-frame is non-ni


From: Po Lu
Subject: master d49ea6de2f: Fix leak of DND toplevels when return-frame is non-nil
Date: Fri, 3 Jun 2022 21:52:42 -0400 (EDT)

branch: master
commit d49ea6de2f92cb8f092fe30301010273e8c03f8c
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix leak of DND toplevels when return-frame is non-nil
    
    * src/xterm.c (x_dnd_free_toplevels): Don't leak DND toplevels
    if returning a frame.
    (x_dnd_begin_drag_and_drop): Make this function reentrant from
    the IO error handler.
---
 src/xterm.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 73 insertions(+), 10 deletions(-)

diff --git a/src/xterm.c b/src/xterm.c
index ecee000439..99aa0ae929 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -2292,7 +2292,31 @@ x_dnd_free_toplevels (bool display_alive)
 {
   struct x_client_list_window *last;
   struct x_client_list_window *tem = x_dnd_toplevels;
+  ptrdiff_t n_windows, i, buffer_size;
+  Window *destroy_windows;
+  unsigned long *prev_masks;
+  specpdl_ref count;
+  Display *dpy;
+
+  if (!x_dnd_toplevels)
+    /* Probably called inside an IO error handler.  */
+    return;
 
+  /* Pacify GCC.  */
+  prev_masks = NULL;
+  destroy_windows = NULL;
+
+  if (display_alive)
+    {
+      buffer_size = 1024;
+      destroy_windows = xmalloc (sizeof *destroy_windows
+                                * buffer_size);
+      prev_masks = xmalloc (sizeof *prev_masks *
+                           buffer_size);
+      n_windows = 0;
+    }
+
+  block_input ();
   while (tem)
     {
       last = tem;
@@ -2300,13 +2324,20 @@ x_dnd_free_toplevels (bool display_alive)
 
       if (display_alive)
        {
-         x_catch_errors (last->dpy);
-         XSelectInput (last->dpy, last->window,
-                       last->previous_event_mask);
-#ifdef HAVE_XSHAPE
-         XShapeSelectInput (last->dpy, last->window, None);
-#endif
-         x_uncatch_errors ();
+         if (++n_windows >= buffer_size)
+           {
+             buffer_size += 1024;
+             destroy_windows
+               = xrealloc (destroy_windows, (sizeof *destroy_windows
+                                             * buffer_size));
+             prev_masks
+               = xrealloc (prev_masks, (sizeof *prev_masks
+                                        * buffer_size));
+           }
+
+         dpy = last->dpy;
+         prev_masks[n_windows - 1] = last->previous_event_mask;
+         destroy_windows[n_windows - 1] = last->window;
        }
 
 #ifdef HAVE_XSHAPE
@@ -2320,6 +2351,34 @@ x_dnd_free_toplevels (bool display_alive)
     }
 
   x_dnd_toplevels = NULL;
+
+  if (!display_alive)
+    {
+      unblock_input ();
+      return;
+    }
+
+  count = SPECPDL_INDEX ();
+  record_unwind_protect_ptr (xfree, destroy_windows);
+  record_unwind_protect_ptr (xfree, prev_masks);
+
+  if (display_alive)
+    {
+      x_catch_errors (dpy);
+
+      for (i = 0; i < n_windows; ++i)
+       {
+         XSelectInput (dpy, destroy_windows[i], prev_masks[i]);
+#ifdef HAVE_XSHAPE
+         XShapeSelectInput (dpy, destroy_windows[i], None);
+#endif
+       }
+
+      x_uncatch_errors ();
+    }
+
+  unbind_to (count, Qnil);
+  unblock_input ();
 }
 
 static int
@@ -10625,6 +10684,10 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
       unblock_input ();
     }
 
+  /* This shouldn't happen.  */
+  if (x_dnd_toplevels)
+    x_dnd_free_toplevels (true);
+
   x_dnd_in_progress = true;
   x_dnd_frame = f;
   x_dnd_last_seen_window = None;
@@ -10990,6 +11053,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
                     FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
   unblock_input ();
 
+  if (x_dnd_use_toplevels)
+    x_dnd_free_toplevels (true);
+
   if (x_dnd_return_frame == 3
       && FRAME_LIVE_P (x_dnd_return_frame_object))
     {
@@ -11008,9 +11074,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
     }
 
   x_dnd_return_frame_object = NULL;
-
-  if (x_dnd_use_toplevels)
-    x_dnd_free_toplevels (true);
   FRAME_DISPLAY_INFO (f)->grabbed = 0;
 
   /* Emacs can't respond to DND events inside the nested event



reply via email to

[Prev in Thread] Current Thread [Next in Thread]