Fix two mouse drag and drop issues (Bug#28620, Bug#36269)

Allow 'mouse-drag-and-drop-region' to move/copy text from one
frame to another (Bug#28620).  Prevent mouse avoidance mode from
interfering with 'mouse-drag-and-drop-region' (Bug#36269).

* lisp/avoid.el (mouse-avoidance-ignore-p): Suspend avoidance
when 'track-mouse' equals 'dropping'.
* lisp/mouse.el (mouse-drag-and-drop-region): Set
'track-mouse' to 'dropping'.  Continue reading events also
when switching frames.
* src/keyboard.c (Finternal_track_mouse): Rename from
Ftrack_mouse.
(some_mouse_moved): Return NULL also when mouse is not tracked.
(show_help_echo, readable_events, kbd_buffer_get_event): Don't
check whether mouse is tracked, some_mouse_moved does it now.
(track_mouse): Rename variable from do_mouse_tracking.  Adjust
all users.  In doc-string explain meanings of special values
'dragging' and 'dropping'.
* src/nsterm.m (ns_mouse_position): During drag and drop
consider last mouse frame only when there is no currently
focused frame.
* src/w32fns.c (w32_wnd_proc): Don't set mouse capture during a
drag and drop operation.
* src/w32term.c (w32_mouse_position): Track frame under mouse
during mouse drag and drop.
(mouse_or_wdesc_frame): New function.
(w32_read_socket): Call mouse_or_wdesc_frame on mouse events.
* src/xdisp.c (define_frame_cursor1): Don't change mouse cursor
shape during mouse drag and drop.
(syms_of_xdisp): New symbol Qdropping.
* src/xterm.c (XTmouse_position): Allow mouse drag and drop move
to another frame
(mouse_or_wdesc_frame): New function.
(handle_one_xevent): Use mouse_or_wdesc_frame for mouse events.
This commit is contained in:
Martin Rudalics 2019-08-04 09:21:18 +02:00
parent 01661f33c1
commit 5ec3f70527
10 changed files with 242 additions and 159 deletions

View file

@ -327,6 +327,9 @@ redefine this function to suit your own tastes."
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.

View file

@ -1296,7 +1296,7 @@ The region will be defined with mark and point."
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 @@ is copied instead of being cut."
(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

View file

@ -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;

View file

@ -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);
@ -11643,8 +11640,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 special values `dragging' and `dropping' assert that the mouse
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.

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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. */
if (bar)
f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
}
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;
if (!f1 && insist > 0)
f1 = SELECTED_FRAME ();
*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 (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:

View file

@ -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");

View file

@ -5196,20 +5196,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);
@ -5232,21 +5227,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;
@ -5256,16 +5247,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
@ -5328,13 +5315,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;
@ -5348,7 +5357,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)
@ -7817,6 +7826,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.
@ -8749,15 +8789,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;
@ -8999,33 +9038,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 ();
}
}