From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Alan Third Newsgroups: gmane.emacs.bugs Subject: bug#25265: [PATCH] Rework NS event handling (bug#25265) Date: Sat, 31 Dec 2016 16:09:30 +0000 Message-ID: <20161231160930.GA29122@breton.holly.idiocy.org> References: <83vau0h2u5.fsf@gnu.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1483200622 30555 195.159.176.226 (31 Dec 2016 16:10:22 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sat, 31 Dec 2016 16:10:22 +0000 (UTC) User-Agent: Mutt/1.7.1 (2016-10-04) Cc: charles@aurox.ch, 25265@debbugs.gnu.org To: Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sat Dec 31 17:10:17 2016 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cNMEZ-0006SV-2J for geb-bug-gnu-emacs@m.gmane.org; Sat, 31 Dec 2016 17:10:15 +0100 Original-Received: from localhost ([::1]:44636 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cNMEY-00010l-PJ for geb-bug-gnu-emacs@m.gmane.org; Sat, 31 Dec 2016 11:10:14 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:36383) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cNMEP-0000yB-T9 for bug-gnu-emacs@gnu.org; Sat, 31 Dec 2016 11:10:08 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cNMEM-0001Kg-KE for bug-gnu-emacs@gnu.org; Sat, 31 Dec 2016 11:10:05 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:46221) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cNMEM-0001Kc-Fe for bug-gnu-emacs@gnu.org; Sat, 31 Dec 2016 11:10:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1cNMEM-0007CU-5D for bug-gnu-emacs@gnu.org; Sat, 31 Dec 2016 11:10:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Alan Third Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 31 Dec 2016 16:10:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 25265 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 25265-submit@debbugs.gnu.org id=B25265.148320058127641 (code B ref 25265); Sat, 31 Dec 2016 16:10:02 +0000 Original-Received: (at 25265) by debbugs.gnu.org; 31 Dec 2016 16:09:41 +0000 Original-Received: from localhost ([127.0.0.1]:33387 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cNME0-0007Bi-PJ for submit@debbugs.gnu.org; Sat, 31 Dec 2016 11:09:41 -0500 Original-Received: from mail-wm0-f68.google.com ([74.125.82.68]:34614) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cNMDz-0007BS-3s for 25265@debbugs.gnu.org; Sat, 31 Dec 2016 11:09:39 -0500 Original-Received: by mail-wm0-f68.google.com with SMTP id c85so37460332wmi.1 for <25265@debbugs.gnu.org>; Sat, 31 Dec 2016 08:09:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=GKRueCPN26bVrJxqpxUYhp44F3jkJPpWhtJBEhLISVA=; b=AEGwktJ8lFRrua/z/uhDMIlY7EDKOXmO0GgnvxXsGV2ORmoj4WzmpJgANDmswuoNfo 5oRDRb76GAqo3dqfw4JXGYEVtMWntDFdVJAs/jepQEBV4m31/KVtPOHwLEpcYiqzMIBB /tOoj3h17qIvGGQ/R7Np3ty2CfGvNZsSlv9uwaekKyzcDnQhqTZ6Un62ccKZOjOShnus fUzXJXuuCydx5U6yuZSvp2TrEk95Rap2N8z9RT1F2kacII87cgeUwTd2YECIuhWRxJ8q 46r6lqn4Tu+P5iBgTNXbVHyhng9ZGiZXpugF8buO95wtPHjQiL0cJMwdP1i6FhlZ/TW+ FWuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :references:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=GKRueCPN26bVrJxqpxUYhp44F3jkJPpWhtJBEhLISVA=; b=UW1d1EIgw42qxCnS22r2YodoBCNHtu+D0JtWxgh9g2V7qdoawth1d0Ei+OH1OsIjvD bBaCwcwr4duKuwFVW7c+Hh7xP45tamo55lnu0zzRgu9+k+KqNmjreR3AQhZifwT4KEFD NcJyKT5SK1UMPc6sclOaBqYQ3iqpq0h7AJ4TX5puXTsub1mAeUrYC+L8S+G8FNvvaaPO 997eNLsAMv3a1bg8bTc254Kco5WMwQlsENI8wgaDNJZoi+GWTcc+KOMfOD9mdrFARxuo cjlkZL1b8ho+0GP5Wndbz6SXecZduHQSg5NeKbTQ5GnfYIMop/sEtyGFFO90xaA4AV4i pRAQ== X-Gm-Message-State: AIkVDXIK0QObGa0DTfjMJVdZRaL2qkM9D3mmorDeuhVys6ToZSyOEHK3oolfCSkAnfFXrA== X-Received: by 10.28.52.201 with SMTP id b192mr42371969wma.118.1483200573029; Sat, 31 Dec 2016 08:09:33 -0800 (PST) Original-Received: from breton.holly.idiocy.org (ip6-2001-08b0-03f8-8129-fcf8-7042-dd5f-6680.holly.idiocy.org. [2001:8b0:3f8:8129:fcf8:7042:dd5f:6680]) by smtp.gmail.com with ESMTPSA id cl6sm78941883wjc.10.2016.12.31.08.09.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 31 Dec 2016 08:09:32 -0800 (PST) Content-Disposition: inline In-Reply-To: <83vau0h2u5.fsf@gnu.org> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:127628 Archived-At: * 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. --- src/nsterm.h | 1 - src/nsterm.m | 380 +++++++++++------------------------------------------------ 2 files changed, 68 insertions(+), 313 deletions(-) diff --git a/src/nsterm.h b/src/nsterm.h index 35c6e1a..dc222a7 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -392,7 +392,6 @@ 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 7e6ec85..98fd8ab 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -279,18 +279,10 @@ - (NSColor *)colorUsingDefaultColorSpace /*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; @@ -457,7 +449,6 @@ - (NSColor *)colorUsingDefaultColorSpace 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 @@ -3872,31 +3863,17 @@ overwriting cursor (usually when cursor on a tab) */ 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) + /* 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) { 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) { @@ -4011,14 +3988,6 @@ in certain situations (rapid incoming events). } #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) @@ -4029,13 +3998,10 @@ in certain situations (rapid incoming events). -------------------------------------------------------------------------- */ { struct input_event ev; - int nevents; + int nevents = 0; 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 @@ -4052,54 +4018,49 @@ in certain situations (rapid incoming events). return i; } - 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]]) + if ([NSThread isMainThread]) { - [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); - - if (++apploopnr != 1) + 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]]) { - emacs_abort (); + [ns_pending_files removeObjectAtIndex: 0]; } - record_unwind_protect (unwind_apploopnr, Qt); - [NSApp run]; - unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */ - } + /* 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); - nevents = n_emacs_events_pending; - n_emacs_events_pending = 0; - ns_finish_events (); - q_event_ptr = NULL; - unblock_input (); + [NSApp run]; + } + + nevents = n_emacs_events_pending; + n_emacs_events_pending = 0; + ns_finish_events (); + q_event_ptr = NULL; + unblock_input (); + } return nevents; } @@ -4114,15 +4075,11 @@ in certain situations (rapid incoming events). -------------------------------------------------------------------------- */ { int result; - int t, k, nr = 0; - struct input_event event; - char c; + NSDate *timeout_date = nil; + NSEvent *ns_event; NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select"); - if (apploopnr > 0) - return -1; /* Already within event loop. */ - #ifdef HAVE_NATIVE_FS check_native_fs (); #endif @@ -4135,121 +4092,34 @@ in certain situations (rapid incoming events). 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); + return pselect(nfds, readfds, writefds, + exceptfds, timeout, sigmask); + + result = pselect(nfds, readfds, writefds, exceptfds, + &(struct timespec){.tv_sec = 0, .tv_nsec = 100}, + 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) + if (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); - if (++apploopnr != 1) - { - emacs_abort (); - } - - { - ptrdiff_t specpdl_count = SPECPDL_INDEX (); - record_unwind_protect (unwind_apploopnr, Qt); - [NSApp run]; - unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */ - } - - ns_finish_events (); - if (nr > 0 && readfds) - { - c = 's'; - emacs_write_sig (selfds[1], &c, 1); + timeout_date = [NSDate dateWithTimeIntervalSinceNow:time]; } - unblock_input (); - t = last_appdefined_event_data; + /* Listen for a new NSEvent. */ + ns_event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:timeout_date + inMode:NSDefaultRunLoopMode + dequeue:NO]; - if (t != NO_APPDEFINED_DATA) + if (ns_event != nil) { - 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; + raise (SIGIO); } return result; @@ -4765,21 +4635,6 @@ static Lisp_Object ns_string_to_lispmod (const char *s) 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]; @@ -4792,11 +4647,6 @@ Needs to be here because ns_initialize_display_info () uses AppKit classes. 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:) @@ -5178,10 +5028,6 @@ - (void)sendEvent: (NSEvent *)theEvent last_appdefined_event_data = [theEvent data1]; [self stop: self]; } - else - { - send_appdefined = YES; - } } @@ -5484,95 +5330,6 @@ - (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; - } - } -} - /* ========================================================================== @@ -6361,7 +6118,7 @@ - (void)mouseMoved: (NSEvent *)e help_echo_object, help_echo_pos); } - if (emacsframe->mouse_moved && send_appdefined) + if (emacsframe->mouse_moved) ns_send_appdefined (-1); } @@ -7058,8 +6815,7 @@ - (void)windowDidExpose: sender SET_FRAME_VISIBLE (emacsframe, 1); SET_FRAME_GARBAGED (emacsframe); - if (send_appdefined) - ns_send_appdefined (-1); + ns_send_appdefined (-1); } -- Here we go. This seems to work. It turns out there are trade‐offs between the GUI and network performance. If I remove NSApp:nextEventMatchingMask from ns_select, eww loads web pages *significantly* faster, but the scrollbars become effectively unusable. -- Alan Third