1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-05 11:45:45 +00:00

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.
This commit is contained in:
Eli Zaretskii 2023-04-08 18:36:23 +03:00
parent 14d1c00e80
commit 08cda286c3
2 changed files with 131 additions and 73 deletions

View File

@ -4112,7 +4112,7 @@ has the same meaning as the @var{action} argument to
Emacs implements receiving text and URLs individually for each
window system, and does not by default support receiving other kinds
of data as drops. To support receiving other kinds of data, use the
X-specific interface described below:
X-specific interface described below.
@vindex x-dnd-test-function
@vindex x-dnd-known-types
@ -4141,29 +4141,71 @@ depending on the specific drag-and-drop protocol being used. For
example, the data type used for plain text may be either
@code{"STRING"} or @code{"text/plain"}.
@cindex XDS
@cindex direct save protocol
@vindex x-dnd-direct-save-function
@c FIXME: This description is overly-complicated and confusing. In
@c particular, the two calls to the function basically sound
@c identical, so it is unclear how should the function distinguish
@c between the first and the second one. The description of who asks
@c whom to do what is also very hard to understand. Needs rewording,
@c and needs shorter sentences. Perhaps examples could help.
However, @code{x-dnd-types-alist} does not handle a special kind of
drop sent by a program that wants Emacs to tell it where to save a
file in a specific location determined by the user. These drops are
instead handled by a function that is the value of the variable
@code{x-dnd-direct-save-function}. This function should accept two arguments.
If the first argument is non-@code{nil}, then the second argument is a
file name to save (with leading directories) that the other
program recommends, and the
function should return the full file name under which it should be
saved. After the function completes, Emacs will ask the other program
to save the file under the name that was returned, and if the file was
successfully saved, call the function again with the first argument
set to a non-@code{nil} value and the second argument set to the file
name that was returned. The function should then perform whatever
action is appropriate (i.e., opening the file or refreshing a
directory listing.)
When Emacs runs on X window system, it supports the X Direct Save
(@acronym{XDS}) protocol, which allows users to save a file by
dragging and dropping it onto an Emacs window, such as a Dired window.
To comply with the unique requirements of @acronym{XDS}, these
drag-and-drop requests are processed specially: instead of being
handled according to @code{x-dnd-types-alist}, they are handled by the
@dfn{direct-save function} that is the value of the variable
@code{x-dnd-direct-save-function}. The value should be a function of
two arguments, @var{need-name} and @var{filename}. The @acronym{XDS}
protocol uses a two-step procedure for dragging files:
@enumerate 1
@item
The application from which the file is dragged asks Emacs to provide
the full file name under which to save the file. For this purpose,
the direct-save function is called with its first argument
@var{need-name} non-@code{nil}, and the second argument @var{filename}
set to the basename of the file to be saved. It should return the
fully-expanded absolute file name under which to save the file. For
example, if a file is dragged to a Dired window, the natural directory
for the file is the directory of the file shown at location of the
drop. If saving the file is not possible for some reason, the
function should return @code{nil}, which will cancel the drag-and-drop
operation.
@item
The application from which the file is dragged saves the file under
the name returned by the first call to the direct-save function. If
it succeeds in saving the file, the direct-save function is called
again, this time with the first argument @var{need-name} set to
@code{nil} and the second argument @var{filename} set to the full
absolute name of the saved file. The function is then expected to do
whatever is needed given the fact that file was saved. For example,
Dired should update the directory on display by showing the new file
there.
@end enumerate
The default value of @code{x-dnd-direct-save-function} is
@code{x-dnd-save-direct}.
@defun x-dnd-save-direct need-name filename
When called with the @var{need-name} argument non-@code{nil}, this
function prompts the user for the absolute file name under which it
should be saved. If the specified file already exists, it
additionally asks the user whether to overwrite it, and returns the
absolute file name only if the user confirms the overwriting.
When called with the @var{need-name} argument @code{nil}, it reverts
the Dired listing if the current buffer is in Dired mode or one of its
descendants, and otherwise visits the file by calling @code{find-file}
(@pxref{Visiting Functions}).
@end defun
@defun x-dnd-save-direct-immediately need-name filename
This function works like @code{x-dnd-save-direct}, but when called
with its @var{need-name} argument non-@code{nil}, it doesn't prompt
the user for the full name of the file to be saved; instead, it
returns its argument @var{filename} expanded against the current
buffer's default directory (@pxref{File Name Expansion}). (It still
asks for confirmation if a file by that name already exists in the
default directory.)
@end defun
@cindex initiating drag-and-drop
On capable window systems, Emacs also supports dragging contents

View File

@ -34,20 +34,20 @@
;;; Customizable variables
(defcustom x-dnd-test-function #'x-dnd-default-test-function
"The function drag and drop uses to determine if to accept or reject a drop.
The function takes three arguments, WINDOW, ACTION and TYPES.
WINDOW is where the mouse is when the function is called. WINDOW
may be a frame if the mouse isn't over a real window (i.e. menu
bar, tool bar or scroll bar). ACTION is the suggested action
from the drag and drop source, one of the symbols move, copy,
link or ask. TYPES is a vector of available types for the drop.
Each element of TYPE should either be a string (containing the
"Function to be used by drag-and-drop to determine whether to accept a drop.
The function takes three arguments: WINDOW, ACTION, and TYPES.
WINDOW is where the window under the mouse is when the function is called.
WINDOW may be a frame if the mouse isn't over a real window (e.g., menu
bar, tool bar, scroll bar, etc.).
ACTION is the suggested action from the drag and drop source, one of the
symbols `move', `copy', `link' or `ask'.
TYPES is a vector of available types for the drop.
Each element of TYPES should either be a string (containing the
name of the type's X atom), or a symbol, whose name will be used.
The function shall return nil to reject the drop or a cons with
two values, the wanted action as car and the wanted type as cdr.
The wanted action can be copy, move, link, ask or private.
two values, the wanted action as `car' and the wanted type as `cdr'.
The wanted action can be `copy', `move', `link', `ask' or `private'.
The default value for this variable is `x-dnd-default-test-function'."
:version "22.1"
@ -70,14 +70,18 @@ The default value for this variable is `x-dnd-default-test-function'."
(,(purecopy "DndTypeFile") . x-dnd-handle-offix-file)
(,(purecopy "DndTypeFiles") . x-dnd-handle-offix-files)
(,(purecopy "DndTypeText") . dnd-insert-text))
"Which function to call to handle a drop of that type.
If the type for the drop is not present, or the function is nil,
the drop is rejected. The function takes three arguments, WINDOW, ACTION
and DATA. WINDOW is where the drop occurred, ACTION is the action for
this drop (copy, move, link, private or ask) as determined by a previous
call to `x-dnd-test-function'. DATA is the drop data.
The function shall return the action used (copy, move, link or private)
if drop is successful, nil if not."
"Functions to call to handle drag-and-drop of known types.
If the type of the drop is not present in the alist, or the
function corresponding to the type is nil, the drop of that
type will be rejected.
Each function takes three arguments: WINDOW, ACTION, and DATA.
WINDOW is the window where the drop occurred.
ACTION is the action for this drop (`copy', `move', `link', `private'
or `ask'), as determined by a previous call to `x-dnd-test-function'.
DATA is the drop data.
The function shall return the action it used (one of the above,
excluding `ask') if drop is successful, nil if not."
:version "22.1"
:type 'alist
:group 'x)
@ -122,22 +126,27 @@ like xterm) for text."
:group 'x)
(defcustom x-dnd-direct-save-function #'x-dnd-save-direct
"Function called when a file is dropped that Emacs must save.
It is called with two arguments: the first is either nil or t,
and the second is a string.
"Function called when a file is dropped via XDS protocol.
The value should be a function of two arguments that supports
the X Direct Save (XDS) protocol. The function will be called
twice during the protocol execution.
If the first argument is t, the second argument is the name the
dropped file should be saved under. The function should return a
complete file name describing where the file should be saved.
When the function is called with the first argument non-nil,
it should return an absolute file name whose base name is
the value of the second argument, a string. The return value
is the file name for the dragged file to be saved. The function
can also return nil if saving the file should be refused for some
reason; in that case the drop will be canceled.
It can also return nil, which means to cancel the drop.
If the first argument is nil, the second is the name of the file
that was dropped."
When the function is called with the first argument nil, the
second argument specifies the file name where the file was saved;
the function should then do whatever is appropriate when such a
file is saved, like show the file in the Dired buffer or visit
the file."
:version "29.1"
:type '(choice (const :tag "Prompt for name before saving"
:type '(choice (const :tag "Prompt for file name to save"
x-dnd-save-direct)
(const :tag "Save and open immediately without prompting"
(const :tag "Save in `default-directory' without prompting"
x-dnd-save-direct-immediately)
(function :tag "Other function"))
:group 'x)
@ -222,14 +231,14 @@ any protocol specific data.")
(cdr (x-dnd-get-state-cons-for-frame frame-or-window)))
(defun x-dnd-default-test-function (_window _action types)
"The default test function for drag and drop.
"The default test function for drag-and-drop.
WINDOW is where the mouse is when this function is called. It
may be a frame if the mouse is over the menu bar, scroll bar or
tool bar. ACTION is the suggested action from the source, and
TYPES are the types the drop data can have. This function only
accepts drops with types in `x-dnd-known-types'. It always
returns the action `private', unless `types' contains a value
inside `x-dnd-copy-types'."
inside `x-dnd-copy-types', in which case it may return `copy'."
(let ((type (x-dnd-choose-type types)))
(when type (let ((list x-dnd-copy-types))
(catch 'out
@ -1564,17 +1573,24 @@ was taken, or the direct save failed."
(when (not (equal file-name original-file-name))
(delete-file file-name)))))
(defun x-dnd-save-direct (need-name name)
"Handle dropping a file that should be saved immediately.
NEED-NAME tells whether or not the file was not yet saved. NAME
is either the name of the file, or the name the drop source wants
us to save under.
(defun x-dnd-save-direct (need-name filename)
"Handle dropping a file FILENAME that should be saved first, asking the user.
NEED-NAME non-nil means the caller requests the full absolute
file name of FILENAME under which to save it; FILENAME is just
the base name in that case. The function then prompts the user
for where to save to file and returns the result to the caller.
Prompt the user for a file name, then open it."
NEED-NAME nil means the file was saved as FILENAME (which should
be the full absolute file name in that case). The function then
refreshes the Dired display, if the current buffer is in Dired
mode, or visits the file otherwise.
This function is intended to be the value of `x-dnd-direct-save-function',
which see."
(if need-name
(let ((file-name (read-file-name "Write file: "
default-directory
nil nil name)))
nil nil filename)))
(when (file-exists-p file-name)
(unless (y-or-n-p (format-message
"File `%s' exists; overwrite? " file-name))
@ -1584,18 +1600,18 @@ Prompt the user for a file name, then open it."
;; interface can be found.
(if (derived-mode-p 'dired-mode)
(revert-buffer)
(find-file name))))
(find-file filename))))
(defun x-dnd-save-direct-immediately (need-name name)
"Save and open a dropped file, like `x-dnd-save-direct'.
NEED-NAME tells whether or not the file was not yet saved. NAME
is either the name of the file, or the name the drop source wants
us to save under.
(defun x-dnd-save-direct-immediately (need-name filename)
"Handle dropping a file FILENAME that should be saved first.
Like `x-dnd-save-direct', but do not prompt for the file name;
instead, return its absolute file name for saving in the current
directory.
Unlike `x-dnd-save-direct', do not prompt for the name by which
to save the file. Simply save it in the current directory."
This function is intended to be the value of `x-dnd-direct-save-function',
which see."
(if need-name
(let ((file-name (expand-file-name name)))
(let ((file-name (expand-file-name filename)))
(when (file-exists-p file-name)
(unless (y-or-n-p (format-message
"File `%s' exists; overwrite? " file-name))
@ -1605,7 +1621,7 @@ to save the file. Simply save it in the current directory."
;; interface can be found.
(if (derived-mode-p 'dired-mode)
(revert-buffer)
(find-file name))))
(find-file filename))))
(defun x-dnd-handle-octet-stream-for-drop (save-to)
"Save the contents of the XDS selection to SAVE-TO.