diff options
| author | Po Lu | 2022-07-19 09:33:09 +0800 |
|---|---|---|
| committer | Po Lu | 2022-07-19 09:33:09 +0800 |
| commit | bcbd06b4bbb57d285988937f82afd70538303536 (patch) | |
| tree | 9f81f7179b3111117f99d27d1f79cbccd6283ca3 /src | |
| parent | 7a937167030d44341409b3a2ac7ff1704142a191 (diff) | |
| download | emacs-bcbd06b4bbb57d285988937f82afd70538303536.tar.gz emacs-bcbd06b4bbb57d285988937f82afd70538303536.zip | |
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'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xterm.c | 155 |
1 files changed, 138 insertions, 17 deletions
diff --git a/src/xterm.c b/src/xterm.c index 0436d3c00c0..88028948ba3 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -1353,6 +1353,21 @@ static struct frame *x_dnd_movement_frame; | |||
| 1353 | with. */ | 1353 | with. */ |
| 1354 | static int x_dnd_movement_x, x_dnd_movement_y; | 1354 | static int x_dnd_movement_x, x_dnd_movement_y; |
| 1355 | 1355 | ||
| 1356 | /* The frame for which `x-dnd-wheel-function' should be called. */ | ||
| 1357 | static struct frame *x_dnd_wheel_frame; | ||
| 1358 | |||
| 1359 | /* The coordinates which the wheel function should be called with. */ | ||
| 1360 | static int x_dnd_wheel_x, x_dnd_wheel_y; | ||
| 1361 | |||
| 1362 | /* The button that was pressed. */ | ||
| 1363 | static int x_dnd_wheel_button; | ||
| 1364 | |||
| 1365 | /* The modifier state when the button was pressed. */ | ||
| 1366 | static int x_dnd_wheel_state; | ||
| 1367 | |||
| 1368 | /* When the button was pressed. */ | ||
| 1369 | static Time x_dnd_wheel_time; | ||
| 1370 | |||
| 1356 | #ifdef HAVE_XKB | 1371 | #ifdef HAVE_XKB |
| 1357 | /* The keyboard state during the drag-and-drop operation. */ | 1372 | /* The keyboard state during the drag-and-drop operation. */ |
| 1358 | static unsigned int x_dnd_keyboard_state; | 1373 | static unsigned int x_dnd_keyboard_state; |
| @@ -4734,6 +4749,7 @@ x_dnd_cleanup_drag_and_drop (void *frame) | |||
| 4734 | #endif | 4749 | #endif |
| 4735 | x_dnd_return_frame_object = NULL; | 4750 | x_dnd_return_frame_object = NULL; |
| 4736 | x_dnd_movement_frame = NULL; | 4751 | x_dnd_movement_frame = NULL; |
| 4752 | x_dnd_wheel_frame = NULL; | ||
| 4737 | x_dnd_frame = NULL; | 4753 | x_dnd_frame = NULL; |
| 4738 | 4754 | ||
| 4739 | x_restore_events_after_dnd (f, &x_dnd_old_window_attrs); | 4755 | x_restore_events_after_dnd (f, &x_dnd_old_window_attrs); |
| @@ -4764,6 +4780,37 @@ x_dnd_note_self_position (struct x_display_info *dpyinfo, Window target, | |||
| 4764 | } | 4780 | } |
| 4765 | 4781 | ||
| 4766 | static void | 4782 | static void |
| 4783 | x_dnd_note_self_wheel (struct x_display_info *dpyinfo, Window target, | ||
| 4784 | unsigned short root_x, unsigned short root_y, | ||
| 4785 | int button, unsigned int state, Time time) | ||
| 4786 | { | ||
| 4787 | struct frame *f; | ||
| 4788 | int dest_x, dest_y; | ||
| 4789 | Window child_return; | ||
| 4790 | |||
| 4791 | if (button < 4 || button > 7) | ||
| 4792 | return; | ||
| 4793 | |||
| 4794 | f = x_top_window_to_frame (dpyinfo, target); | ||
| 4795 | |||
| 4796 | if (f && XTranslateCoordinates (dpyinfo->display, | ||
| 4797 | dpyinfo->root_window, | ||
| 4798 | FRAME_X_WINDOW (f), | ||
| 4799 | root_x, root_y, &dest_x, | ||
| 4800 | &dest_y, &child_return)) | ||
| 4801 | { | ||
| 4802 | x_dnd_wheel_frame = f; | ||
| 4803 | x_dnd_wheel_x = dest_x; | ||
| 4804 | x_dnd_wheel_y = dest_y; | ||
| 4805 | x_dnd_wheel_button = button; | ||
| 4806 | x_dnd_wheel_state = state; | ||
| 4807 | x_dnd_wheel_time = time; | ||
| 4808 | |||
| 4809 | return; | ||
| 4810 | } | ||
| 4811 | } | ||
| 4812 | |||
| 4813 | static void | ||
| 4767 | x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target, | 4814 | x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target, |
| 4768 | unsigned short root_x, unsigned short root_y, | 4815 | unsigned short root_x, unsigned short root_y, |
| 4769 | Time timestamp) | 4816 | Time timestamp) |
| @@ -11395,6 +11442,7 @@ x_dnd_process_quit (struct frame *f, Time timestamp) | |||
| 11395 | x_dnd_waiting_for_finish = false; | 11442 | x_dnd_waiting_for_finish = false; |
| 11396 | x_dnd_return_frame_object = NULL; | 11443 | x_dnd_return_frame_object = NULL; |
| 11397 | x_dnd_movement_frame = NULL; | 11444 | x_dnd_movement_frame = NULL; |
| 11445 | x_dnd_wheel_frame = NULL; | ||
| 11398 | } | 11446 | } |
| 11399 | 11447 | ||
| 11400 | /* This function is defined far away from the rest of the XDND code so | 11448 | /* 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, | |||
| 11618 | x_dnd_toplevels = NULL; | 11666 | x_dnd_toplevels = NULL; |
| 11619 | x_dnd_allow_current_frame = allow_current_frame; | 11667 | x_dnd_allow_current_frame = allow_current_frame; |
| 11620 | x_dnd_movement_frame = NULL; | 11668 | x_dnd_movement_frame = NULL; |
| 11669 | x_dnd_wheel_frame = NULL; | ||
| 11621 | x_dnd_init_type_lists = false; | 11670 | x_dnd_init_type_lists = false; |
| 11622 | x_dnd_need_send_drop = false; | 11671 | x_dnd_need_send_drop = false; |
| 11623 | #ifdef HAVE_XKB | 11672 | #ifdef HAVE_XKB |
| @@ -11787,6 +11836,43 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11787 | } | 11836 | } |
| 11788 | } | 11837 | } |
| 11789 | 11838 | ||
| 11839 | if (x_dnd_wheel_frame | ||
| 11840 | && (x_dnd_in_progress || x_dnd_waiting_for_finish)) | ||
| 11841 | { | ||
| 11842 | XSETFRAME (frame_object, x_dnd_wheel_frame); | ||
| 11843 | XSETINT (x, x_dnd_wheel_x); | ||
| 11844 | XSETINT (y, x_dnd_wheel_y); | ||
| 11845 | x_dnd_wheel_frame = NULL; | ||
| 11846 | |||
| 11847 | if (!NILP (Vx_dnd_wheel_function) | ||
| 11848 | && FRAME_LIVE_P (XFRAME (frame_object)) | ||
| 11849 | && !FRAME_TOOLTIP_P (XFRAME (frame_object)) | ||
| 11850 | && x_dnd_movement_x >= 0 | ||
| 11851 | && x_dnd_movement_y >= 0 | ||
| 11852 | && x_dnd_frame | ||
| 11853 | && (XFRAME (frame_object) != x_dnd_frame | ||
| 11854 | || x_dnd_allow_current_frame)) | ||
| 11855 | { | ||
| 11856 | x_dnd_old_window_attrs = root_window_attrs; | ||
| 11857 | x_dnd_unwind_flag = true; | ||
| 11858 | |||
| 11859 | ref = SPECPDL_INDEX (); | ||
| 11860 | record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f); | ||
| 11861 | call4 (Vx_dnd_wheel_function, | ||
| 11862 | Fposn_at_x_y (x, y, frame_object, Qnil), | ||
| 11863 | make_fixnum (x_dnd_wheel_button), | ||
| 11864 | make_uint (x_dnd_wheel_state), | ||
| 11865 | make_uint (x_dnd_wheel_time)); | ||
| 11866 | x_dnd_unwind_flag = false; | ||
| 11867 | unbind_to (ref, Qnil); | ||
| 11868 | |||
| 11869 | /* Redisplay this way to preserve the echo area. | ||
| 11870 | Otherwise, the contents will abruptly disappear | ||
| 11871 | when the mouse moves over a frame. */ | ||
| 11872 | redisplay_preserve_echo_area (33); | ||
| 11873 | } | ||
| 11874 | } | ||
| 11875 | |||
| 11790 | if (hold_quit.kind != NO_EVENT) | 11876 | if (hold_quit.kind != NO_EVENT) |
| 11791 | { | 11877 | { |
| 11792 | x_dnd_process_quit (f, hold_quit.timestamp); | 11878 | 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, | |||
| 11890 | if (x_dnd_movement_frame) | 11976 | if (x_dnd_movement_frame) |
| 11891 | x_dnd_movement_frame = NULL; | 11977 | x_dnd_movement_frame = NULL; |
| 11892 | 11978 | ||
| 11979 | if (x_dnd_wheel_frame) | ||
| 11980 | x_dnd_wheel_frame = NULL; | ||
| 11981 | |||
| 11893 | if (hold_quit.kind != NO_EVENT) | 11982 | if (hold_quit.kind != NO_EVENT) |
| 11894 | EVENT_INIT (hold_quit); | 11983 | EVENT_INIT (hold_quit); |
| 11895 | } | 11984 | } |
| @@ -11902,6 +11991,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11902 | current_hold_quit = NULL; | 11991 | current_hold_quit = NULL; |
| 11903 | #endif | 11992 | #endif |
| 11904 | x_dnd_movement_frame = NULL; | 11993 | x_dnd_movement_frame = NULL; |
| 11994 | x_dnd_wheel_frame = NULL; | ||
| 11905 | x_restore_events_after_dnd (f, &root_window_attrs); | 11995 | x_restore_events_after_dnd (f, &root_window_attrs); |
| 11906 | 11996 | ||
| 11907 | if (x_dnd_return_frame == 3 | 11997 | if (x_dnd_return_frame == 3 |
| @@ -18914,18 +19004,26 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 18914 | dpyinfo->grabbed &= ~(1 << event->xbutton.button); | 19004 | dpyinfo->grabbed &= ~(1 << event->xbutton.button); |
| 18915 | 19005 | ||
| 18916 | if (event->xbutton.type == ButtonPress | 19006 | if (event->xbutton.type == ButtonPress |
| 18917 | && x_dnd_last_seen_window != None | 19007 | && x_dnd_last_seen_window != None) |
| 18918 | && x_dnd_last_protocol_version != -1) | ||
| 18919 | { | 19008 | { |
| 18920 | x_dnd_send_position (x_dnd_frame, | 19009 | if (x_dnd_last_window_is_frame) |
| 18921 | x_dnd_last_seen_window, | 19010 | x_dnd_note_self_wheel (dpyinfo, |
| 18922 | x_dnd_last_protocol_version, | 19011 | x_dnd_last_seen_window, |
| 18923 | event->xbutton.x_root, | 19012 | event->xbutton.x_root, |
| 18924 | event->xbutton.y_root, | 19013 | event->xbutton.y_root, |
| 18925 | x_dnd_selection_timestamp, | 19014 | event->xbutton.button, |
| 18926 | x_dnd_wanted_action, | 19015 | event->xbutton.state, |
| 18927 | event->xbutton.button, | 19016 | event->xbutton.time); |
| 18928 | event->xbutton.state); | 19017 | else if (x_dnd_last_protocol_version != -1) |
| 19018 | x_dnd_send_position (x_dnd_frame, | ||
| 19019 | x_dnd_last_seen_window, | ||
| 19020 | x_dnd_last_protocol_version, | ||
| 19021 | event->xbutton.x_root, | ||
| 19022 | event->xbutton.y_root, | ||
| 19023 | x_dnd_selection_timestamp, | ||
| 19024 | x_dnd_wanted_action, | ||
| 19025 | event->xbutton.button, | ||
| 19026 | event->xbutton.state); | ||
| 18929 | 19027 | ||
| 18930 | goto OTHER; | 19028 | goto OTHER; |
| 18931 | } | 19029 | } |
| @@ -20315,15 +20413,21 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20315 | #endif | 20413 | #endif |
| 20316 | 20414 | ||
| 20317 | if (xev->evtype == XI_ButtonPress | 20415 | if (xev->evtype == XI_ButtonPress |
| 20318 | && x_dnd_last_seen_window != None | 20416 | && x_dnd_last_seen_window != None) |
| 20319 | && x_dnd_last_protocol_version != -1) | ||
| 20320 | { | 20417 | { |
| 20321 | dnd_state = xi_convert_event_state (xev); | 20418 | dnd_state = xi_convert_event_state (xev); |
| 20322 | 20419 | ||
| 20323 | x_dnd_send_position (x_dnd_frame, x_dnd_last_seen_window, | 20420 | if (x_dnd_last_window_is_frame) |
| 20324 | x_dnd_last_protocol_version, xev->root_x, | 20421 | x_dnd_note_self_wheel (dpyinfo, |
| 20325 | xev->root_y, x_dnd_selection_timestamp, | 20422 | x_dnd_last_seen_window, |
| 20326 | x_dnd_wanted_action, xev->detail, dnd_state); | 20423 | xev->root_x, xev->root_y, |
| 20424 | xev->detail, dnd_state, | ||
| 20425 | xev->time); | ||
| 20426 | else | ||
| 20427 | x_dnd_send_position (x_dnd_frame, x_dnd_last_seen_window, | ||
| 20428 | x_dnd_last_protocol_version, xev->root_x, | ||
| 20429 | xev->root_y, x_dnd_selection_timestamp, | ||
| 20430 | x_dnd_wanted_action, xev->detail, dnd_state); | ||
| 20327 | 20431 | ||
| 20328 | goto XI_OTHER; | 20432 | goto XI_OTHER; |
| 20329 | } | 20433 | } |
| @@ -23482,6 +23586,7 @@ x_connection_closed (Display *dpy, const char *error_message, bool ioerror) | |||
| 23482 | 23586 | ||
| 23483 | x_dnd_return_frame_object = NULL; | 23587 | x_dnd_return_frame_object = NULL; |
| 23484 | x_dnd_movement_frame = NULL; | 23588 | x_dnd_movement_frame = NULL; |
| 23589 | x_dnd_wheel_frame = NULL; | ||
| 23485 | x_dnd_frame = NULL; | 23590 | x_dnd_frame = NULL; |
| 23486 | } | 23591 | } |
| 23487 | 23592 | ||
| @@ -27750,6 +27855,7 @@ x_delete_terminal (struct terminal *terminal) | |||
| 27750 | 27855 | ||
| 27751 | x_dnd_return_frame_object = NULL; | 27856 | x_dnd_return_frame_object = NULL; |
| 27752 | x_dnd_movement_frame = NULL; | 27857 | x_dnd_movement_frame = NULL; |
| 27858 | x_dnd_wheel_frame = NULL; | ||
| 27753 | x_dnd_frame = NULL; | 27859 | x_dnd_frame = NULL; |
| 27754 | } | 27860 | } |
| 27755 | 27861 | ||
| @@ -28008,6 +28114,12 @@ mark_xterm (void) | |||
| 28008 | mark_object (val); | 28114 | mark_object (val); |
| 28009 | } | 28115 | } |
| 28010 | 28116 | ||
| 28117 | if (x_dnd_wheel_frame) | ||
| 28118 | { | ||
| 28119 | XSETFRAME (val, x_dnd_wheel_frame); | ||
| 28120 | mark_object (val); | ||
| 28121 | } | ||
| 28122 | |||
| 28011 | #if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \ | 28123 | #if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \ |
| 28012 | || defined HAVE_XRANDR || defined USE_GTK | 28124 | || defined HAVE_XRANDR || defined USE_GTK |
| 28013 | for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) | 28125 | 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 | |||
| 28454 | mouse position list. */); | 28566 | mouse position list. */); |
| 28455 | Vx_dnd_movement_function = Qnil; | 28567 | Vx_dnd_movement_function = Qnil; |
| 28456 | 28568 | ||
| 28569 | DEFVAR_LISP ("x-dnd-wheel-function", Vx_dnd_wheel_function, | ||
| 28570 | doc: /* Function called upon wheel movement on a frame during drag-and-drop. | ||
| 28571 | It should either be nil, or accept four arguments POSITION, BUTTON, | ||
| 28572 | STATE and TIME, where POSITION is a mouse position list describing | ||
| 28573 | where the wheel moved, BUTTON is the wheel button that was pressed, | ||
| 28574 | STATE is the X modifier state at the time of the wheel movement, and | ||
| 28575 | TIME is the X server time at which the wheel moved. */); | ||
| 28576 | Vx_dnd_wheel_function = Qnil; | ||
| 28577 | |||
| 28457 | DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function, | 28578 | DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function, |
| 28458 | doc: /* Function called when trying to drop on an unsupported window. | 28579 | doc: /* Function called when trying to drop on an unsupported window. |
| 28459 | This function is called whenever the user tries to drop something on a | 28580 | This function is called whenever the user tries to drop something on a |