]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve behavior of dragging text to windows on top of frames
authorPo Lu <luangruo@yahoo.com>
Mon, 4 Apr 2022 05:10:01 +0000 (13:10 +0800)
committerPo Lu <luangruo@yahoo.com>
Mon, 4 Apr 2022 05:10:01 +0000 (13:10 +0800)
* doc/lispref/frames.texi (Drag and Drop): Document new meaning
of `return-frame' in `x-begin-drag'.
* lisp/mouse.el (mouse-drag-and-drop-region): Use `now' when
calling `x-begin-drag'.
* src/xfns.c (Fx_begin_drag): Update doc string.
* src/xterm.c (x_dnd_begin_drag_and_drop): Accept return_frame
as a Lisp_Object and handle Qnow correctly.
(XTmouse_position): Ignore tooltip frames when processing
`drag-source'.
(syms_of_xterm): New defsym `now'.
* src/xterm.h: Update prototypes.

doc/lispref/frames.texi
lisp/mouse.el
src/xfns.c
src/xterm.c
src/xterm.h

index 057f070cccae22a35dd02e8419b5d342d50c0609..85f92d4f629f5171e097a7f58ff4f025a6121a3e 100644 (file)
@@ -4075,12 +4075,15 @@ describing the available actions, and strings that the drop target is
 expected to present to the user to choose between the available
 actions.
 
-If @var{return-frame} is non-nil and the mouse moves over an Emacs
-frame after first moving out of @var{frame}, then the frame to which
-the mouse moves will be returned immediately.  This is useful when you
-want to treat dragging content from one frame to another specially,
-while also being able to drag content to other programs, but is not
-guaranteed to work on all systems and window managers.
+If @var{return-frame} is non-@code{nil} and the mouse moves over an
+Emacs frame after first moving out of @var{frame}, then the frame to
+which the mouse moves will be returned immediately.  If
+@var{return-frame} is the symbol @code{now}, then any frame underneath
+the mouse pointer will be returned and no further work will be done.
+@var{return-frame} useful when you want to treat dragging content from
+one frame to another specially, while also being able to drag content
+to other programs, but it is not guaranteed to work on all systems and
+window managers.
 
 If the drop was rejected or no drop target was found, this function
 returns @code{nil}.  Otherwise, it returns a symbol describing the
index f42492bb5d33eadba946ab87fcd9affa993a1a36..26a17365da2a987ec4cccb9b2c7b2d2f72000bb7 100644 (file)
@@ -3061,7 +3061,8 @@ is copied instead of being cut."
          value-selection    ; This remains nil when event was "click".
          text-tooltip
          states
-         window-exempt)
+         window-exempt
+         drag-again-mouse-position)
 
     ;; STATES stores for each window on this frame its start and point
     ;; positions so we can restore them on all windows but for the one
@@ -3171,7 +3172,14 @@ is copied instead of being cut."
                                            (frame-pixel-width frame))
                                         (> (cdr location)
                                            (frame-pixel-height frame)))))
-                             (not (posn-window (event-end event)))))
+                             (and (or (not drag-again-mouse-position)
+                                      (let ((mouse-position (mouse-absolute-pixel-position)))
+                                        (or (< 5 (abs (- (car drag-again-mouse-position)
+                                                         (car mouse-position))))
+                                            (< 5 (abs (- (cdr drag-again-mouse-position)
+                                                         (cdr mouse-position)))))))
+                                  (not (posn-window (event-end event))))))
+                (setq drag-again-mouse-position nil)
                 (mouse-drag-and-drop-region-hide-tooltip)
                 (gui-set-selection 'XdndSelection value-selection)
                 (let ((drag-action-or-frame
@@ -3182,9 +3190,18 @@ is copied instead of being cut."
                                          (if mouse-drag-and-drop-region-cut-when-buffers-differ
                                              'XdndActionMove
                                            'XdndActionCopy)
-                                         (posn-window (event-end event)) t)
+                                         (posn-window (event-end event)) 'now)
                          (quit nil))))
                   (when (framep drag-action-or-frame)
+                    ;; With some window managers `x-begin-drag'
+                    ;; returns a frame sooner than `mouse-position'
+                    ;; will return one, due to over-wide frame windows
+                    ;; being drawn by the window manager.  To avoid
+                    ;; that, we just require the mouse move a few
+                    ;; pixels before beginning another cross-program
+                    ;; drag.
+                    (setq drag-again-mouse-position
+                          (mouse-absolute-pixel-position))
                     (throw 'drag-again nil))
 
                   (let ((min-char (point)))
index 4fa919f36a5b968e665cd2d53247fb07b5341f5e..5cf3eb41996377558f737230d32fb4c729751bce 100644 (file)
@@ -6712,7 +6712,9 @@ https://freedesktop.org/wiki/Specifications/XDND/.
 
 If RETURN-FRAME is non-nil, this function will return the frame if the
 mouse pointer moves onto an Emacs frame, after first moving out of
-FRAME.  (This is not guaranteed to work on some systems.)
+FRAME.  (This is not guaranteed to work on some systems.)  If
+RETURN-FRAME is the symbol `now', any frame underneath the mouse
+pointer will be returned immediately.
 
 If ACTION is a list and not nil, its elements are assumed to be a cons
 of (ITEM . STRING), where ITEM is the name of an action, and STRING is
@@ -6828,7 +6830,7 @@ mouse buttons are released on top of FRAME.  */)
 
   x_set_dnd_targets (target_atoms, ntargets);
   lval = x_dnd_begin_drag_and_drop (f, FRAME_DISPLAY_INFO (f)->last_user_time,
-                                   xaction, !NILP (return_frame), action_list,
+                                   xaction, return_frame, action_list,
                                    (const char **) &name_list, nnames,
                                    !NILP (allow_current_frame));
 
index e3935bacb9af5df398cb4201814ae9d7f1f4799b..c70b31c5ad175f088cb41dc2b85e88b855c9a24f 100644 (file)
@@ -2295,6 +2295,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
 
 static int x_dnd_get_window_proto (struct x_display_info *, Window);
 static Window x_dnd_get_window_proxy (struct x_display_info *, Window);
+static void x_dnd_update_state (struct x_display_info *, Time);
 
 #ifdef USE_XCB
 static void
@@ -8933,9 +8934,9 @@ x_top_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
 
 Lisp_Object
 x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
-                          bool return_frame_p, Atom *ask_action_list,
-                          const char **ask_action_names,
-                          size_t n_ask_actions, bool allow_current_frame)
+                          Lisp_Object return_frame, Atom *ask_action_list,
+                          const char **ask_action_names, size_t n_ask_actions,
+                          bool allow_current_frame)
 {
 #ifndef USE_GTK
   XEvent next_event;
@@ -9046,9 +9047,12 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
        }
     }
 
-  if (return_frame_p)
+  if (!NILP (return_frame))
     x_dnd_return_frame = 1;
 
+  if (EQ (return_frame, Qnow))
+    x_dnd_return_frame = 2;
+
 #ifdef USE_GTK
   current_count = 0;
 #endif
@@ -9070,6 +9074,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
 
   while (x_dnd_in_progress || x_dnd_waiting_for_finish)
     {
+      if (EQ (return_frame, Qnow))
+       x_dnd_update_state (FRAME_DISPLAY_INFO (f), CurrentTime);
+
       hold_quit.kind = NO_EVENT;
 #ifdef USE_GTK
       current_finish = X_EVENT_NORMAL;
@@ -9951,7 +9958,9 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
                                   /* Child of win.  */
                                   &child);
 
-           if (!EQ (track_mouse, Qdrag_source))
+           if (!EQ (track_mouse, Qdrag_source)
+               /* Don't let tooltips interfere.  */
+               || (f1 && FRAME_TOOLTIP_P (f1)))
              f1 = dpyinfo->last_mouse_frame;
            else
              {
@@ -22662,6 +22671,7 @@ syms_of_xterm (void)
 
   DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
   DEFSYM (Qlatin_1, "latin-1");
+  DEFSYM (Qnow, "now");
 
 #ifdef USE_GTK
   xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
index 062b34b35ced56d620bf243ddf3a29dedd5b4d31..57036af2bb57a95fecbb04eb3f0da275e5083042 100644 (file)
@@ -1389,7 +1389,7 @@ extern void x_scroll_bar_configure (GdkEvent *);
 #endif
 
 extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,
-                                             bool, Atom *, const char **,
+                                             Lisp_Object, Atom *, const char **,
                                              size_t, bool);
 extern void x_set_dnd_targets (Atom *, int);