Make dragging stuff to a window above a frame work

* doc/lispref/frames.texi (Mouse Tracking):
* etc/NEWS: Announce new `drag-source' value of `track-mouse'.
* lisp/mouse.el (mouse-drag-and-drop-region): Use new value of
`track-mouse' during interprogram drag and drop.

* src/keyboard.c (make_lispy_position): Handle nil values of f
correctly.
* src/xdisp.c (define_frame_cursor1): Ignore if `drag-source' as
well.
(syms_of_xdisp): New defsym `drag-source'.
* src/xterm.c (XTmouse_position): Implement `drag-source'.
(mouse_or_wdesc_frame): Likewise.
This commit is contained in:
Po Lu 2022-04-03 18:59:12 +08:00
parent 441ce4672d
commit 28f720e7c4
6 changed files with 90 additions and 35 deletions

View file

@ -3512,10 +3512,18 @@ enabled. Typically, @var{body} would use @code{read-event} to read
the motion events and modify the display accordingly. @xref{Motion
Events}, for the format of mouse motion events.
The value of @code{track-mouse} is that of the last form in @var{body}.
You should design @var{body} to return when it sees the up-event that
indicates the release of the button, or whatever kind of event means
it is time to stop tracking.
The value of @code{track-mouse} is that of the last form in
@var{body}. You should design @var{body} to return when it sees the
up-event that indicates the release of the button, or whatever kind of
event means it is time to stop tracking. Its value also controls how
mouse events are reported while a mouse button is held down: if it is
@code{dropping} or @code{drag-source}, the motion events are reported
relative to the frame underneath the pointer. If there is no such
frame, the events will be reported relative to the frame the mouse
buttons were first pressed on. In addition, the @code{posn-window} of
the mouse position list will be @code{nil} if the value is
@code{drag-source}. This is useful to determine if a frame is not
directly visible underneath the mouse pointer.
The @code{track-mouse} form causes Emacs to generate mouse motion
events by binding the variable @code{track-mouse} to a

View file

@ -1331,6 +1331,12 @@ functions.
* Lisp Changes in Emacs 29.1
+++
** 'track-mouse' can be a new value 'drag-source'.
This means the same as 'dropping', but modifies the mouse position
list in reported motion events if there is no frame underneath the
mouse pointer.
+++
** New function 'x-begin-drag'.
This function initiates a drag-and-drop request with the contents of

View file

@ -3085,7 +3085,18 @@ is copied instead of being cut."
(ignore-errors
(catch 'cross-program-drag
(track-mouse
(setq track-mouse 'dropping)
(setq track-mouse (if mouse-drag-and-drop-region-cross-program
;; When `track-mouse' is `drop', we
;; get events with a posn-window of
;; the grabbed frame even if some
;; window is between that and the
;; pointer. This makes dragging to a
;; window on top of a frame
;; impossible. With this value of
;; `track-mouse', no frame is returned
;; in that particular case.
'drag-source
'drop))
;; When event was "click" instead of "drag", skip loop.
(while (progn
(setq event (read-key)) ; read-event or read-key
@ -3151,15 +3162,16 @@ is copied instead of being cut."
(when (and mouse-drag-and-drop-region-cross-program
(display-graphic-p)
(fboundp 'x-begin-drag)
(framep (posn-window (event-end event)))
(let ((location (posn-x-y (event-end event)))
(frame (posn-window (event-end event))))
(or (< (car location) 0)
(< (cdr location) 0)
(> (car location)
(frame-pixel-width frame))
(> (cdr location)
(frame-pixel-height frame)))))
(or (and (framep (posn-window (event-end event)))
(let ((location (posn-x-y (event-end event)))
(frame (posn-window (event-end event))))
(or (< (car location) 0)
(< (cdr location) 0)
(> (car location)
(frame-pixel-width frame))
(> (cdr location)
(frame-pixel-height frame)))))
(not (posn-window (event-end event)))))
(mouse-drag-and-drop-region-hide-tooltip)
(gui-set-selection 'XdndSelection value-selection)
(let ((drag-action-or-frame

View file

@ -5253,13 +5253,13 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
/* Report mouse events on the tab bar and (on GUI frames) on the
tool bar. */
if ((WINDOWP (f->tab_bar_window)
&& EQ (window_or_frame, f->tab_bar_window))
if (f && ((WINDOWP (f->tab_bar_window)
&& EQ (window_or_frame, f->tab_bar_window))
#ifndef HAVE_EXT_TOOL_BAR
|| (WINDOWP (f->tool_bar_window)
&& EQ (window_or_frame, f->tool_bar_window))
|| (WINDOWP (f->tool_bar_window)
&& EQ (window_or_frame, f->tool_bar_window))
#endif
)
))
{
/* While 'track-mouse' is neither nil nor t, do not report this
event as something that happened on the tool or tab bar since
@ -5283,7 +5283,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
window_or_frame = Qnil;
}
if (FRAME_TERMINAL (f)->toolkit_position_hook)
if (f && FRAME_TERMINAL (f)->toolkit_position_hook)
{
FRAME_TERMINAL (f)->toolkit_position_hook (f, mx, my, &menu_bar_p,
&tool_bar_p);
@ -5524,9 +5524,16 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
}
#endif
}
else
window_or_frame = Qnil;
{
if (EQ (track_mouse, Qdrag_source))
{
xret = mx;
yret = my;
}
window_or_frame = Qnil;
}
return Fcons (window_or_frame,
Fcons (posn,
@ -12563,12 +12570,15 @@ and the minor mode maps regardless of `overriding-local-map'. */);
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 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. */);
but `dropping' or `drag-source' asserts that motion events always
relate to the frame where 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. The value `drag-source' is like `dropping', but the
`posn-window' will be nil in mouse position lists inside mouse
movement events if there is no frame directly visible underneath the
mouse pointer. */);
DEFVAR_KBOARD ("system-key-alist", Vsystem_key_alist,
doc: /* Alist of system-specific X windows key symbols.
Each element should have the form (N . SYMBOL) where N is the

View file

@ -33856,7 +33856,8 @@ define_frame_cursor1 (struct frame *f, Emacs_Cursor cursor, Lisp_Object pointer)
return;
/* Do not change cursor shape while dragging mouse. */
if (EQ (track_mouse, Qdragging) || EQ (track_mouse, Qdropping))
if (EQ (track_mouse, Qdragging) || EQ (track_mouse, Qdropping)
|| EQ (track_mouse, Qdrag_source))
return;
if (!NILP (pointer))
@ -35678,6 +35679,7 @@ be let-bound around code that needs to disable messages temporarily. */);
DEFSYM (Qdragging, "dragging");
DEFSYM (Qdropping, "dropping");
DEFSYM (Qdrag_source, "drag-source");
DEFSYM (Qdrag_with_mode_line, "drag-with-mode-line");
DEFSYM (Qdrag_with_header_line, "drag-with-header-line");

View file

@ -9811,7 +9811,8 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
x_catch_errors (FRAME_X_DISPLAY (*fp));
if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping))
if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping)
&& !EQ (track_mouse, Qdrag_source))
{
/* If mouse was grabbed on a frame, give coords for that frame
even if the mouse is now outside it. */
@ -9900,7 +9901,8 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
}
if ((!f1 || FRAME_TOOLTIP_P (f1))
&& EQ (track_mouse, Qdropping)
&& (EQ (track_mouse, Qdropping)
|| EQ (track_mouse, Qdrag_source))
&& gui_mouse_grabbed (dpyinfo))
{
/* When dropping then if we didn't get a frame or only a
@ -9916,12 +9918,26 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
root_x, root_y, &win_x, &win_y,
/* Child of win. */
&child);
f1 = dpyinfo->last_mouse_frame;
if (!EQ (track_mouse, Qdrag_source))
f1 = dpyinfo->last_mouse_frame;
else
{
/* Don't set FP but do set WIN_X and WIN_Y in this
case, so make_lispy_movement knows which
coordinates to report. */
*bar_window = Qnil;
*part = 0;
*fp = NULL;
XSETINT (*x, win_x);
XSETINT (*y, win_y);
*timestamp = dpyinfo->last_mouse_movement_time;
}
}
else if (f1 && FRAME_TOOLTIP_P (f1))
f1 = NULL;
if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
if (x_had_errors_p (dpyinfo->display))
f1 = NULL;
x_uncatch_errors_after_check ();
@ -9931,7 +9947,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
{
struct scroll_bar *bar;
bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win, 2);
bar = x_window_to_scroll_bar (dpyinfo->display, win, 2);
if (bar)
{
@ -12735,7 +12751,8 @@ mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
? dpyinfo->last_mouse_frame
: NULL);
if (lm_f && !EQ (track_mouse, Qdropping))
if (lm_f && !EQ (track_mouse, Qdropping)
&& !EQ (track_mouse, Qdrag_source))
return lm_f;
else
{