aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-08-13 10:35:08 +0800
committerPo Lu2022-08-13 10:35:08 +0800
commite311d05ab100b5518b974ccaee148a35ae2dada0 (patch)
tree2ad97693b31ef5be5d13288ebeeb2143b7334ed0 /src
parent37073492fdf382af2e642a4c80a9153891260374 (diff)
downloademacs-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.
Diffstat (limited to 'src')
-rw-r--r--src/xfns.c19
-rw-r--r--src/xterm.c139
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. */
1399static bool x_dnd_last_tooltip_valid; 1399static 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. */
1404static 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. */
1403struct x_client_list_window 1409struct 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
4721static void
4722x_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
4708static void 4775static void
4709x_dnd_cleanup_drag_and_drop (void *frame) 4776x_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,
26005void 26112void
26006frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) 26113frame_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. */