emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 308d596: Revert "Rework NS event handling (bug#2526


From: Alan Third
Subject: [Emacs-diffs] master 308d596: Revert "Rework NS event handling (bug#25265)"
Date: Wed, 4 Jan 2017 21:01:51 +0000 (UTC)

branch: master
commit 308d5962236448a84795f49d775601599688d78d
Author: Alan Third <address@hidden>
Commit: Alan Third <address@hidden>

    Revert "Rework NS event handling (bug#25265)"
    
    This reverts commit e0e5b0f4a4ce1d19ee0240c514dedd873d4165dc.
---
 src/nsterm.h |    1 +
 src/nsterm.m |  380 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 313 insertions(+), 68 deletions(-)

diff --git a/src/nsterm.h b/src/nsterm.h
index 161c3c2..534ec68 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -392,6 +392,7 @@ char const * nstrace_fullscreen_type_name (int);
 - (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
diff --git a/src/nsterm.m b/src/nsterm.m
index 1d038cd..47fc6c1 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -279,10 +279,18 @@ 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 int apploopnr = 0;
 static NSAutoreleasePool *outerpool;
 static struct input_event *emacs_event = NULL;
 static struct input_event *q_event_ptr = NULL;
@@ -449,6 +457,7 @@ hold_event (struct input_event *event)
   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
@@ -3863,17 +3872,31 @@ ns_send_appdefined (int value)
       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.  */
-  NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
-                                      untilDate:[NSDate distantPast]
-                                         inMode:NSDefaultRunLoopMode
-                                        dequeue:NO];
-  if (! appev)
+  /* 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)
         {
@@ -3988,6 +4011,14 @@ ns_check_pending_open_menu ()
 }
 #endif /* NS_IMPL_COCOA */
 
+static void
+unwind_apploopnr (Lisp_Object not_used)
+{
+  --apploopnr;
+  n_emacs_events_pending = 0;
+  ns_finish_events ();
+  q_event_ptr = NULL;
+}
 
 static int
 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
@@ -3998,10 +4029,13 @@ ns_read_socket (struct terminal *terminal, struct 
input_event *hold_quit)
    -------------------------------------------------------------------------- 
*/
 {
   struct input_event ev;
-  int nevents = 0;
+  int nevents;
 
   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
 
+  if (apploopnr > 0)
+    return -1; /* Already within event loop. */
+
 #ifdef HAVE_NATIVE_FS
   check_native_fs ();
 #endif
@@ -4018,50 +4052,55 @@ ns_read_socket (struct terminal *terminal, struct 
input_event *hold_quit)
       return i;
     }
 
-  if ([NSThread isMainThread])
+  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
+     the loop; strict nesting is occasionally violated but seems not to
+     matter.. earlier methods using full nesting caused major memory leaks */
+  [outerpool release];
+  outerpool = [[NSAutoreleasePool alloc] init];
+
+  /* If have pending open-file requests, attend to the next one of those. */
+  if (ns_pending_files && [ns_pending_files count] != 0
+      && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
     {
-      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
-         the loop; strict nesting is occasionally violated but seems not to
-         matter.. earlier methods using full nesting caused major memory leaks 
*/
-      [outerpool release];
-      outerpool = [[NSAutoreleasePool alloc] init];
-
-      /* If have pending open-file requests, attend to the next one of those. 
*/
-      if (ns_pending_files && [ns_pending_files count] != 0
-          && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
-        {
-          [ns_pending_files removeObjectAtIndex: 0];
-        }
-      /* Deal with pending service requests. */
-      else if (ns_pending_service_names && [ns_pending_service_names count] != 0
-               && [(EmacsApp *)
-                    NSApp fulfillService: [ns_pending_service_names 
objectAtIndex: 0]
-                                 withArg: [ns_pending_service_args 
objectAtIndex: 0]])
-        {
-          [ns_pending_service_names removeObjectAtIndex: 0];
-          [ns_pending_service_args removeObjectAtIndex: 0];
-        }
-      else
-        {
-          /* Run and wait for events.  We must always send one NX_APPDEFINED 
event
-             to ourself, otherwise [NXApp run] will never exit.  */
-          ns_send_appdefined (-1);
+      [ns_pending_files removeObjectAtIndex: 0];
+    }
+  /* Deal with pending service requests. */
+  else if (ns_pending_service_names && [ns_pending_service_names count] != 0
+    && [(EmacsApp *)
+         NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
+                      withArg: [ns_pending_service_args objectAtIndex: 0]])
+    {
+      [ns_pending_service_names removeObjectAtIndex: 0];
+      [ns_pending_service_args removeObjectAtIndex: 0];
+    }
+  else
+    {
+      ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+      /* 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];
+      if (++apploopnr != 1)
+        {
+          emacs_abort ();
         }
-
-      nevents = n_emacs_events_pending;
-      n_emacs_events_pending = 0;
-      ns_finish_events ();
-      q_event_ptr = NULL;
-      unblock_input ();
+      record_unwind_protect (unwind_apploopnr, Qt);
+      [NSApp run];
+      unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
     }
 
+  nevents = n_emacs_events_pending;
+  n_emacs_events_pending = 0;
+  ns_finish_events ();
+  q_event_ptr = NULL;
+  unblock_input ();
+
   return nevents;
 }
 
@@ -4075,11 +4114,15 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds,
    -------------------------------------------------------------------------- 
*/
 {
   int result;
-  NSDate *timeout_date = nil;
-  NSEvent *ns_event;
+  int t, k, nr = 0;
+  struct input_event event;
+  char c;
 
   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
 
+  if (apploopnr > 0)
+    return -1; /* Already within event loop. */
+
 #ifdef HAVE_NATIVE_FS
   check_native_fs ();
 #endif
@@ -4092,34 +4135,121 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds,
       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 pselect(nfds, readfds, writefds,
-                   exceptfds, timeout, sigmask);
-
-  result = pselect(nfds, readfds, writefds, exceptfds,
-                   &(struct timespec){.tv_sec = 0, .tv_nsec = 100},
-                   sigmask);
+    return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
 
   [outerpool release];
   outerpool = [[NSAutoreleasePool alloc] init];
 
-  if (timeout)
+
+  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);
-      timeout_date = [NSDate dateWithTimeIntervalSinceNow:time];
+      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);
+  if (++apploopnr != 1)
+    {
+      emacs_abort ();
     }
 
-  /* Listen for a new NSEvent. */
-  ns_event = [NSApp nextEventMatchingMask:NSEventMaskAny
-                                untilDate:timeout_date
-                                   inMode:NSDefaultRunLoopMode
-                                  dequeue:NO];
+  {
+    ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+    record_unwind_protect (unwind_apploopnr, Qt);
+    [NSApp run];
+    unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
+  }
 
-  if (ns_event != nil)
+  ns_finish_events ();
+  if (nr > 0 && readfds)
     {
-      raise (SIGIO);
+      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;
@@ -4635,6 +4765,21 @@ 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];
@@ -4647,6 +4792,11 @@ ns_term_init (Lisp_Object display_name)
     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:)
@@ -5028,6 +5178,10 @@ ns_term_shutdown (int sig)
           last_appdefined_event_data = [theEvent data1];
           [self stop: self];
         }
+      else
+        {
+          send_appdefined = YES;
+        }
     }
 
 
@@ -5330,6 +5484,95 @@ not_in_argv (NSString *arg)
   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;
+        }
+    }
+}
+
 
 
 /* ==========================================================================
@@ -6118,7 +6361,7 @@ not_in_argv (NSString *arg)
                       help_echo_object, help_echo_pos);
     }
 
-  if (emacsframe->mouse_moved)
+  if (emacsframe->mouse_moved && send_appdefined)
     ns_send_appdefined (-1);
 }
 
@@ -6815,7 +7058,8 @@ not_in_argv (NSString *arg)
   SET_FRAME_VISIBLE (emacsframe, 1);
   SET_FRAME_GARBAGED (emacsframe);
 
-  ns_send_appdefined (-1);
+  if (send_appdefined)
+    ns_send_appdefined (-1);
 }
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]