diff options
| author | Po Lu | 2022-08-13 10:35:08 +0800 |
|---|---|---|
| committer | Po Lu | 2022-08-13 10:35:08 +0800 |
| commit | e311d05ab100b5518b974ccaee148a35ae2dada0 (patch) | |
| tree | 2ad97693b31ef5be5d13288ebeeb2143b7334ed0 | |
| parent | 37073492fdf382af2e642a4c80a9153891260374 (diff) | |
| download | emacs-e311d05ab100b5518b974ccaee148a35ae2dada0.tar.gz emacs-e311d05ab100b5518b974ccaee148a35ae2dada0.zip | |
Improve MPX interaction with drag-and-drop
* src/xfns.c (Fx_set_mouse_absolute_pixel_position): Use
internal client pointer record.
* src/xterm.c (x_dnd_cancel_dnd_early): New function. Only used
on XI2 builds so far.
(x_dnd_begin_drag_and_drop): Set the pointer device used for DND
events.
(xi_disable_devices): Cancel the drag-and-drop operation if that
device is disabled.
(x_send_scroll_bar_event): Update outdated comment.
(handle_one_xevent): Only accept DND events from that device.
(frame_set_mouse_pixel_position): Use internal client pointer
record.
| -rw-r--r-- | src/xfns.c | 19 | ||||
| -rw-r--r-- | src/xterm.c | 139 |
2 files changed, 131 insertions, 27 deletions
diff --git a/src/xfns.c b/src/xfns.c index 2845ecca6a9..144f64f6f62 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -6851,17 +6851,16 @@ The coordinates X and Y are interpreted in pixels relative to a position | |||
| 6851 | #ifdef HAVE_XINPUT2 | 6851 | #ifdef HAVE_XINPUT2 |
| 6852 | int deviceid; | 6852 | int deviceid; |
| 6853 | 6853 | ||
| 6854 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) | 6854 | deviceid = FRAME_DISPLAY_INFO (f)->client_pointer_device; |
| 6855 | |||
| 6856 | if (FRAME_DISPLAY_INFO (f)->supports_xi2 | ||
| 6857 | && deviceid != -1) | ||
| 6855 | { | 6858 | { |
| 6856 | XGrabServer (FRAME_X_DISPLAY (f)); | 6859 | x_catch_errors_for_lisp (FRAME_X_DISPLAY (f)); |
| 6857 | if (XIGetClientPointer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | 6860 | XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, |
| 6858 | &deviceid)) | 6861 | FRAME_DISPLAY_INFO (f)->root_window, |
| 6859 | { | 6862 | 0, 0, 0, 0, xval, yval); |
| 6860 | XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, | 6863 | x_uncatch_errors_for_lisp (FRAME_X_DISPLAY (f)); |
| 6861 | FRAME_DISPLAY_INFO (f)->root_window, | ||
| 6862 | 0, 0, 0, 0, xval, yval); | ||
| 6863 | } | ||
| 6864 | XUngrabServer (FRAME_X_DISPLAY (f)); | ||
| 6865 | } | 6864 | } |
| 6866 | else | 6865 | else |
| 6867 | #endif | 6866 | #endif |
diff --git a/src/xterm.c b/src/xterm.c index 48f10269dfc..e48d6fd2513 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -1398,6 +1398,12 @@ static int x_dnd_last_tooltip_x, x_dnd_last_tooltip_y; | |||
| 1398 | /* Whether or not those values are actually known yet. */ | 1398 | /* Whether or not those values are actually known yet. */ |
| 1399 | static bool x_dnd_last_tooltip_valid; | 1399 | static bool x_dnd_last_tooltip_valid; |
| 1400 | 1400 | ||
| 1401 | #ifdef HAVE_XINPUT2 | ||
| 1402 | /* The master pointer device being used for the drag-and-drop | ||
| 1403 | operation. */ | ||
| 1404 | static int x_dnd_pointer_device; | ||
| 1405 | #endif | ||
| 1406 | |||
| 1401 | /* Structure describing a single window that can be the target of | 1407 | /* Structure describing a single window that can be the target of |
| 1402 | drag-and-drop operations. */ | 1408 | drag-and-drop operations. */ |
| 1403 | struct x_client_list_window | 1409 | struct x_client_list_window |
| @@ -4705,6 +4711,67 @@ x_restore_events_after_dnd (struct frame *f, XWindowAttributes *wa) | |||
| 4705 | dpyinfo->Xatom_XdndTypeList); | 4711 | dpyinfo->Xatom_XdndTypeList); |
| 4706 | } | 4712 | } |
| 4707 | 4713 | ||
| 4714 | #ifdef HAVE_XINPUT2 | ||
| 4715 | |||
| 4716 | /* Cancel the current drag-and-drop operation, sending leave messages | ||
| 4717 | to any relevant toplevels. This is called from the event loop when | ||
| 4718 | an event is received telling Emacs to gracefully cancel the | ||
| 4719 | drag-and-drop operation. */ | ||
| 4720 | |||
| 4721 | static void | ||
| 4722 | x_dnd_cancel_dnd_early (void) | ||
| 4723 | { | ||
| 4724 | struct frame *f; | ||
| 4725 | xm_drop_start_message dmsg; | ||
| 4726 | |||
| 4727 | eassert (x_dnd_frame && x_dnd_in_progress); | ||
| 4728 | |||
| 4729 | f = x_dnd_frame; | ||
| 4730 | |||
| 4731 | if (x_dnd_last_seen_window != None | ||
| 4732 | && x_dnd_last_protocol_version != -1) | ||
| 4733 | x_dnd_send_leave (x_dnd_frame, | ||
| 4734 | x_dnd_last_seen_window); | ||
| 4735 | else if (x_dnd_last_seen_window != None | ||
| 4736 | && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style) | ||
| 4737 | && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE | ||
| 4738 | && x_dnd_motif_setup_p) | ||
| 4739 | { | ||
| 4740 | dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR, | ||
| 4741 | XM_DRAG_REASON_DROP_START); | ||
| 4742 | dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST; | ||
| 4743 | dmsg.timestamp = FRAME_DISPLAY_INFO (f)->last_user_time; | ||
| 4744 | dmsg.side_effects | ||
| 4745 | = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), | ||
| 4746 | x_dnd_wanted_action), | ||
| 4747 | XM_DROP_SITE_VALID, x_dnd_motif_operations, | ||
| 4748 | XM_DROP_ACTION_DROP_CANCEL); | ||
| 4749 | dmsg.x = 0; | ||
| 4750 | dmsg.y = 0; | ||
| 4751 | dmsg.index_atom = x_dnd_motif_atom; | ||
| 4752 | dmsg.source_window = FRAME_X_WINDOW (f); | ||
| 4753 | |||
| 4754 | x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f, | ||
| 4755 | x_dnd_last_seen_window, | ||
| 4756 | FRAME_DISPLAY_INFO (f)->last_user_time); | ||
| 4757 | xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f), | ||
| 4758 | x_dnd_last_seen_window, &dmsg); | ||
| 4759 | } | ||
| 4760 | |||
| 4761 | x_dnd_last_seen_window = None; | ||
| 4762 | x_dnd_last_seen_toplevel = None; | ||
| 4763 | x_dnd_in_progress = false; | ||
| 4764 | x_dnd_waiting_for_finish = false; | ||
| 4765 | x_dnd_return_frame_object = NULL; | ||
| 4766 | x_dnd_movement_frame = NULL; | ||
| 4767 | x_dnd_wheel_frame = NULL; | ||
| 4768 | x_dnd_frame = NULL; | ||
| 4769 | x_dnd_action = None; | ||
| 4770 | x_dnd_action_symbol = Qnil; | ||
| 4771 | } | ||
| 4772 | |||
| 4773 | #endif | ||
| 4774 | |||
| 4708 | static void | 4775 | static void |
| 4709 | x_dnd_cleanup_drag_and_drop (void *frame) | 4776 | x_dnd_cleanup_drag_and_drop (void *frame) |
| 4710 | { | 4777 | { |
| @@ -12089,6 +12156,25 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 12089 | x_dnd_wheel_frame = NULL; | 12156 | x_dnd_wheel_frame = NULL; |
| 12090 | x_dnd_init_type_lists = false; | 12157 | x_dnd_init_type_lists = false; |
| 12091 | x_dnd_need_send_drop = false; | 12158 | x_dnd_need_send_drop = false; |
| 12159 | |||
| 12160 | #ifdef HAVE_XINPUT2 | ||
| 12161 | |||
| 12162 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) | ||
| 12163 | { | ||
| 12164 | /* Only accept input from the last master pointer to have interacted | ||
| 12165 | with Emacs. This prevents another pointer device getting our | ||
| 12166 | idea of the button state messed up. */ | ||
| 12167 | if (FRAME_DISPLAY_INFO (f)->client_pointer_device != -1) | ||
| 12168 | x_dnd_pointer_device | ||
| 12169 | = FRAME_DISPLAY_INFO (f)->client_pointer_device; | ||
| 12170 | else | ||
| 12171 | /* This returns Bool but cannot actually fail. */ | ||
| 12172 | XIGetClientPointer (FRAME_X_DISPLAY (f), None, | ||
| 12173 | &x_dnd_pointer_device); | ||
| 12174 | } | ||
| 12175 | |||
| 12176 | #endif | ||
| 12177 | |||
| 12092 | #ifdef HAVE_XKB | 12178 | #ifdef HAVE_XKB |
| 12093 | x_dnd_keyboard_state = 0; | 12179 | x_dnd_keyboard_state = 0; |
| 12094 | 12180 | ||
| @@ -12882,6 +12968,13 @@ xi_disable_devices (struct x_display_info *dpyinfo, | |||
| 12882 | { | 12968 | { |
| 12883 | if (to_disable[j] == dpyinfo->devices[i].device_id) | 12969 | if (to_disable[j] == dpyinfo->devices[i].device_id) |
| 12884 | { | 12970 | { |
| 12971 | if (x_dnd_in_progress | ||
| 12972 | /* If the drag-and-drop pointer device is being | ||
| 12973 | disabled, then cancel the drag and drop | ||
| 12974 | operation. */ | ||
| 12975 | && to_disable[j] == x_dnd_pointer_device) | ||
| 12976 | x_dnd_cancel_dnd_early (); | ||
| 12977 | |||
| 12885 | /* Free any scroll valuators that might be on this | 12978 | /* Free any scroll valuators that might be on this |
| 12886 | device. */ | 12979 | device. */ |
| 12887 | #ifdef HAVE_XINPUT2_1 | 12980 | #ifdef HAVE_XINPUT2_1 |
| @@ -14164,11 +14257,13 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, | |||
| 14164 | ev->window = FRAME_X_WINDOW (f); | 14257 | ev->window = FRAME_X_WINDOW (f); |
| 14165 | ev->format = 32; | 14258 | ev->format = 32; |
| 14166 | 14259 | ||
| 14167 | /* A 32-bit X client on a 64-bit X server can pass a window pointer | 14260 | /* A 32-bit X client can pass a window pointer through the X server |
| 14168 | as-is. A 64-bit client on a 32-bit X server is in trouble | 14261 | as-is. |
| 14169 | because a pointer does not fit and would be truncated while | 14262 | |
| 14170 | passing through the server. So use two slots and hope that X12 | 14263 | A 64-bit client is in trouble because a pointer does not fit in |
| 14171 | will resolve such issues someday. */ | 14264 | the 32 bits given for ClientMessage data and will be truncated by |
| 14265 | Xlib. So use two slots and hope that X12 will resolve such | ||
| 14266 | issues someday. */ | ||
| 14172 | ev->data.l[0] = iw >> 31 >> 1; | 14267 | ev->data.l[0] = iw >> 31 >> 1; |
| 14173 | ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift; | 14268 | ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift; |
| 14174 | ev->data.l[2] = part; | 14269 | ev->data.l[2] = part; |
| @@ -18465,6 +18560,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 18465 | #endif | 18560 | #endif |
| 18466 | 18561 | ||
| 18467 | if (x_dnd_in_progress | 18562 | if (x_dnd_in_progress |
| 18563 | /* When _NET_WM_CLIENT_LIST stacking is being used, changes | ||
| 18564 | in that property are watched for, and it's not necessary | ||
| 18565 | to update the state in response to ordinary window | ||
| 18566 | substructure events. */ | ||
| 18567 | && !x_dnd_use_toplevels | ||
| 18468 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) | 18568 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) |
| 18469 | x_dnd_update_state (dpyinfo, dpyinfo->last_user_time); | 18569 | x_dnd_update_state (dpyinfo, dpyinfo->last_user_time); |
| 18470 | 18570 | ||
| @@ -20299,6 +20399,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20299 | 20399 | ||
| 20300 | case CirculateNotify: | 20400 | case CirculateNotify: |
| 20301 | if (x_dnd_in_progress | 20401 | if (x_dnd_in_progress |
| 20402 | /* When _NET_WM_CLIENT_LIST stacking is being used, changes | ||
| 20403 | in that property are watched for, and it's not necessary | ||
| 20404 | to update the state in response to ordinary window | ||
| 20405 | substructure events. */ | ||
| 20406 | && !x_dnd_use_toplevels | ||
| 20302 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) | 20407 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) |
| 20303 | x_dnd_update_state (dpyinfo, dpyinfo->last_user_time); | 20408 | x_dnd_update_state (dpyinfo, dpyinfo->last_user_time); |
| 20304 | goto OTHER; | 20409 | goto OTHER; |
| @@ -20987,6 +21092,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 20987 | `x-dnd-movement-function`. */ | 21092 | `x-dnd-movement-function`. */ |
| 20988 | && (command_loop_level + minibuf_level | 21093 | && (command_loop_level + minibuf_level |
| 20989 | <= x_dnd_recursion_depth) | 21094 | <= x_dnd_recursion_depth) |
| 21095 | && xev->deviceid == x_dnd_pointer_device | ||
| 20990 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) | 21096 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) |
| 20991 | { | 21097 | { |
| 20992 | Window target, toplevel; | 21098 | Window target, toplevel; |
| @@ -21321,6 +21427,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 21321 | if (x_dnd_in_progress | 21427 | if (x_dnd_in_progress |
| 21322 | && (command_loop_level + minibuf_level | 21428 | && (command_loop_level + minibuf_level |
| 21323 | <= x_dnd_recursion_depth) | 21429 | <= x_dnd_recursion_depth) |
| 21430 | && xev->deviceid == x_dnd_pointer_device | ||
| 21324 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) | 21431 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) |
| 21325 | { | 21432 | { |
| 21326 | f = mouse_or_wdesc_frame (dpyinfo, xev->event); | 21433 | f = mouse_or_wdesc_frame (dpyinfo, xev->event); |
| @@ -26005,27 +26112,25 @@ x_set_window_size (struct frame *f, bool change_gravity, | |||
| 26005 | void | 26112 | void |
| 26006 | frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) | 26113 | frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) |
| 26007 | { | 26114 | { |
| 26008 | block_input (); | ||
| 26009 | #ifdef HAVE_XINPUT2 | 26115 | #ifdef HAVE_XINPUT2 |
| 26010 | int deviceid; | 26116 | int deviceid; |
| 26011 | 26117 | ||
| 26012 | if (FRAME_DISPLAY_INFO (f)->supports_xi2) | 26118 | deviceid = FRAME_DISPLAY_INFO (f)->client_pointer_device; |
| 26119 | |||
| 26120 | if (FRAME_DISPLAY_INFO (f)->supports_xi2 | ||
| 26121 | && deviceid != -1) | ||
| 26013 | { | 26122 | { |
| 26014 | if (XIGetClientPointer (FRAME_X_DISPLAY (f), | 26123 | block_input (); |
| 26015 | FRAME_X_WINDOW (f), | 26124 | x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); |
| 26016 | &deviceid)) | 26125 | XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, |
| 26017 | { | 26126 | FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y); |
| 26018 | x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); | 26127 | x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); |
| 26019 | XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, | 26128 | unblock_input (); |
| 26020 | FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y); | ||
| 26021 | x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); | ||
| 26022 | } | ||
| 26023 | } | 26129 | } |
| 26024 | else | 26130 | else |
| 26025 | #endif | 26131 | #endif |
| 26026 | XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f), | 26132 | XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f), |
| 26027 | 0, 0, 0, 0, pix_x, pix_y); | 26133 | 0, 0, 0, 0, pix_x, pix_y); |
| 26028 | unblock_input (); | ||
| 26029 | } | 26134 | } |
| 26030 | 26135 | ||
| 26031 | /* Raise frame F. */ | 26136 | /* Raise frame F. */ |