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. <[EMAIL PROTECTED]>
(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. <[EMAIL PROTECTED]>
(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)
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.
_______________________________________________
Emacs-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/emacs-devel