diff --git a/lisp/avoid.el b/lisp/avoid.el index 7d69fa2a24..43e5062b76 100644 --- a/lisp/avoid.el +++ b/lisp/avoid.el @@ -327,6 +327,9 @@ mouse-avoidance-ignore-p executing-kbd-macro ; don't check inside macro (null (cadr mp)) ; don't move unless in an Emacs frame (not (eq (car mp) (selected-frame))) + ;; Don't interfere with ongoing `mouse-drag-and-drop-region' + ;; (Bug#36269). + (eq track-mouse 'dropping) ;; Don't do anything if last event was a mouse event. ;; FIXME: this code fails in the case where the mouse was moved ;; since the last key-press but without generating any event. diff --git a/lisp/mouse.el b/lisp/mouse.el index 4a532a15e5..e947e16d47 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -1296,7 +1296,7 @@ mouse-drag-track t (lambda () (setq track-mouse old-track-mouse) (setq auto-hscroll-mode auto-hscroll-mode-saved) - (deactivate-mark) + (deactivate-mark) (pop-mark))))) (defun mouse--drag-set-mark-and-point (start click click-count) @@ -2467,12 +2467,13 @@ mouse-drag-and-drop-region (ignore-errors (track-mouse + (setq track-mouse 'dropping) ;; When event was "click" instead of "drag", skip loop. (while (progn (setq event (read-key)) ; read-event or read-key (or (mouse-movement-p event) ;; Handle `mouse-autoselect-window'. - (eq (car-safe event) 'select-window))) + (memq (car event) '(select-window switch-frame)))) ;; Obtain the dragged text in region. When the loop was ;; skipped, value-selection remains nil. (unless value-selection diff --git a/src/dispnew.c b/src/dispnew.c index 0131b63767..74d53fb46d 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3402,9 +3402,9 @@ update_window (struct window *w, bool force_p) if (!force_p) detect_input_pending_ignore_squeezables (); - /* If forced to complete the update, or if no input is pending, do - the update. */ - if (force_p || !input_pending || !NILP (do_mouse_tracking)) + /* If forced to complete the update, no input is pending or we are + tracking the mouse do the update. */ + if (force_p || !input_pending || !NILP (track_mouse)) { struct glyph_row *row, *end; struct glyph_row *mode_line_row; diff --git a/src/keyboard.c b/src/keyboard.c index b86ad03851..4224ab01b3 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1159,14 +1159,14 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, user_error ("No recursive edit is in progress"); } -/* Restore mouse tracking enablement. See Ftrack_mouse for the only use - of this function. */ +/* Restore mouse tracking enablement. See Finternal_track_mouse for + the only use of this function. */ static void -tracking_off (Lisp_Object old_value) +tracking_off (Lisp_Object old_track_mouse) { - do_mouse_tracking = old_value; - if (NILP (old_value)) + track_mouse = old_track_mouse; + if (NILP (old_track_mouse)) { /* Redisplay may have been preempted because there was input available, and it assumes it will be called again after the @@ -1181,24 +1181,24 @@ tracking_off (Lisp_Object old_value) } } -DEFUN ("internal--track-mouse", Ftrack_mouse, Strack_mouse, 1, 1, 0, +DEFUN ("internal--track-mouse", Finternal_track_mouse, Sinternal_track_mouse, + 1, 1, 0, doc: /* Call BODYFUN with mouse movement events enabled. */) (Lisp_Object bodyfun) { ptrdiff_t count = SPECPDL_INDEX (); Lisp_Object val; - record_unwind_protect (tracking_off, do_mouse_tracking); + record_unwind_protect (tracking_off, track_mouse); - do_mouse_tracking = Qt; + track_mouse = Qt; val = call0 (bodyfun); return unbind_to (count, val); } -/* If mouse has moved on some frame, return one of those frames. - - Return 0 otherwise. +/* If mouse has moved on some frame and we are tracking the mouse, + return one of those frames. Return NULL otherwise. If ignore_mouse_drag_p is non-zero, ignore (implicit) mouse movement after resizing the tool-bar window. */ @@ -1210,11 +1210,8 @@ some_mouse_moved (void) { Lisp_Object tail, frame; - if (ignore_mouse_drag_p) - { - /* ignore_mouse_drag_p = false; */ - return 0; - } + if (NILP (track_mouse) || ignore_mouse_drag_p) + return NULL; FOR_EACH_FRAME (tail, frame) { @@ -1222,7 +1219,7 @@ some_mouse_moved (void) return XFRAME (frame); } - return 0; + return NULL; } @@ -2071,7 +2068,8 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object, This causes trouble if we are trying to read a mouse motion event (i.e., if we are inside a `track-mouse' form), so we restore the mouse_moved flag. */ - struct frame *f = NILP (do_mouse_tracking) ? NULL : some_mouse_moved (); + struct frame *f = some_mouse_moved (); + help = call1 (Qmouse_fixup_help_message, help); if (f) f->mouse_moved = true; @@ -3403,8 +3401,7 @@ readable_events (int flags) return 1; } - if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) - && !NILP (do_mouse_tracking) && some_mouse_moved ()) + if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ()) return 1; if (single_kboard) { @@ -3786,7 +3783,7 @@ kbd_buffer_get_event (KBOARD **kbp, if (kbd_fetch_ptr != kbd_store_ptr) break; - if (!NILP (do_mouse_tracking) && some_mouse_moved ()) + if (some_mouse_moved ()) break; /* If the quit flag is set, then read_char will return @@ -3802,7 +3799,7 @@ kbd_buffer_get_event (KBOARD **kbp, #endif if (kbd_fetch_ptr != kbd_store_ptr) break; - if (!NILP (do_mouse_tracking) && some_mouse_moved ()) + if (some_mouse_moved ()) break; if (end_time) { @@ -3941,8 +3938,9 @@ kbd_buffer_get_event (KBOARD **kbp, break; default: { - /* If this event is on a different frame, return a switch-frame this - time, and leave the event in the queue for next time. */ + /* If this event is on a different frame, return a + switch-frame this time and leave the event in the queue + for next time. */ Lisp_Object frame; Lisp_Object focus; @@ -3956,14 +3954,13 @@ kbd_buffer_get_event (KBOARD **kbp, if (! NILP (focus)) frame = focus; - if (! EQ (frame, internal_last_event_frame) + if (!EQ (frame, internal_last_event_frame) && !EQ (frame, selected_frame)) obj = make_lispy_switch_frame (frame); internal_last_event_frame = frame; /* If we didn't decide to make a switch-frame event, go ahead and build a real event from the queue entry. */ - if (NILP (obj)) { obj = make_lispy_event (&event->ie); @@ -3995,7 +3992,7 @@ kbd_buffer_get_event (KBOARD **kbp, } } /* Try generating a mouse motion event. */ - else if (!NILP (do_mouse_tracking) && some_mouse_moved ()) + else if (some_mouse_moved ()) { struct frame *f = some_mouse_moved (); Lisp_Object bar_window; @@ -4027,7 +4024,7 @@ kbd_buffer_get_event (KBOARD **kbp, if (NILP (frame)) XSETFRAME (frame, f); - if (! EQ (frame, internal_last_event_frame) + if (!EQ (frame, internal_last_event_frame) && !EQ (frame, selected_frame)) obj = make_lispy_switch_frame (frame); internal_last_event_frame = frame; @@ -10935,7 +10932,7 @@ init_keyboard (void) recent_keys_index = 0; kbd_fetch_ptr = kbd_buffer; kbd_store_ptr = kbd_buffer; - do_mouse_tracking = Qnil; + track_mouse = Qnil; input_pending = false; interrupt_input_blocked = 0; pending_signals = false; @@ -11297,7 +11294,7 @@ syms_of_keyboard (void) defsubr (&Sread_key_sequence); defsubr (&Sread_key_sequence_vector); defsubr (&Srecursive_edit); - defsubr (&Strack_mouse); + defsubr (&Sinternal_track_mouse); defsubr (&Sinput_pending_p); defsubr (&Srecent_keys); defsubr (&Sthis_command_keys); @@ -11642,8 +11639,15 @@ and the minor mode maps regardless of `overriding-local-map'. */); doc: /* Keymap defining bindings for special events to execute at low level. */); Vspecial_event_map = list1 (Qkeymap); - DEFVAR_LISP ("track-mouse", do_mouse_tracking, - doc: /* Non-nil means generate motion events for mouse motion. */); + DEFVAR_LISP ("track-mouse", track_mouse, + doc: /* Non-nil means generate motion events for mouse motion. +The sepecial values 'dragging' and 'dropping' assert that the moue +cursor retains its appearance during mouse motion. Any non-nil value +but 'dropping' asserts that motion events always relate to the frame +where the the mouse movement started. The value 'dropping' asserts +that motion events relate to the frame where the mouse cursor is seen +when generating the event. If there's no such frame, such motion +events relate to the frame where the mouse movement started. */); DEFVAR_KBOARD ("system-key-alist", Vsystem_key_alist, doc: /* Alist of system-specific X windows key symbols. diff --git a/src/nsterm.m b/src/nsterm.m index 02331826d9..75bf85617b 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2480,7 +2480,11 @@ so some key presses (TAB) are swallowed by the system. */ XFRAME (frame)->mouse_moved = 0; dpyinfo->last_mouse_scroll_bar = nil; + f = dpyinfo->ns_focus_frame ? dpyinfo->ns_focus_frame : SELECTED_FRAME (); if (dpyinfo->last_mouse_frame + /* While dropping use the last mouse frame only if there is no + currently focused frame. */ + && (!EQ (track_mouse, Qdropping) || !f) && FRAME_LIVE_P (dpyinfo->last_mouse_frame)) f = dpyinfo->last_mouse_frame; else diff --git a/src/term.c b/src/term.c index b058d8bdad..a88d47f923 100644 --- a/src/term.c +++ b/src/term.c @@ -3033,18 +3033,18 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, bool usable_input = 1; mi_result st = MI_CONTINUE; struct tty_display_info *tty = FRAME_TTY (sf); - Lisp_Object saved_mouse_tracking = do_mouse_tracking; + Lisp_Object old_track_mouse = track_mouse; /* Signal the keyboard reading routines we are displaying a menu on this terminal. */ tty->showing_menu = 1; /* We want mouse movements be reported by read_menu_command. */ - do_mouse_tracking = Qt; + track_mouse = Qt; do { cmd = read_menu_command (); } while (NILP (cmd)); tty->showing_menu = 0; - do_mouse_tracking = saved_mouse_tracking; + track_mouse = old_track_mouse; if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit) /* If some input switched frames under our feet, exit the diff --git a/src/w32fns.c b/src/w32fns.c index acd9c80528..a2a88b2588 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -4586,7 +4586,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (button_state & this) return 0; - if (button_state == 0) + /* Don't capture mouse when dropping. */ + if (button_state == 0 && !EQ (track_mouse, Qdropping)) SetCapture (hwnd); button_state |= this; @@ -4707,8 +4708,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (parse_button (msg, HIWORD (wParam), &button, &up)) { - if (up) ReleaseCapture (); - else SetCapture (hwnd); + if (up) + ReleaseCapture (); + /* Don't capture mouse when dropping. */ + else if (!EQ (track_mouse, Qdropping)) + SetCapture (hwnd); button = (button == 0) ? LMOUSE : ((button == 1) ? MMOUSE : RMOUSE); if (up) @@ -5351,8 +5355,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) else if (button_state & RMOUSE) flags |= TPM_RIGHTBUTTON; - /* Remember we did a SetCapture on the initial mouse down event, - so for safety, we make sure the capture is canceled now. */ + /* We may have done a SetCapture on the initial mouse down + event, so for safety, make sure the capture is canceled + now. */ ReleaseCapture (); button_state = 0; diff --git a/src/w32term.c b/src/w32term.c index c6e175e7e5..ad96287a43 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -3525,72 +3525,78 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, /* Now we have a position on the root; find the innermost window containing the pointer. */ - { - /* If mouse was grabbed on a frame, give coords for that - frame even if the mouse is now outside it. Otherwise - check for window under mouse on one of our frames. */ - if (gui_mouse_grabbed (dpyinfo)) - f1 = dpyinfo->last_mouse_frame; - else - { - HWND wfp = WindowFromPoint (pt); - if (wfp) - { - f1 = w32_window_to_frame (dpyinfo, wfp); - if (f1) - { - HWND cwfp = ChildWindowFromPoint (wfp, pt); + /* If mouse was grabbed on a frame and we are not dropping, + give coords for that frame even if the mouse is now outside + it. Otherwise check for window under mouse on one of our + frames. */ + if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping)) + f1 = dpyinfo->last_mouse_frame; + else + { + HWND wfp = WindowFromPoint (pt); - if (cwfp) - { - struct frame *f2 = w32_window_to_frame (dpyinfo, cwfp); + if (wfp) + { + f1 = w32_window_to_frame (dpyinfo, wfp); + if (f1) + { + HWND cwfp = ChildWindowFromPoint (wfp, pt); - /* If a child window was found, make sure that its - frame is a child frame (Bug#26615, maybe). */ - if (f2 && FRAME_PARENT_FRAME (f2)) - f1 = f2; - } - } - } - } + if (cwfp) + { + struct frame *f2 = w32_window_to_frame (dpyinfo, cwfp); - /* If not, is it one of our scroll bars? */ - if (! f1) - { - struct scroll_bar *bar - = w32_window_to_scroll_bar (WindowFromPoint (pt), 2); + /* If a child window was found, make sure that its + frame is a child frame (Bug#26615, maybe). */ + if (f2 && FRAME_PARENT_FRAME (f2)) + f1 = f2; + } + } + } + } - if (bar) - f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); - } + if (!f1 || FRAME_TOOLTIP_P (f1)) + /* Don't use a tooltip frame. */ + f1 = ((EQ (track_mouse, Qdropping) && gui_mouse_grabbed (dpyinfo)) + ? dpyinfo->last_mouse_frame + : NULL); - if (f1 == 0 && insist > 0) - f1 = SELECTED_FRAME (); + /* If not, is it one of our scroll bars? */ + if (!f1) + { + struct scroll_bar *bar + = w32_window_to_scroll_bar (WindowFromPoint (pt), 2); - if (f1) - { - /* Ok, we found a frame. Store all the values. - last_mouse_glyph is a rectangle used to reduce the - generation of mouse events. To not miss any motion - events, we must divide the frame into rectangles of the - size of the smallest character that could be displayed - on it, i.e. into the same rectangles that matrices on - the frame are divided into. */ - - dpyinfo = FRAME_DISPLAY_INFO (f1); - ScreenToClient (FRAME_W32_WINDOW (f1), &pt); - remember_mouse_glyph (f1, pt.x, pt.y, &dpyinfo->last_mouse_glyph); - dpyinfo->last_mouse_glyph_frame = f1; - - *bar_window = Qnil; - *part = scroll_bar_above_handle; - *fp = f1; - XSETINT (*x, pt.x); - XSETINT (*y, pt.y); - *time = dpyinfo->last_mouse_movement_time; - } - } + if (bar) + f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + } + + if (!f1 && insist > 0) + f1 = SELECTED_FRAME (); + + if (f1) + { + /* Ok, we found a frame. Store all the values. + last_mouse_glyph is a rectangle used to reduce the + generation of mouse events. To not miss any motion + events, we must divide the frame into rectangles of the + size of the smallest character that could be displayed + on it, i.e. into the same rectangles that matrices on + the frame are divided into. */ + + dpyinfo = FRAME_DISPLAY_INFO (f1); + ScreenToClient (FRAME_W32_WINDOW (f1), &pt); + remember_mouse_glyph (f1, pt.x, pt.y, &dpyinfo->last_mouse_glyph); + dpyinfo->last_mouse_glyph_frame = f1; + + *bar_window = Qnil; + *part = scroll_bar_above_handle; + *fp = f1; + XSETINT (*x, pt.x); + XSETINT (*y, pt.y); + *time = dpyinfo->last_mouse_movement_time; + } } unblock_input (); @@ -4667,6 +4673,37 @@ static short temp_buffer[100]; /* Temporarily store lead byte of DBCS input sequences. */ static char dbcs_lead = 0; +/** + mouse_or_wdesc_frame: When not dropping and the mouse was grabbed + for DPYINFO, return the frame where the mouse was seen last. If + there's no such frame, return the frame according to WDESC. When + dropping, return the frame according to WDESC. If there's no such + frame and the mouse was grabbed for DPYINFO, return the frame where + the mouse was seen last. In either case, never return a tooltip + frame. */ +static struct frame * +mouse_or_wdesc_frame (struct w32_display_info *dpyinfo, HWND wdesc) +{ + struct frame *lm_f = (gui_mouse_grabbed (dpyinfo) + ? dpyinfo->last_mouse_frame + : NULL); + + if (lm_f && !EQ (track_mouse, Qdropping)) + return lm_f; + else + { + struct frame *w_f = w32_window_to_frame (dpyinfo, wdesc); + + /* Do not return a tooltip frame. */ + if (!w_f || FRAME_TOOLTIP_P (w_f)) + return EQ (track_mouse, Qdropping) ? lm_f : NULL; + else + /* When dropping it would be probably nice to raise w_f + here. */ + return w_f; + } +} + /* Read events coming from the W32 shell. This routine is called by the SIGIO handler. We return as soon as there are no more events to be read. @@ -4940,15 +4977,13 @@ w32_read_socket (struct terminal *terminal, previous_help_echo_string = help_echo_string; help_echo_string = Qnil; - f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame - : w32_window_to_frame (dpyinfo, msg.msg.hwnd)); - if (hlinfo->mouse_face_hidden) { hlinfo->mouse_face_hidden = false; clear_mouse_face (hlinfo); } + f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd); if (f) { /* Maybe generate SELECT_WINDOW_EVENTs for @@ -5020,9 +5055,7 @@ w32_read_socket (struct terminal *terminal, int button = 0; int up = 0; - f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame - : w32_window_to_frame (dpyinfo, msg.msg.hwnd)); - + f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd); if (f) { w32_construct_mouse_click (&inev, &msg, f); @@ -5081,9 +5114,7 @@ w32_read_socket (struct terminal *terminal, case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: { - f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame - : w32_window_to_frame (dpyinfo, msg.msg.hwnd)); - + f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd); if (f) { if (!dpyinfo->w32_focus_frame @@ -5439,6 +5470,7 @@ w32_read_socket (struct terminal *terminal, if (any_help_event_p) do_help = -1; } + break; case WM_SETFOCUS: diff --git a/src/xdisp.c b/src/xdisp.c index 1bb5f5e0f2..7338d2b7d4 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -17289,7 +17289,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) the mouse, resulting in an unwanted mouse-movement rather than a simple mouse-click. */ if (!w->start_at_line_beg - && NILP (do_mouse_tracking) + && NILP (track_mouse) && CHARPOS (startp) > BEGV && CHARPOS (startp) > BEG + beg_unchanged && CHARPOS (startp) <= Z - end_unchanged @@ -30279,7 +30279,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) #ifdef HAVE_WINDOW_SYSTEM /* Change the mouse cursor. */ - if (FRAME_WINDOW_P (f) && NILP (do_mouse_tracking)) + if (FRAME_WINDOW_P (f) && NILP (track_mouse)) { #ifndef HAVE_EXT_TOOL_BAR if (draw == DRAW_NORMAL_TEXT @@ -31226,7 +31226,7 @@ define_frame_cursor1 (struct frame *f, Emacs_Cursor cursor, Lisp_Object pointer) return; /* Do not change cursor shape while dragging mouse. */ - if (EQ (do_mouse_tracking, Qdragging)) + if (EQ (track_mouse, Qdragging) || EQ (track_mouse, Qdropping)) return; if (!NILP (pointer)) @@ -32956,6 +32956,7 @@ be let-bound around code that needs to disable messages temporarily. */); /* also Qtext */ DEFSYM (Qdragging, "dragging"); + DEFSYM (Qdropping, "dropping"); DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces"); diff --git a/src/xterm.c b/src/xterm.c index c96aa74a7a..97d14f7d45 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5167,20 +5167,15 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, /* Figure out which root window we're on. */ XQueryPointer (FRAME_X_DISPLAY (*fp), DefaultRootWindow (FRAME_X_DISPLAY (*fp)), - /* The root window which contains the pointer. */ &root, - /* Trash which we can't trust if the pointer is on a different screen. */ &dummy_window, - /* The position on that root window. */ &root_x, &root_y, - /* More trash we can't trust. */ &dummy, &dummy, - /* Modifier keys and pointer buttons, about which we don't care. */ (unsigned int *) &dummy); @@ -5203,21 +5198,17 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, x_catch_errors (FRAME_X_DISPLAY (*fp)); - if (gui_mouse_grabbed (dpyinfo)) + if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping)) { /* If mouse was grabbed on a frame, give coords for that frame even if the mouse is now outside it. */ XTranslateCoordinates (FRAME_X_DISPLAY (*fp), - /* From-window. */ root, - /* To-window. */ FRAME_X_WINDOW (dpyinfo->last_mouse_frame), - /* From-position, to-position. */ root_x, root_y, &win_x, &win_y, - /* Child of win. */ &child); f1 = dpyinfo->last_mouse_frame; @@ -5227,16 +5218,12 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, while (true) { XTranslateCoordinates (FRAME_X_DISPLAY (*fp), - /* From-window, to-window. */ root, win, - /* From-position, to-position. */ root_x, root_y, &win_x, &win_y, - /* Child of win. */ &child); - if (child == None || child == win) { #ifdef USE_GTK @@ -5299,13 +5286,35 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, #endif /* USE_X_TOOLKIT */ } + if ((!f1 || FRAME_TOOLTIP_P (f1)) + && EQ (track_mouse, Qdropping) + && gui_mouse_grabbed (dpyinfo)) + { + /* When dropping then if we didn't get a frame or only a + tooltip frame and the mouse was grabbed on a frame, + give coords for that frame even if the mouse is now + outside it. */ + XTranslateCoordinates (FRAME_X_DISPLAY (*fp), + /* From-window. */ + root, + /* To-window. */ + FRAME_X_WINDOW (dpyinfo->last_mouse_frame), + /* From-position, to-position. */ + root_x, root_y, &win_x, &win_y, + /* Child of win. */ + &child); + f1 = dpyinfo->last_mouse_frame; + } + else if (f1 && FRAME_TOOLTIP_P (f1)) + f1 = NULL; + if (x_had_errors_p (FRAME_X_DISPLAY (*fp))) - f1 = 0; + f1 = NULL; x_uncatch_errors_after_check (); /* If not, is it one of our scroll bars? */ - if (! f1) + if (!f1) { struct scroll_bar *bar; @@ -5319,7 +5328,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, } } - if (f1 == 0 && insist > 0) + if (!f1 && insist > 0) f1 = SELECTED_FRAME (); if (f1) @@ -7788,6 +7797,37 @@ flush_dirty_back_buffers (void) unblock_input (); } +/** + mouse_or_wdesc_frame: When not dropping and the mouse was grabbed + for DPYINFO, return the frame where the mouse was seen last. If + there's no such frame, return the frame according to WDESC. When + dropping, return the frame according to WDESC. If there's no such + frame and the mouse was grabbed for DPYINFO, return the frame where + the mouse was seen last. In either case, never return a tooltip + frame. */ +static struct frame * +mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc) +{ + struct frame *lm_f = (gui_mouse_grabbed (dpyinfo) + ? dpyinfo->last_mouse_frame + : NULL); + + if (lm_f && !EQ (track_mouse, Qdropping)) + return lm_f; + else + { + struct frame *w_f = x_window_to_frame (dpyinfo, wdesc); + + /* Do not return a tooltip frame. */ + if (!w_f || FRAME_TOOLTIP_P (w_f)) + return EQ (track_mouse, Qdropping) ? lm_f : NULL; + else + /* When dropping it would be probably nice to raise w_f + here. */ + return w_f; + } +} + /* Handles the XEvent EVENT on display DPYINFO. *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events. @@ -8720,15 +8760,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, previous_help_echo_string = help_echo_string; help_echo_string = Qnil; - f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame - : x_window_to_frame (dpyinfo, event->xmotion.window)); - - if (hlinfo->mouse_face_hidden) + if (hlinfo->mouse_face_hidden) { hlinfo->mouse_face_hidden = false; clear_mouse_face (hlinfo); } + f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window); + #ifdef USE_GTK if (f && xg_event_is_for_scrollbar (f, event)) f = 0; @@ -8970,33 +9009,27 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->last_mouse_glyph_frame = NULL; x_display_set_last_user_time (dpyinfo, event->xbutton.time); - if (gui_mouse_grabbed (dpyinfo)) - f = dpyinfo->last_mouse_frame; - else + f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window); + if (f && event->xbutton.type == ButtonPress + && !popup_activated () + && !x_window_to_scroll_bar (event->xbutton.display, + event->xbutton.window, 2) + && !FRAME_NO_ACCEPT_FOCUS (f)) { - f = x_window_to_frame (dpyinfo, event->xbutton.window); + /* When clicking into a child frame or when clicking + into a parent frame with the child frame selected and + `no-accept-focus' is not set, select the clicked + frame. */ + struct frame *hf = dpyinfo->highlight_frame; - if (f && event->xbutton.type == ButtonPress - && !popup_activated () - && !x_window_to_scroll_bar (event->xbutton.display, - event->xbutton.window, 2) - && !FRAME_NO_ACCEPT_FOCUS (f)) + if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf))) { - /* When clicking into a child frame or when clicking - into a parent frame with the child frame selected and - `no-accept-focus' is not set, select the clicked - frame. */ - struct frame *hf = dpyinfo->highlight_frame; - - if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf))) - { - block_input (); - XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), - RevertToParent, CurrentTime); - if (FRAME_PARENT_FRAME (f)) - XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f)); - unblock_input (); - } + block_input (); + XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + RevertToParent, CurrentTime); + if (FRAME_PARENT_FRAME (f)) + XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f)); + unblock_input (); } }