X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/ab5796a9f97180707734a81320e3eb81937281fe..aa5c6b3ea11c0f09415aaa789b1d55f8f4e0e3a1:/src/mac.c diff --git a/src/mac.c b/src/mac.c index 9d3af05349..cce1b858cb 100644 --- a/src/mac.c +++ b/src/mac.c @@ -24,12 +24,14 @@ Boston, MA 02111-1307, USA. */ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -45,6 +47,8 @@ Boston, MA 02111-1307, USA. */ #undef realloc #undef init_process #include +#undef mktime +#define mktime emacs_mktime #undef free #define free unexec_free #undef malloc @@ -71,6 +75,7 @@ Boston, MA 02111-1307, USA. */ #include "process.h" #include "sysselect.h" #include "systime.h" +#include "blockinput.h" Lisp_Object QCLIPBOARD; @@ -257,6 +262,22 @@ posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen) return 1; } +#if TARGET_API_MAC_CARBON +CFStringRef +cfstring_create_with_utf8_cstring (c_str) + const char *c_str; +{ + CFStringRef str; + + str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingUTF8); + if (str == NULL) + /* Failed to interpret as UTF 8. Fall back on Mac Roman. */ + str = CFStringCreateWithCString (NULL, c_str, kCFStringEncodingMacRoman); + + return str; +} +#endif + #ifndef MAC_OSX /* The following functions with "sys_" prefix are stubs to Unix @@ -824,6 +845,8 @@ check_alarm () } +extern Boolean mac_wait_next_event (EventRecord *, UInt32, Boolean); + int select (n, rfds, wfds, efds, timeout) int n; @@ -832,49 +855,24 @@ select (n, rfds, wfds, efds, timeout) SELECT_TYPE *efds; struct timeval *timeout; { -#ifdef TARGET_API_MAC_CARBON +#if TARGET_API_MAC_CARBON return 1; #else /* not TARGET_API_MAC_CARBON */ - EMACS_TIME end_time, now; EventRecord e; + UInt32 sleep_time = EMACS_SECS (*timeout) * 60 + + ((EMACS_USECS (*timeout) * 60) / 1000000); /* Can only handle wait for keyboard input. */ if (n > 1 || wfds || efds) return -1; - EMACS_GET_TIME (end_time); - EMACS_ADD_TIME (end_time, end_time, *timeout); - - do - { - /* 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 (FD_ISSET (0, rfds) && EventAvail (everyEvent, &e)) - return 1; - - /* Also check movement of the mouse. */ - { - Point mouse_pos; - static Point old_mouse_pos = {-1, -1}; - - GetMouse (&mouse_pos); - if (!EqualPt (mouse_pos, old_mouse_pos)) - { - old_mouse_pos = mouse_pos; - return 1; - } - } - - WaitNextEvent (0, &e, 1UL, NULL); /* Accept no event; wait 1 - tic. by T.I. */ - - EMACS_GET_TIME (now); - EMACS_SUB_TIME (now, end_time, now); - } - while (!EMACS_TIME_NEG_P (now)); + /* 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 (FD_ISSET (0, rfds) && mac_wait_next_event (&e, sleep_time, false)) + return 1; return 0; #endif /* not TARGET_API_MAC_CARBON */ @@ -1164,6 +1162,13 @@ static struct passwd my_passwd = my_passwd_dir, }; +static struct group my_group = +{ + /* There are no groups on the mac, so we just return "root" as the + group name. */ + "root", +}; + /* Initialized by main () in macterm.c to pathname of emacs directory. */ @@ -1258,6 +1263,13 @@ getpwuid (uid_t uid) } +struct group * +getgrgid (gid_t gid) +{ + return &my_group; +} + + struct passwd * getpwnam (const char *name) { @@ -1961,7 +1973,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) const char *workdir; const char *infn, *outfn, *errfn; { -#ifdef TARGET_API_MAC_CARBON +#if TARGET_API_MAC_CARBON return -1; #else /* not TARGET_API_MAC_CARBON */ char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1]; @@ -2046,7 +2058,7 @@ run_mac_command (argv, workdir, infn, outfn, errfn) strcat (t, newargv[0]); #endif /* 0 */ Lisp_Object path; - openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, + openp (Vexec_path, build_string (newargv[0]), Vexec_suffixes, &path, make_number (X_OK)); if (NILP (path)) @@ -2532,7 +2544,9 @@ component. */) CHECK_STRING (script); + BLOCK_INPUT; status = do_applescript (SDATA (script), &result); + UNBLOCK_INPUT; if (status) { if (!result) @@ -2602,26 +2616,23 @@ DEFUN ("mac-paste-function", Fmac_paste_function, Smac_paste_function, 0, 0, 0, () { #if TARGET_API_MAC_CARBON + OSStatus err; ScrapRef scrap; ScrapFlavorFlags sff; Size s; int i; char *data; - if (GetCurrentScrap (&scrap) != noErr) - return Qnil; - - if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) != noErr) - return Qnil; - - if (GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s) != noErr) - return Qnil; - - if ((data = (char*) alloca (s)) == NULL) - return Qnil; - - if (GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data) != noErr - || s == 0) + BLOCK_INPUT; + err = GetCurrentScrap (&scrap); + if (err == noErr) + err = GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff); + if (err == noErr) + err = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &s); + if (err == noErr && (data = (char*) alloca (s))) + err = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &s, data); + UNBLOCK_INPUT; + if (err != noErr || s == 0) return Qnil; /* Emacs expects clipboard contents have Unix-style eol's */ @@ -2686,13 +2697,22 @@ DEFUN ("mac-cut-function", Fmac_cut_function, Smac_cut_function, 1, 2, 0, #if TARGET_API_MAC_CARBON { ScrapRef scrap; + + BLOCK_INPUT; ClearCurrentScrap (); if (GetCurrentScrap (&scrap) != noErr) - error ("cannot get current scrap"); + { + UNBLOCK_INPUT; + error ("cannot get current scrap"); + } if (PutScrapFlavor (scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, len, buf) != noErr) - error ("cannot put to scrap"); + { + UNBLOCK_INPUT; + error ("cannot put to scrap"); + } + UNBLOCK_INPUT; } #else /* not TARGET_API_MAC_CARBON */ ZeroScrap (); @@ -2727,9 +2747,11 @@ and t is the same as `SECONDARY'. */) ScrapRef scrap; ScrapFlavorFlags sff; + BLOCK_INPUT; if (GetCurrentScrap (&scrap) == noErr) if (GetScrapFlavorFlags (scrap, kScrapFlavorTypeText, &sff) == noErr) val = Qt; + UNBLOCK_INPUT; #else /* not TARGET_API_MAC_CARBON */ Handle my_handle; long rc, scrap_offset; @@ -2748,97 +2770,284 @@ and t is the same as `SECONDARY'. */) return Qnil; } +extern void mac_clear_font_name_table P_ ((void)); + +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. */) + () +{ + check_mac (); + mac_clear_font_name_table (); + return Qnil; +} + #ifdef MAC_OSX #undef select extern int inhibit_window_system; extern int noninteractive; -/* When Emacs is started from the Finder, SELECT always immediately - returns as if input is present when file descriptor 0 is polled for - input. Strangely, when Emacs is run as a GUI application from the - command line, it blocks in the same situation. This `wrapper' of - the system call SELECT corrects this discrepancy. */ +/* Unlike in X11, window events in Carbon do not come from sockets. + So we cannot simply use `select' to monitor two kinds of inputs: + window events and process outputs. We emulate such functionality + by regarding fd 0 as the window event channel and simultaneously + monitoring both kinds of input channels. It is implemented by + dividing into some cases: + 1. The window event channel is not involved. + -> 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 + involved, and timeout is not too short (greater than + SELECT_TIMEOUT_THRESHHOLD_RUNLOOP seconds). + -> Create CFSocket for each socket and add it into the current + event RunLoop so that an `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. + 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 +#define SELECT_TIMEOUT_THRESHOLD_RUNLOOP 0.2 +#define EVENT_CLASS_SOCK 'Sock' + +static void +socket_callback (s, type, address, data, info) + CFSocketRef s; + CFSocketCallBackType type; + CFDataRef address; + 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; +{ + int r; + OSErr err; + + r = select (n, rfds, wfds, efds, timeout); + if (r != -1) + { + BLOCK_INPUT; + err = ReceiveNextEvent (0, NULL, kEventDurationNoWait, + kEventLeaveInQueue, NULL); + UNBLOCK_INPUT; + if (err == noErr) + { + FD_SET (0, rfds); + r++; + } + } + return r; +} + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1020 +#undef SELECT_INVALIDATE_CFSOCKET +#endif + int sys_select (n, rfds, wfds, efds, timeout) - int n; - SELECT_TYPE *rfds; - SELECT_TYPE *wfds; - SELECT_TYPE *efds; - struct timeval *timeout; + int n; + SELECT_TYPE *rfds; + SELECT_TYPE *wfds; + SELECT_TYPE *efds; + struct timeval *timeout; { - if (!inhibit_window_system && rfds && FD_ISSET (0, rfds)) - return 1; - else if (inhibit_window_system || noninteractive || - (timeout && (EMACS_SECS(*timeout)==0) && - (EMACS_USECS(*timeout)==0))) - return select(n, rfds, wfds, efds, timeout); - else + OSErr err; + int i, r; + EMACS_TIME select_timeout; + + if (inhibit_window_system || noninteractive + || rfds == NULL || !FD_ISSET (0, rfds)) + return select (n, rfds, wfds, efds, timeout); + + FD_CLR (0, rfds); + + if (wfds == NULL && efds == NULL) { - EMACS_TIME end_time, now; + int nsocks = 0; + SELECT_TYPE orfds = *rfds; - EMACS_GET_TIME (end_time); - if (timeout) - EMACS_ADD_TIME (end_time, end_time, *timeout); + EventTimeout timeout_sec = + (timeout + ? (EMACS_SECS (*timeout) * kEventDurationSecond + + EMACS_USECS (*timeout) * kEventDurationMicrosecond) + : kEventDurationForever); - do - { - int r; - EMACS_TIME one_second; - SELECT_TYPE orfds; + for (i = 1; i < n; i++) + if (FD_ISSET (i, rfds)) + nsocks++; - FD_ZERO (&orfds); - if (rfds) + if (nsocks == 0) + { + BLOCK_INPUT; + err = ReceiveNextEvent (0, NULL, timeout_sec, + kEventLeaveInQueue, NULL); + UNBLOCK_INPUT; + if (err == noErr) { - orfds = *rfds; + FD_SET (0, rfds); + return 1; } + else + return 0; + } + + /* 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) + return r; + + *rfds = orfds; + +#ifdef SELECT_USE_CFSOCKET + if (timeout_sec > 0 && timeout_sec <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP) + goto poll_periodically; - EMACS_SET_SECS (one_second, 1); - EMACS_SET_USECS (one_second, 0); + { + CFRunLoopRef runloop = + (CFRunLoopRef) GetCFRunLoopFromEventLoop (GetCurrentEventLoop ()); + EventTypeSpec specs[] = {{EVENT_CLASS_SOCK, 0}}; +#ifdef SELECT_INVALIDATE_CFSOCKET + CFSocketRef *shead, *s; +#else + CFRunLoopSourceRef *shead, *s; +#endif - if (timeout && EMACS_TIME_LT(*timeout, one_second)) - one_second = *timeout; + BLOCK_INPUT; - if ((r = select (n, &orfds, wfds, efds, &one_second)) > 0) +#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)) { - *rfds = orfds; - return r; + 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++; } - mac_check_for_quit_char(); + err = ReceiveNextEvent (0, NULL, timeout_sec, kEventLeaveInQueue, NULL); - EMACS_GET_TIME (now); - EMACS_SUB_TIME (now, end_time, now); - } - while (!timeout || !EMACS_TIME_NEG_P (now)); + do + { + --s; +#ifdef SELECT_INVALIDATE_CFSOCKET + CFSocketInvalidate (*s); +#else + CFRunLoopRemoveSource (runloop, *s, kCFRunLoopDefaultMode); +#endif + CFRelease (*s); + } + while (s != shead); - return 0; - } -} + xfree (shead); -#undef read -int sys_read (fds, buf, nbyte) - int fds; - char *buf; - unsigned int nbyte; -{ - SELECT_TYPE rfds; - EMACS_TIME one_second; - int r; + 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); + } - /* Use select to block on IO while still checking for quit_char */ - if (!inhibit_window_system && !noninteractive && - ! (fcntl(fds, F_GETFL, 0) & O_NONBLOCK)) - { - FD_ZERO (&rfds); - FD_SET (fds, &rfds); - if (sys_select (fds+1, &rfds, 0, 0, NULL) < 0) - return -1; + UNBLOCK_INPUT; + + return r; + } +#endif /* SELECT_USE_CFSOCKET */ } - return read (fds, buf, nbyte); -} + 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_GET_TIME (now); + EMACS_ADD_TIME (end_time, now, remaining_time); + } + + do + { + 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); + if (r != 0) + return r; + + *rfds = orfds; + if (wfds) + *wfds = owfds; + if (efds) + *efds = oefds; + + if (timeout) + { + EMACS_GET_TIME (now); + EMACS_SUB_TIME (remaining_time, end_time, now); + } + } + while (!timeout || EMACS_TIME_LT (now, end_time)); + FD_ZERO (rfds); + if (wfds) + FD_ZERO (wfds); + if (efds) + FD_ZERO (efds); + return 0; + } +} /* Set up environment variables so that Emacs can correctly find its support files when packaged as an application bundle. Directories @@ -2983,6 +3192,7 @@ syms_of_mac () defsubr (&Smac_paste_function); defsubr (&Smac_cut_function); defsubr (&Sx_selection_exists_p); + defsubr (&Smac_clear_font_name_table); defsubr (&Sdo_applescript); defsubr (&Smac_file_name_to_posix);