diff options
| author | Eli Zaretskii | 2023-04-08 18:36:23 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2023-04-08 18:36:23 +0300 |
| commit | 08cda286c3f5ccf4a898516204884bd7daaae971 (patch) | |
| tree | a75ae38b7750a6e4d69cbc362e27b9a9e12da84e | |
| parent | 14d1c00e806cbd864acc6b4a6f84a4453954b898 (diff) | |
| download | emacs-08cda286c3f5ccf4a898516204884bd7daaae971.tar.gz emacs-08cda286c3f5ccf4a898516204884bd7daaae971.zip | |
Improve the documentation of the XDS support
* doc/lispref/frames.texi (Drag and Drop): Rephrase and rearrange
the documentation of XDS support. Add indexing. Document
'x-dnd-save-direct' and 'x-dnd-save-direct-immediately'. Original
patch from Po Lu <luangruo@yahoo.com>.
* lisp/x-dnd.el (x-dnd-types-alist, x-dnd-test-function)
(x-dnd-default-test-function, x-dnd-direct-save-function): Doc
fixes.
(x-dnd-save-direct, x-dnd-save-direct-immediately): Rename the
second argument to FILENAME. Doc fix.
| -rw-r--r-- | doc/lispref/frames.texi | 88 | ||||
| -rw-r--r-- | lisp/x-dnd.el | 120 |
2 files changed, 133 insertions, 75 deletions
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 7cae94d2627..c78ab1c34ba 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi | |||
| @@ -4112,7 +4112,7 @@ has the same meaning as the @var{action} argument to | |||
| 4112 | Emacs implements receiving text and URLs individually for each | 4112 | Emacs implements receiving text and URLs individually for each |
| 4113 | window system, and does not by default support receiving other kinds | 4113 | window system, and does not by default support receiving other kinds |
| 4114 | of data as drops. To support receiving other kinds of data, use the | 4114 | of data as drops. To support receiving other kinds of data, use the |
| 4115 | X-specific interface described below: | 4115 | X-specific interface described below. |
| 4116 | 4116 | ||
| 4117 | @vindex x-dnd-test-function | 4117 | @vindex x-dnd-test-function |
| 4118 | @vindex x-dnd-known-types | 4118 | @vindex x-dnd-known-types |
| @@ -4141,29 +4141,71 @@ depending on the specific drag-and-drop protocol being used. For | |||
| 4141 | example, the data type used for plain text may be either | 4141 | example, the data type used for plain text may be either |
| 4142 | @code{"STRING"} or @code{"text/plain"}. | 4142 | @code{"STRING"} or @code{"text/plain"}. |
| 4143 | 4143 | ||
| 4144 | @cindex XDS | ||
| 4145 | @cindex direct save protocol | ||
| 4144 | @vindex x-dnd-direct-save-function | 4146 | @vindex x-dnd-direct-save-function |
| 4145 | @c FIXME: This description is overly-complicated and confusing. In | 4147 | When Emacs runs on X window system, it supports the X Direct Save |
| 4146 | @c particular, the two calls to the function basically sound | 4148 | (@acronym{XDS}) protocol, which allows users to save a file by |
| 4147 | @c identical, so it is unclear how should the function distinguish | 4149 | dragging and dropping it onto an Emacs window, such as a Dired window. |
| 4148 | @c between the first and the second one. The description of who asks | 4150 | To comply with the unique requirements of @acronym{XDS}, these |
| 4149 | @c whom to do what is also very hard to understand. Needs rewording, | 4151 | drag-and-drop requests are processed specially: instead of being |
| 4150 | @c and needs shorter sentences. Perhaps examples could help. | 4152 | handled according to @code{x-dnd-types-alist}, they are handled by the |
| 4151 | However, @code{x-dnd-types-alist} does not handle a special kind of | 4153 | @dfn{direct-save function} that is the value of the variable |
| 4152 | drop sent by a program that wants Emacs to tell it where to save a | 4154 | @code{x-dnd-direct-save-function}. The value should be a function of |
| 4153 | file in a specific location determined by the user. These drops are | 4155 | two arguments, @var{need-name} and @var{filename}. The @acronym{XDS} |
| 4154 | instead handled by a function that is the value of the variable | 4156 | protocol uses a two-step procedure for dragging files: |
| 4155 | @code{x-dnd-direct-save-function}. This function should accept two arguments. | 4157 | |
| 4156 | If the first argument is non-@code{nil}, then the second argument is a | 4158 | @enumerate 1 |
| 4157 | file name to save (with leading directories) that the other | 4159 | @item |
| 4158 | program recommends, and the | 4160 | The application from which the file is dragged asks Emacs to provide |
| 4159 | function should return the full file name under which it should be | 4161 | the full file name under which to save the file. For this purpose, |
| 4160 | saved. After the function completes, Emacs will ask the other program | 4162 | the direct-save function is called with its first argument |
| 4161 | to save the file under the name that was returned, and if the file was | 4163 | @var{need-name} non-@code{nil}, and the second argument @var{filename} |
| 4162 | successfully saved, call the function again with the first argument | 4164 | set to the basename of the file to be saved. It should return the |
| 4163 | set to a non-@code{nil} value and the second argument set to the file | 4165 | fully-expanded absolute file name under which to save the file. For |
| 4164 | name that was returned. The function should then perform whatever | 4166 | example, if a file is dragged to a Dired window, the natural directory |
| 4165 | action is appropriate (i.e., opening the file or refreshing a | 4167 | for the file is the directory of the file shown at location of the |
| 4166 | directory listing.) | 4168 | drop. If saving the file is not possible for some reason, the |
| 4169 | function should return @code{nil}, which will cancel the drag-and-drop | ||
| 4170 | operation. | ||
| 4171 | |||
| 4172 | @item | ||
| 4173 | The application from which the file is dragged saves the file under | ||
| 4174 | the name returned by the first call to the direct-save function. If | ||
| 4175 | it succeeds in saving the file, the direct-save function is called | ||
| 4176 | again, this time with the first argument @var{need-name} set to | ||
| 4177 | @code{nil} and the second argument @var{filename} set to the full | ||
| 4178 | absolute name of the saved file. The function is then expected to do | ||
| 4179 | whatever is needed given the fact that file was saved. For example, | ||
| 4180 | Dired should update the directory on display by showing the new file | ||
| 4181 | there. | ||
| 4182 | @end enumerate | ||
| 4183 | |||
| 4184 | The default value of @code{x-dnd-direct-save-function} is | ||
| 4185 | @code{x-dnd-save-direct}. | ||
| 4186 | |||
| 4187 | @defun x-dnd-save-direct need-name filename | ||
| 4188 | When called with the @var{need-name} argument non-@code{nil}, this | ||
| 4189 | function prompts the user for the absolute file name under which it | ||
| 4190 | should be saved. If the specified file already exists, it | ||
| 4191 | additionally asks the user whether to overwrite it, and returns the | ||
| 4192 | absolute file name only if the user confirms the overwriting. | ||
| 4193 | |||
| 4194 | When called with the @var{need-name} argument @code{nil}, it reverts | ||
| 4195 | the Dired listing if the current buffer is in Dired mode or one of its | ||
| 4196 | descendants, and otherwise visits the file by calling @code{find-file} | ||
| 4197 | (@pxref{Visiting Functions}). | ||
| 4198 | @end defun | ||
| 4199 | |||
| 4200 | @defun x-dnd-save-direct-immediately need-name filename | ||
| 4201 | This function works like @code{x-dnd-save-direct}, but when called | ||
| 4202 | with its @var{need-name} argument non-@code{nil}, it doesn't prompt | ||
| 4203 | the user for the full name of the file to be saved; instead, it | ||
| 4204 | returns its argument @var{filename} expanded against the current | ||
| 4205 | buffer's default directory (@pxref{File Name Expansion}). (It still | ||
| 4206 | asks for confirmation if a file by that name already exists in the | ||
| 4207 | default directory.) | ||
| 4208 | @end defun | ||
| 4167 | 4209 | ||
| 4168 | @cindex initiating drag-and-drop | 4210 | @cindex initiating drag-and-drop |
| 4169 | On capable window systems, Emacs also supports dragging contents | 4211 | On capable window systems, Emacs also supports dragging contents |
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index b213b155249..9286a1858cf 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el | |||
| @@ -34,20 +34,20 @@ | |||
| 34 | 34 | ||
| 35 | ;;; Customizable variables | 35 | ;;; Customizable variables |
| 36 | (defcustom x-dnd-test-function #'x-dnd-default-test-function | 36 | (defcustom x-dnd-test-function #'x-dnd-default-test-function |
| 37 | "The function drag and drop uses to determine if to accept or reject a drop. | 37 | "Function to be used by drag-and-drop to determine whether to accept a drop. |
| 38 | The function takes three arguments, WINDOW, ACTION and TYPES. | 38 | The function takes three arguments: WINDOW, ACTION, and TYPES. |
| 39 | WINDOW is where the mouse is when the function is called. WINDOW | 39 | WINDOW is where the window under the mouse is when the function is called. |
| 40 | may be a frame if the mouse isn't over a real window (i.e. menu | 40 | WINDOW may be a frame if the mouse isn't over a real window (e.g., menu |
| 41 | bar, tool bar or scroll bar). ACTION is the suggested action | 41 | bar, tool bar, scroll bar, etc.). |
| 42 | from the drag and drop source, one of the symbols move, copy, | 42 | ACTION is the suggested action from the drag and drop source, one of the |
| 43 | link or ask. TYPES is a vector of available types for the drop. | 43 | symbols `move', `copy', `link' or `ask'. |
| 44 | 44 | TYPES is a vector of available types for the drop. | |
| 45 | Each element of TYPE should either be a string (containing the | 45 | Each element of TYPES should either be a string (containing the |
| 46 | name of the type's X atom), or a symbol, whose name will be used. | 46 | name of the type's X atom), or a symbol, whose name will be used. |
| 47 | 47 | ||
| 48 | The function shall return nil to reject the drop or a cons with | 48 | The function shall return nil to reject the drop or a cons with |
| 49 | two values, the wanted action as car and the wanted type as cdr. | 49 | two values, the wanted action as `car' and the wanted type as `cdr'. |
| 50 | The wanted action can be copy, move, link, ask or private. | 50 | The wanted action can be `copy', `move', `link', `ask' or `private'. |
| 51 | 51 | ||
| 52 | The default value for this variable is `x-dnd-default-test-function'." | 52 | The default value for this variable is `x-dnd-default-test-function'." |
| 53 | :version "22.1" | 53 | :version "22.1" |
| @@ -70,14 +70,18 @@ The default value for this variable is `x-dnd-default-test-function'." | |||
| 70 | (,(purecopy "DndTypeFile") . x-dnd-handle-offix-file) | 70 | (,(purecopy "DndTypeFile") . x-dnd-handle-offix-file) |
| 71 | (,(purecopy "DndTypeFiles") . x-dnd-handle-offix-files) | 71 | (,(purecopy "DndTypeFiles") . x-dnd-handle-offix-files) |
| 72 | (,(purecopy "DndTypeText") . dnd-insert-text)) | 72 | (,(purecopy "DndTypeText") . dnd-insert-text)) |
| 73 | "Which function to call to handle a drop of that type. | 73 | "Functions to call to handle drag-and-drop of known types. |
| 74 | If the type for the drop is not present, or the function is nil, | 74 | If the type of the drop is not present in the alist, or the |
| 75 | the drop is rejected. The function takes three arguments, WINDOW, ACTION | 75 | function corresponding to the type is nil, the drop of that |
| 76 | and DATA. WINDOW is where the drop occurred, ACTION is the action for | 76 | type will be rejected. |
| 77 | this drop (copy, move, link, private or ask) as determined by a previous | 77 | |
| 78 | call to `x-dnd-test-function'. DATA is the drop data. | 78 | Each function takes three arguments: WINDOW, ACTION, and DATA. |
| 79 | The function shall return the action used (copy, move, link or private) | 79 | WINDOW is the window where the drop occurred. |
| 80 | if drop is successful, nil if not." | 80 | ACTION is the action for this drop (`copy', `move', `link', `private' |
| 81 | or `ask'), as determined by a previous call to `x-dnd-test-function'. | ||
| 82 | DATA is the drop data. | ||
| 83 | The function shall return the action it used (one of the above, | ||
| 84 | excluding `ask') if drop is successful, nil if not." | ||
| 81 | :version "22.1" | 85 | :version "22.1" |
| 82 | :type 'alist | 86 | :type 'alist |
| 83 | :group 'x) | 87 | :group 'x) |
| @@ -122,22 +126,27 @@ like xterm) for text." | |||
| 122 | :group 'x) | 126 | :group 'x) |
| 123 | 127 | ||
| 124 | (defcustom x-dnd-direct-save-function #'x-dnd-save-direct | 128 | (defcustom x-dnd-direct-save-function #'x-dnd-save-direct |
| 125 | "Function called when a file is dropped that Emacs must save. | 129 | "Function called when a file is dropped via XDS protocol. |
| 126 | It is called with two arguments: the first is either nil or t, | 130 | The value should be a function of two arguments that supports |
| 127 | and the second is a string. | 131 | the X Direct Save (XDS) protocol. The function will be called |
| 128 | 132 | twice during the protocol execution. | |
| 129 | If the first argument is t, the second argument is the name the | 133 | |
| 130 | dropped file should be saved under. The function should return a | 134 | When the function is called with the first argument non-nil, |
| 131 | complete file name describing where the file should be saved. | 135 | it should return an absolute file name whose base name is |
| 132 | 136 | the value of the second argument, a string. The return value | |
| 133 | It can also return nil, which means to cancel the drop. | 137 | is the file name for the dragged file to be saved. The function |
| 134 | 138 | can also return nil if saving the file should be refused for some | |
| 135 | If the first argument is nil, the second is the name of the file | 139 | reason; in that case the drop will be canceled. |
| 136 | that was dropped." | 140 | |
| 141 | When the function is called with the first argument nil, the | ||
| 142 | second argument specifies the file name where the file was saved; | ||
| 143 | the function should then do whatever is appropriate when such a | ||
| 144 | file is saved, like show the file in the Dired buffer or visit | ||
| 145 | the file." | ||
| 137 | :version "29.1" | 146 | :version "29.1" |
| 138 | :type '(choice (const :tag "Prompt for name before saving" | 147 | :type '(choice (const :tag "Prompt for file name to save" |
| 139 | x-dnd-save-direct) | 148 | x-dnd-save-direct) |
| 140 | (const :tag "Save and open immediately without prompting" | 149 | (const :tag "Save in `default-directory' without prompting" |
| 141 | x-dnd-save-direct-immediately) | 150 | x-dnd-save-direct-immediately) |
| 142 | (function :tag "Other function")) | 151 | (function :tag "Other function")) |
| 143 | :group 'x) | 152 | :group 'x) |
| @@ -222,14 +231,14 @@ any protocol specific data.") | |||
| 222 | (cdr (x-dnd-get-state-cons-for-frame frame-or-window))) | 231 | (cdr (x-dnd-get-state-cons-for-frame frame-or-window))) |
| 223 | 232 | ||
| 224 | (defun x-dnd-default-test-function (_window _action types) | 233 | (defun x-dnd-default-test-function (_window _action types) |
| 225 | "The default test function for drag and drop. | 234 | "The default test function for drag-and-drop. |
| 226 | WINDOW is where the mouse is when this function is called. It | 235 | WINDOW is where the mouse is when this function is called. It |
| 227 | may be a frame if the mouse is over the menu bar, scroll bar or | 236 | may be a frame if the mouse is over the menu bar, scroll bar or |
| 228 | tool bar. ACTION is the suggested action from the source, and | 237 | tool bar. ACTION is the suggested action from the source, and |
| 229 | TYPES are the types the drop data can have. This function only | 238 | TYPES are the types the drop data can have. This function only |
| 230 | accepts drops with types in `x-dnd-known-types'. It always | 239 | accepts drops with types in `x-dnd-known-types'. It always |
| 231 | returns the action `private', unless `types' contains a value | 240 | returns the action `private', unless `types' contains a value |
| 232 | inside `x-dnd-copy-types'." | 241 | inside `x-dnd-copy-types', in which case it may return `copy'." |
| 233 | (let ((type (x-dnd-choose-type types))) | 242 | (let ((type (x-dnd-choose-type types))) |
| 234 | (when type (let ((list x-dnd-copy-types)) | 243 | (when type (let ((list x-dnd-copy-types)) |
| 235 | (catch 'out | 244 | (catch 'out |
| @@ -1564,17 +1573,24 @@ was taken, or the direct save failed." | |||
| 1564 | (when (not (equal file-name original-file-name)) | 1573 | (when (not (equal file-name original-file-name)) |
| 1565 | (delete-file file-name))))) | 1574 | (delete-file file-name))))) |
| 1566 | 1575 | ||
| 1567 | (defun x-dnd-save-direct (need-name name) | 1576 | (defun x-dnd-save-direct (need-name filename) |
| 1568 | "Handle dropping a file that should be saved immediately. | 1577 | "Handle dropping a file FILENAME that should be saved first, asking the user. |
| 1569 | NEED-NAME tells whether or not the file was not yet saved. NAME | 1578 | NEED-NAME non-nil means the caller requests the full absolute |
| 1570 | is either the name of the file, or the name the drop source wants | 1579 | file name of FILENAME under which to save it; FILENAME is just |
| 1571 | us to save under. | 1580 | the base name in that case. The function then prompts the user |
| 1581 | for where to save to file and returns the result to the caller. | ||
| 1582 | |||
| 1583 | NEED-NAME nil means the file was saved as FILENAME (which should | ||
| 1584 | be the full absolute file name in that case). The function then | ||
| 1585 | refreshes the Dired display, if the current buffer is in Dired | ||
| 1586 | mode, or visits the file otherwise. | ||
| 1572 | 1587 | ||
| 1573 | Prompt the user for a file name, then open it." | 1588 | This function is intended to be the value of `x-dnd-direct-save-function', |
| 1589 | which see." | ||
| 1574 | (if need-name | 1590 | (if need-name |
| 1575 | (let ((file-name (read-file-name "Write file: " | 1591 | (let ((file-name (read-file-name "Write file: " |
| 1576 | default-directory | 1592 | default-directory |
| 1577 | nil nil name))) | 1593 | nil nil filename))) |
| 1578 | (when (file-exists-p file-name) | 1594 | (when (file-exists-p file-name) |
| 1579 | (unless (y-or-n-p (format-message | 1595 | (unless (y-or-n-p (format-message |
| 1580 | "File `%s' exists; overwrite? " file-name)) | 1596 | "File `%s' exists; overwrite? " file-name)) |
| @@ -1584,18 +1600,18 @@ Prompt the user for a file name, then open it." | |||
| 1584 | ;; interface can be found. | 1600 | ;; interface can be found. |
| 1585 | (if (derived-mode-p 'dired-mode) | 1601 | (if (derived-mode-p 'dired-mode) |
| 1586 | (revert-buffer) | 1602 | (revert-buffer) |
| 1587 | (find-file name)))) | 1603 | (find-file filename)))) |
| 1588 | 1604 | ||
| 1589 | (defun x-dnd-save-direct-immediately (need-name name) | 1605 | (defun x-dnd-save-direct-immediately (need-name filename) |
| 1590 | "Save and open a dropped file, like `x-dnd-save-direct'. | 1606 | "Handle dropping a file FILENAME that should be saved first. |
| 1591 | NEED-NAME tells whether or not the file was not yet saved. NAME | 1607 | Like `x-dnd-save-direct', but do not prompt for the file name; |
| 1592 | is either the name of the file, or the name the drop source wants | 1608 | instead, return its absolute file name for saving in the current |
| 1593 | us to save under. | 1609 | directory. |
| 1594 | 1610 | ||
| 1595 | Unlike `x-dnd-save-direct', do not prompt for the name by which | 1611 | This function is intended to be the value of `x-dnd-direct-save-function', |
| 1596 | to save the file. Simply save it in the current directory." | 1612 | which see." |
| 1597 | (if need-name | 1613 | (if need-name |
| 1598 | (let ((file-name (expand-file-name name))) | 1614 | (let ((file-name (expand-file-name filename))) |
| 1599 | (when (file-exists-p file-name) | 1615 | (when (file-exists-p file-name) |
| 1600 | (unless (y-or-n-p (format-message | 1616 | (unless (y-or-n-p (format-message |
| 1601 | "File `%s' exists; overwrite? " file-name)) | 1617 | "File `%s' exists; overwrite? " file-name)) |
| @@ -1605,7 +1621,7 @@ to save the file. Simply save it in the current directory." | |||
| 1605 | ;; interface can be found. | 1621 | ;; interface can be found. |
| 1606 | (if (derived-mode-p 'dired-mode) | 1622 | (if (derived-mode-p 'dired-mode) |
| 1607 | (revert-buffer) | 1623 | (revert-buffer) |
| 1608 | (find-file name)))) | 1624 | (find-file filename)))) |
| 1609 | 1625 | ||
| 1610 | (defun x-dnd-handle-octet-stream-for-drop (save-to) | 1626 | (defun x-dnd-handle-octet-stream-for-drop (save-to) |
| 1611 | "Save the contents of the XDS selection to SAVE-TO. | 1627 | "Save the contents of the XDS selection to SAVE-TO. |