Improve behavior of dragging text to windows on top of frames

* 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.
This commit is contained in:
Po Lu 2022-04-04 13:10:01 +08:00
parent 9ff2f0be32
commit aea799838b
5 changed files with 49 additions and 17 deletions

View 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

View 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)))

View file

@ -6712,7 +6712,9 @@ Emacs. For that reason, they are not mentioned here. Consult
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));

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

View 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);