diff options
| author | Po Lu | 2022-07-16 11:53:42 +0800 |
|---|---|---|
| committer | Po Lu | 2022-07-16 11:53:42 +0800 |
| commit | 00501e82c735d4b0928888fffc2049f8ec2d5ae6 (patch) | |
| tree | 5bbaad20ede8add15c6cae492330bb8e91888e20 | |
| parent | 97441f742e6b63d583607132f1682d050901d716 (diff) | |
| download | emacs-00501e82c735d4b0928888fffc2049f8ec2d5ae6.tar.gz emacs-00501e82c735d4b0928888fffc2049f8ec2d5ae6.zip | |
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.
| -rw-r--r-- | src/xterm.c | 99 |
1 files 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; | |||
| 1285 | upon receiving an XdndStatus event from said window. */ | 1285 | upon receiving an XdndStatus event from said window. */ |
| 1286 | static XEvent x_dnd_pending_send_position; | 1286 | static XEvent x_dnd_pending_send_position; |
| 1287 | 1287 | ||
| 1288 | /* Whether or not that event corresponds to a button press. */ | ||
| 1289 | static bool x_dnd_pending_send_position_button; | ||
| 1290 | |||
| 1291 | /* The root-window position of that event. */ | ||
| 1292 | static int x_dnd_pending_send_position_root_x; | ||
| 1293 | |||
| 1294 | /* Likewise. */ | ||
| 1295 | static int x_dnd_pending_send_position_root_y; | ||
| 1296 | |||
| 1288 | /* If true, send a drop from `x_dnd_finish_frame' to the pending | 1297 | /* If true, send a drop from `x_dnd_finish_frame' to the pending |
| 1289 | status window after receiving all pending XdndStatus events. */ | 1298 | status window after receiving all pending XdndStatus events. */ |
| 1290 | static bool x_dnd_need_send_drop; | 1299 | static bool x_dnd_need_send_drop; |
| @@ -4453,22 +4462,6 @@ x_dnd_send_position (struct frame *f, Window target, int supported, | |||
| 4453 | struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | 4462 | struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); |
| 4454 | XEvent msg; | 4463 | XEvent msg; |
| 4455 | 4464 | ||
| 4456 | if (target == x_dnd_mouse_rect_target | ||
| 4457 | && x_dnd_mouse_rect.width | ||
| 4458 | && x_dnd_mouse_rect.height | ||
| 4459 | /* Ignore the mouse rectangle if we're supposed to be sending a | ||
| 4460 | button press instead. */ | ||
| 4461 | && (supported < 5 || !button)) | ||
| 4462 | { | ||
| 4463 | if (root_x >= x_dnd_mouse_rect.x | ||
| 4464 | && root_x < (x_dnd_mouse_rect.x | ||
| 4465 | + x_dnd_mouse_rect.width) | ||
| 4466 | && root_y >= x_dnd_mouse_rect.y | ||
| 4467 | && root_y < (x_dnd_mouse_rect.y | ||
| 4468 | + x_dnd_mouse_rect.height)) | ||
| 4469 | return; | ||
| 4470 | } | ||
| 4471 | |||
| 4472 | msg.xclient.type = ClientMessage; | 4465 | msg.xclient.type = ClientMessage; |
| 4473 | msg.xclient.message_type = dpyinfo->Xatom_XdndPosition; | 4466 | msg.xclient.message_type = dpyinfo->Xatom_XdndPosition; |
| 4474 | msg.xclient.format = 32; | 4467 | msg.xclient.format = 32; |
| @@ -4502,9 +4495,30 @@ x_dnd_send_position (struct frame *f, Window target, int supported, | |||
| 4502 | msg.xclient.data.l[4] = action; | 4495 | msg.xclient.data.l[4] = action; |
| 4503 | 4496 | ||
| 4504 | if (x_dnd_waiting_for_status_window == target) | 4497 | if (x_dnd_waiting_for_status_window == target) |
| 4505 | x_dnd_pending_send_position = msg; | 4498 | { |
| 4499 | x_dnd_pending_send_position = msg; | ||
| 4500 | x_dnd_pending_send_position_button = button; | ||
| 4501 | x_dnd_pending_send_position_root_x = root_x; | ||
| 4502 | x_dnd_pending_send_position_root_y = root_y; | ||
| 4503 | } | ||
| 4506 | else | 4504 | else |
| 4507 | { | 4505 | { |
| 4506 | if (target == x_dnd_mouse_rect_target | ||
| 4507 | && x_dnd_mouse_rect.width | ||
| 4508 | && x_dnd_mouse_rect.height | ||
| 4509 | /* Ignore the mouse rectangle if we're supposed to be sending a | ||
| 4510 | button press instead. */ | ||
| 4511 | && (supported < 5 || !button)) | ||
| 4512 | { | ||
| 4513 | if (root_x >= x_dnd_mouse_rect.x | ||
| 4514 | && root_x < (x_dnd_mouse_rect.x | ||
| 4515 | + x_dnd_mouse_rect.width) | ||
| 4516 | && root_y >= x_dnd_mouse_rect.y | ||
| 4517 | && root_y < (x_dnd_mouse_rect.y | ||
| 4518 | + x_dnd_mouse_rect.height)) | ||
| 4519 | return; | ||
| 4520 | } | ||
| 4521 | |||
| 4508 | x_ignore_errors_for_next_request (dpyinfo); | 4522 | x_ignore_errors_for_next_request (dpyinfo); |
| 4509 | XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); | 4523 | XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); |
| 4510 | x_stop_ignoring_errors (dpyinfo); | 4524 | x_stop_ignoring_errors (dpyinfo); |
| @@ -4530,6 +4544,7 @@ x_dnd_send_leave (struct frame *f, Window target) | |||
| 4530 | msg.xclient.data.l[4] = 0; | 4544 | msg.xclient.data.l[4] = 0; |
| 4531 | 4545 | ||
| 4532 | x_dnd_waiting_for_status_window = None; | 4546 | x_dnd_waiting_for_status_window = None; |
| 4547 | x_dnd_pending_send_position.type = 0; | ||
| 4533 | 4548 | ||
| 4534 | x_ignore_errors_for_next_request (dpyinfo); | 4549 | x_ignore_errors_for_next_request (dpyinfo); |
| 4535 | XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); | 4550 | XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); |
| @@ -16372,6 +16387,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 16372 | { | 16387 | { |
| 16373 | Window target; | 16388 | Window target; |
| 16374 | unsigned long r1, r2; | 16389 | unsigned long r1, r2; |
| 16390 | int root_x, root_y; | ||
| 16391 | bool button; | ||
| 16375 | 16392 | ||
| 16376 | target = event->xclient.data.l[0]; | 16393 | target = event->xclient.data.l[0]; |
| 16377 | 16394 | ||
| @@ -16417,17 +16434,43 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 16417 | { | 16434 | { |
| 16418 | if (x_dnd_pending_send_position.type != 0) | 16435 | if (x_dnd_pending_send_position.type != 0) |
| 16419 | { | 16436 | { |
| 16420 | x_ignore_errors_for_next_request (dpyinfo); | 16437 | /* If the last XdndStatus specified a mouse |
| 16421 | XSendEvent (dpyinfo->display, target, | 16438 | rectangle and this event falls inside, don't |
| 16422 | False, NoEventMask, | 16439 | send the event, but clear |
| 16423 | &x_dnd_pending_send_position); | 16440 | x_dnd_waiting_for_status_window instead. */ |
| 16424 | x_stop_ignoring_errors (dpyinfo); | 16441 | |
| 16425 | x_dnd_pending_send_position.type = 0; | 16442 | root_x = x_dnd_pending_send_position_root_x; |
| 16426 | 16443 | root_y = x_dnd_pending_send_position_root_y; | |
| 16427 | /* Since we sent another XdndPosition message, we | 16444 | button = x_dnd_pending_send_position_button; |
| 16428 | have to wait for another one in reply, so don't | 16445 | |
| 16429 | reset `x_dnd_waiting_for_status_window' | 16446 | if (target == x_dnd_mouse_rect_target |
| 16430 | here. */ | 16447 | && x_dnd_mouse_rect.width |
| 16448 | && x_dnd_mouse_rect.height | ||
| 16449 | /* Ignore the mouse rectangle if we're | ||
| 16450 | supposed to be sending a button press | ||
| 16451 | instead. */ | ||
| 16452 | && (x_dnd_last_protocol_version < 5 || !button) | ||
| 16453 | && (root_x >= x_dnd_mouse_rect.x | ||
| 16454 | && root_x < (x_dnd_mouse_rect.x | ||
| 16455 | + x_dnd_mouse_rect.width) | ||
| 16456 | && root_y >= x_dnd_mouse_rect.y | ||
| 16457 | && root_y < (x_dnd_mouse_rect.y | ||
| 16458 | + x_dnd_mouse_rect.height))) | ||
| 16459 | x_dnd_waiting_for_status_window = None; | ||
| 16460 | else | ||
| 16461 | { | ||
| 16462 | x_ignore_errors_for_next_request (dpyinfo); | ||
| 16463 | XSendEvent (dpyinfo->display, target, | ||
| 16464 | False, NoEventMask, | ||
| 16465 | &x_dnd_pending_send_position); | ||
| 16466 | x_stop_ignoring_errors (dpyinfo); | ||
| 16467 | x_dnd_pending_send_position.type = 0; | ||
| 16468 | |||
| 16469 | /* Since we sent another XdndPosition message, we | ||
| 16470 | have to wait for another one in reply, so don't | ||
| 16471 | reset `x_dnd_waiting_for_status_window' | ||
| 16472 | here. */ | ||
| 16473 | } | ||
| 16431 | } | 16474 | } |
| 16432 | else | 16475 | else |
| 16433 | x_dnd_waiting_for_status_window = None; | 16476 | x_dnd_waiting_for_status_window = None; |