From 2ce686c049a7a35cdc3eb87626d8a94539388a35 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 4 Jun 2022 15:45:41 +0800 Subject: [PATCH] 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. --- lisp/term/ns-win.el | 20 +++++++++++++----- src/nsselect.m | 50 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el index a36d5d11e79..2e021b9b29c 100644 --- a/lisp/term/ns-win.el +++ b/lisp/term/ns-win.el @@ -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) diff --git a/src/nsselect.m b/src/nsselect.m index a4129b12f03..a719eef4e86 100644 --- a/src/nsselect.m +++ b/src/nsselect.m @@ -562,8 +562,12 @@ ns_decode_data_to_pasteboard (Lisp_Object type, Lisp_Object data, 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 @@ ns_decode_data_to_pasteboard (Lisp_Object type, Lisp_Object data, } 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 @@ ns_decode_data_to_pasteboard (Lisp_Object type, Lisp_Object data, [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 @@ the meaning of DATA: 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. -- 2.39.2