fix up ns-extended-platform-support-mode
[bpt/emacs.git] / src / mac.c
index 75a606b..20872b2 100644 (file)
--- a/src/mac.c
+++ b/src/mac.c
@@ -1,13 +1,13 @@
 /* Unix emulation routines for GNU Emacs on the Mac OS.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+                 200 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,9 +15,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 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., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Contributed by Andrew Choi (akochoi@mac.com).  */
 
@@ -79,7 +77,7 @@ static ComponentInstance as_scripting_component;
 /* The single script context used for all script executions.  */
 static OSAID as_script_context;
 
-#ifndef MAC_OS_X
+#ifndef MAC_OSX
 #if TARGET_API_MAC_CARBON
 static int wakeup_from_rne_enabled_p = 0;
 #define ENABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 1)
@@ -817,7 +815,7 @@ init_coercion_handler ()
 }
 
 #if TARGET_API_MAC_CARBON
-static OSErr
+OSErr
 create_apple_event (class, id, result)
      AEEventClass class;
      AEEventID id;
@@ -842,129 +840,75 @@ create_apple_event (class, id, result)
   return err;
 }
 
-OSStatus
-create_apple_event_from_event_ref (event, num_params, names, types, result)
+Lisp_Object
+mac_event_parameters_to_lisp (event, num_params, names, types)
      EventRef event;
      UInt32 num_params;
      const EventParamName *names;
      const EventParamType *types;
-     AppleEvent *result;
 {
   OSStatus err;
-  UInt32 i, size;
+  Lisp_Object result = Qnil;
+  UInt32 i;
+  ByteCount size;
+#ifdef MAC_OSX
   CFStringRef string;
   CFDataRef data;
-  char *buf = NULL;
-
-  err = create_apple_event (0, 0, result); /* Dummy class and ID.  */
-  if (err != noErr)
-    return err;
-
-  for (i = 0; i < num_params; i++)
-    switch (types[i])
-      {
-#ifdef MAC_OSX
-      case typeCFStringRef:
-       err = GetEventParameter (event, names[i], typeCFStringRef, NULL,
-                                sizeof (CFStringRef), NULL, &string);
-       if (err != noErr)
-         break;
-       data = CFStringCreateExternalRepresentation (NULL, string,
-                                                    kCFStringEncodingUTF8,
-                                                    '?');
-       if (data == NULL)
-         break;
-       AEPutParamPtr (result, names[i], typeUTF8Text,
-                      CFDataGetBytePtr (data), CFDataGetLength (data));
-       CFRelease (data);
-       break;
 #endif
-
-      default:
-       err = GetEventParameter (event, names[i], types[i], NULL,
-                                0, &size, NULL);
-       if (err != noErr)
-         break;
-       buf = xrealloc (buf, size);
-       err = GetEventParameter (event, names[i], types[i], NULL,
-                                size, NULL, buf);
-       if (err == noErr)
-         AEPutParamPtr (result, names[i], types[i], buf, size);
-       break;
-      }
-  if (buf)
-    xfree (buf);
-
-  return noErr;
-}
-
-OSErr
-create_apple_event_from_drag_ref (drag, num_types, types, result)
-     DragRef drag;
-     UInt32 num_types;
-     const FlavorType *types;
-     AppleEvent *result;
-{
-  OSErr err;
-  UInt16 num_items;
-  AppleEvent items;
-  long index;
   char *buf = NULL;
 
-  err = CountDragItems (drag, &num_items);
-  if (err != noErr)
-    return err;
-  err = AECreateList (NULL, 0, false, &items);
-  if (err != noErr)
-    return err;
-
-  for (index = 1; index <= num_items; index++)
+  for (i = 0; i < num_params; i++)
     {
-      ItemReference item;
-      DescType desc_type = typeNull;
-      Size size;
+      EventParamName name = names[i];
+      EventParamType type = types[i];
 
-      err = GetDragItemReferenceNumber (drag, index, &item);
-      if (err == noErr)
+      switch (type)
        {
-         int i;
+#ifdef MAC_OSX
+       case typeCFStringRef:
+         err = GetEventParameter (event, name, typeCFStringRef, NULL,
+                                  sizeof (CFStringRef), NULL, &string);
+         if (err != noErr)
+           break;
+         data = CFStringCreateExternalRepresentation (NULL, string,
+                                                      kCFStringEncodingUTF8,
+                                                      '?');
+         if (data == NULL)
+           break;
+         name = EndianU32_NtoB (name);
+         type = EndianU32_NtoB (typeUTF8Text);
+         result =
+           Fcons (Fcons (make_unibyte_string ((char *) &name, 4),
+                         Fcons (make_unibyte_string ((char *) &type, 4),
+                                make_unibyte_string (CFDataGetBytePtr (data),
+                                                     CFDataGetLength (data)))),
+                  result);
+         CFRelease (data);
+         break;
+#endif
 
-         for (i = 0; i < num_types; i++)
+       default:
+         err = GetEventParameter (event, name, type, NULL, 0, &size, NULL);
+         if (err != noErr)
+           break;
+         buf = xrealloc (buf, size);
+         err = GetEventParameter (event, name, type, NULL, size, NULL, buf);
+         if (err == noErr)
            {
-             err = GetFlavorDataSize (drag, item, types[i], &size);
-             if (err == noErr)
-               {
-                 buf = xrealloc (buf, size);
-                 err = GetFlavorData (drag, item, types[i], buf, &size, 0);
-               }
-             if (err == noErr)
-               {
-                 desc_type = types[i];
-                 break;
-               }
+             name = EndianU32_NtoB (name);
+             type = EndianU32_NtoB (type);
+             result =
+               Fcons (Fcons (make_unibyte_string ((char *) &name, 4),
+                             Fcons (make_unibyte_string ((char *) &type, 4),
+                                    make_unibyte_string (buf, size))),
+                      result);
            }
+         break;
        }
-      err = AEPutPtr (&items, index, desc_type,
-                     desc_type != typeNull ? buf : NULL,
-                     desc_type != typeNull ? size : 0);
-      if (err != noErr)
-       break;
-    }
-  if (buf)
-    xfree (buf);
-
-  if (err == noErr)
-    {
-      err = create_apple_event (0, 0, result); /* Dummy class and ID.  */
-      if (err == noErr)
-       err = AEPutParamDesc (result, keyDirectObject, &items);
-      if (err != noErr)
-       AEDisposeDesc (result);
     }
+  xfree (buf);
 
-  AEDisposeDesc (&items);
-
-  return err;
+  return result;
 }
 #endif /* TARGET_API_MAC_CARBON */
 \f
@@ -4833,10 +4777,8 @@ cfstring_create_normalized (str, symbol)
                                               out_len / sizeof (UniChar));
       if (uni)
        DisposeUnicodeToTextInfo (&uni);
-      if (out_buf)
-       xfree (out_buf);
-      if (buffer)
-       xfree (buffer);
+      xfree (out_buf);
+      xfree (buffer);
     }
   else
     {
@@ -4989,8 +4931,8 @@ extern int noninteractive;
       SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds).
       -> Create CFSocket for each socket and add it into the current
          event RunLoop so that the current event loop gets quit when
-         the socket becomes ready.  Then CFRunLoopRunInMode can wait
-         for both kinds of inputs.
+         the socket becomes ready.  Then mac_run_loop_run_once can
+         wait for both kinds of inputs.
    4. Otherwise.
       -> Periodically poll the window input channel while repeatedly
          executing `select' with a short timeout
@@ -5004,6 +4946,13 @@ extern int noninteractive;
 #if SELECT_USE_CFSOCKET
 #define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
 
+/* Dictionary of file descriptors vs CFSocketRef's allocated in
+   sys_select.  */
+static CFMutableDictionaryRef cfsockets_for_select;
+
+/* Process ID of Emacs.  */
+static pid_t mac_emacs_pid;
+
 static void
 socket_callback (s, type, address, data, info)
      CFSocketRef s;
@@ -5038,7 +4987,7 @@ select_and_poll_event (nfds, rfds, wfds, efds, timeout)
       if (efds) oefds = *efds;
     }
 
-  /* Try detect_input_pending before CFRunLoopRunInMode in the same
+  /* Try detect_input_pending before mac_run_loop_run_once in the same
      BLOCK_INPUT block, in case that some input has already been read
      asynchronously.  */
   BLOCK_INPUT;
@@ -5055,15 +5004,7 @@ select_and_poll_event (nfds, rfds, wfds, efds, timeout)
       if (timeoutval == 0.0)
        timedout_p = 1;
       else
-       {
-#if USE_CG_DRAWING
-         mac_prepare_for_quickdraw (NULL);
-#endif
-         if (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
-                                 timeoutval >= 0 ? timeoutval : 100000, true)
-             == kCFRunLoopRunTimedOut)
-           timedout_p = 1;
-       }
+       timedout_p = mac_run_loop_run_once (timeoutval);
 
       if (timeout == NULL && timedout_p)
        {
@@ -5089,6 +5030,43 @@ select_and_poll_event (nfds, rfds, wfds, efds, timeout)
     return 0;
 }
 
+/* Clean up the CFSocket associated with the file descriptor FD in
+   case the same descriptor is used in other threads later.  If no
+   CFSocket is associated with FD, then return 0 without closing FD.
+   Otherwise, return 1 with closing FD.  */
+
+int
+mac_try_close_socket (fd)
+     int fd;
+{
+#if SELECT_USE_CFSOCKET
+  if (getpid () == mac_emacs_pid && cfsockets_for_select)
+    {
+      void *key = (void *) fd;
+      CFSocketRef socket =
+       (CFSocketRef) CFDictionaryGetValue (cfsockets_for_select, key);
+
+      if (socket)
+       {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
+         CFOptionFlags flags = CFSocketGetSocketFlags (socket);
+
+         if (!(flags & kCFSocketCloseOnInvalidate))
+           CFSocketSetSocketFlags (socket, flags | kCFSocketCloseOnInvalidate);
+#endif
+         BLOCK_INPUT;
+         CFSocketInvalidate (socket);
+         CFDictionaryRemoveValue (cfsockets_for_select, key);
+         UNBLOCK_INPUT;
+
+         return 1;
+       }
+    }
+#endif
+
+  return 0;
+}
+
 int
 sys_select (nfds, rfds, wfds, efds, timeout)
      int nfds;
@@ -5149,7 +5127,7 @@ sys_select (nfds, rfds, wfds, efds, timeout)
       if (timeoutval > 0 && timeoutval <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP)
        goto poll_periodically;
 
-      /* Try detect_input_pending before CFRunLoopRunInMode in the
+      /* Try detect_input_pending before mac_run_loop_run_once in the
         same BLOCK_INPUT block, in case that some input has already
         been read asynchronously.  */
       BLOCK_INPUT;
@@ -5165,6 +5143,11 @@ sys_select (nfds, rfds, wfds, efds, timeout)
              CFDictionaryCreateMutable (NULL, 0, NULL,
                                         &kCFTypeDictionaryValueCallBacks);
 
+         if (cfsockets_for_select == NULL)
+           cfsockets_for_select =
+             CFDictionaryCreateMutable (NULL, 0, NULL,
+                                        &kCFTypeDictionaryValueCallBacks);
+
          for (minfd = 1; ; minfd++) /* nfds-1 works as a sentinel.  */
            if (FD_ISSET (minfd, rfds) || (wfds && FD_ISSET (minfd, wfds)))
              break;
@@ -5176,7 +5159,7 @@ sys_select (nfds, rfds, wfds, efds, timeout)
                CFRunLoopSourceRef source =
                  (CFRunLoopSourceRef) CFDictionaryGetValue (sources, key);
 
-               if (source == NULL)
+               if (source == NULL || !CFRunLoopSourceIsValid (source))
                  {
                    CFSocketRef socket =
                      CFSocketCreateWithNative (NULL, fd,
@@ -5186,23 +5169,18 @@ sys_select (nfds, rfds, wfds, efds, timeout)
 
                    if (socket == NULL)
                      continue;
+                   CFDictionarySetValue (cfsockets_for_select, key, socket);
                    source = CFSocketCreateRunLoopSource (NULL, socket, 0);
                    CFRelease (socket);
                    if (source == NULL)
                      continue;
-                   CFDictionaryAddValue (sources, key, source);
+                   CFDictionarySetValue (sources, key, source);
                    CFRelease (source);
                  }
                CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode);
              }
 
-#if USE_CG_DRAWING
-         mac_prepare_for_quickdraw (NULL);
-#endif
-         if (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
-                                 timeoutval >= 0 ? timeoutval : 100000, true)
-             == kCFRunLoopRunTimedOut)
-           timedout_p = 1;
+         timedout_p = mac_run_loop_run_once (timeoutval);
 
          for (fd = minfd; fd < nfds; fd++)
            if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds)))
@@ -5292,6 +5270,8 @@ init_mac_osx_environment ()
   char *p, *q;
   struct stat st;
 
+  mac_emacs_pid = getpid ();
+
   /* Initialize locale related variables.  */
   mac_system_script_code =
     (ScriptCode) GetScriptManagerVariable (smSysScript);