summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Rudalics <rudalics@gmx.at>2019-08-04 09:21:18 +0200
committerMartin Rudalics <rudalics@gmx.at>2019-08-04 09:21:18 +0200
commit5ec3f70527e330abf4c0c3519fa4914c5f094358 (patch)
tree3e91fb7a326694d8b46cf9f1ed4e548ce4f7f19d
parent01661f33c11654d1fe5fe1013332db2500b7f449 (diff)
downloademacs-5ec3f70527e330abf4c0c3519fa4914c5f094358.tar.gz
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.
-rw-r--r--lisp/avoid.el3
-rw-r--r--lisp/mouse.el5
-rw-r--r--src/dispnew.c6
-rw-r--r--src/keyboard.c68
-rw-r--r--src/nsterm.m4
-rw-r--r--src/term.c6
-rw-r--r--src/w32fns.c15
-rw-r--r--src/w32term.c168
-rw-r--r--src/xdisp.c7
-rw-r--r--src/xterm.c123
10 files changed, 244 insertions, 161 deletions
diff --git a/lisp/avoid.el b/lisp/avoid.el
index 7d69fa2a247..43e5062b76c 100644
--- a/lisp/avoid.el
+++ b/lisp/avoid.el
@@ -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.
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 4a532a15e5f..e947e16d47f 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -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
diff --git a/src/dispnew.c b/src/dispnew.c
index 0131b63767b..799ef2beae8 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 db5ca4e547e..30686a25898 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);
@@ -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.
diff --git a/src/nsterm.m b/src/nsterm.m
index b8754278f04..42ef4dd0106 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2480,7 +2480,11 @@ ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
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 b058d8bdad0..a88d47f9238 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 acd9c80528a..a2a88b25881 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 c6e175e7e5c..ad96287a43a 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 1bb5f5e0f2a..7338d2b7d4f 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 75568a82a18..bbe68ef6221 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -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 ();
}
}