From 9e77c1b7bcfd0807be7fe67daf73c2320e864309 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Wed, 17 Dec 2014 21:03:30 -0500 Subject: [PATCH] * src/keyboard.c (input_was_pending): New var. (read_char): Use it to make sure we only skip redisplay when we can't keep up with the repeat rate. --- src/ChangeLog | 6 ++++++ src/keyboard.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index 01653de22ed..16e99aec99a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2014-12-18 Stefan Monnier + + * keyboard.c (input_was_pending): New var. + (read_char): Use it to make sure we only skip redisplay when we can't + keep up with the repeat rate. + 2014-12-17 Stefan Monnier * keyboard.c (swallow_events): Don't redisplay if there's input pending. diff --git a/src/keyboard.c b/src/keyboard.c index 9e12f590c57..d76a8fcb783 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -273,6 +273,54 @@ static FILE *dribble; /* True if input is available. */ bool input_pending; +/* True if more input was available last time we read an event. + + Since redisplay can take a significant amount of time and is not + indispensible to perform the user's commands, when input arrives + "too fast", Emacs skips redisplay. More specifically, if the next + command has already been input when we finish the previous command, + we skip the intermediate redisplay. + + This is useful to try and make sure Emacs keeps up with fast input + rates, such as auto-repeating keys. But in some cases, this proves + too conservative: we may end up disabling redisplay for the whole + duration of a key repetition, even though we could afford to + redisplay every once in a while. + + So we "sample" the input_pending flag before running a command and + use *that* value after running the command to decide whether to + skip redisplay or not. This way, we only skip redisplay if we + really can't keep up with the repeat rate. + + This only makes a difference if the next input arrives while running the + command, which is very unlikely if the command is executed quickly. + IOW this tends to avoid skipping redisplay after a long running command + (which is a case where skipping redisplay is not very useful since the + redisplay time is small compared to the time it took to run the command). + + A typical use case is when scrolling. Scrolling time can be split into: + - Time to do jit-lock on the newly displayed portion of buffer. + - Time to run the actual scroll command. + - Time to perform the redisplay. + Jit-lock can happen either during the command or during the redisplay. + In the most painful cases, the jit-lock time is the one that dominates. + Also jit-lock can be tweaked (via jit-lock-defer) to delay its job, at the + cost of temporary inaccuracy in display and scrolling. + So without input_was_pending, what typically happens is the following: + - when the command starts, there's no pending input (yet). + - the scroll command triggers jit-lock. + - during the long jit-lock time the next input arrives. + - at the end of the command, we check input_pending and hence decide to + skip redisplay. + - we read the next input and start over. + End result: all the hard work of jit-locking is "wasted" since redisplay + doesn't actually happens (at least not before the input rate slows down). + With input_was_pending redisplay is still skipped if Emacs can't keep up + with the input rate, but if it can keep up just enough that there's no + input_pending when we begin the command, then redisplay is not skipped + which results in better feedback to the user. */ +static bool input_was_pending; + /* Circular buffer for pre-read keyboard input. */ static struct input_event kbd_buffer[KBD_BUFFER_SIZE]; @@ -2585,8 +2633,10 @@ read_char (int commandflag, Lisp_Object map, swallow_events (false); /* May clear input_pending. */ /* Redisplay if no pending input. */ - while (!input_pending) + while (!(input_pending + && (input_was_pending || !redisplay_dont_pause))) { + input_was_pending = input_pending; if (help_echo_showing_p && !EQ (selected_window, minibuf_window)) redisplay_preserve_echo_area (5); else @@ -3255,6 +3305,7 @@ read_char (int commandflag, Lisp_Object map, exit: RESUME_POLLING; + input_was_pending = input_pending; RETURN_UNGCPRO (c); } -- 2.11.4.GIT