X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c832df2ec2f6528bc35f69f9fd9a4b2e470d2ebe..9fb9136398821ed5f3a8b4405bbc222964f54028:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index 060784cf0a..5b66050aa9 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -270,9 +270,57 @@ static Lisp_Object Qhelp_form_show; /* File in which we write all commands we read. */ static FILE *dribble; -/* Nonzero if input is available. */ +/* 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 + indispensable 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]; @@ -2403,9 +2451,9 @@ echo_keystrokes_p (void) /* commandflag 0 means do not autosave, but do redisplay. -1 means do not redisplay, but do autosave. -2 means do neither. - 1 means do both. */ + 1 means do both. -/* The argument MAP is a keymap for menu prompting. + The argument MAP is a keymap for menu prompting. PREV_EVENT is the previous input event, or nil if we are reading the first event of a key sequence (or not reading a key sequence). @@ -2582,11 +2630,13 @@ read_char (int commandflag, Lisp_Object map, user-visible, such as X selection_request events. */ if (input_pending || detect_input_pending_run_timers (0)) - swallow_events (0); /* May clear input_pending. */ + 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 @@ -2598,7 +2648,7 @@ read_char (int commandflag, Lisp_Object map, /* Input arrived and pre-empted redisplay. Process any events which are not user-visible. */ - swallow_events (0); + swallow_events (false); /* If that cleared input_pending, try again to redisplay. */ } @@ -3255,6 +3305,7 @@ read_char (int commandflag, Lisp_Object map, exit: RESUME_POLLING; + input_was_pending = input_pending; RETURN_UNGCPRO (c); } @@ -3878,7 +3929,7 @@ kbd_buffer_get_event (KBOARD **kbp, Lisp_Object obj; #ifdef subprocesses - if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE/4) + if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4) { /* Start reading input again because we have processed enough to be able to accept new events again. */ @@ -4370,7 +4421,7 @@ swallow_events (bool do_display) old_timers_run = timers_run; get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW); - if (timers_run != old_timers_run && do_display) + if (!input_pending && timers_run != old_timers_run && do_display) redisplay_preserve_echo_area (7); } @@ -4429,10 +4480,15 @@ decode_timer (Lisp_Object timer, struct timespec *result) vector = XVECTOR (timer)->contents; if (! NILP (vector[0])) return 0; + if (! INTEGERP (vector[2])) + return false; - return (decode_time_components (vector[1], vector[2], vector[3], vector[8], - result, 0) - && timespec_valid_p (*result)); + struct lisp_time t; + if (! decode_time_components (vector[1], vector[2], vector[3], vector[8], + &t, 0)) + return false; + *result = lisp_to_timespec (t); + return timespec_valid_p (*result); } @@ -11863,7 +11919,7 @@ keys_of_keyboard (void) - we enter the second prompt. current-prefix-arg is non-nil, prefix-arg is nil. - before running the first real event, we run the special iconify-frame - event, but we pass the `special' arg to execute-command so + event, but we pass the `special' arg to command-execute so current-prefix-arg and prefix-arg are left untouched. - here we foolishly copy the non-nil current-prefix-arg to prefix-arg. - the next key event will have a spuriously non-nil current-prefix-arg. */