Commit c342b263 authored by Alan Third's avatar Alan Third
Browse files

Fix drag and drop behaviour on NS (bug#30929)

* doc/emacs/macos.texi (Mac / GNUstep Events): Describe the new drag
and drop behaviour.
* lisp/term/ns-win.el (ns-drag-n-drop): Handle the new event format.
(ns-drag-n-drop-other-frame):
(ns-drag-n-drop-as-text):
(ns-drag-n-drop-as-text-other-frame): Remove functions and key
bindings.
* src/nsterm.m ([EmacsView performDragOperation:]): Send Emacs event
in new format without setting any modifiers.
parent 7ae0a24c
......@@ -170,8 +170,25 @@ the requested line (@code{ns-open-file-select-line}).
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
......
......@@ -1494,6 +1494,12 @@ versions of MS-Windows. Set this variable to 50 if for some reason
you need the old behavior (and please report such situations to Emacs
developers).
+++
** On NS the behaviour of drag and drop can now be modified by use of
modifier keys in line with Apples guidelines. This makes the drag and
drop behaviour more consistent, as previously the sending application
was able to 'set' modifiers without the knowledge of the user.
----------------------------------------------------------------------
This file is part of GNU Emacs.
......
......@@ -501,48 +501,38 @@ unless the current buffer is a scratch buffer."
(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.
......
......@@ -8230,7 +8230,9 @@ -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
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:]");
......@@ -8243,19 +8245,17 @@ -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
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)
{
/* 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)
modifiers |= NSEventModifierFlagControl;
operations = Fcons (Qns_drag_operation_link, operations);
if (op & NSDragOperationCopy)
modifiers |= NSEventModifierFlagOption;
if (op & NSDragOperationGeneric)
modifiers |= NSEventModifierFlagCommand;
}
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;
......@@ -8269,39 +8269,20 @@ -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
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])
......@@ -8311,19 +8292,27 @@ -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
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;
}
......@@ -9358,6 +9347,10 @@ Convert an X font name (XLFD) to an NS font name.
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));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment