]> code.delx.au - gnu-emacs/blobdiff - src/macselect.c
(lgrep, rgrep): Use add-to-history.
[gnu-emacs] / src / macselect.c
index 49246f7eddc9734ae5d3d79174e5e2e54babd45a..845af2a4870da9931be7f4f674f17013e3608e01 100644 (file)
@@ -1,5 +1,5 @@
 /* Selection processing for Emacs on Mac OS.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,14 +15,15 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 
 #include "lisp.h"
 #include "macterm.h"
 #include "blockinput.h"
+#include "keymap.h"
 
 #if !TARGET_API_MAC_CARBON
 #include <Endian.h>
@@ -98,8 +99,10 @@ static Lisp_Object Vselection_converter_alist;
    selection type with a scrap flavor type via `mac-ostype'.  */
 static Lisp_Object Qmac_scrap_name, Qmac_ostype;
 
+#ifdef MAC_OSX
 /* Selection name for communication via Services menu.  */
 static Lisp_Object Vmac_services_selection;
+#endif
 \f
 /* Get a reference to the scrap corresponding to the symbol SYM.  The
    reference is set to *SCRAP, and it becomes NULL if there's no
@@ -150,7 +153,6 @@ static ScrapFlavorType
 get_flavor_type_from_symbol (sym)
      Lisp_Object sym;
 {
-  ScrapFlavorType val;
   Lisp_Object str = Fget (sym, Qmac_ostype);
 
   if (STRINGP (str) && SBYTES (str) == 4)
@@ -319,17 +321,19 @@ get_scrap_private_timestamp (scrap, timestamp)
 
   err = GetScrapFlavorFlags (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP, &flags);
   if (err == noErr)
-    if (!(flags & kScrapFlavorMaskSenderOnly))
-      err = noTypeErr;
-    else
-      {
-       Size size = sizeof (*timestamp);
+    {
+      if (!(flags & kScrapFlavorMaskSenderOnly))
+       err = noTypeErr;
+      else
+       {
+         Size size = sizeof (*timestamp);
 
-       err = GetScrapFlavorData (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
-                                 &size, timestamp);
-       if (err == noErr && size != sizeof (*timestamp))
-         err = noTypeErr;
-      }
+         err = GetScrapFlavorData (scrap, SCRAP_FLAVOR_TYPE_EMACS_TIMESTAMP,
+                                   &size, timestamp);
+         if (err == noErr && size != sizeof (*timestamp))
+           err = noTypeErr;
+       }
+    }
 #else  /* !TARGET_API_MAC_CARBON */
   Handle handle;
   SInt32 size, offset;
@@ -369,15 +373,14 @@ get_scrap_target_type_list (scrap)
   err = GetScrapFlavorCount (scrap, &count);
   if (err == noErr)
     flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
-  if (err == noErr && flavor_info)
+  err = GetScrapFlavorInfoList (scrap, &count, flavor_info);
+  if (err != noErr)
     {
-      err = GetScrapFlavorInfoList (scrap, &count, flavor_info);
-      if (err != noErr)
-       {
-         xfree (flavor_info);
-         flavor_info = NULL;
-       }
+      xfree (flavor_info);
+      flavor_info = NULL;
     }
+  if (flavor_info == NULL)
+    count = 0;
 #endif
   for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
     {
@@ -455,9 +458,11 @@ x_own_selection (selection_name, selection_value)
            value = call3 (handler_fn, selection_name,
                           type, selection_value);
 
-         if (CONSP (value)
-             && EQ (XCAR (value), type)
-             && STRINGP (XCDR (value)))
+         if (STRINGP (value))
+           err = put_scrap_string (scrap, type, value);
+         else if (CONSP (value)
+                  && EQ (XCAR (value), type)
+                  && STRINGP (XCDR (value)))
            err = put_scrap_string (scrap, type, XCDR (value));
        }
 
@@ -622,7 +627,8 @@ x_clear_frame_selections (f)
       hooks = Vx_lost_selection_functions;
       selection_symbol = Fcar (Fcar (Vselection_alist));
 
-      if (!EQ (hooks, Qunbound))
+      if (!EQ (hooks, Qunbound)
+         && !NILP (Fx_selection_owner_p (selection_symbol)))
        {
          for (; CONSP (hooks); hooks = Fcdr (hooks))
            call1 (Fcar (hooks), selection_symbol);
@@ -646,7 +652,8 @@ x_clear_frame_selections (f)
        hooks = Vx_lost_selection_functions;
        selection_symbol = Fcar (Fcar (XCDR (rest)));
 
-       if (!EQ (hooks, Qunbound))
+       if (!EQ (hooks, Qunbound)
+         && !NILP (Fx_selection_owner_p (selection_symbol)))
          {
            for (; CONSP (hooks); hooks = Fcdr (hooks))
              call1 (Fcar (hooks), selection_symbol);
@@ -674,18 +681,20 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
 
   err = get_scrap_from_symbol (selection_symbol, 0, &scrap);
   if (err == noErr && scrap)
-    if (EQ (target_type, QTARGETS))
-      {
-       result = get_scrap_target_type_list (scrap);
-       result = Fvconcat (1, &result);
-      }
-    else
-      {
-       result = get_scrap_string (scrap, target_type);
-       if (STRINGP (result))
-         Fput_text_property (make_number (0), make_number (SBYTES (result)),
-                             Qforeign_selection, target_type, result);
-      }
+    {
+      if (EQ (target_type, QTARGETS))
+       {
+         result = get_scrap_target_type_list (scrap);
+         result = Fvconcat (1, &result);
+       }
+      else
+       {
+         result = get_scrap_string (scrap, target_type);
+         if (STRINGP (result))
+           Fput_text_property (make_number (0), make_number (SBYTES (result)),
+                               Qforeign_selection, target_type, result);
+       }
+    }
 
   UNBLOCK_INPUT;
 
@@ -704,7 +713,7 @@ anything that the functions on `selection-converter-alist' know about.  */)
 {
   check_mac ();
   CHECK_SYMBOL (selection_name);
-  if (NILP (selection_value)) error ("selection-value may not be nil");
+  if (NILP (selection_value)) error ("SELECTION-VALUE may not be nil");
   x_own_selection (selection_name, selection_value);
   return selection_value;
 }
@@ -716,11 +725,11 @@ anything that the functions on `selection-converter-alist' know about.  */)
 
 DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
        Sx_get_selection_internal, 2, 3, 0,
-       doc: /* Return text selected from some Mac window.
+       doc: /* Return text selected from some Mac application.
 SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
 TYPE is the type of data desired, typically `STRING'.
 TIME_STAMP is ignored on Mac.  */)
-  (selection_symbol, target_type, time_stamp)
+     (selection_symbol, target_type, time_stamp)
      Lisp_Object selection_symbol, target_type, time_stamp;
 {
   Lisp_Object val = Qnil;
@@ -813,7 +822,7 @@ Disowning it means there is no such selection.  */)
 
 DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p,
        0, 1, 0,
-       doc: /* Whether the current Emacs process owns the given Selection.
+       doc: /* Whether the current Emacs process owns the given SELECTION.
 The arg should be the name of the selection in question, typically one of
 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
 For convenience, the symbol nil is the same as `PRIMARY',
@@ -858,7 +867,7 @@ and t is the same as `SECONDARY'.  */)
 
 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
        0, 1, 0,
-       doc: /* Whether there is an owner for the given Selection.
+       doc: /* Whether there is an owner for the given SELECTION.
 The arg should be the name of the selection in question, typically one of
 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
 For convenience, the symbol nil is the same as `PRIMARY',
@@ -899,6 +908,435 @@ and t is the same as `SECONDARY'.  */)
   return result;
 }
 
+\f
+int mac_ready_for_apple_events = 0;
+static Lisp_Object Vmac_apple_event_map;
+static Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id;
+static struct
+{
+  AppleEvent *buf;
+  int size, count;
+} deferred_apple_events;
+extern Lisp_Object Qundefined;
+extern void mac_store_apple_event P_ ((Lisp_Object, Lisp_Object,
+                                      const AEDesc *));
+
+struct apple_event_binding
+{
+  UInt32 code;                 /* Apple event class or ID.  */
+  Lisp_Object key, binding;
+};
+
+static void
+find_event_binding_fun (key, binding, args, data)
+     Lisp_Object key, binding, args;
+     void *data;
+{
+  struct apple_event_binding *event_binding =
+    (struct apple_event_binding *)data;
+  Lisp_Object code_string;
+
+  if (!SYMBOLP (key))
+    return;
+  code_string = Fget (key, args);
+  if (STRINGP (code_string) && SBYTES (code_string) == 4
+      && (EndianU32_BtoN (*((UInt32 *) SDATA (code_string)))
+         == event_binding->code))
+    {
+      event_binding->key = key;
+      event_binding->binding = binding;
+    }
+}
+
+static void
+find_event_binding (keymap, event_binding, class_p)
+     Lisp_Object keymap;
+     struct apple_event_binding *event_binding;
+     int class_p;
+{
+  if (event_binding->code == 0)
+    event_binding->binding =
+      access_keymap (keymap, event_binding->key, 0, 1, 0);
+  else
+    {
+      event_binding->binding = Qnil;
+      map_keymap (keymap, find_event_binding_fun,
+                 class_p ? Qmac_apple_event_class : Qmac_apple_event_id,
+                 event_binding, 0);
+    }
+}
+
+void
+mac_find_apple_event_spec (class, id, class_key, id_key, binding)
+     AEEventClass class;
+     AEEventID id;
+     Lisp_Object *class_key, *id_key, *binding;
+{
+  struct apple_event_binding event_binding;
+  Lisp_Object keymap;
+
+  *binding = Qnil;
+
+  keymap = get_keymap (Vmac_apple_event_map, 0, 0);
+  if (NILP (keymap))
+    return;
+
+  event_binding.code = class;
+  event_binding.key = *class_key;
+  event_binding.binding = Qnil;
+  find_event_binding (keymap, &event_binding, 1);
+  *class_key = event_binding.key;
+  keymap = get_keymap (event_binding.binding, 0, 0);
+  if (NILP (keymap))
+    return;
+
+  event_binding.code = id;
+  event_binding.key = *id_key;
+  event_binding.binding = Qnil;
+  find_event_binding (keymap, &event_binding, 0);
+  *id_key = event_binding.key;
+  *binding = event_binding.binding;
+}
+
+static OSErr
+defer_apple_events (apple_event, reply)
+     const AppleEvent *apple_event, *reply;
+{
+  OSErr err;
+
+  err = AESuspendTheCurrentEvent (apple_event);
+
+  /* Mac OS 10.3 Xcode manual says AESuspendTheCurrentEvent makes
+     copies of the Apple event and the reply, but Mac OS 10.4 Xcode
+     manual says it doesn't.  Anyway we create copies of them and save
+     them in `deferred_apple_events'.  */
+  if (err == noErr)
+    {
+      if (deferred_apple_events.buf == NULL)
+       {
+         deferred_apple_events.size = 16;
+         deferred_apple_events.count = 0;
+         deferred_apple_events.buf =
+           xmalloc (sizeof (AppleEvent) * deferred_apple_events.size);
+       }
+      else if (deferred_apple_events.count == deferred_apple_events.size)
+       {
+         deferred_apple_events.size *= 2;
+         deferred_apple_events.buf
+           = xrealloc (deferred_apple_events.buf,
+                       sizeof (AppleEvent) * deferred_apple_events.size);
+       }
+    }
+
+  if (err == noErr)
+    {
+      int count = deferred_apple_events.count;
+
+      AEDuplicateDesc (apple_event, deferred_apple_events.buf + count);
+      AEDuplicateDesc (reply, deferred_apple_events.buf + count + 1);
+      deferred_apple_events.count += 2;
+    }
+
+  return err;
+}
+
+static pascal OSErr
+mac_handle_apple_event (apple_event, reply, refcon)
+     const AppleEvent *apple_event;
+     AppleEvent *reply;
+     SInt32 refcon;
+{
+  OSErr err;
+  AEEventClass event_class;
+  AEEventID event_id;
+  Lisp_Object class_key, id_key, binding;
+
+  /* We can't handle an Apple event that requests a reply, but this
+     seems to be too restrictive.  */
+#if 0
+  if (reply->descriptorType != typeNull)
+    return errAEEventNotHandled;
+#endif
+
+  if (!mac_ready_for_apple_events)
+    {
+      err = defer_apple_events (apple_event, reply);
+      if (err != noErr)
+       return errAEEventNotHandled;
+      return noErr;
+    }
+
+  err = AEGetAttributePtr (apple_event, keyEventClassAttr, typeType, NULL,
+                          &event_class, sizeof (AEEventClass), NULL);
+  if (err == noErr)
+    err = AEGetAttributePtr (apple_event, keyEventIDAttr, typeType, NULL,
+                            &event_id, sizeof (AEEventID), NULL);
+  if (err == noErr)
+    {
+      mac_find_apple_event_spec (event_class, event_id,
+                                &class_key, &id_key, &binding);
+      if (!NILP (binding) && !EQ (binding, Qundefined))
+       {
+         if (INTEGERP (binding))
+           return XINT (binding);
+         mac_store_apple_event (class_key, id_key, apple_event);
+         return noErr;
+       }
+    }
+  return errAEEventNotHandled;
+}
+
+void
+init_apple_event_handler ()
+{
+  OSErr err;
+  long result;
+
+  /* Make sure we have Apple events before starting.  */
+  err = Gestalt (gestaltAppleEventsAttr, &result);
+  if (err != noErr)
+    abort ();
+
+  if (!(result & (1 << gestaltAppleEventsPresent)))
+    abort ();
+
+  err = AEInstallEventHandler (typeWildCard, typeWildCard,
+#if TARGET_API_MAC_CARBON
+                              NewAEEventHandlerUPP (mac_handle_apple_event),
+#else
+                              NewAEEventHandlerProc (mac_handle_apple_event),
+#endif
+                              0L, false);
+  if (err != noErr)
+    abort ();
+}
+
+DEFUN ("mac-process-deferred-apple-events", Fmac_process_deferred_apple_events, Smac_process_deferred_apple_events, 0, 0, 0,
+       doc: /* Process Apple events that are deferred at the startup time.  */)
+  ()
+{
+  Lisp_Object result = Qnil;
+  long i;
+
+  if (mac_ready_for_apple_events)
+    return Qnil;
+
+  BLOCK_INPUT;
+  mac_ready_for_apple_events = 1;
+  if (deferred_apple_events.buf)
+    {
+      for (i = 0; i < deferred_apple_events.count; i += 2)
+       {
+         AEResumeTheCurrentEvent (deferred_apple_events.buf + i,
+                                  deferred_apple_events.buf + i + 1,
+                                  ((AEEventHandlerUPP)
+                                   kAEUseStandardDispatch), 0);
+         AEDisposeDesc (deferred_apple_events.buf + i);
+         AEDisposeDesc (deferred_apple_events.buf + i + 1);
+       }
+      xfree (deferred_apple_events.buf);
+      bzero (&deferred_apple_events, sizeof (deferred_apple_events));
+
+      result = Qt;
+    }
+  UNBLOCK_INPUT;
+
+  return result;
+}
+
+\f
+#if TARGET_API_MAC_CARBON
+static Lisp_Object Vmac_dnd_known_types;
+static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef,
+                                          void *, DragRef));
+static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
+static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
+static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
+
+extern void mac_store_drag_event P_ ((WindowRef, Point, SInt16,
+                                     const AEDesc *));
+
+static pascal OSErr
+mac_do_track_drag (message, window, refcon, drag)
+     DragTrackingMessage message;
+     WindowRef window;
+     void *refcon;
+     DragRef drag;
+{
+  OSErr err = noErr;
+  static int can_accept;
+  UInt16 num_items, index;
+
+  if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
+    return dragNotAcceptedErr;
+
+  switch (message)
+    {
+    case kDragTrackingEnterHandler:
+      err = CountDragItems (drag, &num_items);
+      if (err != noErr)
+       break;
+      can_accept = 0;
+      for (index = 1; index <= num_items; index++)
+       {
+         ItemReference item;
+         FlavorFlags flags;
+         Lisp_Object rest;
+
+         err = GetDragItemReferenceNumber (drag, index, &item);
+         if (err != noErr)
+           continue;
+         for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
+           {
+             Lisp_Object str;
+             FlavorType type;
+
+             str = XCAR (rest);
+             if (!(STRINGP (str) && SBYTES (str) == 4))
+               continue;
+             type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
+
+             err = GetFlavorFlags (drag, item, type, &flags);
+             if (err == noErr)
+               {
+                 can_accept = 1;
+                 break;
+               }
+           }
+       }
+      break;
+
+    case kDragTrackingEnterWindow:
+      if (can_accept)
+       {
+         RgnHandle hilite_rgn = NewRgn ();
+
+         if (hilite_rgn)
+           {
+             Rect r;
+
+             GetWindowPortBounds (window, &r);
+             OffsetRect (&r, -r.left, -r.top);
+             RectRgn (hilite_rgn, &r);
+             ShowDragHilite (drag, hilite_rgn, true);
+             DisposeRgn (hilite_rgn);
+           }
+         SetThemeCursor (kThemeCopyArrowCursor);
+       }
+      break;
+
+    case kDragTrackingInWindow:
+      break;
+
+    case kDragTrackingLeaveWindow:
+      if (can_accept)
+       {
+         HideDragHilite (drag);
+         SetThemeCursor (kThemeArrowCursor);
+       }
+      break;
+
+    case kDragTrackingLeaveHandler:
+      break;
+    }
+
+  if (err != noErr)
+    return dragNotAcceptedErr;
+  return noErr;
+}
+
+static pascal OSErr
+mac_do_receive_drag (window, refcon, drag)
+     WindowRef window;
+     void *refcon;
+     DragRef drag;
+{
+  OSErr err;
+  UInt16 index;
+  int num_types, i;
+  Lisp_Object rest, str;
+  FlavorType *types;
+  AppleEvent apple_event;
+  Point mouse_pos;
+  SInt16 modifiers;
+
+  if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
+    return dragNotAcceptedErr;
+
+  num_types = 0;
+  for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
+    {
+      str = XCAR (rest);
+      if (STRINGP (str) && SBYTES (str) == 4)
+       num_types++;
+    }
+
+  types = xmalloc (sizeof (FlavorType) * num_types);
+  i = 0;
+  for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
+    {
+      str = XCAR (rest);
+      if (STRINGP (str) && SBYTES (str) == 4)
+       types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
+    }
+
+  err = create_apple_event_from_drag_ref (drag, num_types, types,
+                                         &apple_event);
+  xfree (types);
+
+  if (err == noErr)
+    err = GetDragMouse (drag, &mouse_pos, NULL);
+  if (err == noErr)
+    {
+      GlobalToLocal (&mouse_pos);
+      err = GetDragModifiers (drag, NULL, NULL, &modifiers);
+    }
+
+  if (err == noErr)
+    {
+      mac_store_drag_event (window, mouse_pos, modifiers, &apple_event);
+      AEDisposeDesc (&apple_event);
+      /* Post a harmless event so as to wake up from ReceiveNextEvent.  */
+      mac_post_mouse_moved_event ();
+      return noErr;
+    }
+  else
+    return dragNotAcceptedErr;
+}
+#endif /* TARGET_API_MAC_CARBON */
+
+OSErr
+install_drag_handler (window)
+     WindowRef window;
+{
+  OSErr err = noErr;
+
+#if TARGET_API_MAC_CARBON
+  if (mac_do_track_dragUPP == NULL)
+    mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
+  if (mac_do_receive_dragUPP == NULL)
+    mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
+
+  err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
+  if (err == noErr)
+    err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
+#endif
+
+  return err;
+}
+
+void
+remove_drag_handler (window)
+     WindowRef window;
+{
+#if TARGET_API_MAC_CARBON
+  if (mac_do_track_dragUPP)
+    RemoveTrackingHandler (mac_do_track_dragUPP, window);
+  if (mac_do_receive_dragUPP)
+    RemoveReceiveHandler (mac_do_receive_dragUPP, window);
+#endif
+}
+
 \f
 #ifdef MAC_OSX
 void
@@ -912,7 +1350,48 @@ init_service_handler ()
                                  GetEventTypeCount (specs), specs, NULL, NULL);
 }
 
-extern void mac_store_services_event P_ ((EventRef));
+extern OSErr mac_store_services_event P_ ((EventRef));
+
+static OSStatus
+copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
+     ScrapRef from_scrap, to_scrap;
+     ScrapFlavorType flavor_type;
+{
+  OSStatus err;
+  Size size, size_allocated;
+  char *buf = NULL;
+
+  err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
+  if (err == noErr)
+    buf = xmalloc (size);
+  while (buf)
+    {
+      size_allocated = size;
+      err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
+      if (err != noErr)
+       {
+         xfree (buf);
+         buf = NULL;
+       }
+      else if (size_allocated < size)
+       buf = xrealloc (buf, size);
+      else
+       break;
+    }
+  if (err == noErr)
+    {
+      if (buf == NULL)
+       err = memFullErr;
+      else
+       {
+         err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
+                               size, buf);
+         xfree (buf);
+       }
+    }
+
+  return err;
+}
 
 static OSStatus
 mac_handle_service_event (call_ref, event, data)
@@ -921,7 +1400,12 @@ mac_handle_service_event (call_ref, event, data)
      void *data;
 {
   OSStatus err = noErr;
-  ScrapRef cur_scrap;
+  ScrapRef cur_scrap, specific_scrap;
+  UInt32 event_kind = GetEventKind (event);
+  CFMutableArrayRef copy_types, paste_types;
+  CFStringRef type;
+  Lisp_Object rest;
+  ScrapFlavorType flavor_type;
 
   /* Check if Vmac_services_selection is a valid selection that has a
      corresponding scrap.  */
@@ -932,86 +1416,100 @@ mac_handle_service_event (call_ref, event, data)
   if (!(err == noErr && cur_scrap))
     return eventNotHandledErr;
 
-  switch (GetEventKind (event))
+  switch (event_kind)
     {
     case kEventServiceGetTypes:
-      {
-       CFMutableArrayRef copy_types, paste_types;
-       CFStringRef type;
-       Lisp_Object rest;
-       ScrapFlavorType flavor_type;
-
-       /* Set paste types. */
-       err = GetEventParameter (event, kEventParamServicePasteTypes,
-                                typeCFMutableArrayRef, NULL,
-                                sizeof (CFMutableArrayRef), NULL,
-                                &paste_types);
-       if (err == noErr)
-         for (rest = Vselection_converter_alist; CONSP (rest);
-              rest = XCDR (rest))
-           if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
-               && (flavor_type =
-                   get_flavor_type_from_symbol (XCAR (XCAR (rest)))))
+      /* Set paste types. */
+      err = GetEventParameter (event, kEventParamServicePasteTypes,
+                              typeCFMutableArrayRef, NULL,
+                              sizeof (CFMutableArrayRef), NULL,
+                              &paste_types);
+      if (err != noErr)
+       break;
+
+      for (rest = Vselection_converter_alist; CONSP (rest);
+          rest = XCDR (rest))
+       if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
+           && (flavor_type =
+               get_flavor_type_from_symbol (XCAR (XCAR (rest)))))
+         {
+           type = CreateTypeStringWithOSType (flavor_type);
+           if (type)
              {
-               type = CreateTypeStringWithOSType (flavor_type);
-               if (type)
-                 {
-                   CFArrayAppendValue (paste_types, type);
-                   CFRelease (type);
-                 }
+               CFArrayAppendValue (paste_types, type);
+               CFRelease (type);
              }
+         }
 
-       /* Set copy types.  */
-       err = GetEventParameter (event, kEventParamServiceCopyTypes,
-                                typeCFMutableArrayRef, NULL,
-                                sizeof (CFMutableArrayRef), NULL,
-                                &copy_types);
-       if (err == noErr
-           && !NILP (Fx_selection_owner_p (Vmac_services_selection)))
-         for (rest = get_scrap_target_type_list (cur_scrap);
-              CONSP (rest) && SYMBOLP (XCAR (rest)); rest = XCDR (rest))
-           {
-             flavor_type = get_flavor_type_from_symbol (XCAR (rest));
-             if (flavor_type)
-               {
-                 type = CreateTypeStringWithOSType (flavor_type);
-                 if (type)
-                   {
-                     CFArrayAppendValue (copy_types, type);
-                     CFRelease (type);
-                   }
-               }
-           }
-      }
-      break;
+      /* Set copy types.  */
+      err = GetEventParameter (event, kEventParamServiceCopyTypes,
+                              typeCFMutableArrayRef, NULL,
+                              sizeof (CFMutableArrayRef), NULL,
+                              &copy_types);
+      if (err != noErr)
+       break;
+
+      if (NILP (Fx_selection_owner_p (Vmac_services_selection)))
+       break;
+      else
+       goto copy_all_flavors;
 
     case kEventServiceCopy:
-      {
-       ScrapRef specific_scrap;
-       Lisp_Object rest, data;
-
-       err = GetEventParameter (event, kEventParamScrapRef,
-                                typeScrapRef, NULL,
-                                sizeof (ScrapRef), NULL, &specific_scrap);
-       if (err == noErr
-           && !NILP (Fx_selection_owner_p (Vmac_services_selection)))
-         for (rest = get_scrap_target_type_list (cur_scrap);
-              CONSP (rest) && SYMBOLP (XCAR (rest)); rest = XCDR (rest))
-           {
-             data = get_scrap_string (cur_scrap, XCAR (rest));
-             if (STRINGP (data))
-               err = put_scrap_string (specific_scrap, XCAR (rest), data);
-           }
-       else
+      err = GetEventParameter (event, kEventParamScrapRef,
+                              typeScrapRef, NULL,
+                              sizeof (ScrapRef), NULL, &specific_scrap);
+      if (err != noErr
+         || NILP (Fx_selection_owner_p (Vmac_services_selection)))
+       {
          err = eventNotHandledErr;
+         break;
+       }
+
+    copy_all_flavors:
+      {
+       UInt32 count, i;
+       ScrapFlavorInfo *flavor_info = NULL;
+       ScrapFlavorFlags flags;
+
+       err = GetScrapFlavorCount (cur_scrap, &count);
+       if (err == noErr)
+         flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
+       err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
+       if (err != noErr)
+         {
+           xfree (flavor_info);
+           flavor_info = NULL;
+         }
+       if (flavor_info == NULL)
+         break;
+
+       for (i = 0; i < count; i++)
+         {
+           flavor_type = flavor_info[i].flavorType;
+           err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
+           if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
+             {
+               if (event_kind == kEventServiceCopy)
+                 err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
+                                               flavor_type);
+               else         /* event_kind == kEventServiceGetTypes */
+                 {
+                   type = CreateTypeStringWithOSType (flavor_type);
+                   if (type)
+                     {
+                       CFArrayAppendValue (copy_types, type);
+                       CFRelease (type);
+                     }
+                 }
+             }
+         }
+       xfree (flavor_info);
       }
       break;
 
     case kEventServicePaste:
     case kEventServicePerform:
       {
-        ScrapRef specific_scrap;
-       Lisp_Object rest, data;
        int data_exists_p = 0;
 
         err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
@@ -1025,25 +1523,24 @@ mac_handle_service_event (call_ref, event, data)
            {
              if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
                continue;
-             data = get_scrap_string (specific_scrap, XCAR (XCAR (rest)));
-             if (STRINGP (data))
-               {
-                 err = put_scrap_string (cur_scrap, XCAR (XCAR (rest)),
-                                         data);
-                 if (err != noErr)
-                   break;
-                 data_exists_p = 1;
-               }
+             flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)));
+             if (flavor_type == 0)
+               continue;
+             err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
+                                           flavor_type);
+             if (err == noErr)
+               data_exists_p = 1;
            }
-       if (err == noErr)
-         if (data_exists_p)
-           mac_store_application_menu_event (event);
-         else
-           err = eventNotHandledErr;
+       if (!data_exists_p)
+         err = eventNotHandledErr;
+       else
+         err = mac_store_services_event (event);
       }
       break;
     }
 
+  if (err != noErr)
+    err = eventNotHandledErr;
   return err;
 }
 #endif
@@ -1057,6 +1554,7 @@ syms_of_macselect ()
   defsubr (&Sx_disown_selection_internal);
   defsubr (&Sx_selection_owner_p);
   defsubr (&Sx_selection_exists_p);
+  defsubr (&Smac_process_deferred_apple_events);
 
   Vselection_alist = Qnil;
   staticpro (&Vselection_alist);
@@ -1069,7 +1567,7 @@ a desired type to which the selection should be converted;
 and the local selection value (whatever was given to `x-own-selection').
 
 The function should return the value to send to the Scrap Manager
-\(a string).  A return value of nil
+\(must be a string).  A return value of nil
 means that the conversion could not be done.
 A return value which is the symbol `NULL'
 means that a side-effect was executed,
@@ -1098,9 +1596,26 @@ next communication only.  After the communication, this variable is
 set to nil.  */);
   Vnext_selection_coding_system = Qnil;
 
+  DEFVAR_LISP ("mac-apple-event-map", &Vmac_apple_event_map,
+              doc: /* Keymap for Apple events handled by Emacs.  */);
+  Vmac_apple_event_map = Qnil;
+
+#if TARGET_API_MAC_CARBON
+  DEFVAR_LISP ("mac-dnd-known-types", &Vmac_dnd_known_types,
+              doc: /* The types accepted by default for dropped data.
+The types are chosen in the order they appear in the list.  */);
+  Vmac_dnd_known_types = list4 (build_string ("hfs "), build_string ("utxt"),
+                               build_string ("TEXT"), build_string ("TIFF"));
+#ifdef MAC_OSX
+  Vmac_dnd_known_types = Fcons (build_string ("furl"), Vmac_dnd_known_types);
+#endif
+#endif
+
+#ifdef MAC_OSX
   DEFVAR_LISP ("mac-services-selection", &Vmac_services_selection,
               doc: /* Selection name for communication via Services menu.  */);
-  Vmac_services_selection = intern ("CLIPBOARD");
+  Vmac_services_selection = intern ("PRIMARY");
+#endif
 
   QPRIMARY   = intern ("PRIMARY");     staticpro (&QPRIMARY);
   QSECONDARY = intern ("SECONDARY");   staticpro (&QSECONDARY);
@@ -1115,6 +1630,12 @@ set to nil.  */);
 
   Qmac_ostype = intern ("mac-ostype");
   staticpro (&Qmac_ostype);
+
+  Qmac_apple_event_class = intern ("mac-apple-event-class");
+  staticpro (&Qmac_apple_event_class);
+
+  Qmac_apple_event_id = intern ("mac-apple-event-id");
+  staticpro (&Qmac_apple_event_id);
 }
 
 /* arch-tag: f3c91ad8-99e0-4bd6-9eef-251b2f848732