diff options
| author | Po Lu | 2022-04-04 20:32:46 +0800 |
|---|---|---|
| committer | Po Lu | 2022-04-04 20:32:46 +0800 |
| commit | 84cf3be6f77f61dd361acdb3683ab9d71e76c995 (patch) | |
| tree | ccf6ea1ff0d6ac533f3665991f311750af99f738 /src | |
| parent | 3d2531c12c54f9ab923603655016077450c23ab2 (diff) | |
| download | emacs-84cf3be6f77f61dd361acdb3683ab9d71e76c995.tar.gz emacs-84cf3be6f77f61dd361acdb3683ab9d71e76c995.zip | |
Handle mouse movement correctly during DND from one of our own frames
* lisp/dnd.el (dnd-handle-movement): Select the window specified
in posn.
* lisp/term/x-win.el (x-dnd-movement): New function.
(x-dnd-movement-function): Set it as the default.
* src/frame.c (delete_frame): Prevent deleting the drop source
frame.
* src/xterm.c (x_dnd_send_position): Set new mouse movement
flags if the target window is one of our own frames.
(x_dnd_begin_drag_and_drop): Call DND movement function whenever
appropriate.
(x_free_frame_resources): Remove useless code.
(syms_of_xterm): New defvar `x-dnd-movement-function'.
* src/xterm.h: Update prototypes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/frame.c | 4 | ||||
| -rw-r--r-- | src/xterm.c | 106 | ||||
| -rw-r--r-- | src/xterm.h | 3 |
3 files changed, 66 insertions, 47 deletions
diff --git a/src/frame.c b/src/frame.c index 7a9ed3302e4..05b22ac72ba 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -1987,6 +1987,10 @@ delete_frame (Lisp_Object frame, Lisp_Object force) | |||
| 1987 | else | 1987 | else |
| 1988 | error ("Attempt to delete the only frame"); | 1988 | error ("Attempt to delete the only frame"); |
| 1989 | } | 1989 | } |
| 1990 | #ifdef HAVE_X_WINDOWS | ||
| 1991 | else if (x_dnd_in_progress && f == x_dnd_frame) | ||
| 1992 | error ("Attempt to delete the drop source frame"); | ||
| 1993 | #endif | ||
| 1990 | 1994 | ||
| 1991 | XSETFRAME (frame, f); | 1995 | XSETFRAME (frame, f); |
| 1992 | 1996 | ||
diff --git a/src/xterm.c b/src/xterm.c index 2e4df67c76e..d29a7a122aa 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -846,7 +846,10 @@ static int x_filter_event (struct x_display_info *, XEvent *); | |||
| 846 | /* Global state maintained during a drag-and-drop operation. */ | 846 | /* Global state maintained during a drag-and-drop operation. */ |
| 847 | 847 | ||
| 848 | /* Flag that indicates if a drag-and-drop operation is in progress. */ | 848 | /* Flag that indicates if a drag-and-drop operation is in progress. */ |
| 849 | static bool x_dnd_in_progress; | 849 | bool x_dnd_in_progress; |
| 850 | |||
| 851 | /* The frame where the drag-and-drop operation originated. */ | ||
| 852 | struct frame *x_dnd_frame; | ||
| 850 | 853 | ||
| 851 | /* Flag that indicates if a drag-and-drop operation is no longer in | 854 | /* Flag that indicates if a drag-and-drop operation is no longer in |
| 852 | progress, but the nested event loop should continue to run, because | 855 | progress, but the nested event loop should continue to run, because |
| @@ -946,9 +949,6 @@ static Atom *x_dnd_targets = NULL; | |||
| 946 | /* The number of elements in that array. */ | 949 | /* The number of elements in that array. */ |
| 947 | static int x_dnd_n_targets; | 950 | static int x_dnd_n_targets; |
| 948 | 951 | ||
| 949 | /* The frame where the drag-and-drop operation originated. */ | ||
| 950 | static struct frame *x_dnd_frame; | ||
| 951 | |||
| 952 | /* The old window attributes of the root window before the | 952 | /* The old window attributes of the root window before the |
| 953 | drag-and-drop operation started. It is used to keep the old event | 953 | drag-and-drop operation started. It is used to keep the old event |
| 954 | mask around, since that should be restored after the operation | 954 | mask around, since that should be restored after the operation |
| @@ -959,6 +959,13 @@ static XWindowAttributes x_dnd_old_window_attrs; | |||
| 959 | up the drag and drop operation. */ | 959 | up the drag and drop operation. */ |
| 960 | static bool x_dnd_unwind_flag; | 960 | static bool x_dnd_unwind_flag; |
| 961 | 961 | ||
| 962 | /* The frame for which `x-dnd-movement-function' should be called. */ | ||
| 963 | static struct frame *x_dnd_movement_frame; | ||
| 964 | |||
| 965 | /* The coordinates which the movement function should be called | ||
| 966 | with. */ | ||
| 967 | static int x_dnd_movement_x, x_dnd_movement_y; | ||
| 968 | |||
| 962 | struct x_client_list_window | 969 | struct x_client_list_window |
| 963 | { | 970 | { |
| 964 | Window window; | 971 | Window window; |
| @@ -3137,6 +3144,23 @@ x_dnd_send_position (struct frame *f, Window target, int supported, | |||
| 3137 | { | 3144 | { |
| 3138 | struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | 3145 | struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); |
| 3139 | XEvent msg; | 3146 | XEvent msg; |
| 3147 | struct frame *target_frame; | ||
| 3148 | int dest_x, dest_y; | ||
| 3149 | Window child_return; | ||
| 3150 | |||
| 3151 | target_frame = x_top_window_to_frame (dpyinfo, target); | ||
| 3152 | |||
| 3153 | if (target_frame && XTranslateCoordinates (dpyinfo->display, | ||
| 3154 | dpyinfo->root_window, | ||
| 3155 | FRAME_X_WINDOW (target_frame), | ||
| 3156 | root_x, root_y, &dest_x, | ||
| 3157 | &dest_y, &child_return)) | ||
| 3158 | { | ||
| 3159 | x_dnd_movement_frame = target_frame; | ||
| 3160 | x_dnd_movement_x = dest_x; | ||
| 3161 | x_dnd_movement_y = dest_y; | ||
| 3162 | return; | ||
| 3163 | } | ||
| 3140 | 3164 | ||
| 3141 | if (target == x_dnd_mouse_rect_target | 3165 | if (target == x_dnd_mouse_rect_target |
| 3142 | && x_dnd_mouse_rect.width | 3166 | && x_dnd_mouse_rect.width |
| @@ -3151,9 +3175,6 @@ x_dnd_send_position (struct frame *f, Window target, int supported, | |||
| 3151 | return; | 3175 | return; |
| 3152 | } | 3176 | } |
| 3153 | 3177 | ||
| 3154 | if (x_top_window_to_frame (dpyinfo, target)) | ||
| 3155 | return; | ||
| 3156 | |||
| 3157 | msg.xclient.type = ClientMessage; | 3178 | msg.xclient.type = ClientMessage; |
| 3158 | msg.xclient.message_type = dpyinfo->Xatom_XdndPosition; | 3179 | msg.xclient.message_type = dpyinfo->Xatom_XdndPosition; |
| 3159 | msg.xclient.format = 32; | 3180 | msg.xclient.format = 32; |
| @@ -9143,6 +9164,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 9143 | ptrdiff_t i, end, fill; | 9164 | ptrdiff_t i, end, fill; |
| 9144 | XTextProperty prop; | 9165 | XTextProperty prop; |
| 9145 | xm_drop_start_message dmsg; | 9166 | xm_drop_start_message dmsg; |
| 9167 | Lisp_Object frame_object, x, y; | ||
| 9146 | 9168 | ||
| 9147 | if (!FRAME_VISIBLE_P (f)) | 9169 | if (!FRAME_VISIBLE_P (f)) |
| 9148 | error ("Frame is invisible"); | 9170 | error ("Frame is invisible"); |
| @@ -9229,6 +9251,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 9229 | = x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking); | 9251 | = x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking); |
| 9230 | x_dnd_toplevels = NULL; | 9252 | x_dnd_toplevels = NULL; |
| 9231 | x_dnd_allow_current_frame = allow_current_frame; | 9253 | x_dnd_allow_current_frame = allow_current_frame; |
| 9254 | x_dnd_movement_frame = NULL; | ||
| 9232 | 9255 | ||
| 9233 | if (x_dnd_use_toplevels) | 9256 | if (x_dnd_use_toplevels) |
| 9234 | { | 9257 | { |
| @@ -9307,6 +9330,28 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 9307 | #endif | 9330 | #endif |
| 9308 | #endif | 9331 | #endif |
| 9309 | 9332 | ||
| 9333 | if (x_dnd_movement_frame) | ||
| 9334 | { | ||
| 9335 | XSETFRAME (frame_object, x_dnd_movement_frame); | ||
| 9336 | XSETINT (x, x_dnd_movement_x); | ||
| 9337 | XSETINT (y, x_dnd_movement_y); | ||
| 9338 | x_dnd_movement_frame = NULL; | ||
| 9339 | |||
| 9340 | if (!NILP (Vx_dnd_movement_function) | ||
| 9341 | && !FRAME_TOOLTIP_P (XFRAME (frame_object))) | ||
| 9342 | { | ||
| 9343 | x_dnd_old_window_attrs = root_window_attrs; | ||
| 9344 | x_dnd_unwind_flag = true; | ||
| 9345 | |||
| 9346 | ref = SPECPDL_INDEX (); | ||
| 9347 | record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f); | ||
| 9348 | call2 (Vx_dnd_movement_function, frame_object, | ||
| 9349 | Fposn_at_x_y (x, y, frame_object, Qnil)); | ||
| 9350 | x_dnd_unwind_flag = false; | ||
| 9351 | unbind_to (ref, Qnil); | ||
| 9352 | } | ||
| 9353 | } | ||
| 9354 | |||
| 9310 | if (hold_quit.kind != NO_EVENT) | 9355 | if (hold_quit.kind != NO_EVENT) |
| 9311 | { | 9356 | { |
| 9312 | if (hold_quit.kind == SELECTION_REQUEST_EVENT) | 9357 | if (hold_quit.kind == SELECTION_REQUEST_EVENT) |
| @@ -20746,46 +20791,6 @@ x_free_frame_resources (struct frame *f) | |||
| 20746 | Lisp_Object bar; | 20791 | Lisp_Object bar; |
| 20747 | struct scroll_bar *b; | 20792 | struct scroll_bar *b; |
| 20748 | #endif | 20793 | #endif |
| 20749 | xm_drop_start_message dmsg; | ||
| 20750 | |||
| 20751 | if (x_dnd_in_progress && f == x_dnd_frame) | ||
| 20752 | { | ||
| 20753 | block_input (); | ||
| 20754 | if (x_dnd_last_seen_window != None | ||
| 20755 | && x_dnd_last_protocol_version != -1) | ||
| 20756 | x_dnd_send_leave (f, x_dnd_last_seen_window); | ||
| 20757 | else if (x_dnd_last_seen_window != None | ||
| 20758 | && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style) | ||
| 20759 | && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE | ||
| 20760 | && x_dnd_motif_setup_p) | ||
| 20761 | { | ||
| 20762 | dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR, | ||
| 20763 | XM_DRAG_REASON_DROP_START); | ||
| 20764 | dmsg.byte_order = XM_TARGETS_TABLE_CUR; | ||
| 20765 | dmsg.timestamp = 0; | ||
| 20766 | dmsg.side_effects | ||
| 20767 | = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, | ||
| 20768 | x_dnd_wanted_action), | ||
| 20769 | XM_DROP_SITE_VALID, | ||
| 20770 | xm_side_effect_from_action (dpyinfo, | ||
| 20771 | x_dnd_wanted_action), | ||
| 20772 | XM_DROP_ACTION_DROP_CANCEL); | ||
| 20773 | dmsg.x = 0; | ||
| 20774 | dmsg.y = 0; | ||
| 20775 | dmsg.index_atom = dpyinfo->Xatom_XdndSelection; | ||
| 20776 | dmsg.source_window = FRAME_X_WINDOW (f); | ||
| 20777 | |||
| 20778 | xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (f), | ||
| 20779 | x_dnd_last_seen_window, &dmsg); | ||
| 20780 | } | ||
| 20781 | unblock_input (); | ||
| 20782 | |||
| 20783 | x_dnd_end_window = None; | ||
| 20784 | x_dnd_last_seen_window = None; | ||
| 20785 | x_dnd_in_progress = false; | ||
| 20786 | x_dnd_waiting_for_finish = false; | ||
| 20787 | x_dnd_frame = NULL; | ||
| 20788 | } | ||
| 20789 | 20794 | ||
| 20790 | block_input (); | 20795 | block_input (); |
| 20791 | 20796 | ||
| @@ -23054,4 +23059,11 @@ coordinates to a Motif drop receiver when the mouse moves outside it | |||
| 23054 | during a drag-and-drop session, to work around broken implementations | 23059 | during a drag-and-drop session, to work around broken implementations |
| 23055 | of Motif. */); | 23060 | of Motif. */); |
| 23056 | x_dnd_fix_motif_leave = true; | 23061 | x_dnd_fix_motif_leave = true; |
| 23062 | |||
| 23063 | DEFVAR_LISP ("x-dnd-movement-function", Vx_dnd_movement_function, | ||
| 23064 | doc: /* Function called upon mouse movement on a frame during drag-and-drop. | ||
| 23065 | It should either be nil, or accept two arguments FRAME and POSITION, | ||
| 23066 | where FRAME is the frame the mouse is on top of, and POSITION is a | ||
| 23067 | mouse position list. */); | ||
| 23068 | Vx_dnd_movement_function = Qnil; | ||
| 23057 | } | 23069 | } |
diff --git a/src/xterm.h b/src/xterm.h index 57036af2bb5..5627fd23c57 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -1548,6 +1548,9 @@ extern void x_session_close (void); | |||
| 1548 | extern struct input_event xg_pending_quit_event; | 1548 | extern struct input_event xg_pending_quit_event; |
| 1549 | #endif | 1549 | #endif |
| 1550 | 1550 | ||
| 1551 | extern bool x_dnd_in_progress; | ||
| 1552 | extern struct frame *x_dnd_frame; | ||
| 1553 | |||
| 1551 | #ifdef HAVE_XINPUT2 | 1554 | #ifdef HAVE_XINPUT2 |
| 1552 | struct xi_device_t *xi_device_from_id (struct x_display_info *, int); | 1555 | struct xi_device_t *xi_device_from_id (struct x_display_info *, int); |
| 1553 | #endif | 1556 | #endif |