Handle mouse movement correctly during DND from one of our own frames
* lisp/dnd.el (dnd-handle-movement): Select the window specified in posn. * lisp/term/x-win.el (x-dnd-movement): New function. (x-dnd-movement-function): Set it as the default. * src/frame.c (delete_frame): Prevent deleting the drop source frame. * src/xterm.c (x_dnd_send_position): Set new mouse movement flags if the target window is one of our own frames. (x_dnd_begin_drag_and_drop): Call DND movement function whenever appropriate. (x_free_frame_resources): Remove useless code. (syms_of_xterm): New defvar `x-dnd-movement-function'. * src/xterm.h: Update prototypes.
This commit is contained in:
parent
3d2531c12c
commit
84cf3be6f7
5 changed files with 101 additions and 72 deletions
52
lisp/dnd.el
52
lisp/dnd.el
|
@ -107,31 +107,33 @@ program."
|
|||
|
||||
(defun dnd-handle-movement (posn)
|
||||
"Handle mouse movement to POSN when receiving a drop from another program."
|
||||
(when dnd-scroll-margin
|
||||
(ignore-errors
|
||||
(let* ((row (cdr (posn-col-row posn)))
|
||||
(window (when (windowp (posn-window posn))
|
||||
(posn-window posn)))
|
||||
(text-height (window-text-height window))
|
||||
;; Make sure it's possible to scroll both up
|
||||
;; and down if the margin is too large for the
|
||||
;; window.
|
||||
(margin (min (/ text-height 3) dnd-scroll-margin)))
|
||||
;; At 2 lines, the window becomes too small for any
|
||||
;; meaningful scrolling.
|
||||
(unless (<= text-height 2)
|
||||
(cond
|
||||
;; Inside the bottom scroll margin, scroll up.
|
||||
((> row (- text-height margin))
|
||||
(with-selected-window window
|
||||
(scroll-up 1)))
|
||||
;; Inside the top scroll margin, scroll down.
|
||||
((< row margin)
|
||||
(with-selected-window window
|
||||
(scroll-down 1))))))))
|
||||
(when dnd-indicate-insertion-point
|
||||
(ignore-errors
|
||||
(goto-char (posn-point posn)))))
|
||||
(when (windowp (posn-window posn))
|
||||
(with-selected-window (posn-window posn)
|
||||
(when dnd-scroll-margin
|
||||
(ignore-errors
|
||||
(let* ((row (cdr (posn-col-row posn)))
|
||||
(window (when (windowp (posn-window posn))
|
||||
(posn-window posn)))
|
||||
(text-height (window-text-height window))
|
||||
;; Make sure it's possible to scroll both up
|
||||
;; and down if the margin is too large for the
|
||||
;; window.
|
||||
(margin (min (/ text-height 3) dnd-scroll-margin)))
|
||||
;; At 2 lines, the window becomes too small for any
|
||||
;; meaningful scrolling.
|
||||
(unless (<= text-height 2)
|
||||
(cond
|
||||
;; Inside the bottom scroll margin, scroll up.
|
||||
((> row (- text-height margin))
|
||||
(with-selected-window window
|
||||
(scroll-up 1)))
|
||||
;; Inside the top scroll margin, scroll down.
|
||||
((< row margin)
|
||||
(with-selected-window window
|
||||
(scroll-down 1))))))))
|
||||
(when dnd-indicate-insertion-point
|
||||
(ignore-errors
|
||||
(goto-char (posn-point posn)))))))
|
||||
|
||||
(defun dnd-handle-one-url (window action url)
|
||||
"Handle one dropped url by calling the appropriate handler.
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
(defvar x-selection-timeout)
|
||||
(defvar x-session-id)
|
||||
(defvar x-session-previous-id)
|
||||
(defvar x-dnd-movement-function)
|
||||
|
||||
(defun x-handle-no-bitmap-icon (_switch)
|
||||
(setq default-frame-alist (cons '(icon-type) default-frame-alist)))
|
||||
|
@ -1576,6 +1577,13 @@ frames on all displays."
|
|||
(add-variable-watcher 'x-gtk-use-native-input
|
||||
#'x-gtk-use-native-input-watcher)
|
||||
|
||||
(defun x-dnd-movement (_frame position)
|
||||
"Handle movement to POSITION during drag-and-drop."
|
||||
(dnd-handle-movement position)
|
||||
(redisplay))
|
||||
|
||||
(setq x-dnd-movement-function #'x-dnd-movement)
|
||||
|
||||
(provide 'x-win)
|
||||
(provide 'term/x-win)
|
||||
|
||||
|
|
|
@ -1987,6 +1987,10 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
|
|||
else
|
||||
error ("Attempt to delete the only frame");
|
||||
}
|
||||
#ifdef HAVE_X_WINDOWS
|
||||
else if (x_dnd_in_progress && f == x_dnd_frame)
|
||||
error ("Attempt to delete the drop source frame");
|
||||
#endif
|
||||
|
||||
XSETFRAME (frame, f);
|
||||
|
||||
|
|
106
src/xterm.c
106
src/xterm.c
|
@ -846,7 +846,10 @@ static int x_filter_event (struct x_display_info *, XEvent *);
|
|||
/* Global state maintained during a drag-and-drop operation. */
|
||||
|
||||
/* Flag that indicates if a drag-and-drop operation is in progress. */
|
||||
static bool x_dnd_in_progress;
|
||||
bool x_dnd_in_progress;
|
||||
|
||||
/* The frame where the drag-and-drop operation originated. */
|
||||
struct frame *x_dnd_frame;
|
||||
|
||||
/* Flag that indicates if a drag-and-drop operation is no longer in
|
||||
progress, but the nested event loop should continue to run, because
|
||||
|
@ -946,9 +949,6 @@ static Atom *x_dnd_targets = NULL;
|
|||
/* The number of elements in that array. */
|
||||
static int x_dnd_n_targets;
|
||||
|
||||
/* The frame where the drag-and-drop operation originated. */
|
||||
static struct frame *x_dnd_frame;
|
||||
|
||||
/* The old window attributes of the root window before the
|
||||
drag-and-drop operation started. It is used to keep the old event
|
||||
mask around, since that should be restored after the operation
|
||||
|
@ -959,6 +959,13 @@ static XWindowAttributes x_dnd_old_window_attrs;
|
|||
up the drag and drop operation. */
|
||||
static bool x_dnd_unwind_flag;
|
||||
|
||||
/* The frame for which `x-dnd-movement-function' should be called. */
|
||||
static struct frame *x_dnd_movement_frame;
|
||||
|
||||
/* The coordinates which the movement function should be called
|
||||
with. */
|
||||
static int x_dnd_movement_x, x_dnd_movement_y;
|
||||
|
||||
struct x_client_list_window
|
||||
{
|
||||
Window window;
|
||||
|
@ -3137,6 +3144,23 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
|
|||
{
|
||||
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
|
||||
XEvent msg;
|
||||
struct frame *target_frame;
|
||||
int dest_x, dest_y;
|
||||
Window child_return;
|
||||
|
||||
target_frame = x_top_window_to_frame (dpyinfo, target);
|
||||
|
||||
if (target_frame && XTranslateCoordinates (dpyinfo->display,
|
||||
dpyinfo->root_window,
|
||||
FRAME_X_WINDOW (target_frame),
|
||||
root_x, root_y, &dest_x,
|
||||
&dest_y, &child_return))
|
||||
{
|
||||
x_dnd_movement_frame = target_frame;
|
||||
x_dnd_movement_x = dest_x;
|
||||
x_dnd_movement_y = dest_y;
|
||||
return;
|
||||
}
|
||||
|
||||
if (target == x_dnd_mouse_rect_target
|
||||
&& x_dnd_mouse_rect.width
|
||||
|
@ -3151,9 +3175,6 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
|
|||
return;
|
||||
}
|
||||
|
||||
if (x_top_window_to_frame (dpyinfo, target))
|
||||
return;
|
||||
|
||||
msg.xclient.type = ClientMessage;
|
||||
msg.xclient.message_type = dpyinfo->Xatom_XdndPosition;
|
||||
msg.xclient.format = 32;
|
||||
|
@ -9143,6 +9164,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
ptrdiff_t i, end, fill;
|
||||
XTextProperty prop;
|
||||
xm_drop_start_message dmsg;
|
||||
Lisp_Object frame_object, x, y;
|
||||
|
||||
if (!FRAME_VISIBLE_P (f))
|
||||
error ("Frame is invisible");
|
||||
|
@ -9229,6 +9251,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
= x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking);
|
||||
x_dnd_toplevels = NULL;
|
||||
x_dnd_allow_current_frame = allow_current_frame;
|
||||
x_dnd_movement_frame = NULL;
|
||||
|
||||
if (x_dnd_use_toplevels)
|
||||
{
|
||||
|
@ -9307,6 +9330,28 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
#endif
|
||||
#endif
|
||||
|
||||
if (x_dnd_movement_frame)
|
||||
{
|
||||
XSETFRAME (frame_object, x_dnd_movement_frame);
|
||||
XSETINT (x, x_dnd_movement_x);
|
||||
XSETINT (y, x_dnd_movement_y);
|
||||
x_dnd_movement_frame = NULL;
|
||||
|
||||
if (!NILP (Vx_dnd_movement_function)
|
||||
&& !FRAME_TOOLTIP_P (XFRAME (frame_object)))
|
||||
{
|
||||
x_dnd_old_window_attrs = root_window_attrs;
|
||||
x_dnd_unwind_flag = true;
|
||||
|
||||
ref = SPECPDL_INDEX ();
|
||||
record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
|
||||
call2 (Vx_dnd_movement_function, frame_object,
|
||||
Fposn_at_x_y (x, y, frame_object, Qnil));
|
||||
x_dnd_unwind_flag = false;
|
||||
unbind_to (ref, Qnil);
|
||||
}
|
||||
}
|
||||
|
||||
if (hold_quit.kind != NO_EVENT)
|
||||
{
|
||||
if (hold_quit.kind == SELECTION_REQUEST_EVENT)
|
||||
|
@ -20746,46 +20791,6 @@ x_free_frame_resources (struct frame *f)
|
|||
Lisp_Object bar;
|
||||
struct scroll_bar *b;
|
||||
#endif
|
||||
xm_drop_start_message dmsg;
|
||||
|
||||
if (x_dnd_in_progress && f == x_dnd_frame)
|
||||
{
|
||||
block_input ();
|
||||
if (x_dnd_last_seen_window != None
|
||||
&& x_dnd_last_protocol_version != -1)
|
||||
x_dnd_send_leave (f, x_dnd_last_seen_window);
|
||||
else if (x_dnd_last_seen_window != None
|
||||
&& !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
|
||||
&& x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
|
||||
&& x_dnd_motif_setup_p)
|
||||
{
|
||||
dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
|
||||
XM_DRAG_REASON_DROP_START);
|
||||
dmsg.byte_order = XM_TARGETS_TABLE_CUR;
|
||||
dmsg.timestamp = 0;
|
||||
dmsg.side_effects
|
||||
= XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
|
||||
x_dnd_wanted_action),
|
||||
XM_DROP_SITE_VALID,
|
||||
xm_side_effect_from_action (dpyinfo,
|
||||
x_dnd_wanted_action),
|
||||
XM_DROP_ACTION_DROP_CANCEL);
|
||||
dmsg.x = 0;
|
||||
dmsg.y = 0;
|
||||
dmsg.index_atom = dpyinfo->Xatom_XdndSelection;
|
||||
dmsg.source_window = FRAME_X_WINDOW (f);
|
||||
|
||||
xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (f),
|
||||
x_dnd_last_seen_window, &dmsg);
|
||||
}
|
||||
unblock_input ();
|
||||
|
||||
x_dnd_end_window = None;
|
||||
x_dnd_last_seen_window = None;
|
||||
x_dnd_in_progress = false;
|
||||
x_dnd_waiting_for_finish = false;
|
||||
x_dnd_frame = NULL;
|
||||
}
|
||||
|
||||
block_input ();
|
||||
|
||||
|
@ -23054,4 +23059,11 @@ coordinates to a Motif drop receiver when the mouse moves outside it
|
|||
during a drag-and-drop session, to work around broken implementations
|
||||
of Motif. */);
|
||||
x_dnd_fix_motif_leave = true;
|
||||
|
||||
DEFVAR_LISP ("x-dnd-movement-function", Vx_dnd_movement_function,
|
||||
doc: /* Function called upon mouse movement on a frame during drag-and-drop.
|
||||
It should either be nil, or accept two arguments FRAME and POSITION,
|
||||
where FRAME is the frame the mouse is on top of, and POSITION is a
|
||||
mouse position list. */);
|
||||
Vx_dnd_movement_function = Qnil;
|
||||
}
|
||||
|
|
|
@ -1548,6 +1548,9 @@ extern void x_session_close (void);
|
|||
extern struct input_event xg_pending_quit_event;
|
||||
#endif
|
||||
|
||||
extern bool x_dnd_in_progress;
|
||||
extern struct frame *x_dnd_frame;
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
struct xi_device_t *xi_device_from_id (struct x_display_info *, int);
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue