From ac13957b86ad699a76a0b248063551f971c4cef9 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 28 May 2022 09:37:29 +0800 Subject: [PATCH] Fix frame destruction issues and misuse of x_get_atom_name * src/frame.c (delete_frame): Prevent deleting the dnd frame while waiting for finish as well. * src/xselect.c (Fx_get_atom_name): Clean up code and fix uninitialized use of need_sync. * src/xterm.c (x_dnd_send_unsupported_drop, x_dnd_send_drop) (handle_one_xevent): Clean up usage of x_get_atom_name. (x_get_atom_name): Accept NULL for need_sync. * src/xterm.h: Update declarations. --- src/frame.c | 3 ++- src/xselect.c | 11 ++++++----- src/xterm.c | 29 ++++++++++++++++++++++++----- src/xterm.h | 2 ++ 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/frame.c b/src/frame.c index 252dc591bfa..ea4c904e20a 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1995,7 +1995,8 @@ delete_frame (Lisp_Object frame, Lisp_Object force) error ("Attempt to delete the only frame"); } #ifdef HAVE_X_WINDOWS - else if (x_dnd_in_progress && f == x_dnd_frame) + else if ((x_dnd_in_progress && f == x_dnd_frame) + || (x_dnd_waiting_for_finish && f == x_dnd_finish_frame)) error ("Attempt to delete the drop source frame"); #endif #ifdef HAVE_HAIKU diff --git a/src/xselect.c b/src/xselect.c index 3f35842daa0..bfd081b1e28 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -2458,24 +2458,25 @@ If the value is 0 or the atom is not known, return the empty string. */) struct x_display_info *dpyinfo; Atom atom; bool had_errors_p, need_sync; + char *name; + Lisp_Object ret; dpyinfo = FRAME_DISPLAY_INFO (f); - CONS_TO_INTEGER (value, Atom, atom); - block_input (); x_catch_errors (dpy); - char *name = atom ? x_get_atom_name (dpyinfo, atom, &need_sync) : NULL; + name = x_get_atom_name (dpyinfo, atom, &need_sync); had_errors_p = need_sync && x_had_errors_p (dpy); x_uncatch_errors_after_check (); - Lisp_Object ret = empty_unibyte_string; + + ret = empty_unibyte_string; + if (name) { if (!had_errors_p) ret = build_string (name); xfree (name); } - unblock_input (); return ret; } diff --git a/src/xterm.c b/src/xterm.c index 756f0308111..94c996a11dc 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1011,11 +1011,16 @@ unsigned x_dnd_unsupported_event_level; /* The frame where the drag-and-drop operation originated. */ struct frame *x_dnd_frame; +/* That frame, but set when x_dnd_waiting_for_finish is true. Used to + prevent the frame from being deleted inside selection handlers and + other callbacks. */ +struct frame *x_dnd_finish_frame; + /* Flag that indicates if a drag-and-drop operation is no longer in progress, but the nested event loop should continue to run, because handle_one_xevent is waiting for the drop target to return some important information. */ -static bool x_dnd_waiting_for_finish; +bool x_dnd_waiting_for_finish; /* The display the drop target that is supposed to send information is on. */ @@ -3277,7 +3282,7 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo } name = x_get_atom_name (dpyinfo, x_dnd_wanted_action, - false); + NULL); if (name) { @@ -3842,7 +3847,7 @@ x_dnd_send_drop (struct frame *f, Window target, Time timestamp, lval = Qnil; atom_names = alloca (x_dnd_n_targets * sizeof *atom_names); - name = x_get_atom_name (dpyinfo, x_dnd_wanted_action, false); + name = x_get_atom_name (dpyinfo, x_dnd_wanted_action, NULL); if (!XGetAtomNames (dpyinfo->display, x_dnd_targets, x_dnd_n_targets, atom_names)) @@ -17226,6 +17231,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { x_dnd_end_window = x_dnd_last_seen_window; x_dnd_in_progress = false; + x_dnd_finish_frame = x_dnd_frame; if (x_dnd_last_seen_window != None && x_dnd_last_protocol_version != -1) @@ -18531,6 +18537,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_end_window = x_dnd_last_seen_window; x_dnd_in_progress = false; + /* This doesn't have to be marked since it + is only accessed if + x_dnd_waiting_for_finish is true, which + is only possible inside the DND event + loop where that frame is on the + stack. */ + x_dnd_finish_frame = x_dnd_frame; + if (x_dnd_last_seen_window != None && x_dnd_last_protocol_version != -1) { @@ -23830,7 +23844,10 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom atom, dpyinfo_pointer = (char *) dpyinfo; value = NULL; - *need_sync = false; + + if (need_sync) + *need_sync = false; + buffer = alloca (45 + INT_STRLEN_BOUND (int)); switch (atom) @@ -23878,7 +23895,9 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom atom, } name = XGetAtomName (dpyinfo->display, atom); - *need_sync = true; + + if (need_sync) + *need_sync = true; if (name) { diff --git a/src/xterm.h b/src/xterm.h index 283d4fa9b11..6c798ea246d 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1603,7 +1603,9 @@ extern struct input_event xg_pending_quit_event; #endif extern bool x_dnd_in_progress; +extern bool x_dnd_waiting_for_finish; extern struct frame *x_dnd_frame; +extern struct frame *x_dnd_finish_frame; extern unsigned x_dnd_unsupported_event_level; #ifdef HAVE_XINPUT2 -- 2.39.2