This event occurs when a user drags an object from another application
into an Emacs frame. The default behavior is to open a file in the
window under the mouse, or to insert text at point of the window under
-the mouse. It may sometimes be necessary to use the @key{Meta} key in
-conjunction with dragging to force text insertion.
+the mouse.
+
+The sending application has some limited ability to decide how Emacs
+handles the sent object, but the user may override the default
+behaviour by holding one or more modifier key.
+
+@table @kbd
+@item control
+Insert as text in the current buffer. If the object is a file, this
+will insert the filename.
+@item alt/option
+Attempt to open the object as though it is a file or URL.
+@item super/command
+Perform the default action for the type. This can be useful when an
+application is overriding the default behaviour.
+@end table
+
+The modifier keys listed above are defined by macOS and are unaffected
+by user changes to the modifiers in Emacs.
@item ns-change-font
This event occurs when the user selects a font in a Nextstep font
(find-file f)))))
-(defun ns-drag-n-drop (event &optional new-frame force-text)
+(defun ns-drag-n-drop (event)
"Edit the files listed in the drag-n-drop EVENT.
-Switch to a buffer editing the last file dropped."
+Switch to a buffer editing the last file dropped, or insert the
+string dropped into the current buffer."
(interactive "e")
(let* ((window (posn-window (event-start event)))
(arg (car (cdr (cdr event))))
(type (car arg))
- (data (car (cdr arg)))
- (url-or-string (cond ((eq type 'file)
- (concat "file:" data))
- (t data))))
+ (operations (car (cdr arg)))
+ (objects (cdr (cdr arg)))
+ (string (mapconcat 'identity objects "\n")))
(set-frame-selected-window nil window)
- (when new-frame
- (select-frame (make-frame)))
(raise-frame)
(setq window (selected-window))
- (if force-text
- (dnd-insert-text window 'private data)
- (dnd-handle-one-url window 'private url-or-string))))
-
-
-(defun ns-drag-n-drop-other-frame (event)
- "Edit the files listed in the drag-n-drop EVENT, in other frames.
-May create new frames, or reuse existing ones. The frame editing
-the last file dropped is selected."
- (interactive "e")
- (ns-drag-n-drop event t))
-
-(defun ns-drag-n-drop-as-text (event)
- "Drop the data in EVENT as text."
- (interactive "e")
- (ns-drag-n-drop event nil t))
-
-(defun ns-drag-n-drop-as-text-other-frame (event)
- "Drop the data in EVENT as text in a new frame."
- (interactive "e")
- (ns-drag-n-drop event t t))
+ (cond ((memq 'ns-drag-operation-generic operations)
+ ;; Perform the default action for the type.
+ (if (eq type 'file)
+ (dolist (data objects)
+ (dnd-handle-one-url window 'private (concat "file:" data)))
+ (dnd-insert-text window 'private string)))
+ ((memq 'ns-drag-operation-copy operations)
+ ;; Try to open the file/URL. If type is nil, try to open
+ ;; it as a URL anyway.
+ (dolist (data objects)
+ (dnd-handle-one-url window 'private (if (eq type 'file)
+ (concat "file:" data)
+ data))))
+ (t
+ ;; Insert the text as is.
+ (dnd-insert-text window 'private string)))))
(global-set-key [drag-n-drop] 'ns-drag-n-drop)
-(global-set-key [C-drag-n-drop] 'ns-drag-n-drop-other-frame)
-(global-set-key [M-drag-n-drop] 'ns-drag-n-drop-as-text)
-(global-set-key [C-M-drag-n-drop] 'ns-drag-n-drop-as-text-other-frame)
;;;; Frame-related functions.
NSEvent *theEvent = [[self window] currentEvent];
NSPoint position;
NSDragOperation op = [sender draggingSourceOperationMask];
- int modifiers = 0;
+ Lisp_Object operations = Qnil;
+ Lisp_Object strings = Qnil;
+ Lisp_Object type_sym;
NSTRACE ("[EmacsView performDragOperation:]");
pb = [sender draggingPasteboard];
type = [pb availableTypeFromArray: ns_drag_types];
- if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
- // URL drags contain all operations (0xf), don't allow all to be set.
- (op & 0xf) != 0xf)
- {
- if (op & NSDragOperationLink)
- modifiers |= NSEventModifierFlagControl;
- if (op & NSDragOperationCopy)
- modifiers |= NSEventModifierFlagOption;
- if (op & NSDragOperationGeneric)
- modifiers |= NSEventModifierFlagCommand;
- }
+ /* We used to convert these drag operations to keyboard modifiers,
+ but because they can be set by the sending program as well as the
+ keyboard modifiers it was difficult to work out a sensible key
+ mapping for drag and drop. */
+ if (op & NSDragOperationLink)
+ operations = Fcons (Qns_drag_operation_link, operations);
+ if (op & NSDragOperationCopy)
+ operations = Fcons (Qns_drag_operation_copy, operations);
+ if (op & NSDragOperationGeneric || NILP (operations))
+ operations = Fcons (Qns_drag_operation_generic, operations);
- modifiers = EV_MODIFIERS2 (modifiers);
if (type == 0)
{
return NO;
if (!(files = [pb propertyListForType: type]))
return NO;
+ type_sym = Qfile;
+
fenum = [files objectEnumerator];
while ( (file = [fenum nextObject]) )
- {
- emacs_event->kind = DRAG_N_DROP_EVENT;
- XSETINT (emacs_event->x, x);
- XSETINT (emacs_event->y, y);
- emacs_event->modifiers = modifiers;
- emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
- EV_TRAILER (theEvent);
- }
- return YES;
+ strings = Fcons (build_string ([file UTF8String]), strings);
}
else if ([type isEqualToString: NSURLPboardType])
{
NSURL *url = [NSURL URLFromPasteboard: pb];
if (url == nil) return NO;
- emacs_event->kind = DRAG_N_DROP_EVENT;
- XSETINT (emacs_event->x, x);
- XSETINT (emacs_event->y, y);
- emacs_event->modifiers = modifiers;
- emacs_event->arg = list2 (Qurl,
- build_string ([[url absoluteString]
- UTF8String]));
- EV_TRAILER (theEvent);
+ type_sym = Qurl;
- if ([url isFileURL] != NO)
- {
- NSString *file = [url path];
- ns_input_file = append2 (ns_input_file,
- build_string ([file UTF8String]));
- }
- return YES;
+ strings = Fcons (build_string ([[url absoluteString] UTF8String]), Qnil);
}
else if ([type isEqualToString: NSStringPboardType]
|| [type isEqualToString: NSTabularTextPboardType])
if (! (data = [pb stringForType: type]))
return NO;
- emacs_event->kind = DRAG_N_DROP_EVENT;
- XSETINT (emacs_event->x, x);
- XSETINT (emacs_event->y, y);
- emacs_event->modifiers = modifiers;
- emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
- EV_TRAILER (theEvent);
- return YES;
+ type_sym = Qnil;
+
+ strings = Fcons (build_string ([data UTF8String]), Qnil);
}
else
{
fprintf (stderr, "Invalid data type in dragging pasteboard");
return NO;
}
+
+ emacs_event->kind = DRAG_N_DROP_EVENT;
+ XSETINT (emacs_event->x, x);
+ XSETINT (emacs_event->y, y);
+ emacs_event->modifiers = 0;
+
+ emacs_event->arg = Fcons (type_sym,
+ Fcons (operations,
+ strings));
+ EV_TRAILER (theEvent);
+
+ return YES;
}
DEFSYM (Qfile, "file");
DEFSYM (Qurl, "url");
+ DEFSYM (Qns_drag_operation_copy, "ns-drag-operation-copy");
+ DEFSYM (Qns_drag_operation_link, "ns-drag-operation-link");
+ DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic");
+
Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier));