From b6097fe279b03e2fb50fc6af063d7c8f1e55fe8b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 25 Oct 2022 19:50:57 +0800 Subject: [PATCH] Fix drag-and-drop bugs on Lucid build Also, optimize Fx_translate_coordinates to avoid excessive calls to _XReply. * lisp/x-dnd.el (x-dnd-get-drop-rectangle): Return empty drop rectangle if posn-area. * src/xfns.c (Fx_translate_coordinates): Accept arg `require_child'. If not set, allow optimizations based on cached position data. * src/xselect.c (x_handle_dnd_message): Use x_translate_coordinates. * src/xterm.c (x_translate_coordinates): Export function. (x_handle_translate_coordinates): New function. (handle_one_xevent): Fix coding style. * src/xterm.h: Update prototypes. --- lisp/x-dnd.el | 10 +++++++++- src/xfns.c | 24 +++++++++++++++++++++--- src/xselect.c | 7 +------ src/xterm.c | 30 +++++++++++++++++++++++++++--- src/xterm.h | 4 ++++ 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index ee80e41a22e..058ab99f5cb 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el @@ -675,7 +675,15 @@ with coordinates relative to the root window." (defun x-dnd-get-drop-rectangle (window posn) "Return the drag-and-drop rectangle at POSN on WINDOW." (if (or dnd-scroll-margin - (not (windowp window))) + (not (windowp window)) + ;; Drops on the scroll bar aren't allowed, but the mouse + ;; rectangle can be set while still on the scroll bar, + ;; causing the drag initiator to never send an XdndPosition + ;; event that will an XdndStatus message with the accept + ;; flag set to be set, even after the mouse enters the + ;; window text area. To prevent that, simply don't generate + ;; a mouse rectangle when an area is set. + (posn-area posn)) '(0 0 0 0) (let ((window-rectangle (x-dnd-get-window-rectangle window)) object-rectangle) diff --git a/src/xfns.c b/src/xfns.c index e8732986eb9..3ff7a8c2865 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -7913,7 +7913,7 @@ Otherwise, the return value is a vector with the following fields: DEFUN ("x-translate-coordinates", Fx_translate_coordinates, Sx_translate_coordinates, - 1, 5, 0, doc: /* Translate coordinates from FRAME. + 1, 6, 0, doc: /* Translate coordinates from FRAME. Translate the given coordinates SOURCE-X and SOURCE-Y from SOURCE-WINDOW's coordinate space to that of DEST-WINDOW, on FRAME. @@ -7929,16 +7929,21 @@ Return a list of (X Y CHILD) if the given coordinates are on the same screen, or nil otherwise, where X and Y are the coordinates in DEST-WINDOW's coordinate space, and CHILD is the window ID of any mapped child in DEST-WINDOW at those coordinates, or nil if there is -no such window. */) +no such window. If REQUIRE-CHILD is nil, avoid fetching CHILD if it +would result in an avoidable request to the X server, thereby +improving performance when the X connection is over a slow network. +Otherwise, always obtain the mapped child window from the X +server. */) (Lisp_Object frame, Lisp_Object source_window, Lisp_Object dest_window, Lisp_Object source_x, - Lisp_Object source_y) + Lisp_Object source_y, Lisp_Object require_child) { struct x_display_info *dpyinfo; struct frame *source_frame; int dest_x, dest_y; Window child_return, src, dest; Bool rc; + Lisp_Object temp_result; dpyinfo = check_x_display_info (frame); dest_x = 0; @@ -7956,6 +7961,8 @@ no such window. */) dest_y = XFIXNUM (source_y); } + source_frame = NULL; + if (!NILP (source_window)) CONS_TO_INTEGER (source_window, Window, src); else @@ -7964,6 +7971,17 @@ no such window. */) src = FRAME_X_WINDOW (source_frame); } + /* If require_child is nil, try to avoid an avoidable roundtrip to + the X server. */ + if (NILP (require_child) && source_frame) + { + temp_result + = x_handle_translate_coordinates (source_frame, dest_window, dest_x, + dest_y); + if (!NILP (temp_result)) + return temp_result; + } + if (!src) src = dpyinfo->root_window; diff --git a/src/xselect.c b/src/xselect.c index 498c28af536..db5c7853e7f 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -2787,7 +2787,6 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event, unsigned char *data = (unsigned char *) event->data.b; int idata[5]; ptrdiff_t i; - Window child_return; for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i) if (dpyinfo->x_dnd_atoms[i] == event->message_type) break; @@ -2822,11 +2821,7 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event, if (!root_window_coords) x_relative_mouse_position (f, &x, &y); else - XTranslateCoordinates (dpyinfo->display, - dpyinfo->root_window, - FRAME_X_WINDOW (f), - root_x, root_y, - &x, &y, &child_return); + x_translate_coordinates (f, root_x, root_y, &x, &y); bufp->kind = DRAG_N_DROP_EVENT; bufp->frame_or_window = frame; diff --git a/src/xterm.c b/src/xterm.c index 205c948c461..b061383a2ea 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1143,7 +1143,6 @@ static Window x_get_window_below (Display *, Window, int, int, int *, int *); #ifndef USE_TOOLKIT_SCROLL_BARS static void x_scroll_bar_redraw (struct scroll_bar *); #endif -static void x_translate_coordinates (struct frame *, int, int, int *, int *); /* Global state maintained during a drag-and-drop operation. */ @@ -13658,7 +13657,7 @@ x_compute_root_window_offset (struct frame *f, int root_x, int root_y, many cases while handling events, which would otherwise result in slowdowns over slow network connections. */ -static void +void x_translate_coordinates (struct frame *f, int root_x, int root_y, int *x_out, int *y_out) { @@ -13731,6 +13730,31 @@ x_translate_coordinates_to_root (struct frame *f, int x, int y, } } +/* Do x-translate-coordinates, but try to avoid a roundtrip to the X + server at the cost of not returning `child', which most callers + have no reason to use. */ + +Lisp_Object +x_handle_translate_coordinates (struct frame *f, Lisp_Object dest_window, + int source_x, int source_y) +{ + if (NILP (dest_window)) + { + /* We are translating coordinates from a frame to the root + window. Avoid a roundtrip if possible by using cached + coordinates. */ + + if (!FRAME_X_OUTPUT (f)->window_offset_certain_p) + return Qnil; + + return list3 (make_fixnum (source_x + FRAME_X_OUTPUT (f)->root_x), + make_fixnum (source_y + FRAME_X_OUTPUT (f)->root_y), + Qnil); + } + + return Qnil; +} + /* The same, but for an XIDeviceEvent. */ #ifdef HAVE_XINPUT2 @@ -20826,7 +20850,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, event->xbutton.time); } else if (x_dnd_last_seen_window != None - && x_dnd_last_protocol_version != -1) + && x_dnd_last_protocol_version != -1) { x_dnd_pending_finish_target = x_dnd_last_seen_toplevel; x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version; diff --git a/src/xterm.h b/src/xterm.h index 2967d105ea2..537cabc9577 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1695,8 +1695,12 @@ extern void x_xr_apply_ext_clip (struct frame *, GC); extern void x_xr_reset_ext_clip (struct frame *); #endif +extern void x_translate_coordinates (struct frame *, int, int, int *, int *); extern void x_translate_coordinates_to_root (struct frame *, int, int, int *, int *); +extern Lisp_Object x_handle_translate_coordinates (struct frame *, Lisp_Object, + int, int); + extern Bool x_query_pointer (Display *, Window, Window *, Window *, int *, int *, int *, int *, unsigned int *); -- 2.39.5