From: Alan Mackenzie Date: Mon, 31 May 2021 10:33:10 +0000 (+0000) Subject: Correct mouse handling when window origin changes between down and up events X-Git-Tag: emacs-28.0.90~2247 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=6e2d3bce087d30a535b1f01715d7820576ffe390;p=emacs.git Correct mouse handling when window origin changes between down and up events Do this by using frame relative positions rather than window relative ones, which gave rise to spurious drag events when the origin of the window changed between the mouse down and up events. This fixes bug #48409. * keyboard.c (frame_relative_event_pos): New static variable. (make_lispy_event): Record frame relative position of down event. When the up event is in the same position, "move" this event into the window of the down event when this window (typically a mini-window) is no longer under the mouse. Call make_lispy_position a second time to generate this changed event. (syms_of_keyboard): Declare Qwindow_edges. static_pro frame_relative_event_pos. --- diff --git a/src/keyboard.c b/src/keyboard.c index c855d45afab..4433cfa4193 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -5018,6 +5018,10 @@ static short const internal_border_parts[] = { static Lisp_Object button_down_location; +/* A cons recording the original frame-relative x and y coordinates of + the down mouse event. */ +static Lisp_Object frame_relative_event_pos; + /* Information about the most recent up-going button event: Which button, what location, and what time. */ @@ -5669,6 +5673,7 @@ make_lispy_event (struct input_event *event) double_click_count = 1; button_down_time = event->timestamp; *start_pos_ptr = Fcopy_alist (position); + frame_relative_event_pos = Fcons (event->x, event->y); ignore_mouse_drag_p = false; } @@ -5691,20 +5696,12 @@ make_lispy_event (struct input_event *event) ignore_mouse_drag_p = false; else { - Lisp_Object new_down, down; intmax_t xdiff = double_click_fuzz, ydiff = double_click_fuzz; - /* The third element of every position - should be the (x,y) pair. */ - down = Fcar (Fcdr (Fcdr (start_pos))); - new_down = Fcar (Fcdr (Fcdr (position))); - - if (CONSP (down) - && FIXNUMP (XCAR (down)) && FIXNUMP (XCDR (down))) - { - xdiff = XFIXNUM (XCAR (new_down)) - XFIXNUM (XCAR (down)); - ydiff = XFIXNUM (XCDR (new_down)) - XFIXNUM (XCDR (down)); - } + xdiff = XFIXNUM (event->x) + - XFIXNUM (XCAR (frame_relative_event_pos)); + ydiff = XFIXNUM (event->y) + - XFIXNUM (XCDR (frame_relative_event_pos)); if (! (0 < double_click_fuzz && - double_click_fuzz < xdiff @@ -5721,12 +5718,51 @@ make_lispy_event (struct input_event *event) a click. But mouse-drag-region completely ignores this case and it hasn't caused any real problem, so it's probably OK to ignore it as well. */ - && EQ (Fcar (Fcdr (start_pos)), Fcar (Fcdr (position))))) + && (EQ (Fcar (Fcdr (start_pos)), + Fcar (Fcdr (position))) /* Same buffer pos */ + || !EQ (Fcar (start_pos), + Fcar (position))))) /* Different window */ { /* Mouse has moved enough. */ button_down_time = 0; click_or_drag_modifier = drag_modifier; } + else if (((!EQ (Fcar (start_pos), Fcar (position))) + || (!EQ (Fcar (Fcdr (start_pos)), + Fcar (Fcdr (position))))) + /* Was the down event in a window body? */ + && FIXNUMP (Fcar (Fcdr (start_pos))) + && WINDOW_LIVE_P (Fcar (start_pos)) + && Ffboundp (Qwindow_edges)) + /* If the window (etc.) at the mouse position has + changed between the down event and the up event, + we assume there's been a redisplay between the + two events, and we pretend the mouse is still in + the old window to prevent a spurious drag event + being generated. */ + { + Lisp_Object edges + = call4 (Qwindow_edges, Fcar (start_pos), Qt, Qnil, Qt); + int new_x = XFIXNUM (Fcar (frame_relative_event_pos)); + int new_y = XFIXNUM (Fcdr (frame_relative_event_pos)); + + /* If the up-event is outside the down-event's + window, use coordinates that are within it. */ + if (new_x < XFIXNUM (Fcar (edges))) + new_x = XFIXNUM (Fcar (edges)); + else if (new_x >= XFIXNUM (Fcar (Fcdr (Fcdr (edges))))) + new_x = XFIXNUM (Fcar (Fcdr (Fcdr (edges)))) - 1; + if (new_y < XFIXNUM (Fcar (Fcdr (edges)))) + new_y = XFIXNUM (Fcar (Fcdr (edges))); + else if (new_y + >= XFIXNUM (Fcar (Fcdr (Fcdr (Fcdr (edges)))))) + new_y = XFIXNUM (Fcar (Fcdr (Fcdr (Fcdr (edges))))) - 1; + + position = make_lispy_position + (XFRAME (event->frame_or_window), + make_fixnum (new_x), make_fixnum (new_y), + event->timestamp); + } } /* Don't check is_double; treat this as multiple if the @@ -11645,6 +11681,7 @@ syms_of_keyboard (void) DEFSYM (Qmake_frame_visible, "make-frame-visible"); DEFSYM (Qselect_window, "select-window"); DEFSYM (Qselection_request, "selection-request"); + DEFSYM (Qwindow_edges, "window-edges"); { int i; @@ -11661,6 +11698,7 @@ syms_of_keyboard (void) button_down_location = make_nil_vector (5); staticpro (&button_down_location); + staticpro (&frame_relative_event_pos); mouse_syms = make_nil_vector (5); staticpro (&mouse_syms); wheel_syms = make_nil_vector (ARRAYELTS (lispy_wheel_names));