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.
This commit is contained in:
Po Lu 2022-07-16 11:53:42 +08:00
parent 97441f742e
commit 00501e82c7

View file

@ -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;
/* 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. */
/* 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. */
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;