unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [patch] enhanced mac drag-n-drop
@ 2005-04-06  0:53 Sean O'Rourke
  2005-04-06 11:37 ` Stefan Monnier
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Sean O'Rourke @ 2005-04-06  0:53 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 2837 bytes --]

The included patch to src/macterm.c extends Carbon Emacs' drag-n-drop
to handle directories, URLs, and text.  To use it, the included Lisp
code also needs to be added to the appropriate Lisp file, probably
lisp/term/mac-win.el.  This is my first foray into Emacs C-hackery, so
although it's been working for me for the last few days, I would
appreciate some Mac users' trying it out.

Thanks for your time,
/s

ps -- please Cc me on replies, as I'm not subscribed to emacs-devel.

(defun mac-primary-dnd-function (event)
  "Perform the most common action for each type of item dropped
onto Emacs on Mac OS X.  Currently, this means:
    * File or directory -- call `find-file'.
    * URL -- call `browse-url-browser-function'.
    * Text -- insert text at point."
  (interactive "e")
  ;; Make sure the drop target has positive co-ords before setting the
  ;; selected frame - otherwise it won't work.  <skx@tardis.ed.ac.uk>
  (let* ((window (posn-window (event-start event)))
         (coords (posn-x-y (event-start event)))
         (x (car coords))
         (y (cdr coords)))
    (if (and (> x 0) (> y 0))
        (set-frame-selected-window nil window))
    (mapcar
     (lambda (name)
       (case (car name)
         (text (insert (cdr name)))
         (url (funcall browse-url-browser-function (cdr name)))
         (file
          (setq name (cdr name))
          (if (and (file-exists-p name)
                   (not (string-match (image-file-name-regexp) name)))
              (find-file name)
              (insert name)))))
     (cadd event)))
  (raise-frame)
  (recenter))

(defun mac-secondary-dnd-function (event)
  "Perform a less common action for each type of item dropped
onto Emacs on Mac OS X.  Currently, this means:
    * File or directory -- insert pathname at point.
    * URL -- insert URL text at point.
    * Text -- if it is a file or directory name, edit that file;
      otherwise, insert text at point."
  (interactive "e")
  ;; Make sure the drop target has positive co-ords before setting the
  ;; selected frame - otherwise it won't work.  <skx@tardis.ed.ac.uk>
  (let* ((window (posn-window (event-start event)))
         (coords (posn-x-y (event-start event)))
         (x (car coords))
         (y (cdr coords)))
    (if (and (> x 0) (> y 0))
        (set-frame-selected-window nil window))
    (mapcar
     (lambda (name)
       (case (car name)
         (text (setq name (cdr name))
               (if (and (file-exists-p name)
                        (not (string-match (image-file-name-regexp) name)))
                   (find-file name)
                   (insert name)))
         ((url file) (insert (cdr name)))))
     (caddr event)))
    (raise-frame)
    (recenter))

(global-set-key [drag-n-drop] 'mac-primary-dnd-function)
(global-set-key [shift drag-n-drop] 'mac-secondary-dnd-function)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 8138 bytes --]

Index: macterm.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/macterm.c,v
retrieving revision 1.106
diff -p -u -w -u -r1.106 macterm.c
--- macterm.c	16 Mar 2005 08:08:06 -0000	1.106
+++ macterm.c	5 Apr 2005 20:23:29 -0000
@@ -7155,7 +7159,8 @@ int current_mac_keyboard_text_encoding =
    drag and drop events.  */
 Lisp_Object Qmac_ready_for_drag_n_drop;
 
-Lisp_Object drag_and_drop_file_list;
+/* List of objects for a pending drag-n-drop event. */
+Lisp_Object drag_and_drop_list;
 
 Point saved_menu_event_location;
 
@@ -8078,10 +8083,10 @@ do_ae_open_documents(AppleEvent *message
 
   err = AEGetParamPtr (message, keyAEPosition, typeChar, &actual_type, &position, sizeof(SelectionRange), &actual_size);
   if (err == noErr)
-    drag_and_drop_file_list = Fcons (list3 (make_number (position.lineNum + 1),
+    drag_and_drop_list = Fcons (list3 (make_number (position.lineNum + 1),
 					    make_number (position.startRange + 1),
 					    make_number (position.endRange + 1)),
-				     drag_and_drop_file_list);
+                                drag_and_drop_list);
 
   /* Check to see that we got all of the required parameters from the
      event descriptor.  For an 'odoc' event this should just be the
@@ -8135,10 +8140,11 @@ do_ae_open_documents(AppleEvent *message
 					  sizeof (unix_path_name) - 1) == noErr)
 #endif
 	      /* x-dnd functions expect undecoded filenames.  */
-	      drag_and_drop_file_list =
-		Fcons (make_unibyte_string (unix_path_name,
-					    strlen (unix_path_name)),
-		       drag_and_drop_file_list);
+	      drag_and_drop_list =
+		Fcons (Fcons (intern("file"),
+                              make_unibyte_string (unix_path_name,
+                                                   strlen (unix_path_name))),
+                       drag_and_drop_list);
 	  }
       }
   }
@@ -8152,8 +8158,27 @@ descriptor_error_exit:
   return err;
 }
 
-
 #if TARGET_API_MAC_CARBON
+
+static FlavorType
+mac_favorite_flavor (DragReference theDrag, ItemReference theItem,
+                     FlavorFlags* theFlags)
+{
+    const FlavorType accepted_flavors[] = {
+        flavorTypeHFS,
+        flavorTypeDirectory,
+        'url ',
+        'utxt',
+        0
+    };
+    int j;
+    for (j = 0; accepted_flavors[j]; j++)
+        if (GetFlavorFlags (theDrag, theItem, accepted_flavors[j], &theFlags)
+            == noErr)
+            return accepted_flavors[j];
+    return 0;
+}
+
 static pascal OSErr
 mac_do_track_drag (DragTrackingMessage message, WindowPtr window,
 		   void *handlerRefCon, DragReference theDrag)
@@ -8176,8 +8201,7 @@ mac_do_track_drag (DragTrackingMessage m
       for (index = 1; index <= items; index++)
 	{
 	  GetDragItemReferenceNumber (theDrag, index, &theItem);
-	  result = GetFlavorFlags (theDrag, theItem, flavorTypeHFS, &theFlags);
-	  if (result == noErr)
+          if (mac_favorite_flavor (theDrag, theItem, &theFlags) != 0)
 	    {
 	      can_accept = 1;
 	      break;
@@ -8231,28 +8255,33 @@ mac_do_receive_drag (WindowPtr window, v
   Point mouse;
   OSErr result;
   ItemReference theItem;
-  HFSFlavor data;
-  Size size = sizeof (HFSFlavor);
 
   if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
     return dragNotAcceptedErr;
 
-  drag_and_drop_file_list = Qnil;
+  drag_and_drop_list = Qnil;
   GetDragMouse (theDrag, &mouse, 0L);
   CountDragItems (theDrag, &items);
   for (index = 1; index <= items; index++)
     {
-      /* Only handle file references.  */
+      FlavorType flavor;
+
       GetDragItemReferenceNumber (theDrag, index, &theItem);
-      result = GetFlavorFlags (theDrag, theItem, flavorTypeHFS, &theFlags);
-      if (result == noErr)
+      flavor = mac_favorite_flavor (theDrag, theItem, &theFlags);
+      switch (flavor)
+        {
+        case flavorTypeHFS:
+        case flavorTypeDirectory:
+          /* Handle file/directory references.  */
 	{
+            HFSFlavor data;
+            Size size = sizeof (HFSFlavor);
 #ifdef MAC_OSX
 	  FSRef fref;
 #endif
 	  char unix_path_name[MAXPATHLEN];
 
-	  GetFlavorData (theDrag, theItem, flavorTypeHFS, &data, &size, 0L);
+            GetFlavorData (theDrag, theItem, flavor, &data, &size, 0L);
 #ifdef MAC_OSX
 	  /* Use Carbon routines, otherwise it converts the file name
 	     to /Macintosh HD/..., which is not correct. */
@@ -8262,16 +8291,52 @@ mac_do_receive_drag (WindowPtr window, v
 	  if (fsspec_to_posix_pathname (&data.fileSpec, unix_path_name,
 					sizeof (unix_path_name) - 1) == noErr)
 #endif
-	    /* x-dnd functions expect undecoded filenames.  */
-            drag_and_drop_file_list =
-	      Fcons (make_unibyte_string (unix_path_name,
+              /* x-dnd functions expect undecoded filenames, but we
+                 don't have to follow that. */
+              drag_and_drop_list =
+                Fcons (Fcons
+                       (intern ("file"),
+                        Fdecode_coding_string
+                        (make_unibyte_string (unix_path_name,
 					  strlen (unix_path_name)),
-		     drag_and_drop_file_list);
+                         NILP (Vfile_name_coding_system)
+                         ? Vdefault_file_name_coding_system
+                         : Vfile_name_coding_system,
+                         Qnil)),
+                       drag_and_drop_list);
+          }
+          break;
+
+        case 'url ':
+        case 'utxt':
+          {
+            Size size;
+            char * data;
+            if (GetFlavorDataSize (theDrag, theItem, flavor, &size) != noErr)
+              break;
+            data = xmalloc (size + 1);
+            GetFlavorData (theDrag, theItem, flavor, data, &size, 0L);
+            if (flavor == 'url ')
+                drag_and_drop_list =
+                    Fcons (Fcons (intern ("url"),
+                                  make_unibyte_string (data, size)),
+                           drag_and_drop_list);
+            else
+                drag_and_drop_list =
+                    Fcons (Fcons (intern ("text"),
+                                  Fdecode_coding_string
+                                  (make_unibyte_string (data, size),
+                                   intern ("utf-16"),
+                                   Qnil)),
+                           drag_and_drop_list);
+            free (data);
 	}
+          break;
+        };
     }
   /* If there are items in the list, construct an event and post it to
      the queue like an interrupt using kbd_buffer_store_event.  */
-  if (!NILP (drag_and_drop_file_list))
+  if (!NILP (drag_and_drop_list))
     {
       struct input_event event;
       Lisp_Object frame;
@@ -8288,7 +8353,7 @@ mac_do_receive_drag (WindowPtr window, v
       XSETINT (event.x, mouse.h);
       XSETINT (event.y, mouse.v);
       XSETFRAME (frame, f);
-      event.frame_or_window = Fcons (frame, drag_and_drop_file_list);
+      event.frame_or_window = Fcons (frame, drag_and_drop_list);
       event.arg = Qnil;
       /* Post to the interrupt queue */
       kbd_buffer_store_event (&event);
@@ -8298,12 +8363,13 @@ mac_do_receive_drag (WindowPtr window, v
 	GetCurrentProcess (&psn);
 	SetFrontProcess (&psn);
       }
-
       return noErr;
     }
   else
+    {
     return dragNotAcceptedErr;
 }
+}
 #endif
 
 
@@ -9091,13 +9157,13 @@ XTread_socket (sd, expected, hold_quit)
 	  break;
 
 	case kHighLevelEvent:
-	  drag_and_drop_file_list = Qnil;
+	  drag_and_drop_list = Qnil;
 
 	  AEProcessAppleEvent(&er);
 
 	  /* Build a DRAG_N_DROP_EVENT type event as is done in
 	     constuct_drag_n_drop in w32term.c.  */
-	  if (!NILP (drag_and_drop_file_list))
+	  if (!NILP (drag_and_drop_list))
 	    {
 	      struct frame *f = NULL;
 	      WindowPtr wp;
@@ -9129,7 +9195,7 @@ XTread_socket (sd, expected, hold_quit)
 	      XSETINT (inev.y, 0);
 
 	      XSETFRAME (frame, f);
-	      inev.frame_or_window = Fcons (frame, drag_and_drop_file_list);
+	      inev.frame_or_window = Fcons (frame, drag_and_drop_list);
 
 	      /* Regardless of whether Emacs was suspended or in the
 		 foreground, ask it to redraw its entire screen.

[-- Attachment #3: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2005-04-12 17:24 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-06  0:53 [patch] enhanced mac drag-n-drop Sean O'Rourke
2005-04-06 11:37 ` Stefan Monnier
2005-04-06 16:17 ` Jan D.
2005-04-06 18:12   ` Sean O'Rourke
2005-04-06 19:22     ` Jan D.
     [not found]     ` <uwtrfsjhv.fsf@jasonrumney.net>
2005-04-07  4:36       ` Jan D.
2005-04-07  6:59         ` Jason Rumney
2005-04-07 13:33           ` Sean O'Rourke
2005-04-07 15:18             ` Jan D.
2005-04-11 19:39           ` Jan D.
2005-04-09 11:00 ` YAMAMOTO Mitsuharu
2005-04-09 13:46   ` Jan D.
2005-04-10  2:03     ` YAMAMOTO Mitsuharu
2005-04-10  5:47       ` Jan D.
2005-04-10 14:42       ` Stefan Monnier
2005-04-11  1:56         ` Richard Stallman
2005-04-11  3:35           ` Stefan Monnier
2005-04-11  9:49             ` YAMAMOTO Mitsuharu
2005-04-11 16:39               ` Stefan Monnier
2005-04-12  8:24                 ` YAMAMOTO Mitsuharu
2005-04-12  2:58             ` Richard Stallman
2005-04-12  3:59               ` Stefan Monnier
2005-04-12 17:24                 ` Richard Stallman
2005-04-11  1:56       ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).