aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlan Third2016-12-31 10:31:19 +0000
committerAlan Third2016-12-31 16:55:30 +0000
commite0e5b0f4a4ce1d19ee0240c514dedd873d4165dc (patch)
tree0d629fd5b378ae23237d69ca670e36b582491b3f /src
parent4bbd5424a2290ab4bd88c0af602b7aa7d53a407e (diff)
downloademacs-e0e5b0f4a4ce1d19ee0240c514dedd873d4165dc.tar.gz
emacs-e0e5b0f4a4ce1d19ee0240c514dedd873d4165dc.zip
Rework NS event handling (bug#25265)
* src/nsterm.m (unwind_apploopnr): Remove. (ns_read_socket): Remove references to apploopnr. Make processing the NS event loop conditional on being in the main thread. (ns_select): Remove references to apploopnr. Remove all fd_handler related stuff. Check if there are events waiting on the NS event queue rather than running the event loop. Remove unused variables and code. (fd_handler): Remove. (ns_term_init): Remove creation of fd_handler thread. (hold_event, EmacsApp:sendEvent, EmacsView:mouseMoved, EmacsView:windowDidExpose): Remove send_appdefined. (ns_send_appdefined): Always check the event queue for applicationDefined events rather than relying on send_appdefined var. * src/nsterm.h: Remove reference to fd_handler method.
Diffstat (limited to 'src')
-rw-r--r--src/nsterm.h1
-rw-r--r--src/nsterm.m380
2 files changed, 68 insertions, 313 deletions
diff --git a/src/nsterm.h b/src/nsterm.h
index 35c6e1a4cbc..dc222a75e74 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -392,7 +392,6 @@ char const * nstrace_fullscreen_type_name (int);
392- (void)sendEvent: (NSEvent *)theEvent; 392- (void)sendEvent: (NSEvent *)theEvent;
393- (void)showPreferencesWindow: (id)sender; 393- (void)showPreferencesWindow: (id)sender;
394- (BOOL) openFile: (NSString *)fileName; 394- (BOOL) openFile: (NSString *)fileName;
395- (void)fd_handler: (id)unused;
396- (void)timeout_handler: (NSTimer *)timedEntry; 395- (void)timeout_handler: (NSTimer *)timedEntry;
397- (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg; 396- (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg;
398#ifdef NS_IMPL_GNUSTEP 397#ifdef NS_IMPL_GNUSTEP
diff --git a/src/nsterm.m b/src/nsterm.m
index 7e6ec85abf1..98fd8ab8558 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -279,18 +279,10 @@ static BOOL ns_menu_bar_is_hidden = NO;
279/*static int debug_lock = 0; */ 279/*static int debug_lock = 0; */
280 280
281/* event loop */ 281/* event loop */
282static BOOL send_appdefined = YES;
283#define NO_APPDEFINED_DATA (-8) 282#define NO_APPDEFINED_DATA (-8)
284static int last_appdefined_event_data = NO_APPDEFINED_DATA; 283static int last_appdefined_event_data = NO_APPDEFINED_DATA;
285static NSTimer *timed_entry = 0; 284static NSTimer *timed_entry = 0;
286static NSTimer *scroll_repeat_entry = nil; 285static NSTimer *scroll_repeat_entry = nil;
287static fd_set select_readfds, select_writefds;
288enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
289static int select_nfds = 0, select_valid = 0;
290static struct timespec select_timeout = { 0, 0 };
291static int selfds[2] = { -1, -1 };
292static pthread_mutex_t select_mutex;
293static int apploopnr = 0;
294static NSAutoreleasePool *outerpool; 286static NSAutoreleasePool *outerpool;
295static struct input_event *emacs_event = NULL; 287static struct input_event *emacs_event = NULL;
296static struct input_event *q_event_ptr = NULL; 288static struct input_event *q_event_ptr = NULL;
@@ -457,7 +449,6 @@ hold_event (struct input_event *event)
457 hold_event_q.q[hold_event_q.nr++] = *event; 449 hold_event_q.q[hold_event_q.nr++] = *event;
458 /* Make sure ns_read_socket is called, i.e. we have input. */ 450 /* Make sure ns_read_socket is called, i.e. we have input. */
459 raise (SIGIO); 451 raise (SIGIO);
460 send_appdefined = YES;
461} 452}
462 453
463static Lisp_Object 454static Lisp_Object
@@ -3872,31 +3863,17 @@ ns_send_appdefined (int value)
3872 return; 3863 return;
3873 } 3864 }
3874 3865
3875 /* Only post this event if we haven't already posted one. This will end 3866 /* Only post this event if we haven't already posted one. This will
3876 the [NXApp run] main loop after having processed all events queued at 3867 end the [NXApp run] main loop after having processed all events
3877 this moment. */ 3868 queued at this moment. */
3878 3869 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
3879#ifdef NS_IMPL_COCOA 3870 untilDate:[NSDate distantPast]
3880 if (! send_appdefined) 3871 inMode:NSDefaultRunLoopMode
3881 { 3872 dequeue:NO];
3882 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves 3873 if (! appev)
3883 in certain situations (rapid incoming events).
3884 So check if we have one, if not add one. */
3885 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
3886 untilDate:[NSDate distantPast]
3887 inMode:NSDefaultRunLoopMode
3888 dequeue:NO];
3889 if (! appev) send_appdefined = YES;
3890 }
3891#endif
3892
3893 if (send_appdefined)
3894 { 3874 {
3895 NSEvent *nxev; 3875 NSEvent *nxev;
3896 3876
3897 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3898 send_appdefined = NO;
3899
3900 /* Don't need wakeup timer any more */ 3877 /* Don't need wakeup timer any more */
3901 if (timed_entry) 3878 if (timed_entry)
3902 { 3879 {
@@ -4011,14 +3988,6 @@ ns_check_pending_open_menu ()
4011} 3988}
4012#endif /* NS_IMPL_COCOA */ 3989#endif /* NS_IMPL_COCOA */
4013 3990
4014static void
4015unwind_apploopnr (Lisp_Object not_used)
4016{
4017 --apploopnr;
4018 n_emacs_events_pending = 0;
4019 ns_finish_events ();
4020 q_event_ptr = NULL;
4021}
4022 3991
4023static int 3992static int
4024ns_read_socket (struct terminal *terminal, struct input_event *hold_quit) 3993ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
@@ -4029,13 +3998,10 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4029 -------------------------------------------------------------------------- */ 3998 -------------------------------------------------------------------------- */
4030{ 3999{
4031 struct input_event ev; 4000 struct input_event ev;
4032 int nevents; 4001 int nevents = 0;
4033 4002
4034 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket"); 4003 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4035 4004
4036 if (apploopnr > 0)
4037 return -1; /* Already within event loop. */
4038
4039#ifdef HAVE_NATIVE_FS 4005#ifdef HAVE_NATIVE_FS
4040 check_native_fs (); 4006 check_native_fs ();
4041#endif 4007#endif
@@ -4052,54 +4018,49 @@ ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4052 return i; 4018 return i;
4053 } 4019 }
4054 4020
4055 block_input (); 4021 if ([NSThread isMainThread])
4056 n_emacs_events_pending = 0;
4057 ns_init_events (&ev);
4058 q_event_ptr = hold_quit;
4059
4060 /* we manage autorelease pools by allocate/reallocate each time around
4061 the loop; strict nesting is occasionally violated but seems not to
4062 matter.. earlier methods using full nesting caused major memory leaks */
4063 [outerpool release];
4064 outerpool = [[NSAutoreleasePool alloc] init];
4065
4066 /* If have pending open-file requests, attend to the next one of those. */
4067 if (ns_pending_files && [ns_pending_files count] != 0
4068 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4069 { 4022 {
4070 [ns_pending_files removeObjectAtIndex: 0]; 4023 block_input ();
4071 } 4024 n_emacs_events_pending = 0;
4072 /* Deal with pending service requests. */ 4025 ns_init_events (&ev);
4073 else if (ns_pending_service_names && [ns_pending_service_names count] != 0 4026 q_event_ptr = hold_quit;
4074 && [(EmacsApp *) 4027
4075 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0] 4028 /* we manage autorelease pools by allocate/reallocate each time around
4076 withArg: [ns_pending_service_args objectAtIndex: 0]]) 4029 the loop; strict nesting is occasionally violated but seems not to
4077 { 4030 matter.. earlier methods using full nesting caused major memory leaks */
4078 [ns_pending_service_names removeObjectAtIndex: 0]; 4031 [outerpool release];
4079 [ns_pending_service_args removeObjectAtIndex: 0]; 4032 outerpool = [[NSAutoreleasePool alloc] init];
4080 } 4033
4081 else 4034 /* If have pending open-file requests, attend to the next one of those. */
4082 { 4035 if (ns_pending_files && [ns_pending_files count] != 0
4083 ptrdiff_t specpdl_count = SPECPDL_INDEX (); 4036 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4084 /* Run and wait for events. We must always send one NX_APPDEFINED event
4085 to ourself, otherwise [NXApp run] will never exit. */
4086 send_appdefined = YES;
4087 ns_send_appdefined (-1);
4088
4089 if (++apploopnr != 1)
4090 { 4037 {
4091 emacs_abort (); 4038 [ns_pending_files removeObjectAtIndex: 0];
4092 } 4039 }
4093 record_unwind_protect (unwind_apploopnr, Qt); 4040 /* Deal with pending service requests. */
4094 [NSApp run]; 4041 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4095 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */ 4042 && [(EmacsApp *)
4096 } 4043 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4044 withArg: [ns_pending_service_args objectAtIndex: 0]])
4045 {
4046 [ns_pending_service_names removeObjectAtIndex: 0];
4047 [ns_pending_service_args removeObjectAtIndex: 0];
4048 }
4049 else
4050 {
4051 /* Run and wait for events. We must always send one NX_APPDEFINED event
4052 to ourself, otherwise [NXApp run] will never exit. */
4053 ns_send_appdefined (-1);
4097 4054
4098 nevents = n_emacs_events_pending; 4055 [NSApp run];
4099 n_emacs_events_pending = 0; 4056 }
4100 ns_finish_events (); 4057
4101 q_event_ptr = NULL; 4058 nevents = n_emacs_events_pending;
4102 unblock_input (); 4059 n_emacs_events_pending = 0;
4060 ns_finish_events ();
4061 q_event_ptr = NULL;
4062 unblock_input ();
4063 }
4103 4064
4104 return nevents; 4065 return nevents;
4105} 4066}
@@ -4114,15 +4075,11 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4114 -------------------------------------------------------------------------- */ 4075 -------------------------------------------------------------------------- */
4115{ 4076{
4116 int result; 4077 int result;
4117 int t, k, nr = 0; 4078 NSDate *timeout_date = nil;
4118 struct input_event event; 4079 NSEvent *ns_event;
4119 char c;
4120 4080
4121 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select"); 4081 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4122 4082
4123 if (apploopnr > 0)
4124 return -1; /* Already within event loop. */
4125
4126#ifdef HAVE_NATIVE_FS 4083#ifdef HAVE_NATIVE_FS
4127 check_native_fs (); 4084 check_native_fs ();
4128#endif 4085#endif
@@ -4135,121 +4092,34 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4135 return -1; 4092 return -1;
4136 } 4093 }
4137 4094
4138 for (k = 0; k < nfds+1; k++)
4139 {
4140 if (readfds && FD_ISSET(k, readfds)) ++nr;
4141 if (writefds && FD_ISSET(k, writefds)) ++nr;
4142 }
4143
4144 if (NSApp == nil 4095 if (NSApp == nil
4096 || ![NSThread isMainThread]
4145 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0)) 4097 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4146 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask); 4098 return pselect(nfds, readfds, writefds,
4099 exceptfds, timeout, sigmask);
4100
4101 result = pselect(nfds, readfds, writefds, exceptfds,
4102 &(struct timespec){.tv_sec = 0, .tv_nsec = 100},
4103 sigmask);
4147 4104
4148 [outerpool release]; 4105 [outerpool release];
4149 outerpool = [[NSAutoreleasePool alloc] init]; 4106 outerpool = [[NSAutoreleasePool alloc] init];
4150 4107
4151 4108 if (timeout)
4152 send_appdefined = YES;
4153 if (nr > 0)
4154 {
4155 pthread_mutex_lock (&select_mutex);
4156 select_nfds = nfds;
4157 select_valid = 0;
4158 if (readfds)
4159 {
4160 select_readfds = *readfds;
4161 select_valid += SELECT_HAVE_READ;
4162 }
4163 if (writefds)
4164 {
4165 select_writefds = *writefds;
4166 select_valid += SELECT_HAVE_WRITE;
4167 }
4168
4169 if (timeout)
4170 {
4171 select_timeout = *timeout;
4172 select_valid += SELECT_HAVE_TMO;
4173 }
4174
4175 pthread_mutex_unlock (&select_mutex);
4176
4177 /* Inform fd_handler that select should be called */
4178 c = 'g';
4179 emacs_write_sig (selfds[1], &c, 1);
4180 }
4181 else if (nr == 0 && timeout)
4182 { 4109 {
4183 /* No file descriptor, just a timeout, no need to wake fd_handler */
4184 double time = timespectod (*timeout); 4110 double time = timespectod (*timeout);
4185 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time 4111 timeout_date = [NSDate dateWithTimeIntervalSinceNow:time];
4186 target: NSApp
4187 selector:
4188 @selector (timeout_handler:)
4189 userInfo: 0
4190 repeats: NO]
4191 retain];
4192 }
4193 else /* No timeout and no file descriptors, can this happen? */
4194 {
4195 /* Send appdefined so we exit from the loop */
4196 ns_send_appdefined (-1);
4197 }
4198
4199 block_input ();
4200 ns_init_events (&event);
4201 if (++apploopnr != 1)
4202 {
4203 emacs_abort ();
4204 }
4205
4206 {
4207 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4208 record_unwind_protect (unwind_apploopnr, Qt);
4209 [NSApp run];
4210 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
4211 }
4212
4213 ns_finish_events ();
4214 if (nr > 0 && readfds)
4215 {
4216 c = 's';
4217 emacs_write_sig (selfds[1], &c, 1);
4218 } 4112 }
4219 unblock_input ();
4220 4113
4221 t = last_appdefined_event_data; 4114 /* Listen for a new NSEvent. */
4115 ns_event = [NSApp nextEventMatchingMask:NSEventMaskAny
4116 untilDate:timeout_date
4117 inMode:NSDefaultRunLoopMode
4118 dequeue:NO];
4222 4119
4223 if (t != NO_APPDEFINED_DATA) 4120 if (ns_event != nil)
4224 { 4121 {
4225 last_appdefined_event_data = NO_APPDEFINED_DATA; 4122 raise (SIGIO);
4226
4227 if (t == -2)
4228 {
4229 /* The NX_APPDEFINED event we received was a timeout. */
4230 result = 0;
4231 }
4232 else if (t == -1)
4233 {
4234 /* The NX_APPDEFINED event we received was the result of
4235 at least one real input event arriving. */
4236 errno = EINTR;
4237 result = -1;
4238 }
4239 else
4240 {
4241 /* Received back from select () in fd_handler; copy the results */
4242 pthread_mutex_lock (&select_mutex);
4243 if (readfds) *readfds = select_readfds;
4244 if (writefds) *writefds = select_writefds;
4245 pthread_mutex_unlock (&select_mutex);
4246 result = t;
4247 }
4248 }
4249 else
4250 {
4251 errno = EINTR;
4252 result = -1;
4253 } 4123 }
4254 4124
4255 return result; 4125 return result;
@@ -4765,21 +4635,6 @@ ns_term_init (Lisp_Object display_name)
4765 baud_rate = 38400; 4635 baud_rate = 38400;
4766 Fset_input_interrupt_mode (Qnil); 4636 Fset_input_interrupt_mode (Qnil);
4767 4637
4768 if (selfds[0] == -1)
4769 {
4770 if (emacs_pipe (selfds) != 0)
4771 {
4772 fprintf (stderr, "Failed to create pipe: %s\n",
4773 emacs_strerror (errno));
4774 emacs_abort ();
4775 }
4776
4777 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4778 FD_ZERO (&select_readfds);
4779 FD_ZERO (&select_writefds);
4780 pthread_mutex_init (&select_mutex, NULL);
4781 }
4782
4783 ns_pending_files = [[NSMutableArray alloc] init]; 4638 ns_pending_files = [[NSMutableArray alloc] init];
4784 ns_pending_service_names = [[NSMutableArray alloc] init]; 4639 ns_pending_service_names = [[NSMutableArray alloc] init];
4785 ns_pending_service_args = [[NSMutableArray alloc] init]; 4640 ns_pending_service_args = [[NSMutableArray alloc] init];
@@ -4792,11 +4647,6 @@ ns_term_init (Lisp_Object display_name)
4792 return NULL; 4647 return NULL;
4793 [NSApp setDelegate: NSApp]; 4648 [NSApp setDelegate: NSApp];
4794 4649
4795 /* Start the select thread. */
4796 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4797 toTarget:NSApp
4798 withObject:nil];
4799
4800 /* debugging: log all notifications */ 4650 /* debugging: log all notifications */
4801 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp 4651 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4802 selector: @selector (logNotification:) 4652 selector: @selector (logNotification:)
@@ -5178,10 +5028,6 @@ ns_term_shutdown (int sig)
5178 last_appdefined_event_data = [theEvent data1]; 5028 last_appdefined_event_data = [theEvent data1];
5179 [self stop: self]; 5029 [self stop: self];
5180 } 5030 }
5181 else
5182 {
5183 send_appdefined = YES;
5184 }
5185 } 5031 }
5186 5032
5187 5033
@@ -5484,95 +5330,6 @@ not_in_argv (NSString *arg)
5484 ns_send_appdefined (nextappdefined); 5330 ns_send_appdefined (nextappdefined);
5485} 5331}
5486 5332
5487- (void)fd_handler:(id)unused
5488/* --------------------------------------------------------------------------
5489 Check data waiting on file descriptors and terminate if so
5490 -------------------------------------------------------------------------- */
5491{
5492 int result;
5493 int waiting = 1, nfds;
5494 char c;
5495
5496 fd_set readfds, writefds, *wfds;
5497 struct timespec timeout, *tmo;
5498 NSAutoreleasePool *pool = nil;
5499
5500 /* NSTRACE ("fd_handler"); */
5501
5502 for (;;)
5503 {
5504 [pool release];
5505 pool = [[NSAutoreleasePool alloc] init];
5506
5507 if (waiting)
5508 {
5509 fd_set fds;
5510 FD_ZERO (&fds);
5511 FD_SET (selfds[0], &fds);
5512 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5513 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5514 waiting = 0;
5515 }
5516 else
5517 {
5518 pthread_mutex_lock (&select_mutex);
5519 nfds = select_nfds;
5520
5521 if (select_valid & SELECT_HAVE_READ)
5522 readfds = select_readfds;
5523 else
5524 FD_ZERO (&readfds);
5525
5526 if (select_valid & SELECT_HAVE_WRITE)
5527 {
5528 writefds = select_writefds;
5529 wfds = &writefds;
5530 }
5531 else
5532 wfds = NULL;
5533 if (select_valid & SELECT_HAVE_TMO)
5534 {
5535 timeout = select_timeout;
5536 tmo = &timeout;
5537 }
5538 else
5539 tmo = NULL;
5540
5541 pthread_mutex_unlock (&select_mutex);
5542
5543 FD_SET (selfds[0], &readfds);
5544 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5545
5546 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5547
5548 if (result == 0)
5549 ns_send_appdefined (-2);
5550 else if (result > 0)
5551 {
5552 if (FD_ISSET (selfds[0], &readfds))
5553 {
5554 if (read (selfds[0], &c, 1) == 1 && c == 's')
5555 waiting = 1;
5556 }
5557 else
5558 {
5559 pthread_mutex_lock (&select_mutex);
5560 if (select_valid & SELECT_HAVE_READ)
5561 select_readfds = readfds;
5562 if (select_valid & SELECT_HAVE_WRITE)
5563 select_writefds = writefds;
5564 if (select_valid & SELECT_HAVE_TMO)
5565 select_timeout = timeout;
5566 pthread_mutex_unlock (&select_mutex);
5567
5568 ns_send_appdefined (result);
5569 }
5570 }
5571 waiting = 1;
5572 }
5573 }
5574}
5575
5576 5333
5577 5334
5578/* ========================================================================== 5335/* ==========================================================================
@@ -6361,7 +6118,7 @@ not_in_argv (NSString *arg)
6361 help_echo_object, help_echo_pos); 6118 help_echo_object, help_echo_pos);
6362 } 6119 }
6363 6120
6364 if (emacsframe->mouse_moved && send_appdefined) 6121 if (emacsframe->mouse_moved)
6365 ns_send_appdefined (-1); 6122 ns_send_appdefined (-1);
6366} 6123}
6367 6124
@@ -7058,8 +6815,7 @@ not_in_argv (NSString *arg)
7058 SET_FRAME_VISIBLE (emacsframe, 1); 6815 SET_FRAME_VISIBLE (emacsframe, 1);
7059 SET_FRAME_GARBAGED (emacsframe); 6816 SET_FRAME_GARBAGED (emacsframe);
7060 6817
7061 if (send_appdefined) 6818 ns_send_appdefined (-1);
7062 ns_send_appdefined (-1);
7063} 6819}
7064 6820
7065 6821