Support dragging multiple files on NS

This has to use a deprecated pasteboard type, since Emacs uses
the "old" (but not deprecated) dragImage: method for
drag-and-drop, which can't drop file URLs.

* lisp/term/ns-win.el (x-begin-drag): Update accordingly.
* src/nsselect.m (ns_decode_data_to_pasteboard):
(Fns_begin_drag): Allow files to be a list of filenames as well.
This commit is contained in:
Po Lu 2022-06-04 15:45:41 +08:00
parent 1289d0c3dd
commit 2ce686c049
2 changed files with 57 additions and 13 deletions

View file

@ -905,11 +905,21 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.")
(push (cons 'string ns-dnd-selection-value) pasteboard))
(when (and (member "FILE_NAME" targets)
(file-exists-p ns-dnd-selection-value))
(push (cons 'file
(url-encode-url (concat "file://"
(expand-file-name
ns-dnd-selection-value))))
pasteboard))
(let ((value (if (stringp ns-dnd-selection-value)
(or (get-text-property 0 'FILE_NAME
ns-dnd-selection-value)
ns-dnd-selection-value)
ns-dnd-selection-value)))
(if (vectorp value)
(push (cons 'file
(cl-loop for file across value
collect (expand-file-name file)))
pasteboard)
(push (cons 'file
(url-encode-url (concat "file://"
(expand-file-name
ns-dnd-selection-value))))
pasteboard))))
(ns-begin-drag frame pasteboard action return-frame allow-current-frame)))
(defun ns-handle-drag-motion (frame x y)

View file

@ -562,8 +562,12 @@ Updated by Christian Limpach (chris@nice.ch)
NSPasteboard *pasteboard)
{
NSArray *types, *new;
NSMutableArray *temp;
Lisp_Object tem;
specpdl_ref count;
types = [pasteboard types];
count = SPECPDL_INDEX ();
CHECK_SYMBOL (type);
@ -580,10 +584,11 @@ Updated by Christian Limpach (chris@nice.ch)
}
else if (EQ (type, Qfile))
{
CHECK_STRING (data);
#if NS_USE_NSPasteboardTypeFileURL
new = [types arrayByAddingObject: NSPasteboardTypeFileURL];
if (CONSP (data))
new = [types arrayByAddingObject: NSPasteboardTypeURL];
else
new = [types arrayByAddingObject: NSPasteboardTypeFileURL];
#else
new = [types arrayByAddingObject: NSFilenamesPboardType];
#endif
@ -591,13 +596,41 @@ Updated by Christian Limpach (chris@nice.ch)
[pasteboard declareTypes: new
owner: nil];
if (STRINGP (data))
{
#if NS_USE_NSPasteboardTypeFileURL
[pasteboard setString: [NSString stringWithLispString: data]
forType: NSPasteboardTypeFileURL];
[pasteboard setString: [NSString stringWithLispString: data]
forType: NSPasteboardTypeFileURL];
#else
[pasteboard setString: [NSString stringWithLispString: data]
forType: NSFilenamesPboardType];
[pasteboard setString: [NSString stringWithLispString: data]
forType: NSFilenamesPboardType];
#endif
}
else
{
CHECK_LIST (data);
temp = [[NSMutableArray alloc] init];
record_unwind_protect_ptr (ns_release_object, temp);
for (tem = data; CONSP (tem); tem = XCDR (tem))
{
CHECK_STRING (XCAR (tem));
[temp addObject: [NSString stringWithLispString: XCAR (tem)]];
}
CHECK_LIST_END (tem, data);
#if NS_USE_NSPasteboardTypeFileURL
[pasteboard setPropertyList: temp
/* We have to use this deprecated pasteboard
type, since Apple doesn't let us use
dragImage:at: to drag multiple file URLs. */
forType: @"NSFilenamesPboardType"];
#else
[pasteboard setPropertyList: temp
forType: NSFilenamesPboardType];
#endif
unbind_to (count, Qnil);
}
}
else
signal_error ("Unknown pasteboard type", type);
@ -673,7 +706,8 @@ Updated by Christian Limpach (chris@nice.ch)
be dragged to another program.
- `file' means DATA should be a file URL that will be dragged to
another program.
another program. DATA may also be a list of file names; that
means each file in the list will be dragged to another program.
ACTION is the action that will be taken by the drop target towards the
data inside PBOARD.