#include <c-strcase.h>
#include <ftoastr.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
#include "lisp.h"
#include "blockinput.h"
#include "sysselect.h"
};
static Lisp_Object Qmodifier_value;
-Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
+Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
static Lisp_Object QUTF8_STRING;
static BOOL send_appdefined = YES;
static NSEvent *last_appdefined_event = 0;
static NSTimer *timed_entry = 0;
-static NSTimer *fd_entry = nil;
static NSTimer *scroll_repeat_entry = nil;
-static fd_set select_readfds, t_readfds;
-static int select_nfds;
+static fd_set select_readfds, select_writefds;
+enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
+static int select_nfds = 0, select_valid = 0;
+static EMACS_TIME select_timeout = { 0, 0 };
+static int selfds[2] = { -1, -1 };
+static pthread_mutex_t select_mutex;
+static int apploopnr = 0;
static NSAutoreleasePool *outerpool;
static struct input_event *emacs_event = NULL;
static struct input_event *q_event_ptr = NULL;
static int n_emacs_events_pending = 0;
static NSMutableArray *ns_pending_files, *ns_pending_service_names,
*ns_pending_service_args;
-static BOOL inNsSelect = 0;
static BOOL ns_do_open_file = NO;
/* Convert modifiers in a NeXTstep event to emacs style modifiers. */
/* This is a piece of code which is common to all the event handling
methods. Maybe it should even be a function. */
-#define EV_TRAILER(e) \
- { \
- XSETFRAME (emacs_event->frame_or_window, emacsframe); \
- if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
- n_emacs_events_pending++; \
- kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
- EVENT_INIT (*emacs_event); \
- ns_send_appdefined (-1); \
- }
+#define EV_TRAILER(e) \
+ { \
+ XSETFRAME (emacs_event->frame_or_window, emacsframe); \
+ if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
+ if (q_event_ptr) \
+ { \
+ n_emacs_events_pending++; \
+ kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
+ } \
+ else \
+ kbd_buffer_store_event (emacs_event); \
+ EVENT_INIT (*emacs_event); \
+ ns_send_appdefined (-1); \
+ }
void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
external (RIF) call; for one window called before update_end
-------------------------------------------------------------------------- */
{
- Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (WGET (w, frame)));
+ Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
/* note: this fn is nearly identical in all terms */
if (!w->pseudo_window_p)
External (RIF): Insert or delete n lines at line vpos
-------------------------------------------------------------------------- */
{
- struct frame *f = XFRAME (WGET (w, frame));
+ struct frame *f = XFRAME (w->frame);
int x, y, width, height, from_y, to_y, bottom_y;
NSTRACE (ns_scroll_run);
full-width rows stays visible in the internal border.
Under NS this is drawn inside the fringes. */
if (windows_or_buffers_changed
- && (f = XFRAME (WGET (w, frame)),
+ && (f = XFRAME (w->frame),
width = FRAME_INTERNAL_BORDER_WIDTH (f),
width != 0)
&& (height = desired_row->visible_height,
timed_entry = nil;
}
- /* Ditto for file descriptor poller */
- if (fd_entry)
- {
- [fd_entry invalidate];
- [fd_entry release];
- fd_entry = nil;
- }
-
nxev = [NSEvent otherEventWithType: NSApplicationDefined
location: NSMakePoint (0, 0)
modifierFlags: 0
}
}
-
static int
ns_read_socket (struct terminal *terminal, int expected,
struct input_event *hold_quit)
/* Run and wait for events. We must always send one NX_APPDEFINED event
to ourself, otherwise [NXApp run] will never exit. */
send_appdefined = YES;
+ ns_send_appdefined (-1);
- /* If called via ns_select, this is called once with expected=1,
- because we expect either the timeout or file descriptor activity.
- In this case the first event through will either be real input or
- one of these. read_avail_input() then calls once more with expected=0
- and in that case we need to return quickly if there is nothing.
- If we're being called outside of that, it's also OK to return quickly
- after one iteration through the event loop, since other terms do
- this and emacs expects it. */
- if (!(inNsSelect && expected))
+ if (++apploopnr != 1)
{
- /* Post an application defined event on the event queue. When this is
- received the [NXApp run] will return, thus having processed all
- events which are currently queued, if any. */
- ns_send_appdefined (-1);
+ abort ();
}
-
[NSApp run];
+ --apploopnr;
}
nevents = n_emacs_events_pending;
-------------------------------------------------------------------------- */
{
int result;
- double time;
NSEvent *ev;
- struct timespec select_timeout;
+ int k, nr = 0;
+ struct input_event event;
+ char c;
/* NSTRACE (ns_select); */
- if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
- [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
- inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
+ for (k = 0; readfds && k < nfds+1; k++)
+ if (FD_ISSET(k, readfds)) ++nr;
+
+ if (NSApp == nil
+ || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
- /* Save file descriptor set, which gets overwritten in calls to select ()
- Note, this is called from process.c, and only readfds is ever set */
- if (readfds)
+ [outerpool release];
+ outerpool = [[NSAutoreleasePool alloc] init];
+
+
+ send_appdefined = YES;
+ if (nr > 0)
{
- memcpy (&select_readfds, readfds, sizeof (fd_set));
+ pthread_mutex_lock (&select_mutex);
select_nfds = nfds;
+ select_valid = 0;
+ if (readfds)
+ {
+ select_readfds = *readfds;
+ select_valid += SELECT_HAVE_READ;
+ }
+ if (writefds)
+ {
+ select_writefds = *writefds;
+ select_valid += SELECT_HAVE_WRITE;
+ }
+
+ if (timeout)
+ {
+ select_timeout = *timeout;
+ select_valid += SELECT_HAVE_TMO;
+ }
+
+ pthread_mutex_unlock (&select_mutex);
+
+ /* Inform fd_handler that select should be called */
+ c = 'g';
+ write (selfds[1], &c, 1);
}
- else
- select_nfds = 0;
-
- /* Try an initial select for pending data on input files */
- select_timeout.tv_sec = select_timeout.tv_nsec = 0;
- result = pselect (nfds, readfds, writefds, exceptfds,
- &select_timeout, sigmask);
- if (result)
- return result;
-
- /* if (!timeout || timed_entry || fd_entry)
- fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
-
- /* set a timeout and run the main AppKit event loop while continuing
- to monitor the files */
- time = EMACS_TIME_TO_DOUBLE (*timeout);
- timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
- target: NSApp
- selector: @selector (timeout_handler:)
- userInfo: 0
- repeats: YES] /* for safe removal */
- retain];
-
- /* set a periodic task to try the pselect () again */
- fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
- target: NSApp
- selector: @selector (fd_handler:)
- userInfo: 0
- repeats: YES]
- retain];
-
- /* Let Application dispatch events until it receives an event of the type
- NX_APPDEFINED, which should only be sent by timeout_handler.
- We tell read_avail_input() that input is "expected" because we do expect
- either the timeout or fd handler to fire, and if they don't, the original
- call from process.c that got us here expects us to wait until some input
- comes. */
- inNsSelect = 1;
- gobble_input (1);
+ else if (nr == 0 && timeout)
+ {
+ /* No file descriptor, just a timeout, no need to wake fd_handler */
+ double time = EMACS_TIME_TO_DOUBLE (*timeout);
+ timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
+ target: NSApp
+ selector:
+ @selector (timeout_handler:)
+ userInfo: 0
+ repeats: NO]
+ retain];
+ }
+ else /* No timeout and no file descriptors, can this happen? */
+ {
+ /* Send appdefined so we exit from the loop */
+ ns_send_appdefined (-1);
+ }
+
+ EVENT_INIT (event);
+ BLOCK_INPUT;
+ emacs_event = &event;
+ if (++apploopnr != 1)
+ {
+ abort();
+ }
+ [NSApp run];
+ --apploopnr;
+ emacs_event = NULL;
+ if (nr > 0 && readfds)
+ {
+ c = 's';
+ write (selfds[1], &c, 1);
+ }
+ UNBLOCK_INPUT;
+
ev = last_appdefined_event;
- inNsSelect = 0;
if (ev)
{
if (t == -2)
{
/* The NX_APPDEFINED event we received was a timeout. */
- return 0;
+ result = 0;
}
else if (t == -1)
{
/* The NX_APPDEFINED event we received was the result of
at least one real input event arriving. */
errno = EINTR;
- return -1;
+ result = -1;
}
else
{
- /* Received back from pselect () in fd_handler; copy the results */
- if (readfds)
- memcpy (readfds, &select_readfds, sizeof (fd_set));
- return t;
+ /* Received back from select () in fd_handler; copy the results */
+ pthread_mutex_lock (&select_mutex);
+ if (readfds) *readfds = select_readfds;
+ if (writefds) *writefds = select_writefds;
+ if (timeout) *timeout = select_timeout;
+ pthread_mutex_unlock (&select_mutex);
+ result = t;
}
}
- /* never reached, shut compiler up */
- return 0;
+
+ return result;
}
EmacsScroller *bar;
/* optimization; display engine sends WAY too many of these.. */
- if (!NILP (WGET (window, vertical_scroll_bar)))
+ if (!NILP (window->vertical_scroll_bar))
{
- bar = XNS_SCROLL_BAR (WGET (window, vertical_scroll_bar));
+ bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
if ([bar checkSamePosition: position portion: portion whole: whole])
{
if (view->scrollbarsNeedingUpdate == 0)
/* we want at least 5 lines to display a scrollbar */
if (WINDOW_TOTAL_LINES (window) < 5)
{
- if (!NILP (WGET (window, vertical_scroll_bar)))
+ if (!NILP (window->vertical_scroll_bar))
{
- bar = XNS_SCROLL_BAR (WGET (window, vertical_scroll_bar));
+ bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
[bar removeFromSuperview];
WSET (window, vertical_scroll_bar, Qnil);
}
return;
}
- if (NILP (WGET (window, vertical_scroll_bar)))
+ if (NILP (window->vertical_scroll_bar))
{
ns_clear_frame_area (f, sb_left, top, width, height);
bar = [[EmacsScroller alloc] initFrame: r window: win];
else
{
NSRect oldRect;
- bar = XNS_SCROLL_BAR (WGET (window, vertical_scroll_bar));
+ bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
oldRect = [bar frame];
r.size.width = oldRect.size.width;
if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
{
id bar;
NSTRACE (ns_redeem_scroll_bar);
- if (!NILP (WGET (window, vertical_scroll_bar)))
+ if (!NILP (window->vertical_scroll_bar))
{
- bar = XNS_SCROLL_BAR (WGET (window, vertical_scroll_bar));
+ bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
[bar reprieve];
}
}
{
baud_rate = 38400;
Fset_input_interrupt_mode (Qnil);
+
+ if (selfds[0] == -1)
+ {
+ if (pipe (selfds) == -1)
+ {
+ fprintf (stderr, "Failed to create pipe: %s\n",
+ emacs_strerror (errno));
+ abort ();
+ }
+
+ fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
+ FD_ZERO (&select_readfds);
+ FD_ZERO (&select_writefds);
+ pthread_mutex_init (&select_mutex, NULL);
+ }
ns_initialized = 1;
}
return NULL;
[NSApp setDelegate: NSApp];
+ /* Start the select thread. */
+ [NSThread detachNewThreadSelector:@selector (fd_handler:)
+ toTarget:NSApp
+ withObject:nil];
+
/* debugging: log all notifications */
/* [[NSNotificationCenter defaultCenter] addObserver: NSApp
selector: @selector (logNotification:)
terminal->kboard = xmalloc (sizeof *terminal->kboard);
init_kboard (terminal->kboard);
- KVAR (terminal->kboard, Vwindow_system) = Qns;
+ KSET (terminal->kboard, Vwindow_system, Qns);
terminal->kboard->next_kboard = all_kboards;
all_kboards = terminal->kboard;
/* Don't let the initial kboard remain current longer than necessary.
return NSTerminateNow; /* just in case */
}
+static int
+not_in_argv (NSString *arg)
+{
+ int k;
+ const char *a = [arg UTF8String];
+ for (k = 1; k < initial_argc; ++k)
+ if (strcmp (a, initial_argv[k]) == 0) return 0;
+ return 1;
+}
/* Notification from the Workspace to open a file */
- (BOOL)application: sender openFile: (NSString *)file
{
- if (ns_do_open_file)
+ if (ns_do_open_file || not_in_argv (file))
[ns_pending_files addObject: file];
return YES;
}
/* Open a file as a temporary file */
- (BOOL)application: sender openTempFile: (NSString *)file
{
- if (ns_do_open_file)
+ if (ns_do_open_file || not_in_argv (file))
[ns_pending_files addObject: file];
return YES;
}
/* Notification from the Workspace to open a file noninteractively (?) */
- (BOOL)application: sender openFileWithoutUI: (NSString *)file
{
- if (ns_do_open_file)
+ if (ns_do_open_file || not_in_argv (file))
[ns_pending_files addObject: file];
return YES;
}
-
/* Notification from the Workspace to open multiple files */
- (void)application: sender openFiles: (NSArray *)fileList
{
- /* Don't open files from the command line, Cocoa parses the command line
- wrong anyway, --option value tries to open value if --option is the last
- option. */
- if (ns_do_open_file)
- {
- NSEnumerator *files = [fileList objectEnumerator];
- NSString *file;
- while ((file = [files nextObject]) != nil)
- [ns_pending_files addObject: file];
- }
+ NSEnumerator *files = [fileList objectEnumerator];
+ NSString *file;
+ /* Don't open files from the command line unconditionally,
+ Cocoa parses the command line wrong, --option value tries to open value
+ if --option is the last option. */
+ while ((file = [files nextObject]) != nil)
+ if (ns_do_open_file || not_in_argv (file))
+ [ns_pending_files addObject: file];
[self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
ns_send_appdefined (-2);
}
-- (void)fd_handler: (NSTimer *) fdEntry
+- (void)fd_handler:(id)unused
/* --------------------------------------------------------------------------
Check data waiting on file descriptors and terminate if so
-------------------------------------------------------------------------- */
{
int result;
- struct timespec select_timeout;
- /* NSTRACE (fd_handler); */
+ int waiting = 1, nfds;
+ char c;
- if (select_nfds == 0)
- return;
+ SELECT_TYPE readfds, writefds, *wfds;
+ EMACS_TIME timeout, *tmo;
- memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
+ /* NSTRACE (fd_handler); */
- select_timeout.tv_sec = select_timeout.tv_nsec = 0;
- result = pselect (select_nfds, &t_readfds, NULL, NULL, &select_timeout, NULL);
- if (result)
+ for (;;)
{
- memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
- ns_send_appdefined (result);
+ if (waiting)
+ {
+ SELECT_TYPE fds;
+
+ FD_SET (selfds[0], &fds);
+ result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
+ if (result > 0)
+ {
+ read (selfds[0], &c, 1);
+ if (c == 'g') waiting = 0;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock (&select_mutex);
+ nfds = select_nfds;
+
+ if (select_valid & SELECT_HAVE_READ)
+ readfds = select_readfds;
+ else
+ FD_ZERO (&readfds);
+
+ if (select_valid & SELECT_HAVE_WRITE)
+ {
+ writefds = select_writefds;
+ wfds = &writefds;
+ }
+ else
+ wfds = NULL;
+ if (select_valid & SELECT_HAVE_TMO)
+ {
+ timeout = select_timeout;
+ tmo = &timeout;
+ }
+ else
+ tmo = NULL;
+
+ pthread_mutex_unlock (&select_mutex);
+
+ FD_SET (selfds[0], &readfds);
+ if (selfds[0] >= nfds) nfds = selfds[0]+1;
+
+ result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
+
+ if (result == 0)
+ ns_send_appdefined (-2);
+ else if (result > 0)
+ {
+ if (FD_ISSET (selfds[0], &readfds))
+ {
+ read (selfds[0], &c, 1);
+ if (c == 's') waiting = 1;
+ }
+ else
+ {
+ pthread_mutex_lock (&select_mutex);
+ if (select_valid & SELECT_HAVE_READ)
+ select_readfds = readfds;
+ if (select_valid & SELECT_HAVE_WRITE)
+ select_writefds = writefds;
+ if (select_valid & SELECT_HAVE_TMO)
+ select_timeout = timeout;
+ pthread_mutex_unlock (&select_mutex);
+
+ ns_send_appdefined (result);
+ }
+ }
+ waiting = 1;
+ }
}
}
{
Lisp_Object str = Qnil;
struct frame *f = SELECTED_FRAME ();
- struct buffer *curbuf
- = XBUFFER (WGET (XWINDOW (f->selected_window), buffer));
+ struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
return NSAccessibilityTextFieldRole;
if (pixel_height == 0) pixel_height = 1;
min_portion = 20 / pixel_height;
- frame = XFRAME (WGET (XWINDOW (win), frame));
+ frame = XFRAME (XWINDOW (win)->frame);
if (FRAME_LIVE_P (frame))
{
int i;
XSETINT (emacs_event->x, loc * pixel_height);
XSETINT (emacs_event->y, pixel_height-20);
- n_emacs_events_pending++;
- kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
+ if (q_event_ptr)
+ {
+ n_emacs_events_pending++;
+ kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
+ }
+ else
+ kbd_buffer_store_event (emacs_event);
EVENT_INIT (*emacs_event);
ns_send_appdefined (-1);
}
DEFSYM (Qmeta, "meta");
DEFSYM (Qsuper, "super");
DEFSYM (Qcontrol, "control");
- DEFSYM (Qnone, "none");
DEFSYM (QUTF8_STRING, "UTF8_STRING");
Fput (Qalt, Qmodifier_value, make_number (alt_modifier));