From 00501e82c735d4b0928888fffc2049f8ec2d5ae6 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 16 Jul 2022 11:53:42 +0800 Subject: [PATCH] Handle XDND mouse rects synchronously * src/xterm.c (x_dnd_send_position): Record event X and Y for consumption by the XdndStatus handler. Ignore mouse rects if waiting for status. (x_dnd_send_leave): Clear pending DND event. (handle_one_xevent): When handling XdndStatus, check if the pending event is contained in the new mouse rect. --- src/xterm.c | 99 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index c0a01d0d732..94cfe6f010e 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1285,6 +1285,15 @@ static Window x_dnd_waiting_for_status_window; upon receiving an XdndStatus event from said window. */ static XEvent x_dnd_pending_send_position; +/* Whether or not that event corresponds to a button press. */ +static bool x_dnd_pending_send_position_button; + +/* The root-window position of that event. */ +static int x_dnd_pending_send_position_root_x; + +/* Likewise. */ +static int x_dnd_pending_send_position_root_y; + /* 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; @@ -4453,22 +4462,6 @@ x_dnd_send_position (struct frame *f, Window target, int supported, struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); XEvent msg; - if (target == x_dnd_mouse_rect_target - && x_dnd_mouse_rect.width - && x_dnd_mouse_rect.height - /* Ignore the mouse rectangle if we're supposed to be sending a - button press instead. */ - && (supported < 5 || !button)) - { - if (root_x >= x_dnd_mouse_rect.x - && root_x < (x_dnd_mouse_rect.x - + x_dnd_mouse_rect.width) - && root_y >= x_dnd_mouse_rect.y - && root_y < (x_dnd_mouse_rect.y - + x_dnd_mouse_rect.height)) - return; - } - msg.xclient.type = ClientMessage; msg.xclient.message_type = dpyinfo->Xatom_XdndPosition; msg.xclient.format = 32; @@ -4502,9 +4495,30 @@ x_dnd_send_position (struct frame *f, Window target, int supported, msg.xclient.data.l[4] = action; if (x_dnd_waiting_for_status_window == target) - x_dnd_pending_send_position = msg; + { + x_dnd_pending_send_position = msg; + x_dnd_pending_send_position_button = button; + x_dnd_pending_send_position_root_x = root_x; + x_dnd_pending_send_position_root_y = root_y; + } else { + if (target == x_dnd_mouse_rect_target + && x_dnd_mouse_rect.width + && x_dnd_mouse_rect.height + /* Ignore the mouse rectangle if we're supposed to be sending a + button press instead. */ + && (supported < 5 || !button)) + { + if (root_x >= x_dnd_mouse_rect.x + && root_x < (x_dnd_mouse_rect.x + + x_dnd_mouse_rect.width) + && root_y >= x_dnd_mouse_rect.y + && root_y < (x_dnd_mouse_rect.y + + x_dnd_mouse_rect.height)) + return; + } + x_ignore_errors_for_next_request (dpyinfo); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); @@ -4530,6 +4544,7 @@ x_dnd_send_leave (struct frame *f, Window target) msg.xclient.data.l[4] = 0; x_dnd_waiting_for_status_window = None; + x_dnd_pending_send_position.type = 0; x_ignore_errors_for_next_request (dpyinfo); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); @@ -16372,6 +16387,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, { Window target; unsigned long r1, r2; + int root_x, root_y; + bool button; target = event->xclient.data.l[0]; @@ -16417,17 +16434,43 @@ handle_one_xevent (struct x_display_info *dpyinfo, { if (x_dnd_pending_send_position.type != 0) { - x_ignore_errors_for_next_request (dpyinfo); - XSendEvent (dpyinfo->display, target, - False, NoEventMask, - &x_dnd_pending_send_position); - x_stop_ignoring_errors (dpyinfo); - x_dnd_pending_send_position.type = 0; - - /* Since we sent another XdndPosition message, we - have to wait for another one in reply, so don't - reset `x_dnd_waiting_for_status_window' - here. */ + /* If the last XdndStatus specified a mouse + rectangle and this event falls inside, don't + send the event, but clear + x_dnd_waiting_for_status_window instead. */ + + root_x = x_dnd_pending_send_position_root_x; + root_y = x_dnd_pending_send_position_root_y; + button = x_dnd_pending_send_position_button; + + if (target == x_dnd_mouse_rect_target + && x_dnd_mouse_rect.width + && x_dnd_mouse_rect.height + /* Ignore the mouse rectangle if we're + supposed to be sending a button press + instead. */ + && (x_dnd_last_protocol_version < 5 || !button) + && (root_x >= x_dnd_mouse_rect.x + && root_x < (x_dnd_mouse_rect.x + + x_dnd_mouse_rect.width) + && root_y >= x_dnd_mouse_rect.y + && root_y < (x_dnd_mouse_rect.y + + x_dnd_mouse_rect.height))) + x_dnd_waiting_for_status_window = None; + else + { + x_ignore_errors_for_next_request (dpyinfo); + XSendEvent (dpyinfo->display, target, + False, NoEventMask, + &x_dnd_pending_send_position); + x_stop_ignoring_errors (dpyinfo); + x_dnd_pending_send_position.type = 0; + + /* Since we sent another XdndPosition message, we + have to wait for another one in reply, so don't + reset `x_dnd_waiting_for_status_window' + here. */ + } } else x_dnd_waiting_for_status_window = None; -- 2.39.2