emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 5ec3f70: Fix two mouse drag and drop issues (Bug#28


From: Martin Rudalics
Subject: [Emacs-diffs] master 5ec3f70: Fix two mouse drag and drop issues (Bug#28620, Bug#36269)
Date: Sun, 4 Aug 2019 03:22:11 -0400 (EDT)

branch: master
commit 5ec3f70527e330abf4c0c3519fa4914c5f094358
Author: Martin Rudalics <address@hidden>
Commit: Martin Rudalics <address@hidden>

    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.
---
 lisp/avoid.el  |   3 ++
 lisp/mouse.el  |   5 +-
 src/dispnew.c  |   6 +--
 src/keyboard.c |  68 ++++++++++++-----------
 src/nsterm.m   |   4 ++
 src/term.c     |   6 +--
 src/w32fns.c   |  15 ++++--
 src/w32term.c  | 168 ++++++++++++++++++++++++++++++++++-----------------------
 src/xdisp.c    |   7 +--
 src/xterm.c    | 123 ++++++++++++++++++++++++++----------------
 10 files changed, 244 insertions(+), 161 deletions(-)

diff --git a/lisp/avoid.el b/lisp/avoid.el
index 7d69fa2..43e5062 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 4a532a1..e947e16 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 0131b63..799ef2b 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 db5ca4e..30686a2 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 b875427..42ef4dd 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 b058d8b..a88d47f 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 acd9c80..a2a88b2 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 c6e175e..ad96287 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 1bb5f5e..7338d2b 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 75568a8..bbe68ef 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 ();
              }
          }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]