From: Po Lu Date: Mon, 4 Apr 2022 05:10:01 +0000 (+0800) Subject: Improve behavior of dragging text to windows on top of frames X-Git-Tag: emacs-29.0.90~1931^2~790 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=aea799838b7ffd11f187c2511ecca250c8b99411;p=emacs.git 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. --- diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 057f070ccca..85f92d4f629 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -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 diff --git a/lisp/mouse.el b/lisp/mouse.el index f42492bb5d3..26a17365da2 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -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))) diff --git a/src/xfns.c b/src/xfns.c index 4fa919f36a5..5cf3eb41996 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -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)); diff --git a/src/xterm.c b/src/xterm.c index e3935bacb9a..c70b31c5ad1 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -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"); diff --git a/src/xterm.h b/src/xterm.h index 062b34b35ce..57036af2bb5 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -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);