]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix drag and drop behaviour on NS (bug#30929)
authorAlan Third <alan@idiocy.org>
Sat, 5 Jan 2019 16:11:37 +0000 (16:11 +0000)
committerAlan Third <alan@idiocy.org>
Thu, 10 Jan 2019 19:24:19 +0000 (19:24 +0000)
* 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.

doc/emacs/macos.texi
etc/NEWS
lisp/term/ns-win.el
src/nsterm.m

index 6d27e978217634e9c815de143fe7ab061638087f..d9920957ad728b71ecbdc57ac262c0ae6db0bde2 100644 (file)
@@ -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
index 3d49640ac5d7423b8da0944249c6e6494838da23..a3aa5a29381b973aa75845be672910d692885a7a 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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.
+
 \f
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
index c9f5bfef5207b4144c8e86bd0e0edb39576ecca2..6a668b213dd2be2bc12ff2d4b385782f150ed6e1 100644 (file)
@@ -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.
 
index 016c0447609bb923382d9d21abf18d836b639087..2bce4a89aea4df7115c8843e743d4a6ecd673dd2 100644 (file)
@@ -8230,7 +8230,9 @@ not_in_argv (NSString *arg)
   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 @@ not_in_argv (NSString *arg)
   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;
@@ -8269,39 +8269,20 @@ not_in_argv (NSString *arg)
       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 @@ not_in_argv (NSString *arg)
       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 @@ syms_of_nsterm (void)
   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));