diff options
| author | Po Lu | 2022-06-13 15:01:06 +0800 |
|---|---|---|
| committer | Po Lu | 2022-06-13 15:02:41 +0800 |
| commit | a1a435b3f6c7afa910da2256334471ba49010974 (patch) | |
| tree | add823f06b7f05d4dd4a57d54854e8af2ccae67f | |
| parent | 7cd1f432c62d5677fb2d44ed05ed9546c3c292dc (diff) | |
| download | emacs-a1a435b3f6c7afa910da2256334471ba49010974.tar.gz emacs-a1a435b3f6c7afa910da2256334471ba49010974.zip | |
Respect test function when performing local drag-and-drop
* lisp/x-dnd.el (x-dnd-test-function): Fix doc string to
describe what is actually accepted.
(x-dnd-known-types, x-dnd-targets-list): Fix coding style.
(x-dnd-handle-native-drop): New function.
* src/xselect.c (x_atom_to_symbol): Export.
* src/xterm.c (x_dnd_note_self_drop): Call new variable to
determine what action to return.
(x_clear_dnd_action): New function.
(x_dnd_begin_drag_and_drop): Respect new variable.
(syms_of_xterm): New defvar `x-dnd-native-test-function'.
* src/xterm.h: Update prototypes.
| -rw-r--r-- | lisp/x-dnd.el | 45 | ||||
| -rw-r--r-- | src/xselect.c | 4 | ||||
| -rw-r--r-- | src/xterm.c | 54 | ||||
| -rw-r--r-- | src/xterm.h | 1 |
4 files changed, 83 insertions, 21 deletions
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index 7ee20e0fc3c..bcf74762cc4 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el | |||
| @@ -35,22 +35,24 @@ | |||
| 35 | (defcustom x-dnd-test-function #'x-dnd-default-test-function | 35 | (defcustom x-dnd-test-function #'x-dnd-default-test-function |
| 36 | "The function drag and drop uses to determine if to accept or reject a drop. | 36 | "The function drag and drop uses to determine if to accept or reject a drop. |
| 37 | The function takes three arguments, WINDOW, ACTION and TYPES. | 37 | The function takes three arguments, WINDOW, ACTION and TYPES. |
| 38 | WINDOW is where the mouse is when the function is called. WINDOW may be a | 38 | WINDOW is where the mouse is when the function is called. WINDOW |
| 39 | frame if the mouse isn't over a real window (i.e. menu bar, tool bar or | 39 | may be a frame if the mouse isn't over a real window (i.e. menu |
| 40 | scroll bar). ACTION is the suggested action from the drag and drop source, | 40 | bar, tool bar or scroll bar). ACTION is the suggested action |
| 41 | one of the symbols move, copy, link or ask. TYPES is a list of available | 41 | from the drag and drop source, one of the symbols move, copy, |
| 42 | types for the drop. | 42 | link or ask. TYPES is a vector of available types for the drop. |
| 43 | 43 | ||
| 44 | The function shall return nil to reject the drop or a cons with two values, | 44 | Each element of TYPE should either be a string (containing the |
| 45 | the wanted action as car and the wanted type as cdr. The wanted action | 45 | name of the type's X atom), or a symbol, whose name will be used. |
| 46 | can be copy, move, link, ask or private. | 46 | |
| 47 | The function shall return nil to reject the drop or a cons with | ||
| 48 | two values, the wanted action as car and the wanted type as cdr. | ||
| 49 | The wanted action can be copy, move, link, ask or private. | ||
| 50 | |||
| 47 | The default value for this variable is `x-dnd-default-test-function'." | 51 | The default value for this variable is `x-dnd-default-test-function'." |
| 48 | :version "22.1" | 52 | :version "22.1" |
| 49 | :type 'symbol | 53 | :type 'symbol |
| 50 | :group 'x) | 54 | :group 'x) |
| 51 | 55 | ||
| 52 | |||
| 53 | |||
| 54 | (defcustom x-dnd-types-alist | 56 | (defcustom x-dnd-types-alist |
| 55 | `((,(purecopy "text/uri-list") . x-dnd-handle-uri-list) | 57 | `((,(purecopy "text/uri-list") . x-dnd-handle-uri-list) |
| 56 | (,(purecopy "text/x-moz-url") . x-dnd-handle-moz-url) | 58 | (,(purecopy "text/x-moz-url") . x-dnd-handle-moz-url) |
| @@ -94,8 +96,7 @@ if drop is successful, nil if not." | |||
| 94 | The types are chosen in the order they appear in the list." | 96 | The types are chosen in the order they appear in the list." |
| 95 | :version "22.1" | 97 | :version "22.1" |
| 96 | :type '(repeat string) | 98 | :type '(repeat string) |
| 97 | :group 'x | 99 | :group 'x) |
| 98 | ) | ||
| 99 | 100 | ||
| 100 | ;; Internal variables | 101 | ;; Internal variables |
| 101 | 102 | ||
| @@ -163,7 +164,6 @@ types in `x-dnd-known-types'. It always returns the action private." | |||
| 163 | (let ((type (x-dnd-choose-type types))) | 164 | (let ((type (x-dnd-choose-type types))) |
| 164 | (when type (cons 'private type)))) | 165 | (when type (cons 'private type)))) |
| 165 | 166 | ||
| 166 | |||
| 167 | (defun x-dnd-current-type (frame-or-window) | 167 | (defun x-dnd-current-type (frame-or-window) |
| 168 | "Return the type we want the DND data to be in for the current drop. | 168 | "Return the type we want the DND data to be in for the current drop. |
| 169 | FRAME-OR-WINDOW is the frame or window that the mouse is over." | 169 | FRAME-OR-WINDOW is the frame or window that the mouse is over." |
| @@ -896,6 +896,23 @@ Return a vector of atoms containing the selection targets." | |||
| 896 | (member "COMPOUND_TEXT" targets) | 896 | (member "COMPOUND_TEXT" targets) |
| 897 | (member "TEXT" targets))))) | 897 | (member "TEXT" targets))))) |
| 898 | 898 | ||
| 899 | (defvar x-dnd-targets-list) | ||
| 900 | (defvar x-dnd-native-test-function) | ||
| 901 | |||
| 902 | (defun x-dnd-handle-native-drop (pos action) | ||
| 903 | "Compute the action for a drop at POS. | ||
| 904 | Return the appropriate drag-and-drop action for a local drop at POS. | ||
| 905 | ACTION is the action given to `x-begin-drag'." | ||
| 906 | (let ((state (funcall x-dnd-test-function | ||
| 907 | (posn-window pos) | ||
| 908 | (cdr (assoc (symbol-name action) | ||
| 909 | x-dnd-xdnd-to-action)) | ||
| 910 | (apply #'vector x-dnd-targets-list)))) | ||
| 911 | (when state | ||
| 912 | (intern (car (rassq (car state) x-dnd-xdnd-to-action)))))) | ||
| 913 | |||
| 914 | (setq x-dnd-native-test-function #'x-dnd-handle-native-drop) | ||
| 915 | |||
| 899 | (provide 'x-dnd) | 916 | (provide 'x-dnd) |
| 900 | 917 | ||
| 901 | ;;; x-dnd.el ends here | 918 | ;;; x-dnd.el ends here |
diff --git a/src/xselect.c b/src/xselect.c index bb5a1447df7..490a008dfcb 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -112,7 +112,7 @@ selection_quantum (Display *display) | |||
| 112 | : MAX_SELECTION_QUANTUM); | 112 | : MAX_SELECTION_QUANTUM); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | #define LOCAL_SELECTION(selection_symbol,dpyinfo) \ | 115 | #define LOCAL_SELECTION(selection_symbol, dpyinfo) \ |
| 116 | assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist) | 116 | assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist) |
| 117 | 117 | ||
| 118 | 118 | ||
| @@ -179,7 +179,7 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym) | |||
| 179 | /* This converts a server Atom to a Lisp symbol, avoiding server roundtrips | 179 | /* This converts a server Atom to a Lisp symbol, avoiding server roundtrips |
| 180 | and calls to intern whenever possible. */ | 180 | and calls to intern whenever possible. */ |
| 181 | 181 | ||
| 182 | static Lisp_Object | 182 | Lisp_Object |
| 183 | x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom) | 183 | x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom) |
| 184 | { | 184 | { |
| 185 | char *str; | 185 | char *str; |
diff --git a/src/xterm.c b/src/xterm.c index 81b3b5cbeff..d9dd29ca128 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -1228,6 +1228,10 @@ static XRectangle x_dnd_mouse_rect; | |||
| 1228 | protocol, this is set to the atom XdndActionPrivate. */ | 1228 | protocol, this is set to the atom XdndActionPrivate. */ |
| 1229 | static Atom x_dnd_action; | 1229 | static Atom x_dnd_action; |
| 1230 | 1230 | ||
| 1231 | /* The symbol to return from `x-begin-drag' if non-nil. Takes | ||
| 1232 | precedence over `x_dnd_action`. */ | ||
| 1233 | static Lisp_Object x_dnd_action_symbol; | ||
| 1234 | |||
| 1231 | /* The action we want the drop target to perform. The drop target may | 1235 | /* The action we want the drop target to perform. The drop target may |
| 1232 | elect to perform some different action, which is guaranteed to be | 1236 | elect to perform some different action, which is guaranteed to be |
| 1233 | in `x_dnd_action' upon completion of a drop. */ | 1237 | in `x_dnd_action' upon completion of a drop. */ |
| @@ -1242,7 +1246,7 @@ static uint8_t x_dnd_motif_operations; | |||
| 1242 | static uint8_t x_dnd_first_motif_operation; | 1246 | static uint8_t x_dnd_first_motif_operation; |
| 1243 | 1247 | ||
| 1244 | /* Array of selection targets available to the drop target. */ | 1248 | /* Array of selection targets available to the drop target. */ |
| 1245 | static Atom *x_dnd_targets = NULL; | 1249 | static Atom *x_dnd_targets; |
| 1246 | 1250 | ||
| 1247 | /* The number of elements in that array. */ | 1251 | /* The number of elements in that array. */ |
| 1248 | static int x_dnd_n_targets; | 1252 | static int x_dnd_n_targets; |
| @@ -4298,15 +4302,30 @@ x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target, | |||
| 4298 | if (!f) | 4302 | if (!f) |
| 4299 | return; | 4303 | return; |
| 4300 | 4304 | ||
| 4305 | if (NILP (Vx_dnd_native_test_function)) | ||
| 4306 | return; | ||
| 4307 | |||
| 4301 | if (!XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window, | 4308 | if (!XTranslateCoordinates (dpyinfo->display, dpyinfo->root_window, |
| 4302 | FRAME_X_WINDOW (f), root_x, root_y, | 4309 | FRAME_X_WINDOW (f), root_x, root_y, |
| 4303 | &win_x, &win_y, &dummy)) | 4310 | &win_x, &win_y, &dummy)) |
| 4304 | return; | 4311 | return; |
| 4305 | 4312 | ||
| 4306 | /* Emacs can't respond to DND events inside the nested event | 4313 | /* Emacs can't respond to DND events inside the nested event loop, |
| 4307 | loop, so when dragging items to itself, always return | 4314 | so when dragging items to itself, call the test function |
| 4308 | XdndActionPrivate. */ | 4315 | manually. */ |
| 4309 | x_dnd_action = dpyinfo->Xatom_XdndActionPrivate; | 4316 | |
| 4317 | XSETFRAME (lval, f); | ||
| 4318 | x_dnd_action = None; | ||
| 4319 | x_dnd_action_symbol | ||
| 4320 | = safe_call2 (Vx_dnd_native_test_function, | ||
| 4321 | Fposn_at_x_y (make_fixnum (win_x), | ||
| 4322 | make_fixnum (win_y), | ||
| 4323 | lval, Qnil), | ||
| 4324 | x_atom_to_symbol (dpyinfo, | ||
| 4325 | x_dnd_wanted_action)); | ||
| 4326 | |||
| 4327 | if (!SYMBOLP (x_dnd_action_symbol)) | ||
| 4328 | return; | ||
| 4310 | 4329 | ||
| 4311 | EVENT_INIT (ie); | 4330 | EVENT_INIT (ie); |
| 4312 | 4331 | ||
| @@ -10779,6 +10798,12 @@ x_detect_pending_selection_requests (void) | |||
| 10779 | return pending_selection_requests; | 10798 | return pending_selection_requests; |
| 10780 | } | 10799 | } |
| 10781 | 10800 | ||
| 10801 | static void | ||
| 10802 | x_clear_dnd_action (void) | ||
| 10803 | { | ||
| 10804 | x_dnd_action_symbol = Qnil; | ||
| 10805 | } | ||
| 10806 | |||
| 10782 | /* This function is defined far away from the rest of the XDND code so | 10807 | /* This function is defined far away from the rest of the XDND code so |
| 10783 | it can utilize `x_any_window_to_frame'. */ | 10808 | it can utilize `x_any_window_to_frame'. */ |
| 10784 | 10809 | ||
| @@ -10922,6 +10947,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 10922 | 10947 | ||
| 10923 | x_set_dnd_targets (target_atoms, ntargets); | 10948 | x_set_dnd_targets (target_atoms, ntargets); |
| 10924 | record_unwind_protect_void (x_free_dnd_targets); | 10949 | record_unwind_protect_void (x_free_dnd_targets); |
| 10950 | record_unwind_protect_void (x_clear_dnd_action); | ||
| 10925 | 10951 | ||
| 10926 | ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f), | 10952 | ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f), |
| 10927 | QXdndSelection); | 10953 | QXdndSelection); |
| @@ -11042,6 +11068,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11042 | x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; | 11068 | x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; |
| 11043 | x_dnd_mouse_rect_target = None; | 11069 | x_dnd_mouse_rect_target = None; |
| 11044 | x_dnd_action = None; | 11070 | x_dnd_action = None; |
| 11071 | x_dnd_action_symbol = Qnil; | ||
| 11045 | x_dnd_wanted_action = xaction; | 11072 | x_dnd_wanted_action = xaction; |
| 11046 | x_dnd_return_frame = 0; | 11073 | x_dnd_return_frame = 0; |
| 11047 | x_dnd_waiting_for_finish = false; | 11074 | x_dnd_waiting_for_finish = false; |
| @@ -11435,6 +11462,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11435 | x_dnd_return_frame_object = NULL; | 11462 | x_dnd_return_frame_object = NULL; |
| 11436 | FRAME_DISPLAY_INFO (f)->grabbed = 0; | 11463 | FRAME_DISPLAY_INFO (f)->grabbed = 0; |
| 11437 | 11464 | ||
| 11465 | if (!NILP (x_dnd_action_symbol)) | ||
| 11466 | return unbind_to (base, x_dnd_action_symbol); | ||
| 11467 | |||
| 11438 | if (x_dnd_action != None) | 11468 | if (x_dnd_action != None) |
| 11439 | { | 11469 | { |
| 11440 | block_input (); | 11470 | block_input (); |
| @@ -26942,6 +26972,9 @@ syms_of_xterm (void) | |||
| 26942 | x_dnd_monitors = Qnil; | 26972 | x_dnd_monitors = Qnil; |
| 26943 | staticpro (&x_dnd_monitors); | 26973 | staticpro (&x_dnd_monitors); |
| 26944 | 26974 | ||
| 26975 | x_dnd_action_symbol = Qnil; | ||
| 26976 | staticpro (&x_dnd_action_symbol); | ||
| 26977 | |||
| 26945 | DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms"); | 26978 | DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms"); |
| 26946 | DEFSYM (Qlatin_1, "latin-1"); | 26979 | DEFSYM (Qlatin_1, "latin-1"); |
| 26947 | DEFSYM (Qnow, "now"); | 26980 | DEFSYM (Qnow, "now"); |
| @@ -27189,4 +27222,15 @@ This variable contains the list of drag-and-drop selection targets | |||
| 27189 | during a drag-and-drop operation, in the same format as the TARGET | 27222 | during a drag-and-drop operation, in the same format as the TARGET |
| 27190 | argument to `x-begin-drag'. */); | 27223 | argument to `x-begin-drag'. */); |
| 27191 | Vx_dnd_targets_list = Qnil; | 27224 | Vx_dnd_targets_list = Qnil; |
| 27225 | |||
| 27226 | DEFVAR_LISP ("x-dnd-native-test-function", Vx_dnd_native_test_function, | ||
| 27227 | doc: /* Function called to determine return when dropping on Emacs itself. | ||
| 27228 | It should accept two arguments POS and ACTION, and return a symbol | ||
| 27229 | describing what to return from `x-begin-drag'. POS is a mouse | ||
| 27230 | position list detailing the location of the drop, and ACTION is the | ||
| 27231 | action specified by the caller of `x-begin-drag'. | ||
| 27232 | |||
| 27233 | If nil or a non-symbol value is returned, the drop will be | ||
| 27234 | cancelled. */); | ||
| 27235 | Vx_dnd_native_test_function = Qnil; | ||
| 27192 | } | 27236 | } |
diff --git a/src/xterm.h b/src/xterm.h index 25d145c6c0a..25c2453ee78 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -1535,6 +1535,7 @@ extern void x_handle_property_notify (const XPropertyEvent *); | |||
| 1535 | extern void x_handle_selection_notify (const XSelectionEvent *); | 1535 | extern void x_handle_selection_notify (const XSelectionEvent *); |
| 1536 | extern void x_handle_selection_event (struct selection_input_event *); | 1536 | extern void x_handle_selection_event (struct selection_input_event *); |
| 1537 | extern void x_clear_frame_selections (struct frame *); | 1537 | extern void x_clear_frame_selections (struct frame *); |
| 1538 | extern Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom); | ||
| 1538 | 1539 | ||
| 1539 | extern bool x_handle_dnd_message (struct frame *, | 1540 | extern bool x_handle_dnd_message (struct frame *, |
| 1540 | const XClientMessageEvent *, | 1541 | const XClientMessageEvent *, |