mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-07 12:20:39 -08:00
Make drag-and-drop wheel movement work locally too on X
This is provided by the XDND protocol, so it isn't fair for it to not work with local drag-and-drop. * lisp/x-dnd.el (x-dnd-note-wheel-movement): New function. Set it as the `x-dnd-wheel-function'. * src/xterm.c (x_dnd_cleanup_drag_and_drop): Clear new flags. (x_dnd_note_self_wheel): New function. Set some flags. (x_dnd_process_quit, x_dnd_begin_drag_and_drop, handle_one_xevent) (x_connection_closed, x_delete_terminal, mark_xterm): Handle and set new wheel movement flags (syms_of_xterm): New variable `x-dnd-wheel-function'.
This commit is contained in:
parent
7a93716703
commit
bcbd06b4bb
2 changed files with 156 additions and 17 deletions
|
|
@ -1648,6 +1648,24 @@ VERSION is the version of the XDND protocol understood by SOURCE."
|
|||
0
|
||||
"XdndDirectSave0")))))))
|
||||
|
||||
;; Internal wheel movement.
|
||||
|
||||
(defvar x-dnd-wheel-function)
|
||||
|
||||
(defun x-dnd-note-wheel-movement (position button state time)
|
||||
"Note wheel movement at POSITION.
|
||||
POSITION is a mouse position list describing the position of the
|
||||
wheel movement.
|
||||
BUTTON is the wheel button that was pressed.
|
||||
STATE is the X modifier state at the time of the wheel movement.
|
||||
TIME is the X server time at which the wheel moved."
|
||||
(when (posn-window position)
|
||||
(with-selected-window (posn-window position)
|
||||
(let ((count (x-dnd-note-click button time)))
|
||||
(x-dnd-mwheel-scroll button count state)))))
|
||||
|
||||
(setq x-dnd-wheel-function #'x-dnd-note-wheel-movement)
|
||||
|
||||
(provide 'x-dnd)
|
||||
|
||||
;;; x-dnd.el ends here
|
||||
|
|
|
|||
155
src/xterm.c
155
src/xterm.c
|
|
@ -1353,6 +1353,21 @@ static struct frame *x_dnd_movement_frame;
|
|||
with. */
|
||||
static int x_dnd_movement_x, x_dnd_movement_y;
|
||||
|
||||
/* The frame for which `x-dnd-wheel-function' should be called. */
|
||||
static struct frame *x_dnd_wheel_frame;
|
||||
|
||||
/* The coordinates which the wheel function should be called with. */
|
||||
static int x_dnd_wheel_x, x_dnd_wheel_y;
|
||||
|
||||
/* The button that was pressed. */
|
||||
static int x_dnd_wheel_button;
|
||||
|
||||
/* The modifier state when the button was pressed. */
|
||||
static int x_dnd_wheel_state;
|
||||
|
||||
/* When the button was pressed. */
|
||||
static Time x_dnd_wheel_time;
|
||||
|
||||
#ifdef HAVE_XKB
|
||||
/* The keyboard state during the drag-and-drop operation. */
|
||||
static unsigned int x_dnd_keyboard_state;
|
||||
|
|
@ -4734,6 +4749,7 @@ x_dnd_cleanup_drag_and_drop (void *frame)
|
|||
#endif
|
||||
x_dnd_return_frame_object = NULL;
|
||||
x_dnd_movement_frame = NULL;
|
||||
x_dnd_wheel_frame = NULL;
|
||||
x_dnd_frame = NULL;
|
||||
|
||||
x_restore_events_after_dnd (f, &x_dnd_old_window_attrs);
|
||||
|
|
@ -4763,6 +4779,37 @@ x_dnd_note_self_position (struct x_display_info *dpyinfo, Window target,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
x_dnd_note_self_wheel (struct x_display_info *dpyinfo, Window target,
|
||||
unsigned short root_x, unsigned short root_y,
|
||||
int button, unsigned int state, Time time)
|
||||
{
|
||||
struct frame *f;
|
||||
int dest_x, dest_y;
|
||||
Window child_return;
|
||||
|
||||
if (button < 4 || button > 7)
|
||||
return;
|
||||
|
||||
f = x_top_window_to_frame (dpyinfo, target);
|
||||
|
||||
if (f && XTranslateCoordinates (dpyinfo->display,
|
||||
dpyinfo->root_window,
|
||||
FRAME_X_WINDOW (f),
|
||||
root_x, root_y, &dest_x,
|
||||
&dest_y, &child_return))
|
||||
{
|
||||
x_dnd_wheel_frame = f;
|
||||
x_dnd_wheel_x = dest_x;
|
||||
x_dnd_wheel_y = dest_y;
|
||||
x_dnd_wheel_button = button;
|
||||
x_dnd_wheel_state = state;
|
||||
x_dnd_wheel_time = time;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target,
|
||||
unsigned short root_x, unsigned short root_y,
|
||||
|
|
@ -11395,6 +11442,7 @@ x_dnd_process_quit (struct frame *f, Time timestamp)
|
|||
x_dnd_waiting_for_finish = false;
|
||||
x_dnd_return_frame_object = NULL;
|
||||
x_dnd_movement_frame = NULL;
|
||||
x_dnd_wheel_frame = NULL;
|
||||
}
|
||||
|
||||
/* This function is defined far away from the rest of the XDND code so
|
||||
|
|
@ -11618,6 +11666,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
x_dnd_toplevels = NULL;
|
||||
x_dnd_allow_current_frame = allow_current_frame;
|
||||
x_dnd_movement_frame = NULL;
|
||||
x_dnd_wheel_frame = NULL;
|
||||
x_dnd_init_type_lists = false;
|
||||
x_dnd_need_send_drop = false;
|
||||
#ifdef HAVE_XKB
|
||||
|
|
@ -11787,6 +11836,43 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
}
|
||||
}
|
||||
|
||||
if (x_dnd_wheel_frame
|
||||
&& (x_dnd_in_progress || x_dnd_waiting_for_finish))
|
||||
{
|
||||
XSETFRAME (frame_object, x_dnd_wheel_frame);
|
||||
XSETINT (x, x_dnd_wheel_x);
|
||||
XSETINT (y, x_dnd_wheel_y);
|
||||
x_dnd_wheel_frame = NULL;
|
||||
|
||||
if (!NILP (Vx_dnd_wheel_function)
|
||||
&& FRAME_LIVE_P (XFRAME (frame_object))
|
||||
&& !FRAME_TOOLTIP_P (XFRAME (frame_object))
|
||||
&& x_dnd_movement_x >= 0
|
||||
&& x_dnd_movement_y >= 0
|
||||
&& x_dnd_frame
|
||||
&& (XFRAME (frame_object) != x_dnd_frame
|
||||
|| x_dnd_allow_current_frame))
|
||||
{
|
||||
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);
|
||||
call4 (Vx_dnd_wheel_function,
|
||||
Fposn_at_x_y (x, y, frame_object, Qnil),
|
||||
make_fixnum (x_dnd_wheel_button),
|
||||
make_uint (x_dnd_wheel_state),
|
||||
make_uint (x_dnd_wheel_time));
|
||||
x_dnd_unwind_flag = false;
|
||||
unbind_to (ref, Qnil);
|
||||
|
||||
/* Redisplay this way to preserve the echo area.
|
||||
Otherwise, the contents will abruptly disappear
|
||||
when the mouse moves over a frame. */
|
||||
redisplay_preserve_echo_area (33);
|
||||
}
|
||||
}
|
||||
|
||||
if (hold_quit.kind != NO_EVENT)
|
||||
{
|
||||
x_dnd_process_quit (f, hold_quit.timestamp);
|
||||
|
|
@ -11890,6 +11976,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
if (x_dnd_movement_frame)
|
||||
x_dnd_movement_frame = NULL;
|
||||
|
||||
if (x_dnd_wheel_frame)
|
||||
x_dnd_wheel_frame = NULL;
|
||||
|
||||
if (hold_quit.kind != NO_EVENT)
|
||||
EVENT_INIT (hold_quit);
|
||||
}
|
||||
|
|
@ -11902,6 +11991,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
current_hold_quit = NULL;
|
||||
#endif
|
||||
x_dnd_movement_frame = NULL;
|
||||
x_dnd_wheel_frame = NULL;
|
||||
x_restore_events_after_dnd (f, &root_window_attrs);
|
||||
|
||||
if (x_dnd_return_frame == 3
|
||||
|
|
@ -18914,18 +19004,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
dpyinfo->grabbed &= ~(1 << event->xbutton.button);
|
||||
|
||||
if (event->xbutton.type == ButtonPress
|
||||
&& x_dnd_last_seen_window != None
|
||||
&& x_dnd_last_protocol_version != -1)
|
||||
&& x_dnd_last_seen_window != None)
|
||||
{
|
||||
x_dnd_send_position (x_dnd_frame,
|
||||
x_dnd_last_seen_window,
|
||||
x_dnd_last_protocol_version,
|
||||
event->xbutton.x_root,
|
||||
event->xbutton.y_root,
|
||||
x_dnd_selection_timestamp,
|
||||
x_dnd_wanted_action,
|
||||
event->xbutton.button,
|
||||
event->xbutton.state);
|
||||
if (x_dnd_last_window_is_frame)
|
||||
x_dnd_note_self_wheel (dpyinfo,
|
||||
x_dnd_last_seen_window,
|
||||
event->xbutton.x_root,
|
||||
event->xbutton.y_root,
|
||||
event->xbutton.button,
|
||||
event->xbutton.state,
|
||||
event->xbutton.time);
|
||||
else if (x_dnd_last_protocol_version != -1)
|
||||
x_dnd_send_position (x_dnd_frame,
|
||||
x_dnd_last_seen_window,
|
||||
x_dnd_last_protocol_version,
|
||||
event->xbutton.x_root,
|
||||
event->xbutton.y_root,
|
||||
x_dnd_selection_timestamp,
|
||||
x_dnd_wanted_action,
|
||||
event->xbutton.button,
|
||||
event->xbutton.state);
|
||||
|
||||
goto OTHER;
|
||||
}
|
||||
|
|
@ -20315,15 +20413,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
#endif
|
||||
|
||||
if (xev->evtype == XI_ButtonPress
|
||||
&& x_dnd_last_seen_window != None
|
||||
&& x_dnd_last_protocol_version != -1)
|
||||
&& x_dnd_last_seen_window != None)
|
||||
{
|
||||
dnd_state = xi_convert_event_state (xev);
|
||||
|
||||
x_dnd_send_position (x_dnd_frame, x_dnd_last_seen_window,
|
||||
x_dnd_last_protocol_version, xev->root_x,
|
||||
xev->root_y, x_dnd_selection_timestamp,
|
||||
x_dnd_wanted_action, xev->detail, dnd_state);
|
||||
if (x_dnd_last_window_is_frame)
|
||||
x_dnd_note_self_wheel (dpyinfo,
|
||||
x_dnd_last_seen_window,
|
||||
xev->root_x, xev->root_y,
|
||||
xev->detail, dnd_state,
|
||||
xev->time);
|
||||
else
|
||||
x_dnd_send_position (x_dnd_frame, x_dnd_last_seen_window,
|
||||
x_dnd_last_protocol_version, xev->root_x,
|
||||
xev->root_y, x_dnd_selection_timestamp,
|
||||
x_dnd_wanted_action, xev->detail, dnd_state);
|
||||
|
||||
goto XI_OTHER;
|
||||
}
|
||||
|
|
@ -23482,6 +23586,7 @@ x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
|
|||
|
||||
x_dnd_return_frame_object = NULL;
|
||||
x_dnd_movement_frame = NULL;
|
||||
x_dnd_wheel_frame = NULL;
|
||||
x_dnd_frame = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -27750,6 +27855,7 @@ x_delete_terminal (struct terminal *terminal)
|
|||
|
||||
x_dnd_return_frame_object = NULL;
|
||||
x_dnd_movement_frame = NULL;
|
||||
x_dnd_wheel_frame = NULL;
|
||||
x_dnd_frame = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -28008,6 +28114,12 @@ mark_xterm (void)
|
|||
mark_object (val);
|
||||
}
|
||||
|
||||
if (x_dnd_wheel_frame)
|
||||
{
|
||||
XSETFRAME (val, x_dnd_wheel_frame);
|
||||
mark_object (val);
|
||||
}
|
||||
|
||||
#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \
|
||||
|| defined HAVE_XRANDR || defined USE_GTK
|
||||
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
|
||||
|
|
@ -28454,6 +28566,15 @@ where FRAME is the frame the mouse is on top of, and POSITION is a
|
|||
mouse position list. */);
|
||||
Vx_dnd_movement_function = Qnil;
|
||||
|
||||
DEFVAR_LISP ("x-dnd-wheel-function", Vx_dnd_wheel_function,
|
||||
doc: /* Function called upon wheel movement on a frame during drag-and-drop.
|
||||
It should either be nil, or accept four arguments POSITION, BUTTON,
|
||||
STATE and TIME, where POSITION is a mouse position list describing
|
||||
where the wheel moved, BUTTON is the wheel button that was pressed,
|
||||
STATE is the X modifier state at the time of the wheel movement, and
|
||||
TIME is the X server time at which the wheel moved. */);
|
||||
Vx_dnd_wheel_function = Qnil;
|
||||
|
||||
DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function,
|
||||
doc: /* Function called when trying to drop on an unsupported window.
|
||||
This function is called whenever the user tries to drop something on a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue