From: Po Lu Date: Sun, 3 Apr 2022 10:59:12 +0000 (+0800) Subject: Make dragging stuff to a window above a frame work X-Git-Tag: emacs-29.0.90~1931^2~803 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=28f720e7c483c37a6c94f6b561e8f175b3af51a4;p=emacs.git 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. --- diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index ebf426fe501..057f070ccca 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -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 diff --git a/etc/NEWS b/etc/NEWS index 037a9724d8a..f81d194a2f0 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -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 diff --git a/lisp/mouse.el b/lisp/mouse.el index 92e289b4ced..f42492bb5d3 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -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 diff --git a/src/keyboard.c b/src/keyboard.c index 8b451d834d1..d34bec48a6b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -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 diff --git a/src/xdisp.c b/src/xdisp.c index 62c8f9d4d93..d7313081733 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -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"); diff --git a/src/xterm.c b/src/xterm.c index e7c671de744..aef3d2d840f 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -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 {