From 907f3a4f8d83c228a3be3772a3cb7d5079261752 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 14 Jun 2022 09:41:59 +0800 Subject: [PATCH] Use coordinates provided by DND messages if available This avoids an extra sync, which matters when dropping onto Emacs running over a slow connection. * src/xselect.c (x_handle_dnd_message): New args `root_window_coords', `root_x' and `root_y'. * src/xterm.c (x_coords_from_dnd_message): New function. (handle_one_xevent): Pass root window coordinates to x_handle_dnd_message. * src/xterm.h: Update prototypes. --- src/xselect.c | 14 ++++++++++++-- src/xterm.c | 40 +++++++++++++++++++++++++++++++++++++++- src/xterm.h | 3 ++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/xselect.c b/src/xselect.c index 490a008dfcb..96c1e9830fb 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -2522,7 +2522,8 @@ FRAME is on. If FRAME is nil, the selected frame is used. */) bool x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event, - struct x_display_info *dpyinfo, struct input_event *bufp) + struct x_display_info *dpyinfo, struct input_event *bufp, + bool root_window_coords, int root_x, int root_y) { Lisp_Object vec; Lisp_Object frame; @@ -2532,6 +2533,7 @@ 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; @@ -2563,7 +2565,15 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event, event->format, size)); - x_relative_mouse_position (f, &x, &y); + 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); + bufp->kind = DRAG_N_DROP_EVENT; bufp->frame_or_window = frame; bufp->timestamp = CurrentTime; diff --git a/src/xterm.c b/src/xterm.c index d9dd29ca128..d79871e0210 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -15762,6 +15762,31 @@ x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data) } #endif +/* Extract the root window coordinates from the client message EVENT + if it is a message that we already understand. Return false if the + event was not understood. */ +static bool +x_coords_from_dnd_message (struct x_display_info *dpyinfo, + XEvent *event, int *x_out, int *y_out) +{ + if (event->type != ClientMessage) + return false; + + if (event->xclient.message_type == dpyinfo->Xatom_XdndPosition) + { + if (event->xclient.format != 32) + return false; + + *x_out = (((unsigned long) event->xclient.data.l[2]) >> 16 + & 0xffff); + *y_out = (event->xclient.data.l[2] & 0xffff); + + return true; + } + + return false; +} + /* Handles the XEvent EVENT on display DPYINFO. *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events. @@ -15804,6 +15829,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, GdkEvent *copy = NULL; GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display); #endif + int dx, dy; USE_SAFE_ALLOCA; *finish = X_EVENT_NORMAL; @@ -15835,6 +15861,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, { case ClientMessage: { + int rc; + if (x_dnd_in_progress && FRAME_DISPLAY_INFO (x_dnd_frame) == dpyinfo && event->xclient.message_type == dpyinfo->Xatom_XdndStatus) @@ -16211,7 +16239,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, f = any; if (!f) goto OTHER; - if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie)) + + /* These values are always used initialized, but GCC doesn't + know that. */ + dx = 0; + dy = 0; + + rc = x_coords_from_dnd_message (dpyinfo, (XEvent *) event, + &dx, &dy); + + if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie, + rc, dx, dy)) *finish = X_EVENT_DROP; } break; diff --git a/src/xterm.h b/src/xterm.h index 25c2453ee78..82b4308041a 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1540,7 +1540,8 @@ extern Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom); extern bool x_handle_dnd_message (struct frame *, const XClientMessageEvent *, struct x_display_info *, - struct input_event *); + struct input_event *, + bool, int, int); extern int x_check_property_data (Lisp_Object); extern void x_fill_property_data (Display *, Lisp_Object, -- 2.39.2