/* Unix emulation routines for GNU Emacs on the Mac OS.
Copyright (C) 2000, 2001, 2002, 2003, 2004,
- 2005, 2006 Free Software Foundation, Inc.
+ 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Emacs.
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 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
#include <Folders.h>
#include <Resources.h>
#include <Aliases.h>
-#include <FixMath.h>
#include <Timer.h>
#include <OSA.h>
#include <AppleScript.h>
-#include <Scrap.h>
#include <Events.h>
#include <Processes.h>
#include <EPPC.h>
/* The single script context used for all script executions. */
static OSAID as_script_context;
+#ifndef MAC_OS_X
+#if TARGET_API_MAC_CARBON
+static int wakeup_from_rne_enabled_p = 0;
+#define ENABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 1)
+#define DISABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 0)
+#else
+#define ENABLE_WAKEUP_FROM_RNE 0
+#define DISABLE_WAKEUP_FROM_RNE 0
+#endif
+#endif
+
#ifndef MAC_OSX
static OSErr posix_pathname_to_fsspec P_ ((const char *, FSSpec *));
static OSErr fsspec_to_posix_pathname P_ ((const FSSpec *, char *, int));
static Lisp_Object Qundecoded_file_name;
+static struct {
+ AEKeyword keyword;
+ char *name;
+ Lisp_Object symbol;
+} ae_attr_table [] =
+ {{keyTransactionIDAttr, "transaction-id"},
+ {keyReturnIDAttr, "return-id"},
+ {keyEventClassAttr, "event-class"},
+ {keyEventIDAttr, "event-id"},
+ {keyAddressAttr, "address"},
+ {keyOptionalKeywordAttr, "optional-keyword"},
+ {keyTimeoutAttr, "timeout"},
+ {keyInteractLevelAttr, "interact-level"},
+ {keyEventSourceAttr, "event-source"},
+ /* {keyMissedKeywordAttr, "missed-keyword"}, */
+ {keyOriginalAddressAttr, "original-address"},
+ {keyReplyRequestedAttr, "reply-requested"},
+ {KEY_EMACS_SUSPENSION_ID_ATTR, "emacs-suspension-id"}
+ };
+
static Lisp_Object
mac_aelist_to_lisp (desc_list)
- AEDescList *desc_list;
+ const AEDescList *desc_list;
{
OSErr err;
long count;
Size size;
AEKeyword keyword;
AEDesc desc;
+ int attribute_p = 0;
err = AECountItems (desc_list, &count);
if (err != noErr)
return Qnil;
result = Qnil;
+
+ again:
while (count > 0)
{
- err = AESizeOfNthItem (desc_list, count, &desc_type, &size);
+ if (attribute_p)
+ {
+ keyword = ae_attr_table[count - 1].keyword;
+ err = AESizeOfAttribute (desc_list, keyword, &desc_type, &size);
+ }
+ else
+ err = AESizeOfNthItem (desc_list, count, &desc_type, &size);
+
if (err == noErr)
switch (desc_type)
{
case typeAEList:
case typeAERecord:
case typeAppleEvent:
- err = AEGetNthDesc (desc_list, count, typeWildCard,
- &keyword, &desc);
+ if (attribute_p)
+ err = AEGetAttributeDesc (desc_list, keyword, typeWildCard,
+ &desc);
+ else
+ err = AEGetNthDesc (desc_list, count, typeWildCard,
+ &keyword, &desc);
if (err != noErr)
break;
elem = mac_aelist_to_lisp (&desc);
else
{
elem = make_uninit_string (size);
- err = AEGetNthPtr (desc_list, count, typeWildCard, &keyword,
- &desc_type, SDATA (elem), size, &size);
+ if (attribute_p)
+ err = AEGetAttributePtr (desc_list, keyword, typeWildCard,
+ &desc_type, SDATA (elem),
+ size, &size);
+ else
+ err = AEGetNthPtr (desc_list, count, typeWildCard, &keyword,
+ &desc_type, SDATA (elem), size, &size);
}
if (err != noErr)
break;
break;
}
- if (err != noErr)
- elem = Qnil;
- else if (desc_list->descriptorType != typeAEList)
+ if (err == noErr || desc_list->descriptorType == typeAEList)
{
- keyword = EndianU32_NtoB (keyword);
- elem = Fcons (make_unibyte_string ((char *) &keyword, 4), elem);
+ if (err != noErr)
+ elem = Qnil; /* Don't skip elements in AEList. */
+ else if (desc_list->descriptorType != typeAEList)
+ {
+ if (attribute_p)
+ elem = Fcons (ae_attr_table[count-1].symbol, elem);
+ else
+ {
+ keyword = EndianU32_NtoB (keyword);
+ elem = Fcons (make_unibyte_string ((char *) &keyword, 4),
+ elem);
+ }
+ }
+
+ result = Fcons (elem, result);
}
- result = Fcons (elem, result);
count--;
}
+ if (desc_list->descriptorType == typeAppleEvent && !attribute_p)
+ {
+ attribute_p = 1;
+ count = sizeof (ae_attr_table) / sizeof (ae_attr_table[0]);
+ goto again;
+ }
+
desc_type = EndianU32_NtoB (desc_list->descriptorType);
return Fcons (make_unibyte_string ((char *) &desc_type, 4), result);
}
Lisp_Object
mac_aedesc_to_lisp (desc)
- AEDesc *desc;
+ const AEDesc *desc;
{
OSErr err = noErr;
DescType desc_type = desc->descriptorType;
return Fcons (make_unibyte_string ((char *) &desc_type, 4), result);
}
+OSErr
+mac_ae_put_lisp (desc, keyword_or_index, obj)
+ AEDescList *desc;
+ UInt32 keyword_or_index;
+ Lisp_Object obj;
+{
+ OSErr err;
+
+ if (!(desc->descriptorType == typeAppleEvent
+ || desc->descriptorType == typeAERecord
+ || desc->descriptorType == typeAEList))
+ return errAEWrongDataType;
+
+ if (CONSP (obj) && STRINGP (XCAR (obj)) && SBYTES (XCAR (obj)) == 4)
+ {
+ DescType desc_type1 = EndianU32_BtoN (*((UInt32 *) SDATA (XCAR (obj))));
+ Lisp_Object data = XCDR (obj), rest;
+ AEDesc desc1;
+
+ switch (desc_type1)
+ {
+ case typeNull:
+ case typeAppleEvent:
+ break;
+
+ case typeAEList:
+ case typeAERecord:
+ err = AECreateList (NULL, 0, desc_type1 == typeAERecord, &desc1);
+ if (err == noErr)
+ {
+ for (rest = data; CONSP (rest); rest = XCDR (rest))
+ {
+ UInt32 keyword_or_index1 = 0;
+ Lisp_Object elem = XCAR (rest);
+
+ if (desc_type1 == typeAERecord)
+ {
+ if (CONSP (elem) && STRINGP (XCAR (elem))
+ && SBYTES (XCAR (elem)) == 4)
+ {
+ keyword_or_index1 =
+ EndianU32_BtoN (*((UInt32 *)
+ SDATA (XCAR (elem))));
+ elem = XCDR (elem);
+ }
+ else
+ continue;
+ }
+
+ err = mac_ae_put_lisp (&desc1, keyword_or_index1, elem);
+ if (err != noErr)
+ break;
+ }
+
+ if (err == noErr)
+ {
+ if (desc->descriptorType == typeAEList)
+ err = AEPutDesc (desc, keyword_or_index, &desc1);
+ else
+ err = AEPutParamDesc (desc, keyword_or_index, &desc1);
+ }
+
+ AEDisposeDesc (&desc1);
+ }
+ return err;
+
+ default:
+ if (!STRINGP (data))
+ break;
+ if (desc->descriptorType == typeAEList)
+ err = AEPutPtr (desc, keyword_or_index, desc_type1,
+ SDATA (data), SBYTES (data));
+ else
+ err = AEPutParamPtr (desc, keyword_or_index, desc_type1,
+ SDATA (data), SBYTES (data));
+ return err;
+ }
+ }
+
+ if (desc->descriptorType == typeAEList)
+ err = AEPutPtr (desc, keyword_or_index, typeNull, NULL, 0);
+ else
+ err = AEPutParamPtr (desc, keyword_or_index, typeNull, NULL, 0);
+
+ return err;
+}
+
static pascal OSErr
mac_coerce_file_name_ptr (type_code, data_ptr, data_size,
to_type, handler_refcon, result)
}
else
err = memFullErr;
-#else
- FSSpec fs;
- char *buf;
- buf = xmalloc (data_size + 1);
- if (buf)
+ if (err != noErr)
{
+ /* Just to be paranoid ... */
+ FSRef fref;
+ char *buf;
+
+ buf = xmalloc (data_size + 1);
memcpy (buf, data_ptr, data_size);
buf[data_size] = '\0';
- err = posix_pathname_to_fsspec (buf, &fs);
+ err = FSPathMakeRef (buf, &fref, NULL);
xfree (buf);
+ if (err == noErr)
+ err = AECoercePtr (typeFSRef, &fref, sizeof (FSRef),
+ to_type, result);
}
- else
- err = memFullErr;
+#else
+ FSSpec fs;
+ char *buf;
+
+ buf = xmalloc (data_size + 1);
+ memcpy (buf, data_ptr, data_size);
+ buf[data_size] = '\0';
+ err = posix_pathname_to_fsspec (buf, &fs);
+ xfree (buf);
if (err == noErr)
err = AECoercePtr (typeFSS, &fs, sizeof (FSSpec), to_type, result);
#endif
{
size = AEGetDescDataSize (&desc);
buf = xmalloc (size);
- if (buf)
- {
- err = AEGetDescData (&desc, buf, size);
- if (err == noErr)
- url = CFURLCreateWithBytes (NULL, buf, size,
- kCFStringEncodingUTF8, NULL);
- xfree (buf);
- }
+ err = AEGetDescData (&desc, buf, size);
+ if (err == noErr)
+ url = CFURLCreateWithBytes (NULL, buf, size,
+ kCFStringEncodingUTF8, NULL);
+ xfree (buf);
AEDisposeDesc (&desc);
}
}
CFDataGetLength (data), result);
CFRelease (data);
}
+
+ if (err != noErr)
+ {
+ /* Coercion from typeAlias to typeFileURL fails on Mac OS X
+ 10.2. In such cases, try typeFSRef as a target type. */
+ char file_name[MAXPATHLEN];
+
+ if (type_code == typeFSRef && data_size == sizeof (FSRef))
+ err = FSRefMakePath (data_ptr, file_name, sizeof (file_name));
+ else
+ {
+ AEDesc desc;
+ FSRef fref;
+
+ err = AECoercePtr (type_code, data_ptr, data_size,
+ typeFSRef, &desc);
+ if (err == noErr)
+ {
+ err = AEGetDescData (&desc, &fref, sizeof (FSRef));
+ AEDisposeDesc (&desc);
+ }
+ if (err == noErr)
+ err = FSRefMakePath (&fref, file_name, sizeof (file_name));
+ }
+ if (err == noErr)
+ err = AECreateDesc (TYPE_FILE_NAME, file_name,
+ strlen (file_name), result);
+ }
#else
char file_name[MAXPATHLEN];
#else
fs = *(FSSpec *)(*(desc.dataHandle));
#endif
- if (err == noErr)
- err = fsspec_to_posix_pathname (&fs, file_name,
- sizeof (file_name) - 1);
AEDisposeDesc (&desc);
}
+ if (err == noErr)
+ err = fsspec_to_posix_pathname (&fs, file_name,
+ sizeof (file_name) - 1);
}
if (err == noErr)
err = AECreateDesc (TYPE_FILE_NAME, file_name,
data_size = GetHandleSize (from_desc->dataHandle);
#endif
data_ptr = xmalloc (data_size);
- if (data_ptr)
- {
#if TARGET_API_MAC_CARBON
- err = AEGetDescData (from_desc, data_ptr, data_size);
+ err = AEGetDescData (from_desc, data_ptr, data_size);
#else
- memcpy (data_ptr, *(from_desc->dataHandle), data_size);
+ memcpy (data_ptr, *(from_desc->dataHandle), data_size);
#endif
- if (err == noErr)
- err = mac_coerce_file_name_ptr (from_type, data_ptr,
- data_size, to_type,
- handler_refcon, result);
- xfree (data_ptr);
- }
- else
- err = memFullErr;
+ if (err == noErr)
+ err = mac_coerce_file_name_ptr (from_type, data_ptr,
+ data_size, to_type,
+ handler_refcon, result);
+ xfree (data_ptr);
}
if (err != noErr)
}
#if TARGET_API_MAC_CARBON
-OSErr
-create_apple_event_from_event_ref (event, num_params, names, types, result)
- EventRef event;
- UInt32 num_params;
- EventParamName *names;
- EventParamType *types;
+static OSErr
+create_apple_event (class, id, result)
+ AEEventClass class;
+ AEEventID id;
AppleEvent *result;
{
OSErr err;
static const ProcessSerialNumber psn = {0, kCurrentProcess};
AEAddressDesc address_desc;
- UInt32 i, size;
- CFStringRef string;
- CFDataRef data;
- char *buf;
err = AECreateDesc (typeProcessSerialNumber, &psn,
sizeof (ProcessSerialNumber), &address_desc);
if (err == noErr)
{
- err = AECreateAppleEvent (0, 0, /* Dummy class and ID. */
+ err = AECreateAppleEvent (class, id,
&address_desc, /* NULL is not allowed
on Mac OS Classic. */
kAutoGenerateReturnID,
kAnyTransactionID, result);
AEDisposeDesc (&address_desc);
}
+
+ return err;
+}
+
+OSStatus
+create_apple_event_from_event_ref (event, num_params, names, types, result)
+ EventRef event;
+ UInt32 num_params;
+ const EventParamName *names;
+ const EventParamType *types;
+ AppleEvent *result;
+{
+ OSStatus err;
+ UInt32 i, size;
+ CFStringRef string;
+ CFDataRef data;
+ char *buf = NULL;
+
+ err = create_apple_event (0, 0, result); /* Dummy class and ID. */
if (err != noErr)
return err;
'?');
if (data == NULL)
break;
- /* typeUTF8Text is not available on Mac OS X 10.1. */
- AEPutParamPtr (result, names[i], 'utf8',
+ AEPutParamPtr (result, names[i], typeUTF8Text,
CFDataGetBytePtr (data), CFDataGetLength (data));
CFRelease (data);
break;
0, &size, NULL);
if (err != noErr)
break;
- buf = xmalloc (size);
- if (buf == NULL)
- 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);
- xfree (buf);
break;
}
+ if (buf)
+ xfree (buf);
return noErr;
}
-#endif
+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++)
+ {
+ ItemReference item;
+ DescType desc_type = typeNull;
+ Size size;
+
+ err = GetDragItemReferenceNumber (drag, index, &item);
+ if (err == noErr)
+ {
+ int i;
+
+ for (i = 0; i < num_types; i++)
+ {
+ 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;
+ }
+ }
+ }
+ 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);
+ }
+
+ AEDisposeDesc (&items);
+
+ return err;
+}
+#endif /* TARGET_API_MAC_CARBON */
\f
/***********************************************************************
Conversion between Lisp and Core Foundation objects
cfdate_to_lisp (date)
CFDateRef date;
{
- static const CFGregorianDate epoch_gdate = {1970, 1, 1, 0, 0, 0.0};
- static CFAbsoluteTime epoch = 0.0, sec;
- int high, low;
-
- if (epoch == 0.0)
- epoch = CFGregorianDateGetAbsoluteTime (epoch_gdate, NULL);
+ CFTimeInterval sec;
+ int high, low, microsec;
- sec = CFDateGetAbsoluteTime (date) - epoch;
+ sec = CFDateGetAbsoluteTime (date) + kCFAbsoluteTimeIntervalSince1970;
high = sec / 65536.0;
low = sec - high * 65536.0;
+ microsec = (sec - floor (sec)) * 1000000.0;
- return list3 (make_number (high), make_number (low), make_number (0));
+ return list3 (make_number (high), make_number (low), make_number (microsec));
}
static void
skip_white_space (p)
- char **p;
+ const char **p;
{
/* WhiteSpace = {<space> | <horizontal tab>} */
while (*P == ' ' || *P == '\t')
static int
parse_comment (p)
- char **p;
+ const char **p;
{
/* Comment = "!" {<any character except null or newline>} */
if (*P == '!')
/* Don't interpret filename. Just skip until the newline. */
static int
parse_include_file (p)
- char **p;
+ const char **p;
{
/* IncludeFile = "#" WhiteSpace "include" WhiteSpace FileName WhiteSpace */
if (*P == '#')
static char
parse_binding (p)
- char **p;
+ const char **p;
{
/* Binding = "." | "*" */
if (*P == '.' || *P == '*')
static Lisp_Object
parse_component (p)
- char **p;
+ const char **p;
{
/* Component = "?" | ComponentName
ComponentName = NameChar {NameChar}
}
else if (isalnum (*P) || *P == '_' || *P == '-')
{
- char *start = P++;
+ const char *start = P++;
while (isalnum (*P) || *P == '_' || *P == '-')
P++;
static Lisp_Object
parse_resource_name (p)
- char **p;
+ const char **p;
{
Lisp_Object result = Qnil, component;
char binding;
static Lisp_Object
parse_value (p)
- char **p;
+ const char **p;
{
char *q, *buf;
Lisp_Object seq = Qnil, result;
static Lisp_Object
parse_resource_line (p)
- char **p;
+ const char **p;
{
Lisp_Object quarks, value;
void
xrm_merge_string_database (database, data)
XrmDatabase database;
- char *data;
+ const char *data;
{
Lisp_Object quarks_value;
Lisp_Object
xrm_get_resource (database, name, class)
XrmDatabase database;
- char *name, *class;
+ const char *name, *class;
{
Lisp_Object key, query_cache, quark_name, quark_class, tmp;
int i, nn, nc;
XrmDatabase
xrm_get_preference_database (application)
- char *application;
+ const char *application;
{
#if TARGET_API_MAC_CARBON
CFStringRef app_id, *keys, user_doms[2], host_doms[2];
GCPRO3 (database, quarks, value);
- BLOCK_INPUT;
-
app_id = kCFPreferencesCurrentApplication;
if (application)
{
if (app_id == NULL)
goto out;
}
+ if (!CFPreferencesAppSynchronize (app_id))
+ goto out;
key_set = CFSetCreateMutable (NULL, 0, &kCFCopyStringSetCallBacks);
if (key_set == NULL)
count = CFSetGetCount (key_set);
keys = xmalloc (sizeof (CFStringRef) * count);
- if (keys == NULL)
- goto out;
CFSetGetValues (key_set, (const void **)keys);
for (index = 0; index < count; index++)
{
CFRelease (key_set);
CFRelease (app_id);
- UNBLOCK_INPUT;
-
UNGCPRO;
return database;
int res = open (mac_pathname, oflag);
/* if (oflag == O_WRONLY || oflag == O_RDWR) */
if (oflag & O_CREAT)
- fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+ fsetfileinfo (mac_pathname, MAC_EMACS_CREATOR_CODE, 'TEXT');
return res;
#else /* not __MRC__ */
return open (mac_pathname, oflag);
{
#ifdef __MRC__
int result = creat (mac_pathname);
- fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+ fsetfileinfo (mac_pathname, MAC_EMACS_CREATOR_CODE, 'TEXT');
return result;
#else /* not __MRC__ */
return creat (mac_pathname, mode);
{
#ifdef __MRC__
if (mode[0] == 'w' || mode[0] == 'a')
- fsetfileinfo (mac_pathname, 'EMAx', 'TEXT');
+ fsetfileinfo (mac_pathname, MAC_EMACS_CREATOR_CODE, 'TEXT');
#endif /* not __MRC__ */
return fopen (mac_pathname, mode);
}
}
-#include "keyboard.h"
-extern Boolean mac_wait_next_event (EventRecord *, UInt32, Boolean);
+extern Boolean mac_wait_next_event P_ ((EventRecord *, UInt32, Boolean));
int
-select (n, rfds, wfds, efds, timeout)
- int n;
- SELECT_TYPE *rfds;
- SELECT_TYPE *wfds;
- SELECT_TYPE *efds;
- struct timeval *timeout;
+select (nfds, rfds, wfds, efds, timeout)
+ int nfds;
+ SELECT_TYPE *rfds, *wfds, *efds;
+ EMACS_TIME *timeout;
{
- OSErr err;
-#if TARGET_API_MAC_CARBON
- EventTimeout timeout_sec =
- (timeout
- ? (EMACS_SECS (*timeout) * kEventDurationSecond
- + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
- : kEventDurationForever);
-
- BLOCK_INPUT;
- err = ReceiveNextEvent (0, NULL, timeout_sec, kEventLeaveInQueue, NULL);
- UNBLOCK_INPUT;
-#else /* not TARGET_API_MAC_CARBON */
- EventRecord e;
- UInt32 sleep_time = EMACS_SECS (*timeout) * 60 +
- ((EMACS_USECS (*timeout) * 60) / 1000000);
+ OSStatus err = noErr;
/* Can only handle wait for keyboard input. */
- if (n > 1 || wfds || efds)
+ if (nfds > 1 || wfds || efds)
return -1;
- /* Also return true if an event other than a keyDown has occurred.
- This causes kbd_buffer_get_event in keyboard.c to call
- read_avail_input which in turn calls XTread_socket to poll for
- these events. Otherwise these never get processed except but a
- very slow poll timer. */
- if (mac_wait_next_event (&e, sleep_time, false))
- err = noErr;
- else
- err = -9875; /* eventLoopTimedOutErr */
+ /* Try detect_input_pending before ReceiveNextEvent in the same
+ BLOCK_INPUT block, in case that some input has already been read
+ asynchronously. */
+ BLOCK_INPUT;
+ ENABLE_WAKEUP_FROM_RNE;
+ if (!detect_input_pending ())
+ {
+#if TARGET_API_MAC_CARBON
+ EventTimeout timeoutval =
+ (timeout
+ ? (EMACS_SECS (*timeout) * kEventDurationSecond
+ + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
+ : kEventDurationForever);
+
+ if (timeoutval == 0.0)
+ err = eventLoopTimedOutErr;
+ else
+ err = ReceiveNextEvent (0, NULL, timeoutval,
+ kEventLeaveInQueue, NULL);
+#else /* not TARGET_API_MAC_CARBON */
+ EventRecord e;
+ UInt32 sleep_time = EMACS_SECS (*timeout) * 60 +
+ ((EMACS_USECS (*timeout) * 60) / 1000000);
+
+ if (sleep_time == 0)
+ err = -9875; /* eventLoopTimedOutErr */
+ else
+ {
+ if (mac_wait_next_event (&e, sleep_time, false))
+ err = noErr;
+ else
+ err = -9875; /* eventLoopTimedOutErr */
+ }
#endif /* not TARGET_API_MAC_CARBON */
+ }
+ DISABLE_WAKEUP_FROM_RNE;
+ UNBLOCK_INPUT;
- if (FD_ISSET (0, rfds))
- if (err == noErr)
- return 1;
- else
- {
- FD_ZERO (rfds);
- return 0;
- }
+ if (err == noErr)
+ {
+ /* Pretend that `select' is interrupted by a signal. */
+ detect_input_pending ();
+ errno = EINTR;
+ return -1;
+ }
else
- if (err == noErr)
- {
- if (input_polling_used ())
- {
- /* It could be confusing if a real alarm arrives while
- processing the fake one. Turn it off and let the
- handler reset it. */
- extern void poll_for_input_1 P_ ((void));
- int old_poll_suppress_count = poll_suppress_count;
- poll_suppress_count = 1;
- poll_for_input_1 ();
- poll_suppress_count = old_poll_suppress_count;
- }
- errno = EINTR;
- return -1;
- }
- else
+ {
+ if (rfds)
+ FD_ZERO (rfds);
return 0;
+ }
}
(filename)
Lisp_Object filename;
{
- OSErr status;
+ OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
(filename)
Lisp_Object filename;
{
- OSErr status;
+ OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
(filename, code)
Lisp_Object filename, code;
{
- OSErr status;
+ OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
OSType cCode;
CHECK_STRING (filename);
- cCode = mac_get_code_from_arg(code, 'EMAx');
+ cCode = mac_get_code_from_arg(code, MAC_EMACS_CREATOR_CODE);
if (NILP(Ffile_exists_p(filename)) || !NILP(Ffile_directory_p(filename))) {
return Qnil;
(filename, code)
Lisp_Object filename, code;
{
- OSErr status;
+ OSStatus status;
#ifdef MAC_OSX
FSRef fref;
#else
CFStringRef app_id, key_str;
CFPropertyListRef app_plist = NULL, plist;
Lisp_Object result = Qnil, tmp;
+ struct gcpro gcpro1, gcpro2;
if (STRINGP (key))
key = Fcons (key, Qnil);
CHECK_CONS (key);
for (tmp = key; CONSP (tmp); tmp = XCDR (tmp))
CHECK_STRING_CAR (tmp);
- if (!NILP (tmp))
- wrong_type_argument (Qlistp, key);
+ CHECK_LIST_END (tmp, key);
}
if (!NILP (application))
CHECK_STRING (application);
if (!NILP (hash_bound))
CHECK_NUMBER (hash_bound);
+ GCPRO2 (key, format);
+
BLOCK_INPUT;
app_id = kCFPreferencesCurrentApplication;
if (app_id == NULL)
goto out;
}
+ if (!CFPreferencesAppSynchronize (app_id))
+ goto out;
+
key_str = cfstring_create_with_string (XCAR (key));
if (key_str == NULL)
goto out;
UNBLOCK_INPUT;
+ UNGCPRO;
+
return result;
}
UnicodeMapping map;
CFIndex length;
UniChar *in_text, *buffer = NULL, *out_buf = NULL;
- OSErr err = noErr;
+ OSStatus err = noErr;
ByteCount out_read, out_size, out_len;
map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
if (in_text == NULL)
{
buffer = xmalloc (sizeof (UniChar) * length);
- if (buffer)
- {
- CFStringGetCharacters (str, CFRangeMake (0, length), buffer);
- in_text = buffer;
- }
+ CFStringGetCharacters (str, CFRangeMake (0, length), buffer);
+ in_text = buffer;
}
if (in_text)
- err = CreateUnicodeToTextInfo(&map, &uni);
+ err = CreateUnicodeToTextInfo (&map, &uni);
while (err == noErr)
{
out_buf = xmalloc (out_size);
- if (out_buf == NULL)
- err = mFulErr;
- else
- err = ConvertFromUnicodeToText (uni, length * sizeof (UniChar),
- in_text,
- kUnicodeDefaultDirectionMask,
- 0, NULL, NULL, NULL,
- out_size, &out_read, &out_len,
- out_buf);
+ err = ConvertFromUnicodeToText (uni, length * sizeof (UniChar),
+ in_text,
+ kUnicodeDefaultDirectionMask,
+ 0, NULL, NULL, NULL,
+ out_size, &out_read, &out_len,
+ out_buf);
if (err == noErr && out_read < length * sizeof (UniChar))
{
xfree (out_buf);
doc: /* Convert STRING from SOURCE encoding to TARGET encoding.
The conversion is performed using the converter provided by the system.
Each encoding is specified by either a coding system symbol, a mime
-charset string, or an integer as a CFStringEncoding value. Nil for
-encoding means UTF-16 in native byte order, no byte order mark.
+charset string, or an integer as a CFStringEncoding value. An encoding
+of nil means UTF-16 in native byte order, no byte order mark.
On Mac OS X 10.2 and later, you can do Unicode Normalization by
specifying the optional argument NORMALIZATION-FORM with a symbol NFD,
NFKD, NFC, NFKC, HFS+D, or HFS+C.
Lisp_Object string, source, target, normalization_form;
{
Lisp_Object result = Qnil;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
CFStringEncoding src_encoding, tgt_encoding;
CFStringRef str = NULL;
CHECK_SYMBOL (target);
CHECK_SYMBOL (normalization_form);
+ GCPRO4 (string, source, target, normalization_form);
+
BLOCK_INPUT;
src_encoding = get_cfstring_encoding_from_lisp (source);
UNBLOCK_INPUT;
+ UNGCPRO;
+
return result;
}
-#endif /* TARGET_API_MAC_CARBON */
-
-DEFUN ("mac-clear-font-name-table", Fmac_clear_font_name_table, Smac_clear_font_name_table, 0, 0, 0,
- doc: /* Clear the font name table. */)
- ()
+DEFUN ("mac-process-hi-command", Fmac_process_hi_command, Smac_process_hi_command, 1, 1, 0,
+ doc: /* Send a HI command whose ID is COMMAND-ID to the command chain.
+COMMAND-ID must be a 4-character string. Some common command IDs are
+defined in the Carbon Event Manager. */)
+ (command_id)
+ Lisp_Object command_id;
{
- check_mac ();
- mac_clear_font_name_table ();
+ OSStatus err;
+ HICommand command;
+
+ bzero (&command, sizeof (HICommand));
+ command.commandID = mac_get_code_from_arg (command_id, 0);
+
+ BLOCK_INPUT;
+ err = ProcessHICommand (&command);
+ UNBLOCK_INPUT;
+
+ if (err != noErr)
+ error ("HI command (command ID: '%s') not handled.", SDATA (command_id));
+
return Qnil;
}
+#endif /* TARGET_API_MAC_CARBON */
+
static Lisp_Object
mac_get_system_locale ()
{
- OSErr err;
+ OSStatus err;
LangCode lang;
RegionCode region;
LocaleRef locale;
-> Use `select'.
2. Sockets are not involved.
-> Use ReceiveNextEvent.
- 3. [If SELECT_USE_CFSOCKET is defined]
- Only the window event channel and socket read channels are
+ 3. [If SELECT_USE_CFSOCKET is set]
+ Only the window event channel and socket read/write channels are
involved, and timeout is not too short (greater than
- SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds).
+ SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds).
-> Create CFSocket for each socket and add it into the current
- event RunLoop so that a `ready-to-read' event can be posted
- to the event queue that is also used for window events. Then
- ReceiveNextEvent can wait for both kinds of inputs.
+ event RunLoop so that the current event loop gets quit when
+ the socket becomes ready. Then CFRunLoopRunInMode can wait
+ for both kinds of inputs.
4. Otherwise.
-> Periodically poll the window input channel while repeatedly
executing `select' with a short timeout
(SELECT_POLLING_PERIOD_USEC microseconds). */
-#define SELECT_POLLING_PERIOD_USEC 20000
-#ifdef SELECT_USE_CFSOCKET
+#ifndef SELECT_USE_CFSOCKET
+#define SELECT_USE_CFSOCKET 1
+#endif
+
+#define SELECT_POLLING_PERIOD_USEC 100000
+#if SELECT_USE_CFSOCKET
#define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2
-#define EVENT_CLASS_SOCK 'Sock'
static void
socket_callback (s, type, address, data, info)
const void *data;
void *info;
{
- EventRef event;
-
- CreateEvent (NULL, EVENT_CLASS_SOCK, 0, 0, kEventAttributeNone, &event);
- PostEventToQueue (GetCurrentEventQueue (), event, kEventPriorityStandard);
- ReleaseEvent (event);
}
#endif /* SELECT_USE_CFSOCKET */
static int
-select_and_poll_event (n, rfds, wfds, efds, timeout)
- int n;
- SELECT_TYPE *rfds;
- SELECT_TYPE *wfds;
- SELECT_TYPE *efds;
- struct timeval *timeout;
+select_and_poll_event (nfds, rfds, wfds, efds, timeout)
+ int nfds;
+ SELECT_TYPE *rfds, *wfds, *efds;
+ EMACS_TIME *timeout;
{
- int r;
- OSErr err;
+ int timedout_p = 0;
+ int r = 0;
+ EMACS_TIME select_timeout;
+ EventTimeout timeoutval =
+ (timeout
+ ? (EMACS_SECS (*timeout) * kEventDurationSecond
+ + EMACS_USECS (*timeout) * kEventDurationMicrosecond)
+ : kEventDurationForever);
+ SELECT_TYPE orfds, owfds, oefds;
- r = select (n, rfds, wfds, efds, timeout);
- if (r != -1)
+ if (timeout == NULL)
{
- BLOCK_INPUT;
- err = ReceiveNextEvent (0, NULL, kEventDurationNoWait,
- kEventLeaveInQueue, NULL);
- UNBLOCK_INPUT;
- if (err == noErr)
+ if (rfds) orfds = *rfds;
+ if (wfds) owfds = *wfds;
+ if (efds) oefds = *efds;
+ }
+
+ /* Try detect_input_pending before CFRunLoopRunInMode in the same
+ BLOCK_INPUT block, in case that some input has already been read
+ asynchronously. */
+ BLOCK_INPUT;
+ while (1)
+ {
+ if (detect_input_pending ())
+ break;
+
+ EMACS_SET_SECS_USECS (select_timeout, 0, 0);
+ r = select (nfds, rfds, wfds, efds, &select_timeout);
+ if (r != 0)
+ break;
+
+ 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;
+ }
+
+ if (timeout == NULL && timedout_p)
{
- FD_SET (0, rfds);
- r++;
+ if (rfds) *rfds = orfds;
+ if (wfds) *wfds = owfds;
+ if (efds) *efds = oefds;
}
+ else
+ break;
}
- return r;
-}
+ UNBLOCK_INPUT;
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 1020
-#undef SELECT_INVALIDATE_CFSOCKET
-#endif
+ if (r != 0)
+ return r;
+ else if (!timedout_p)
+ {
+ /* Pretend that `select' is interrupted by a signal. */
+ detect_input_pending ();
+ errno = EINTR;
+ return -1;
+ }
+ else
+ return 0;
+}
int
-sys_select (n, rfds, wfds, efds, timeout)
- int n;
- SELECT_TYPE *rfds;
- SELECT_TYPE *wfds;
- SELECT_TYPE *efds;
- struct timeval *timeout;
+sys_select (nfds, rfds, wfds, efds, timeout)
+ int nfds;
+ SELECT_TYPE *rfds, *wfds, *efds;
+ EMACS_TIME *timeout;
{
- OSErr err;
- int i, r;
+ int timedout_p = 0;
+ int r;
EMACS_TIME select_timeout;
+ SELECT_TYPE orfds, owfds, oefds;
if (inhibit_window_system || noninteractive
- || rfds == NULL || !FD_ISSET (0, rfds))
- return select (n, rfds, wfds, efds, timeout);
+ || nfds < 1 || rfds == NULL || !FD_ISSET (0, rfds))
+ return select (nfds, rfds, wfds, efds, timeout);
FD_CLR (0, rfds);
+ orfds = *rfds;
- if (wfds == NULL && efds == NULL)
- {
- int nsocks = 0;
- SELECT_TYPE orfds = *rfds;
+ if (wfds)
+ owfds = *wfds;
+ else
+ FD_ZERO (&owfds);
- EventTimeout timeout_sec =
+ if (efds)
+ oefds = *efds;
+ else
+ {
+ EventTimeout timeoutval =
(timeout
? (EMACS_SECS (*timeout) * kEventDurationSecond
+ EMACS_USECS (*timeout) * kEventDurationMicrosecond)
: kEventDurationForever);
- for (i = 1; i < n; i++)
- if (FD_ISSET (i, rfds))
- nsocks++;
-
- if (nsocks == 0)
+ FD_SET (0, rfds); /* sentinel */
+ do
{
- BLOCK_INPUT;
- err = ReceiveNextEvent (0, NULL, timeout_sec,
- kEventLeaveInQueue, NULL);
- UNBLOCK_INPUT;
- if (err == noErr)
- {
- FD_SET (0, rfds);
- return 1;
- }
- else
- return 0;
+ nfds--;
}
+ while (!(FD_ISSET (nfds, rfds) || (wfds && FD_ISSET (nfds, wfds))));
+ nfds++;
+ FD_CLR (0, rfds);
+
+ if (nfds == 1)
+ return select_and_poll_event (nfds, rfds, wfds, efds, timeout);
-#if USE_CG_DRAWING
- mac_prepare_for_quickdraw (NULL);
-#endif
/* Avoid initial overhead of RunLoop setup for the case that
some input is already available. */
EMACS_SET_SECS_USECS (select_timeout, 0, 0);
- r = select_and_poll_event (n, rfds, wfds, efds, &select_timeout);
- if (r != 0 || timeout_sec == 0.0)
+ r = select_and_poll_event (nfds, rfds, wfds, efds, &select_timeout);
+ if (r != 0 || timeoutval == 0.0)
return r;
*rfds = orfds;
+ if (wfds)
+ *wfds = owfds;
-#ifdef SELECT_USE_CFSOCKET
- if (timeout_sec > 0 && timeout_sec <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP)
+#if SELECT_USE_CFSOCKET
+ if (timeoutval > 0 && timeoutval <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP)
goto poll_periodically;
- {
- CFRunLoopRef runloop =
- (CFRunLoopRef) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
- EventTypeSpec specs[] = {{EVENT_CLASS_SOCK, 0}};
-#ifdef SELECT_INVALIDATE_CFSOCKET
- CFSocketRef *shead, *s;
-#else
- CFRunLoopSourceRef *shead, *s;
-#endif
-
- BLOCK_INPUT;
-
-#ifdef SELECT_INVALIDATE_CFSOCKET
- shead = xmalloc (sizeof (CFSocketRef) * nsocks);
-#else
- shead = xmalloc (sizeof (CFRunLoopSourceRef) * nsocks);
-#endif
- s = shead;
- for (i = 1; i < n; i++)
- if (FD_ISSET (i, rfds))
- {
- CFSocketRef socket =
- CFSocketCreateWithNative (NULL, i, kCFSocketReadCallBack,
- socket_callback, NULL);
- CFRunLoopSourceRef source =
- CFSocketCreateRunLoopSource (NULL, socket, 0);
-
-#ifdef SELECT_INVALIDATE_CFSOCKET
- CFSocketSetSocketFlags (socket, 0);
-#endif
- CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode);
-#ifdef SELECT_INVALIDATE_CFSOCKET
- CFRelease (source);
- *s = socket;
-#else
- CFRelease (socket);
- *s = source;
-#endif
- s++;
- }
+ /* Try detect_input_pending before CFRunLoopRunInMode in the
+ same BLOCK_INPUT block, in case that some input has already
+ been read asynchronously. */
+ BLOCK_INPUT;
+ if (!detect_input_pending ())
+ {
+ int minfd, fd;
+ CFRunLoopRef runloop =
+ (CFRunLoopRef) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ());
+ static CFMutableDictionaryRef sources;
+
+ if (sources == NULL)
+ sources =
+ 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;
- err = ReceiveNextEvent (0, NULL, timeout_sec, kEventLeaveInQueue, NULL);
+ for (fd = minfd; fd < nfds; fd++)
+ if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds)))
+ {
+ void *key = (void *) fd;
+ CFRunLoopSourceRef source =
+ (CFRunLoopSourceRef) CFDictionaryGetValue (sources, key);
+
+ if (source == NULL)
+ {
+ CFSocketRef socket =
+ CFSocketCreateWithNative (NULL, fd,
+ (kCFSocketReadCallBack
+ | kCFSocketConnectCallBack),
+ socket_callback, NULL);
+
+ if (socket == NULL)
+ continue;
+ source = CFSocketCreateRunLoopSource (NULL, socket, 0);
+ CFRelease (socket);
+ if (source == NULL)
+ continue;
+ CFDictionaryAddValue (sources, key, source);
+ CFRelease (source);
+ }
+ CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode);
+ }
- do
- {
- --s;
-#ifdef SELECT_INVALIDATE_CFSOCKET
- CFSocketInvalidate (*s);
-#else
- CFRunLoopRemoveSource (runloop, *s, kCFRunLoopDefaultMode);
+#if USE_CG_DRAWING
+ mac_prepare_for_quickdraw (NULL);
#endif
- CFRelease (*s);
- }
- while (s != shead);
+ if (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
+ timeoutval >= 0 ? timeoutval : 100000, true)
+ == kCFRunLoopRunTimedOut)
+ timedout_p = 1;
- xfree (shead);
-
- if (err)
- {
- FD_ZERO (rfds);
- r = 0;
- }
- else
- {
- FlushEventsMatchingListFromQueue (GetCurrentEventQueue (),
- GetEventTypeCount (specs),
- specs);
- EMACS_SET_SECS_USECS (select_timeout, 0, 0);
- r = select_and_poll_event (n, rfds, wfds, efds, &select_timeout);
- }
+ for (fd = minfd; fd < nfds; fd++)
+ if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds)))
+ {
+ void *key = (void *) fd;
+ CFRunLoopSourceRef source =
+ (CFRunLoopSourceRef) CFDictionaryGetValue (sources, key);
- UNBLOCK_INPUT;
+ CFRunLoopRemoveSource (runloop, source, kCFRunLoopDefaultMode);
+ }
+ }
+ UNBLOCK_INPUT;
- return r;
- }
+ if (!timedout_p)
+ {
+ EMACS_SET_SECS_USECS (select_timeout, 0, 0);
+ return select_and_poll_event (nfds, rfds, wfds, efds,
+ &select_timeout);
+ }
+ else
+ {
+ FD_ZERO (rfds);
+ if (wfds)
+ FD_ZERO (wfds);
+ return 0;
+ }
#endif /* SELECT_USE_CFSOCKET */
}
poll_periodically:
{
EMACS_TIME end_time, now, remaining_time;
- SELECT_TYPE orfds = *rfds, owfds, oefds;
- if (wfds)
- owfds = *wfds;
- if (efds)
- oefds = *efds;
if (timeout)
{
remaining_time = *timeout;
EMACS_SET_SECS_USECS (select_timeout, 0, SELECT_POLLING_PERIOD_USEC);
if (timeout && EMACS_TIME_LT (remaining_time, select_timeout))
select_timeout = remaining_time;
- r = select_and_poll_event (n, rfds, wfds, efds, &select_timeout);
+ r = select_and_poll_event (nfds, rfds, wfds, efds, &select_timeout);
if (r != 0)
return r;
}
while (!timeout || EMACS_TIME_LT (now, end_time));
- FD_ZERO (rfds);
- if (wfds)
- FD_ZERO (wfds);
- if (efds)
- FD_ZERO (efds);
- return 0;
+ EMACS_SET_SECS_USECS (select_timeout, 0, 0);
+ return select_and_poll_event (nfds, rfds, wfds, efds, &select_timeout);
}
}
/* P should have sufficient room for the pathname of the bundle plus
the subpath in it leading to the respective directories. Q
should have three times that much room because EMACSLOADPATH can
- have the value "<path to lisp dir>:<path to leim dir>:<path to
- site-lisp dir>". */
+ have the value "<path to site-lisp dir>:<path to lisp dir>:<path
+ to leim dir>". */
p = (char *) alloca (app_bundle_pathname_len + 50);
q = (char *) alloca (3 * app_bundle_pathname_len + 150);
if (!getenv ("EMACSLOADPATH"))
q[0] = '\0';
strcpy (p, app_bundle_pathname);
- strcat (p, "/Contents/Resources/lisp");
+ strcat (p, "/Contents/Resources/site-lisp");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
strcat (q, p);
strcpy (p, app_bundle_pathname);
- strcat (p, "/Contents/Resources/leim");
+ strcat (p, "/Contents/Resources/lisp");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
{
if (q[0] != '\0')
}
strcpy (p, app_bundle_pathname);
- strcat (p, "/Contents/Resources/site-lisp");
+ strcat (p, "/Contents/Resources/leim");
if (stat (p, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
{
if (q[0] != '\0')
}
#endif /* MAC_OSX */
+#if TARGET_API_MAC_CARBON
+void
+mac_wakeup_from_rne ()
+{
+#ifndef MAC_OSX
+ if (wakeup_from_rne_enabled_p)
+ /* Post a harmless event so as to wake up from
+ ReceiveNextEvent. */
+ mac_post_mouse_moved_event ();
+#endif
+}
+#endif
void
syms_of_mac ()
QHFS_plus_C = intern ("HFS+C"); staticpro (&QHFS_plus_C);
#endif
+ {
+ int i;
+
+ for (i = 0; i < sizeof (ae_attr_table) / sizeof (ae_attr_table[0]); i++)
+ {
+ ae_attr_table[i].symbol = intern (ae_attr_table[i].name);
+ staticpro (&ae_attr_table[i].symbol);
+ }
+ }
+
defsubr (&Smac_coerce_ae_data);
#if TARGET_API_MAC_CARBON
defsubr (&Smac_get_preference);
defsubr (&Smac_code_convert_string);
+ defsubr (&Smac_process_hi_command);
#endif
- defsubr (&Smac_clear_font_name_table);
defsubr (&Smac_set_file_creator);
defsubr (&Smac_set_file_type);