[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master bcbd06b4bb: Make drag-and-drop wheel movement work locally too on
From: |
Po Lu |
Subject: |
master bcbd06b4bb: Make drag-and-drop wheel movement work locally too on X |
Date: |
Mon, 18 Jul 2022 21:33:21 -0400 (EDT) |
branch: master
commit bcbd06b4bbb57d285988937f82afd70538303536
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
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'.
---
lisp/x-dnd.el | 18 +++++++
src/xterm.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 156 insertions(+), 17 deletions(-)
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el
index ffb94c18bb..62a5bbdfc3 100644
--- a/lisp/x-dnd.el
+++ b/lisp/x-dnd.el
@@ -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
diff --git a/src/xterm.c b/src/xterm.c
index 0436d3c00c..88028948ba 100644
--- a/src/xterm.c
+++ b/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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master bcbd06b4bb: Make drag-and-drop wheel movement work locally too on X,
Po Lu <=