From 1da6a6d3271be003b545e41ae21c3071faf22f86 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 4 Jul 2022 13:41:20 +0800 Subject: [PATCH] Always wait for XdndStatus before sending XdndDrop * src/xterm.c (x_dnd_do_drop): New function. (x_dnd_begin_drag_and_drop): Clear new flag. (handle_one_xevent): Use that function; send drops upon receipt of pending XdndStatus, to avoid race conditions where we don't yet know the selected action. --- src/xterm.c | 64 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index 6a357b473d6..de8e973173f 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1268,6 +1268,13 @@ static Window x_dnd_waiting_for_status_window; upon receiving an XdndStatus event from said window. */ static XEvent x_dnd_pending_send_position; +/* If true, send a drop from `x_dnd_finish_frame' to the pending + status window after receiving all pending XdndStatus events. */ +static bool x_dnd_need_send_drop; + +/* The protocol version of any such drop. */ +static int x_dnd_send_drop_proto; + /* The action the drop target actually chose to perform. Under XDND, this is set upon receiving the XdndFinished or @@ -4529,6 +4536,19 @@ x_dnd_send_drop (struct frame *f, Window target, Time timestamp, return true; } +static bool +x_dnd_do_drop (Window target, int supported) +{ + if (x_dnd_waiting_for_status_window != target) + return x_dnd_send_drop (x_dnd_frame, target, + x_dnd_selection_timestamp, supported); + + x_dnd_need_send_drop = true; + x_dnd_send_drop_proto = supported; + + return true; +} + static void x_set_dnd_targets (Atom *targets, int ntargets) { @@ -11398,6 +11418,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f), QXdndSelection); + if (NILP (ltimestamp)) + error ("No local value for XdndSelection"); + if (BIGNUMP (ltimestamp)) x_dnd_selection_timestamp = bignum_to_intmax (ltimestamp); else @@ -11538,6 +11561,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, x_dnd_allow_current_frame = allow_current_frame; x_dnd_movement_frame = NULL; x_dnd_init_type_lists = false; + x_dnd_need_send_drop = false; #ifdef HAVE_XKB x_dnd_keyboard_state = 0; @@ -16426,8 +16450,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, { int rc; - if (x_dnd_in_progress - && FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo + if (((x_dnd_in_progress + && FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo) + || (x_dnd_waiting_for_finish + && FRAME_DISPLAY_INFO (x_dnd_finish_frame) == dpyinfo)) && event->xclient.message_type == dpyinfo->Xatom_XdndStatus) { Window target; @@ -16436,6 +16462,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, target = event->xclient.data.l[0]; if (x_dnd_last_protocol_version != -1 + && x_dnd_in_progress && target == x_dnd_last_seen_window && event->xclient.data.l[1] & 2) { @@ -16452,7 +16479,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_mouse_rect_target = None; if (x_dnd_last_protocol_version != -1 - && target == x_dnd_last_seen_window) + && (x_dnd_in_progress + && target == x_dnd_last_seen_window)) { if (event->xclient.data.l[1] & 1) { @@ -16484,6 +16512,26 @@ handle_one_xevent (struct x_display_info *dpyinfo, } else x_dnd_waiting_for_status_window = None; + + /* Send any pending drop if warranted. */ + if (x_dnd_waiting_for_finish && x_dnd_need_send_drop + && x_dnd_waiting_for_status_window == None) + { + if (event->xclient.data.l[1] & 1) + { + if (x_dnd_send_drop_proto >= 2) + x_dnd_action = event->xclient.data.l[4]; + else + x_dnd_action = dpyinfo->Xatom_XdndActionCopy; + } + else + x_dnd_action = None; + + x_dnd_waiting_for_finish + = x_dnd_send_drop (x_dnd_finish_frame, + target, x_dnd_selection_timestamp, + x_dnd_send_drop_proto); + } } goto done; @@ -18948,9 +18996,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version; x_dnd_waiting_for_finish - = x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window, - x_dnd_selection_timestamp, - x_dnd_last_protocol_version); + = x_dnd_do_drop (x_dnd_last_seen_window, + x_dnd_last_protocol_version); x_dnd_finish_display = dpyinfo->display; } else if (x_dnd_last_seen_window != None) @@ -20354,9 +20401,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version; x_dnd_waiting_for_finish - = x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window, - x_dnd_selection_timestamp, - x_dnd_last_protocol_version); + = x_dnd_do_drop (x_dnd_last_seen_window, + x_dnd_last_protocol_version); x_dnd_finish_display = dpyinfo->display; } else if (x_dnd_last_seen_window != None) -- 2.39.2