diff options
author | Alan Third <alan@idiocy.org> | 2018-06-23 15:26:26 +0100 |
---|---|---|
committer | Alan Third <alan@idiocy.org> | 2020-03-22 15:31:45 +0000 |
commit | 3316e78c120f69aa3ac12ff7345a79dd09654c9a (patch) | |
tree | 95dab41336265e82d71bc45c621733bfdbe06a74 | |
parent | 41f54289058ec42829cd19f7c469b2e4e325b830 (diff) | |
download | emacs-scratch/ns/next.tar.gz |
Run NSApp loop in its own threadscratch/ns/next
* src/emacs.c (main) [HAVE_NS]: Rename to emacs_main.
* src/lisp.h (emacs_main) [HAVE_NS]: Define function.
* src/nsfns.m (Fns_do_applescript): Remove runloop.
(Fx_create_frame): Initialize the frame on the main thread.
* src/nsterm.h ([EmacsApp initLispThread:withArgv:]): New method.
([EmacsApp fd_handler:]):
([EmacsApp timeout_handler:]):
([EmacsApp sendFromMainThread:]): Remove function definitions.
([EmacsApp initLispThread:]): New function.
([EmacsThread initWithArgc:Argv:]):
([EmacsThread sendEmacsEvent:NSEvent:frameOrWindow:]): New functions.
* src/nsterm.m (EV_TRAILER): Reduce to a single function.
(EV_TRAILER2): Remove.
(ns_init_events):
(ns_finish_events):
(hold_event):
(ns_send_appdefined):
(ns_run_loop_break):
([EmacsApp timeout_handler:]):
([EmacsApp sendFromMainThread:]):
([EmacsApp fd_handler:]): Remove functions.
(ns_check_menu_open):
([EmacsApp newFrame:]):
([EmacsApp openFile:]):
([EmacsApp terminate:]):
([EmacsApp fulfillService:withArg:]):
([EmacsView changeFont:]):
([EmacsView keyDown:]):
([EmacsView insertText:]):
([EmacsView setmarkedtext:selectedRange:]):
([EmacsView deleteWorkingText:]):
([EmacsView doCommandBySelector:]):
([EmacsView mouseDown:]):
([EmacsView mouseMoved:]):
([EmacsView windowShouldClose:]):
([EmacsView windowDidResize:]):
([EmacsView windowDidBecomeKey]):
([EmacsView windowDidResignKey:]):
([EmacsView windowDidMove:]):
([EmacsView windowDidDeminiaturize:]):
([EmacsView windowDidExpose:]):
([EmacsView windowDidMiniaturize:]):
([EmacsView menuDown:]):
([EmacsView toolbarClicked:]):
([EmacsView toggleToolbar:]):
([EmacsView performDragOperation:]):
([EmacsScroller sendScrollEventAtLoc:fromEvent:]): Change event handling.
([EmacsApp applicationDidFinishLaunching:]):
([EmacsApp applicationDidResignActive:]): Remove call to ns_send_appdefined.
(ns_read_socket): Change event handling, use thread local runloop.
(ns_select): Remove unused fd_handler and runloop related code.
(ns_term_init): Move some NS initialisation code to new
main function and remove fd_handler related code.
([EmacsApp sendEvent:]): Stop run loop from exiting.
([EmacsApp initLispThread:withArgv:]): New method.
([EmacsThread initWithArgc:Argv:]):
([EmacsThread processEmacsEvent:]):
([EmacsThread sendEmacsEvent:NSEvent:frameOrWindow:]): New functions.
(main): New function to initialise NS stuff and run emacs_main in its
own thread.
* src/systhread.c (sys_cond_broadcast): Remove NS runloop related
code.
-rw-r--r-- | src/emacs.c | 4 | ||||
-rw-r--r-- | src/lisp.h | 4 | ||||
-rw-r--r-- | src/nsfns.m | 13 | ||||
-rw-r--r-- | src/nsterm.h | 14 | ||||
-rw-r--r-- | src/nsterm.m | 909 | ||||
-rw-r--r-- | src/systhread.c | 7 |
6 files changed, 308 insertions, 643 deletions
diff --git a/src/emacs.c b/src/emacs.c index ea9c4cd79dc..ad64ffa08f2 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -924,7 +924,11 @@ load_pdump (int argc, char **argv) #endif /* HAVE_PDUMPER */ int +#ifdef HAVE_NS +emacs_main (int argc, char **argv) +#else main (int argc, char **argv) +#endif { /* Variable near the bottom of the stack, and aligned appropriately for pointers. */ diff --git a/src/lisp.h b/src/lisp.h index a379977d353..34d97a8efc9 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4717,6 +4717,10 @@ extern void syms_of_xterm (void); extern char *get_keysym_name (int); #endif /* HAVE_WINDOW_SYSTEM */ +#ifdef HAVE_NS +extern int emacs_main (int, char **); +#endif + /* Defined in xml.c. */ extern void syms_of_xml (void); #ifdef HAVE_LIBXML2 diff --git a/src/nsfns.m b/src/nsfns.m index dea51bdba00..d693873d422 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1310,7 +1310,10 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, f->output_data.ns->in_animation = NO; - f->output_data.ns->frame = [[EmacsFrame alloc] initWithEmacsframe:f]; + f->output_data.ns->frame = + [(EmacsFrame *)[[[MainThreadProxy alloc] initWithObject:[EmacsFrame alloc] + waitUntilDone:YES] autorelease] + initWithEmacsframe:f]; ns_icon (f, parms); @@ -2141,7 +2144,6 @@ In case the execution fails, an error is signaled. */) Lisp_Object result; int status; NSEvent *nxev; - struct input_event ev; CHECK_STRING (script); check_window_system (NULL); @@ -2167,13 +2169,6 @@ In case the execution fails, an error is signaled. */) [NSApp postEvent: nxev atStart: NO]; - /* If there are other events, the event loop may exit. Keep running - until the script has been handled. */ - ns_init_events (&ev); - while (! NILP (as_script)) - [NSApp run]; - ns_finish_events (); - status = as_status; as_status = 0; as_result = 0; diff --git a/src/nsterm.h b/src/nsterm.h index 1aff5ad1c96..1eb5ac92a70 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -391,12 +391,8 @@ typedef id instancetype; - (void)sendEvent: (NSEvent *)theEvent; - (void)showPreferencesWindow: (id)sender; - (BOOL) openFile: (NSString *)fileName; -- (void)fd_handler: (id)unused; -- (void)timeout_handler: (NSTimer *)timedEntry; - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg; -#ifdef NS_IMPL_GNUSTEP -- (void)sendFromMainThread:(id)unused; -#endif +- (void)initLispThread: (int)argc withArgv: (char **)argv; @end #ifdef NS_IMPL_GNUSTEP @@ -758,6 +754,14 @@ typedef id instancetype; + (CGFloat)scrollerWidth; @end +@interface EmacsThread: NSThread +{ +} +- (instancetype) initWithArgc: (int)argc Argv: (char **)argv; +- (void) sendEmacsEvent: (struct input_event *)emacs_event + NSEvent: (NSEvent *)e + frameOrWindow: (void *)frame_or_window; +@end /* ========================================================================== diff --git a/src/nsterm.m b/src/nsterm.m index 37163cef1e4..f1ec60fbc15 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -192,6 +192,8 @@ char const * nstrace_fullscreen_type_name (int fs_type) ========================================================================== */ +EmacsThread *emacsMainThread; + /* Convert a symbol indexed with an NSxxx value to a value as defined in keyboard.c (lispy_function_key). I hope this is a correct way of doing things... */ @@ -298,19 +300,8 @@ static BOOL ns_menu_bar_is_hidden = NO; /* static int debug_lock = 0; */ /* event loop */ -static BOOL send_appdefined = YES; -#define NO_APPDEFINED_DATA (-8) -static int last_appdefined_event_data = NO_APPDEFINED_DATA; -static NSTimer *timed_entry = 0; static NSTimer *scroll_repeat_entry = nil; -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 struct timespec select_timeout = { 0, 0 }; -static int selfds[2] = { -1, -1 }; -static pthread_mutex_t select_mutex; 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, @@ -323,13 +314,6 @@ static BOOL ns_last_use_native_fullscreen; static BOOL any_help_event_p = NO; -static struct { - struct input_event *q; - int nr, cap; -} hold_event_q = { - NULL, 0, 0 -}; - #ifdef NS_IMPL_COCOA /* * State for pending menu activation: @@ -448,28 +432,9 @@ ev_modifiers_helper (unsigned int flags, unsigned int left_mask, /* 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); \ - EV_TRAILER2 (e); \ - } - -#define EV_TRAILER2(e) \ - { \ - if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \ - if (q_event_ptr) \ - { \ - Lisp_Object tem = Vinhibit_quit; \ - Vinhibit_quit = Qt; \ - n_emacs_events_pending++; \ - kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \ - Vinhibit_quit = tem; \ - } \ - else \ - hold_event (emacs_event); \ - EVENT_INIT (*emacs_event); \ - ns_send_appdefined (-1); \ - } - + [emacsMainThread sendEmacsEvent:&emacs_event \ + NSEvent:e \ + frameOrWindow:emacsframe]; /* These flags will be OR'd or XOR'd with the NSWindow's styleMask property depending on what we're doing. */ @@ -490,36 +455,6 @@ static void ns_judge_scroll_bars (struct frame *f); ========================================================================== */ -void -ns_init_events (struct input_event *ev) -{ - EVENT_INIT (*ev); - emacs_event = ev; -} - -void -ns_finish_events (void) -{ - emacs_event = NULL; -} - -static void -hold_event (struct input_event *event) -{ - if (hold_event_q.nr == hold_event_q.cap) - { - if (hold_event_q.cap == 0) hold_event_q.cap = 10; - else hold_event_q.cap *= 2; - hold_event_q.q = - xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q); - } - - hold_event_q.q[hold_event_q.nr++] = *event; - /* Make sure ns_read_socket is called, i.e. we have input. */ - raise (SIGIO); - send_appdefined = YES; -} - static Lisp_Object append2 (Lisp_Object list, Lisp_Object item) /* -------------------------------------------------------------------------- @@ -4181,78 +4116,6 @@ ns_draw_glyph_string (struct glyph_string *s) ========================================================================== */ - -static void -ns_send_appdefined (int value) -/* -------------------------------------------------------------------------- - Internal: post an appdefined event which EmacsApp-sendEvent will - recognize and take as a command to halt the event loop. - -------------------------------------------------------------------------- */ -{ - NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value); - - // GNUstep needs postEvent to happen on the main thread. - // Cocoa needs nextEventMatchingMask to happen on the main thread too. - if (! [[NSThread currentThread] isMainThread]) - { - EmacsApp *app = (EmacsApp *)NSApp; - app->nextappdefined = value; - [app performSelectorOnMainThread:@selector (sendFromMainThread:) - withObject:nil - waitUntilDone:NO]; - return; - } - - /* Only post this event if we haven't already posted one. This will end - the [NXApp run] main loop after having processed all events queued at - this moment. */ - -#ifdef NS_IMPL_COCOA - if (! send_appdefined) - { - /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves - in certain situations (rapid incoming events). - So check if we have one, if not add one. */ - NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:NO]; - if (! appev) send_appdefined = YES; - } -#endif - - if (send_appdefined) - { - NSEvent *nxev; - - /* We only need one NX_APPDEFINED event to stop NXApp from running. */ - send_appdefined = NO; - - /* Don't need wakeup timer any more. */ - if (timed_entry) - { - [timed_entry invalidate]; - [timed_entry release]; - timed_entry = nil; - } - - nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined - location: NSMakePoint (0, 0) - modifierFlags: 0 - timestamp: 0 - windowNumber: [[NSApp mainWindow] windowNumber] - context: [NSApp context] - subtype: 0 - data1: value - data2: 0]; - - /* 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. */ - [NSApp postEvent: nxev atStart: NO]; - } -} - #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 static void check_native_fs () @@ -4298,10 +4161,13 @@ ns_check_menu_open (NSMenu *menu) found = menu == [[a objectAtIndex:i] submenu]; if (found) { - if (menu_will_open_state == MENU_NONE && emacs_event) + if (menu_will_open_state == MENU_NONE) { NSEvent *theEvent = [NSApp currentEvent]; struct frame *emacsframe = SELECTED_FRAME (); + struct input_event emacs_event; + + EVENT_INIT (emacs_event); /* On macOS, the following can cause an event loop when the Spotlight for Help search field is populated. Avoid this by @@ -4312,7 +4178,7 @@ ns_check_menu_open (NSMenu *menu) { [menu cancelTracking]; menu_will_open_state = MENU_PENDING; - emacs_event->kind = MENU_BAR_ACTIVATE_EVENT; + emacs_event.kind = MENU_BAR_ACTIVATE_EVENT; EV_TRAILER (theEvent); CGEventRef ourEvent = CGEventCreate (NULL); @@ -4358,7 +4224,6 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit) From 21+ we have to manage the event buffer ourselves. -------------------------------------------------------------------------- */ { - struct input_event ev; int nevents; NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket"); @@ -4370,20 +4235,10 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit) if ([NSApp modalWindow] != nil) return -1; - if (hold_event_q.nr > 0) - { - int i; - for (i = 0; i < hold_event_q.nr; ++i) - kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit); - hold_event_q.nr = 0; - return i; - } - - if ([NSThread isMainThread]) + if ([NSThread currentThread] == emacsMainThread) { block_input (); n_emacs_events_pending = 0; - ns_init_events (&ev); q_event_ptr = hold_quit; /* We manage autorelease pools by allocate/reallocate each time around @@ -4409,17 +4264,19 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit) } else { - /* 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); - - [NSApp run]; + /* Run this thread's RunLoop. This will process all events + sent by the NS GUI thread. + + We use CFRunLoop instead of NSRunLoop as it allows us to + run once and check why it returned. If it processed an + event we want it to try again, if it "times out" then + there was nothing more to process and we finish up. */ + while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, YES) + == kCFRunLoopRunHandledSource); } nevents = n_emacs_events_pending; n_emacs_events_pending = 0; - ns_finish_events (); q_event_ptr = NULL; unblock_input (); } @@ -4438,156 +4295,16 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, Replacement for select, checking for events -------------------------------------------------------------------------- */ { - int result; - int t, k, nr = 0; - struct input_event event; - char c; - NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select"); #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 check_native_fs (); #endif - if (hold_event_q.nr > 0) - { - /* We already have events pending. */ - raise (SIGIO); - errno = EINTR; - return -1; - } - - for (k = 0; k < nfds+1; k++) - { - if (readfds && FD_ISSET(k, readfds)) ++nr; - if (writefds && FD_ISSET(k, writefds)) ++nr; - } - - if (NSApp == nil - || ![NSThread isMainThread] - || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0)) - return thread_select(pselect, nfds, readfds, writefds, + return thread_select(pselect, nfds, readfds, writefds, exceptfds, timeout, sigmask); - else - { - struct timespec t = {0, 0}; - thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask); - } - - [outerpool release]; - outerpool = [[NSAutoreleasePool alloc] init]; - - - send_appdefined = YES; - if (nr > 0) - { - 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'; - emacs_write_sig (selfds[1], &c, 1); - } - else if (nr == 0 && timeout) - { - /* No file descriptor, just a timeout, no need to wake fd_handler. */ - double time = timespectod (*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); - } - - block_input (); - ns_init_events (&event); - - [NSApp run]; - - ns_finish_events (); - if (nr > 0 && readfds) - { - c = 's'; - emacs_write_sig (selfds[1], &c, 1); - } - unblock_input (); - - t = last_appdefined_event_data; - - if (t != NO_APPDEFINED_DATA) - { - last_appdefined_event_data = NO_APPDEFINED_DATA; - - if (t == -2) - { - /* The NX_APPDEFINED event we received was a timeout. */ - 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; - result = -1; - } - else - { - /* 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; - pthread_mutex_unlock (&select_mutex); - result = t; - } - } - else - { - errno = EINTR; - result = -1; - } - - return result; } -#ifdef HAVE_PTHREAD -void -ns_run_loop_break () -/* Break out of the NS run loop in ns_select or ns_read_socket. */ -{ - NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break"); - - /* If we don't have a GUI, don't send the event. */ - if (NSApp != NULL) - ns_send_appdefined(-1); -} -#endif - /* ========================================================================== @@ -5118,9 +4835,6 @@ ns_term_init (Lisp_Object display_name) NSTRACE ("ns_term_init"); - [outerpool release]; - outerpool = [[NSAutoreleasePool alloc] init]; - /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */ /*GSDebugAllocationActive (YES); */ block_input (); @@ -5128,38 +4842,10 @@ ns_term_init (Lisp_Object display_name) baud_rate = 38400; Fset_input_interrupt_mode (Qnil); - if (selfds[0] == -1) - { - if (emacs_pipe (selfds) != 0) - { - fprintf (stderr, "Failed to create pipe: %s\n", - emacs_strerror (errno)); - emacs_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_pending_files = [[NSMutableArray alloc] init]; ns_pending_service_names = [[NSMutableArray alloc] init]; ns_pending_service_args = [[NSMutableArray alloc] init]; - /* Start app and create the main menu, window, view. - Needs to be here because ns_initialize_display_info () uses AppKit classes. - The view will then ask the NSApp to stop and return to Emacs. */ - [EmacsApp sharedApplication]; - if (NSApp == nil) - 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:) @@ -5356,9 +5042,9 @@ ns_term_init (Lisp_Object display_name) right for fullscreen windows, so set this. */ [NSApp activateIgnoringOtherApps:YES]; - NSTRACE_MSG ("Call NSApp run"); + // NSTRACE_MSG ("Call NSApp run"); - [NSApp run]; + // [NSApp run]; ns_do_open_file = YES; #ifdef NS_IMPL_GNUSTEP @@ -5968,12 +5654,10 @@ ns_term_shutdown (int sig) #ifdef NS_IMPL_COCOA case NSAPP_DATA2_RUNASSCRIPT: ns_run_ascript (); - [self stop: self]; return; #endif case NSAPP_DATA2_RUNFILEDIALOG: ns_run_file_dialog (); - [self stop: self]; return; } } @@ -5984,24 +5668,6 @@ ns_term_shutdown (int sig) return; } - if (type == NSEventTypeApplicationDefined) - { - /* Events posted by ns_send_appdefined interrupt the run loop here. - But, if a modal window is up, an appdefined can still come through, - (e.g., from a makeKeyWindow event) but stopping self also stops the - modal loop. Just defer it until later. */ - if ([NSApp modalWindow] == nil) - { - last_appdefined_event_data = [theEvent data1]; - [self stop: self]; - } - else - { - send_appdefined = YES; - } - } - - #ifdef NS_IMPL_COCOA /* If no dialog and none of our frames have focus and it is a move, skip it. It is a mouse move in an auxiliary menu, i.e. on the top right on macOS, @@ -6028,12 +5694,13 @@ ns_term_shutdown (int sig) { struct frame *emacsframe = SELECTED_FRAME (); NSEvent *theEvent = [NSApp currentEvent]; + struct input_event emacs_event; - if (!emacs_event) - return; - emacs_event->kind = NS_NONKEY_EVENT; - emacs_event->code = KEY_NS_SHOW_PREFS; - emacs_event->modifiers = 0; + EVENT_INIT (emacs_event); + + emacs_event.kind = NS_NONKEY_EVENT; + emacs_event.code = KEY_NS_SHOW_PREFS; + emacs_event.modifiers = 0; EV_TRAILER (theEvent); } @@ -6044,12 +5711,13 @@ ns_term_shutdown (int sig) struct frame *emacsframe = SELECTED_FRAME (); NSEvent *theEvent = [NSApp currentEvent]; + struct input_event emacs_event; - if (!emacs_event) - return; - emacs_event->kind = NS_NONKEY_EVENT; - emacs_event->code = KEY_NS_NEW_FRAME; - emacs_event->modifiers = 0; + EVENT_INIT (emacs_event); + + emacs_event.kind = NS_NONKEY_EVENT; + emacs_event.code = KEY_NS_NEW_FRAME; + emacs_event.modifiers = 0; EV_TRAILER (theEvent); } @@ -6061,15 +5729,15 @@ ns_term_shutdown (int sig) struct frame *emacsframe = SELECTED_FRAME (); NSEvent *theEvent = [NSApp currentEvent]; + struct input_event emacs_event; - if (!emacs_event) - return NO; + EVENT_INIT (emacs_event); - emacs_event->kind = NS_NONKEY_EVENT; - emacs_event->code = KEY_NS_OPEN_FILE_LINE; + emacs_event.kind = NS_NONKEY_EVENT; + emacs_event.code = KEY_NS_OPEN_FILE_LINE; ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String])); ns_input_line = Qnil; /* can be start or cons start,end */ - emacs_event->modifiers =0; + emacs_event.modifiers = 0; EV_TRAILER (theEvent); return YES; @@ -6115,8 +5783,6 @@ ns_term_shutdown (int sig) build_string("icons/hicolor/128x128/apps/emacs.png")]]; } #endif - - ns_send_appdefined (-2); } - (void)antialiasThresholdDidChange:(NSNotification *)notification @@ -6153,13 +5819,13 @@ ns_term_shutdown (int sig) NSTRACE ("[EmacsApp terminate:]"); struct frame *emacsframe = SELECTED_FRAME (); + struct input_event emacs_event; - if (!emacs_event) - return; + EVENT_INIT (emacs_event); - emacs_event->kind = NS_NONKEY_EVENT; - emacs_event->code = KEY_NS_POWER_OFF; - emacs_event->arg = Qt; /* mark as non-key event */ + emacs_event.kind = NS_NONKEY_EVENT; + emacs_event.code = KEY_NS_POWER_OFF; + emacs_event.arg = Qt; /* mark as non-key event */ EV_TRAILER ((id)nil); } @@ -6287,123 +5953,9 @@ not_in_argv (NSString *arg) NSTRACE ("[EmacsApp applicationDidResignActive:]"); // ns_app_active=NO; - ns_send_appdefined (-1); } - -/* ========================================================================== - - EmacsApp aux handlers for managing event loop - - ========================================================================== */ - - -- (void)timeout_handler: (NSTimer *)timedEntry -/* -------------------------------------------------------------------------- - The timeout specified to ns_select has passed. - -------------------------------------------------------------------------- */ -{ - /* NSTRACE ("timeout_handler"); */ - ns_send_appdefined (-2); -} - -- (void)sendFromMainThread:(id)unused -{ - ns_send_appdefined (nextappdefined); -} - -- (void)fd_handler:(id)unused -/* -------------------------------------------------------------------------- - Check data waiting on file descriptors and terminate if so. - -------------------------------------------------------------------------- */ -{ - int result; - int waiting = 1, nfds; - char c; - - fd_set readfds, writefds, *wfds; - struct timespec timeout, *tmo; - NSAutoreleasePool *pool = nil; - - /* NSTRACE ("fd_handler"); */ - - for (;;) - { - [pool release]; - pool = [[NSAutoreleasePool alloc] init]; - - if (waiting) - { - fd_set fds; - FD_ZERO (&fds); - FD_SET (selfds[0], &fds); - result = select (selfds[0]+1, &fds, NULL, NULL, NULL); - if (result > 0 && read (selfds[0], &c, 1) == 1 && 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)) - { - if (read (selfds[0], &c, 1) == 1 && 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; - } - } -} - - - /* ========================================================================== Service provision @@ -6426,22 +5978,30 @@ not_in_argv (NSString *arg) { struct frame *emacsframe = SELECTED_FRAME (); NSEvent *theEvent = [NSApp currentEvent]; + struct input_event emacs_event; NSTRACE ("[EmacsApp fulfillService:withArg:]"); - if (!emacs_event) - return NO; + EVENT_INIT (emacs_event); - emacs_event->kind = NS_NONKEY_EVENT; - emacs_event->code = KEY_NS_SPI_SERVICE_CALL; + emacs_event.kind = NS_NONKEY_EVENT; + emacs_event.code = KEY_NS_SPI_SERVICE_CALL; ns_input_spi_name = build_string ([name UTF8String]); ns_input_spi_arg = build_string ([arg UTF8String]); - emacs_event->modifiers = EV_MODIFIERS (theEvent); + emacs_event.modifiers = EV_MODIFIERS (theEvent); EV_TRAILER (theEvent); return YES; } +-(void) initLispThread:(int)argc withArgv:(char **)argv +{ + [outerpool release]; + outerpool = [[NSAutoreleasePool alloc] init]; + + emacs_main (argc, argv); +} + @end /* EmacsApp */ @@ -6483,11 +6043,11 @@ not_in_argv (NSString *arg) id newFont; CGFloat size; NSFont *nsfont; + struct input_event emacs_event; NSTRACE ("[EmacsView changeFont:]"); - if (!emacs_event) - return; + EVENT_INIT (emacs_event); #ifdef NS_IMPL_GNUSTEP nsfont = ((struct nsfont_info *)font)->nsfont; @@ -6500,9 +6060,9 @@ not_in_argv (NSString *arg) { SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */ - emacs_event->kind = NS_NONKEY_EVENT; - emacs_event->modifiers = 0; - emacs_event->code = KEY_NS_CHANGE_FONT; + emacs_event.kind = NS_NONKEY_EVENT; + emacs_event.modifiers = 0; + emacs_event.code = KEY_NS_CHANGE_FONT; size = [newFont pointSize]; ns_input_fontsize = make_fixnum (lrint (size)); @@ -6552,6 +6112,7 @@ not_in_argv (NSString *arg) unsigned fnKeysym = 0; static NSMutableArray *nsEvArray; unsigned int flags = [theEvent modifierFlags]; + struct input_event emacs_event; NSTRACE ("[EmacsView keyDown:]"); @@ -6561,8 +6122,7 @@ not_in_argv (NSString *arg) else if ([theEvent type] != NSEventTypeKeyDown) return; - if (!emacs_event) - return; + EVENT_INIT (emacs_event); if (![[self window] isKeyWindow] && [[theEvent window] isKindOfClass: [EmacsWindow class]] @@ -6644,7 +6204,7 @@ not_in_argv (NSString *arg) Therefore its return value is the set of control-like modifiers. */ Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; - emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); + emacs_event.modifiers = EV_MODIFIERS2 (flags, kind); /* Function keys (such as the F-keys, arrow keys, etc.) set modifiers as though the fn key has been pressed when it @@ -6653,21 +6213,21 @@ not_in_argv (NSString *arg) <home>). We need to unset the fn modifier in these cases. FIXME: Can we avoid setting it in the first place? */ if (fnKeysym && (flags & NS_FUNCTION_KEY_MASK)) - emacs_event->modifiers + emacs_event.modifiers ^= parse_solitary_modifier (mod_of_kind (ns_function_modifier, QCfunction)); if (NS_KEYLOG) fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", - code, fnKeysym, flags, emacs_event->modifiers); + code, fnKeysym, flags, emacs_event.modifiers); /* If it was a function key or had control-like modifiers, pass it directly to Emacs. */ - if (fnKeysym || (emacs_event->modifiers - && (emacs_event->modifiers != shift_modifier) + if (fnKeysym || (emacs_event.modifiers + && (emacs_event.modifiers != shift_modifier) && [[theEvent charactersIgnoringModifiers] length] > 0)) { - emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; + emacs_event.kind = NON_ASCII_KEYSTROKE_EVENT; /* FIXME: What are the next four lines supposed to do? */ if (code < 0x20) code |= (1<<28)|(3<<16); @@ -6686,12 +6246,14 @@ not_in_argv (NSString *arg) [0x80, 0xFF] are not ASCII characters. Can’t we just use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds of characters? */ - emacs_event->kind = code > 0xFF + emacs_event.kind = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; } - emacs_event->code = code; + emacs_event.code = code; + EV_TRAILER (theEvent); + processingCompose = NO; return; } @@ -6739,6 +6301,7 @@ not_in_argv (NSString *arg) { NSString *s; NSUInteger len; + struct input_event emacs_event; NSTRACE ("[EmacsView insertText:]"); @@ -6753,8 +6316,7 @@ not_in_argv (NSString *arg) NSLog (@"insertText '%@'\tlen = %lu", aString, (unsigned long) len); processingCompose = NO; - if (!emacs_event) - return; + EVENT_INIT(emacs_event); /* First, clear any working text. */ if (workingText != nil) @@ -6782,10 +6344,10 @@ not_in_argv (NSString *arg) if (code == 0x2DC) code = '~'; /* 0x7E */ if (code != 32) /* Space */ - emacs_event->modifiers = 0; - emacs_event->kind + emacs_event.modifiers = 0; + emacs_event.kind = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; - emacs_event->code = code; + emacs_event.code = code; EV_TRAILER ((id)nil); } } @@ -6796,6 +6358,7 @@ not_in_argv (NSString *arg) { NSString *str = [aString respondsToSelector: @selector (string)] ? [aString string] : aString; + struct input_event emacs_event; NSTRACE ("[EmacsView setMarkedText:selectedRange:]"); @@ -6811,16 +6374,15 @@ not_in_argv (NSString *arg) return; } - if (!emacs_event) - return; + EVENT_INIT (emacs_event); processingCompose = YES; [workingText release]; workingText = [str copy]; ns_working_text = build_string ([workingText UTF8String]); - emacs_event->kind = NS_TEXT_EVENT; - emacs_event->code = KEY_NS_PUT_WORKING_TEXT; + emacs_event.kind = NS_TEXT_EVENT; + emacs_event.code = KEY_NS_PUT_WORKING_TEXT; EV_TRAILER ((id)nil); } @@ -6828,6 +6390,8 @@ not_in_argv (NSString *arg) /* Delete display of composing characters [not in <NSTextInput>]. */ - (void)deleteWorkingText { + struct input_event emacs_event; + NSTRACE ("[EmacsView deleteWorkingText]"); if (workingText == nil) @@ -6838,11 +6402,10 @@ not_in_argv (NSString *arg) workingText = nil; processingCompose = NO; - if (!emacs_event) - return; + EVENT_INIT (emacs_event); - emacs_event->kind = NS_TEXT_EVENT; - emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT; + emacs_event.kind = NS_TEXT_EVENT; + emacs_event.code = KEY_NS_UNPUT_WORKING_TEXT; EV_TRAILER ((id)nil); } @@ -6943,12 +6506,12 @@ not_in_argv (NSString *arg) processingCompose = NO; if (aSelector == @selector (deleteBackward:)) { - /* Happens when user backspaces over an ongoing composition: + struct input_event emacs_event; + /* Happens when user backspaces over an ongoing composition: throw a 'delete' into the event queue. */ - if (!emacs_event) - return; - emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; - emacs_event->code = 0xFF08; + EVENT_INIT (emacs_event); + emacs_event.kind = NON_ASCII_KEYSTROKE_EVENT; + emacs_event.code = 0xFF08; EV_TRAILER ((id)nil); } } @@ -6998,11 +6561,11 @@ not_in_argv (NSString *arg) { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil]; + struct input_event emacs_event; NSTRACE ("[EmacsView mouseDown:]"); - if (!emacs_event) - return; + EVENT_INIT (emacs_event); dpyinfo->last_mouse_frame = emacsframe; /* Appears to be needed to prevent spurious movement events generated on @@ -7111,11 +6674,11 @@ not_in_argv (NSString *arg) if (lines == 0) return; - emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT; - emacs_event->arg = (make_fixnum (lines)); + emacs_event.kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT; + emacs_event.arg = (make_fixnum (lines)); - emacs_event->code = 0; - emacs_event->modifiers = EV_MODIFIERS (theEvent) | + emacs_event.code = 0; + emacs_event.modifiers = EV_MODIFIERS (theEvent) | (scrollUp ? up_modifier : down_modifier); #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 } @@ -7135,27 +6698,27 @@ not_in_argv (NSString *arg) NSTRACE_MSG ("deltaIsZero"); return; } - emacs_event->kind = HORIZ_WHEEL_EVENT; + emacs_event.kind = HORIZ_WHEEL_EVENT; } else - emacs_event->kind = WHEEL_EVENT; + emacs_event.kind = WHEEL_EVENT; - emacs_event->code = 0; - emacs_event->modifiers = EV_MODIFIERS (theEvent) | + emacs_event.code = 0; + emacs_event.modifiers = EV_MODIFIERS (theEvent) | ((delta > 0) ? up_modifier : down_modifier); } #endif } else { - emacs_event->kind = MOUSE_CLICK_EVENT; - emacs_event->code = EV_BUTTON (theEvent); - emacs_event->modifiers = EV_MODIFIERS (theEvent) + emacs_event.kind = MOUSE_CLICK_EVENT; + emacs_event.code = EV_BUTTON (theEvent); + emacs_event.modifiers = EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent); } - XSETINT (emacs_event->x, lrint (p.x)); - XSETINT (emacs_event->y, lrint (p.y)); + XSETINT (emacs_event.x, lrint (p.x)); + XSETINT (emacs_event.y, lrint (p.y)); EV_TRAILER (theEvent); return; } @@ -7243,10 +6806,14 @@ not_in_argv (NSString *arg) || (EQ (XWINDOW (window)->frame, XWINDOW (selected_window)->frame)))) { + struct input_event emacs_event; + NSTRACE_MSG ("in_window"); - emacs_event->kind = SELECT_WINDOW_EVENT; - emacs_event->frame_or_window = window; - EV_TRAILER2 (e); + EVENT_INIT (emacs_event); + + emacs_event.kind = SELECT_WINDOW_EVENT; + emacs_event.frame_or_window = window; + EV_TRAILER (e); } /* Remember the last window where we saw the mouse. */ last_mouse_window = window; @@ -7266,8 +6833,8 @@ not_in_argv (NSString *arg) help_echo_object, help_echo_pos); } - if (emacsframe->mouse_moved && send_appdefined) - ns_send_appdefined (-1); + if (emacsframe->mouse_moved) + raise (SIGIO); } @@ -7295,14 +6862,14 @@ not_in_argv (NSString *arg) - (BOOL)windowShouldClose: (id)sender { NSEvent *e =[[self window] currentEvent]; + struct input_event emacs_event; NSTRACE ("[EmacsView windowShouldClose:]"); windowClosing = YES; - if (!emacs_event) - return NO; - emacs_event->kind = DELETE_WINDOW_EVENT; - emacs_event->modifiers = 0; - emacs_event->code = 0; + EVENT_INIT (emacs_event); + emacs_event.kind = DELETE_WINDOW_EVENT; + emacs_event.modifiers = 0; + emacs_event.code = 0; EV_TRAILER (e); /* Don't close this window, let this be done from lisp code. */ return NO; @@ -7550,8 +7117,6 @@ not_in_argv (NSString *arg) { [self updateFrameSize: YES]; } - - ns_send_appdefined (-1); } #ifdef NS_IMPL_COCOA @@ -7582,19 +7147,19 @@ not_in_argv (NSString *arg) { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); struct frame *old_focus = dpyinfo->ns_focus_frame; + struct input_event emacs_event; NSTRACE ("[EmacsView windowDidBecomeKey]"); + EVENT_INIT (emacs_event); + if (emacsframe != old_focus) dpyinfo->ns_focus_frame = emacsframe; ns_frame_rehighlight (emacsframe); - if (emacs_event) - { - emacs_event->kind = FOCUS_IN_EVENT; - EV_TRAILER ((id)nil); - } + emacs_event.kind = FOCUS_IN_EVENT; + EV_TRAILER ((id)nil); } @@ -7603,6 +7168,8 @@ not_in_argv (NSString *arg) { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); BOOL is_focus_frame = dpyinfo->ns_focus_frame == emacsframe; + struct input_event emacs_event; + NSTRACE ("[EmacsView windowDidResignKey:]"); if (is_focus_frame) @@ -7627,9 +7194,10 @@ not_in_argv (NSString *arg) gen_help_event (Qnil, frame, Qnil, Qnil, 0); } - if (emacs_event && is_focus_frame) + if (is_focus_frame) { - emacs_event->kind = FOCUS_OUT_EVENT; + EVENT_INIT (emacs_event); + emacs_event.kind = FOCUS_OUT_EVENT; EV_TRAILER ((id)nil); } } @@ -7858,6 +7426,7 @@ not_in_argv (NSString *arg) NSRect r = [win frame]; NSArray *screens = [NSScreen screens]; NSScreen *screen = [screens objectAtIndex: 0]; + struct input_event emacs_event; NSTRACE ("[EmacsView windowDidMove:]"); @@ -7865,6 +7434,8 @@ not_in_argv (NSString *arg) return; if (screen != nil) { + EVENT_INIT (emacs_event); + emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe); emacsframe->top_pos = NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height); @@ -7872,7 +7443,7 @@ not_in_argv (NSString *arg) // FIXME: after event part below didExitFullScreen is not received // if (emacs_event) // { - // emacs_event->kind = MOVE_FRAME_EVENT; + // emacs_event.kind = MOVE_FRAME_EVENT; // EV_TRAILER ((id)nil); // } } @@ -8016,7 +7587,12 @@ not_in_argv (NSString *arg) - (void)windowDidDeminiaturize: sender { + struct input_event emacs_event; + NSTRACE ("[EmacsView windowDidDeminiaturize:]"); + + EVENT_INIT (emacs_event); + if (!emacsframe->output_data.ns) return; @@ -8024,11 +7600,8 @@ not_in_argv (NSString *arg) SET_FRAME_VISIBLE (emacsframe, 1); windows_or_buffers_changed = 63; - if (emacs_event) - { - emacs_event->kind = DEICONIFY_EVENT; - EV_TRAILER ((id)nil); - } + emacs_event.kind = DEICONIFY_EVENT; + EV_TRAILER ((id)nil); } @@ -8040,26 +7613,25 @@ not_in_argv (NSString *arg) SET_FRAME_VISIBLE (emacsframe, 1); SET_FRAME_GARBAGED (emacsframe); - - if (send_appdefined) - ns_send_appdefined (-1); } - (void)windowDidMiniaturize: sender { + struct input_event emacs_event; + NSTRACE ("[EmacsView windowDidMiniaturize:]"); + + EVENT_INIT (emacs_event); + if (!emacsframe->output_data.ns) return; SET_FRAME_ICONIFIED (emacsframe, 1); SET_FRAME_VISIBLE (emacsframe, 0); - if (emacs_event) - { - emacs_event->kind = ICONIFY_EVENT; - EV_TRAILER ((id)nil); - } + emacs_event.kind = ICONIFY_EVENT; + EV_TRAILER ((id)nil); } #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 @@ -8505,7 +8077,6 @@ not_in_argv (NSString *arg) (void *)tag); } - ns_send_appdefined (-1); return self; } @@ -8521,18 +8092,22 @@ not_in_argv (NSString *arg) { NSEvent *theEvent; int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS; + struct input_event emacs_event; NSTRACE ("[EmacsView toolbarClicked:]"); - if (!emacs_event) - return self; + EVENT_INIT (emacs_event); theEvent = [[self window] currentEvent]; - emacs_event->kind = TOOL_BAR_EVENT; + emacs_event.kind = TOOL_BAR_EVENT; + XSETFRAME (emacs_event.arg, emacsframe); + EV_TRAILER (theEvent); + + emacs_event.kind = TOOL_BAR_EVENT; /* XSETINT (emacs_event->code, 0); */ - emacs_event->arg = AREF (emacsframe->tool_bar_items, + emacs_event.arg = AREF (emacsframe->tool_bar_items, idx + TOOL_BAR_ITEM_KEY); - emacs_event->modifiers = EV_MODIFIERS (theEvent); + emacs_event.modifiers = EV_MODIFIERS (theEvent); EV_TRAILER (theEvent); return self; } @@ -8540,13 +8115,14 @@ not_in_argv (NSString *arg) - (instancetype)toggleToolbar: (id)sender { + struct input_event emacs_event; + NSTRACE ("[EmacsView toggleToolbar:]"); - if (!emacs_event) - return self; + EVENT_INIT (emacs_event); - emacs_event->kind = NS_NONKEY_EVENT; - emacs_event->code = KEY_NS_TOGGLE_TOOLBAR; + emacs_event.kind = NS_NONKEY_EVENT; + emacs_event.code = KEY_NS_TOGGLE_TOOLBAR; EV_TRAILER ((id)nil); return self; } @@ -8722,11 +8298,12 @@ not_in_argv (NSString *arg) Lisp_Object operations = Qnil; Lisp_Object strings = Qnil; Lisp_Object type_sym; + int modifiers = 0; + struct input_event emacs_event; NSTRACE ("[EmacsView performDragOperation:]"); - if (!emacs_event) - return NO; + EVENT_INIT (emacs_event); position = [self convertPoint: [sender draggingLocation] fromView: nil]; x = lrint (position.x); y = lrint (position.y); @@ -8794,14 +8371,14 @@ not_in_argv (NSString *arg) return NO; } - emacs_event->kind = DRAG_N_DROP_EVENT; - XSETINT (emacs_event->x, x); - XSETINT (emacs_event->y, y); - emacs_event->modifiers = 0; + emacs_event.kind = DRAG_N_DROP_EVENT; + XSETINT (emacs_event.x, x); + XSETINT (emacs_event.y, y); + emacs_event.modifiers = 0; - emacs_event->arg = Fcons (type_sym, - Fcons (operations, - strings)); + emacs_event.arg = Fcons (type_sym, + Fcons (operations, + strings)); EV_TRAILER (theEvent); return YES; @@ -9427,46 +9004,38 @@ not_in_argv (NSString *arg) return self; } -/* Set up emacs_event. */ - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e { Lisp_Object win; + struct input_event emacs_event; NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]"); - if (!emacs_event) - return; + EVENT_INIT (emacs_event); - emacs_event->part = last_hit_part; - emacs_event->code = 0; - emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier; + emacs_event.part = last_hit_part; + emacs_event.code = 0; + emacs_event.modifiers = EV_MODIFIERS (e) | down_modifier; XSETWINDOW (win, window); - emacs_event->frame_or_window = win; - emacs_event->timestamp = EV_TIMESTAMP (e); - emacs_event->arg = Qnil; + emacs_event.arg = Qnil; if (horizontal) { - emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; - XSETINT (emacs_event->x, em_whole * loc / pixel_length); - XSETINT (emacs_event->y, em_whole); + emacs_event.kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; + XSETINT (emacs_event.x, em_whole * loc / pixel_length); + XSETINT (emacs_event.y, em_whole); } else { - emacs_event->kind = SCROLL_BAR_CLICK_EVENT; - XSETINT (emacs_event->x, loc); - XSETINT (emacs_event->y, pixel_length-20); + emacs_event.kind = SCROLL_BAR_CLICK_EVENT; + XSETINT (emacs_event.x, loc); + XSETINT (emacs_event.y, pixel_length-20); } - if (q_event_ptr) - { - n_emacs_events_pending++; - kbd_buffer_store_event_hold (emacs_event, q_event_ptr); - } - else - hold_event (emacs_event); - EVENT_INIT (*emacs_event); - ns_send_appdefined (-1); + [emacsMainThread sendEmacsEvent:&emacs_event + NSEvent:e + frameOrWindow:win]; + } @@ -9698,6 +9267,85 @@ not_in_argv (NSString *arg) @end /* EmacsScroller */ +/* ========================================================================== + + EmacsThread implementation + + ========================================================================== */ + +/* EmacsThread extends NSThread and provides a few convenience methods + for passing events and such like. */ + +@implementation EmacsThread + +- (instancetype) initWithArgc: (int)argc Argv: (char **)argv +{ + NSMethodSignature *lispSignature; + NSInvocation *lispInvocation; + + lispSignature = [NSApp methodSignatureForSelector:@selector(initLispThread:withArgv:)]; + lispInvocation = [NSInvocation invocationWithMethodSignature:lispSignature]; + [lispInvocation setTarget:NSApp]; + [lispInvocation setSelector:@selector(initLispThread:withArgv:)]; + [lispInvocation setArgument:&argc atIndex:2]; + [lispInvocation setArgument:&argv atIndex:3]; + + return [self initWithTarget:lispInvocation + selector:@selector (invoke) + object:nil]; +} + + +/* Put the input_event held in data into the emacs event queue. + + This method should be run in the Emacs Main Lisp thread, so never + call it directly, only from sendEmacsEvent. */ +- (void) processEmacsEvent: (NSData *)data +{ + struct input_event *event; + Lisp_Object tem = Vinhibit_quit; + + NSTRACE ("[EmacsThread processEmacsEvent:]"); + + event = (struct input_event *)[data bytes]; + + Vinhibit_quit = Qt; + n_emacs_events_pending++; + kbd_buffer_store_event_hold (event, q_event_ptr); + Vinhibit_quit = tem; +} + +/* Send an input_event to the Emacs main thread. */ +- (void) sendEmacsEvent: (struct input_event *)emacs_event + NSEvent: (NSEvent *)e + frameOrWindow: (void *)frame_or_window +{ + NSData *event; + + NSTRACE ("[EmacsThread sendEmacsEvent:]"); + + XSETFRAME (emacs_event->frame_or_window, frame_or_window); + + if (e) + emacs_event->timestamp = EV_TIMESTAMP (e); + + /* Package the input_event inside an NSData object so we can pass it + to the lisp thread using performSelector. performSelector + doesn't handle complex C types. Even using an NSInvocation to + package it up fails. */ + event = [NSData dataWithBytes:emacs_event + length:sizeof(struct input_event)]; + + [emacsMainThread performSelector:@selector(processEmacsEvent:) + onThread:emacsMainThread + withObject:event + waitUntilDone:NO]; + + raise (SIGIO); +} + +@end /* EmacsThread */ + #ifdef NS_IMPL_GNUSTEP /* Dummy class to get rid of startup warnings. */ @implementation EmacsDocument @@ -9825,6 +9473,23 @@ ns_xlfd_to_fontname (const char *xlfd) } +int +main (int argc, char **argv) +{ + // if (! initialized) + // return emacs_main(argc, argv); + + [EmacsApp sharedApplication]; + [NSApp setDelegate: NSApp]; + + /* Start the Lisp thread. */ + emacsMainThread = [[EmacsThread alloc] initWithArgc:argc Argv:argv]; + [emacsMainThread start]; + + [NSApp run]; +} + + void syms_of_nsterm (void) { diff --git a/src/systhread.c b/src/systhread.c index 0d600d6895e..ff2b43dc92b 100644 --- a/src/systhread.c +++ b/src/systhread.c @@ -175,13 +175,6 @@ sys_cond_broadcast (sys_cond_t *cond) { int error = pthread_cond_broadcast (cond); eassert (error == 0); -#ifdef HAVE_NS - /* Send an app defined event to break out of the NS run loop. - It seems that if ns_select is running the NS run loop, this - broadcast has no effect until the loop is done, breaking a couple - of tests in thread-tests.el. */ - ns_run_loop_break (); -#endif } void |