From: martin rudalics <rudalics@gmx.at>
To: Eli Zaretskii <eliz@gnu.org>
Cc: rswgnu@gmail.com, scotto@sharpleaf.org, 28620@debbugs.gnu.org,
36269@debbugs.gnu.org
Subject: bug#28620: Mouse drag event records wrong window for release when crossing frames
Date: Sun, 28 Jul 2019 09:34:00 +0200 [thread overview]
Message-ID: <42eec0a5-2c91-aaab-a536-08f3157ca864@gmx.at> (raw)
In-Reply-To: <8336irn617.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 1191 bytes --]
> Thanks, a few minor comments below.
Thanks for the comments. I hopefully applied all changes you
proposed.
Please keep in mind that I wrote the code almost two years ago and
then forgot about it. It's only in the context of Bug#36269 that I
resurrected it - with all its inadequacies.
>> @@ -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 ())
>
> Can't we have mouse motion events outside track-mouse?
Not to my knowledge. In either case, I wouldn't want to change
anything in this regard here.
> There's too much of whitespace changes in the rest of the patch,
> making it very hard to review. Can you show the patch without
> whitespace differences?
I attach a patch which re-adds some extraneous braces to w32term.c.
If you want me to restore more of the old code, please tell me.
Also, I do not intend to push the changes until someone tells me that
they work. I neither use the mouse to drop nor mouse avoidance mode
and so have never given it any serious testing.
Thanks, martin
[-- Attachment #2: track-mouse-with-braces.diff --]
[-- Type: text/plain, Size: 25044 bytes --]
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..799ef2beae 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..765b6e85c1 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");
}
\f
-/* 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;
}
\f
@@ -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 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.
diff --git a/src/nsterm.m b/src/nsterm.m
index 02331826d9..fb2e55929e 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..0058b98ed4 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3525,11 +3525,13 @@ 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))
+ /* 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
{
@@ -3555,17 +3557,23 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *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 not, is it one of our scroll bars? */
- if (! f1)
+ if (!f1)
{
struct scroll_bar *bar
- = w32_window_to_scroll_bar (WindowFromPoint (pt), 2);
+ = w32_window_to_scroll_bar (WindowFromPoint (pt), 2);
if (bar)
f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
}
- if (f1 == 0 && insist > 0)
+ if (!f1 && insist > 0)
f1 = SELECTED_FRAME ();
if (f1)
@@ -4667,6 +4675,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 +4979,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 +5057,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 +5116,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 +5472,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 ();
}
}
next prev parent reply other threads:[~2019-07-28 7:34 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-27 15:44 bug#28620: Mouse drag event records wrong window for release when crossing frames Robert Weiner
2017-10-03 20:54 ` bug#28620: (mouse-position_ wrong on macOS after mouse-1 click (Was: Interact directly on Emacs bug#28620: mouse drag event records wrong release window) Robert Weiner
2017-10-16 15:57 ` bug#28620: (PARTIAL SOLUTION) Mouse drag event records wrong window for release when crossing frames Bob Weiner
2019-07-27 9:26 ` bug#36269: bug#28620: " martin rudalics
2019-07-27 10:08 ` Eli Zaretskii
2019-07-28 7:34 ` martin rudalics [this message]
2019-07-29 23:21 ` Robert Weiner
2019-07-30 7:00 ` bug#36269: " martin rudalics
2019-08-03 11:25 ` Eli Zaretskii
2019-08-04 7:59 ` martin rudalics
2020-08-18 11:31 ` bug#28620: bug#36269: " Stefan Kangas
2020-08-18 12:15 ` Eli Zaretskii
-- strict thread matches above, loose matches on Subject: below --
2017-09-27 16:01 bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Robert Weiner
2017-09-27 21:34 ` John Wiegley
2017-09-29 8:34 ` martin rudalics
2017-09-29 16:48 ` Robert Weiner
2017-09-29 19:42 ` Eli Zaretskii
2017-09-29 19:41 ` Eli Zaretskii
2017-09-29 20:11 ` Robert Weiner
2017-09-30 8:32 ` martin rudalics
2017-09-30 12:45 ` Robert Weiner
2017-09-30 12:52 ` Robert Weiner
2017-09-30 17:12 ` martin rudalics
2017-09-30 21:56 ` bug#28620: " Robert Weiner
2017-09-30 23:34 ` Robert Weiner
2017-10-16 15:11 ` bug#28620: Emacs bug#28620: (PARTIAL SOLUTION) mouse-position wrong on macOS and Windows 7 after mouse-1 click Bob Weiner
2019-06-24 16:08 ` bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Lars Ingebrigtsen
2019-06-27 2:20 ` Robert Weiner
2019-06-27 10:39 ` Lars Ingebrigtsen
2019-06-27 12:27 ` Robert Weiner
2020-08-24 13:28 ` Lars Ingebrigtsen
2020-08-24 13:29 ` Lars Ingebrigtsen
2020-10-11 2:06 ` Lars Ingebrigtsen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=42eec0a5-2c91-aaab-a536-08f3157ca864@gmx.at \
--to=rudalics@gmx.at \
--cc=28620@debbugs.gnu.org \
--cc=36269@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=rswgnu@gmail.com \
--cc=scotto@sharpleaf.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.