0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 8.1.0834: GUI may wait too long before dealing with messages

Problem:    GUI may wait too long before dealing with messages.  Returning
            early may cause a mapping to time out.
Solution:   Use the waiting loop from Unix also for the GUI.
            (closes #3817, closes #3824)
This commit is contained in:
Bram Moolenaar
2019-01-27 16:55:47 +01:00
parent d93090f41f
commit e40b9d47bf
6 changed files with 297 additions and 214 deletions

212
src/ui.c
View File

@@ -178,6 +178,48 @@ ui_inchar(
ctrl_c_interrupts = FALSE;
}
/*
* Here we call gui_inchar() or mch_inchar(), the GUI or machine-dependent
* input function. The functionality they implement is like this:
*
* while (not timed out)
* {
* handle-resize;
* parse-queued-messages;
* if (waited for 'updatetime')
* trigger-cursorhold;
* ui_wait_for_chars_or_timer()
* if (character available)
* break;
* }
*
* ui_wait_for_chars_or_timer() does:
*
* while (not timed out)
* {
* if (any-timer-triggered)
* invoke-timer-callback;
* wait-for-character();
* if (character available)
* break;
* }
*
* wait-for-character() does:
* while (not timed out)
* {
* Wait for event;
* if (something on channel)
* read/write channel;
* else if (resized)
* handle_resize();
* else if (system event)
* deal-with-system-event;
* else if (character available)
* break;
* }
*
*/
#ifdef FEAT_GUI
if (gui.in_use)
retval = gui_inchar(buf, maxlen, wtime, tb_change_cnt);
@@ -205,6 +247,176 @@ theend:
return retval;
}
#if defined(UNIX) || defined(FEAT_GUI) || defined(PROTO)
/*
* Common code for mch_inchar() and gui_inchar(): Wait for a while or
* indefinitely until characters are available, dealing with timers and
* messages on channels.
*
* "buf" may be NULL if the available characters are not to be returned, only
* check if they are available.
*
* Return the number of characters that are available.
* If "wtime" == 0 do not wait for characters.
* If "wtime" == n wait a short time for characters.
* If "wtime" == -1 wait forever for characters.
*/
int
inchar_loop(
char_u *buf,
int maxlen,
long wtime, // don't use "time", MIPS cannot handle it
int tb_change_cnt,
int (*wait_func)(long wtime, int *interrupted, int ignore_input),
int (*resize_func)(int check_only))
{
int len;
int interrupted = FALSE;
int did_start_blocking = FALSE;
long wait_time;
long elapsed_time = 0;
#ifdef ELAPSED_FUNC
elapsed_T start_tv;
ELAPSED_INIT(start_tv);
#endif
/* repeat until we got a character or waited long enough */
for (;;)
{
/* Check if window changed size while we were busy, perhaps the ":set
* columns=99" command was used. */
if (resize_func != NULL)
resize_func(FALSE);
#ifdef MESSAGE_QUEUE
// Only process messages when waiting.
if (wtime != 0)
{
parse_queued_messages();
// If input was put directly in typeahead buffer bail out here.
if (typebuf_changed(tb_change_cnt))
return 0;
}
#endif
if (wtime < 0 && did_start_blocking)
// blocking and already waited for p_ut
wait_time = -1;
else
{
if (wtime >= 0)
wait_time = wtime;
else
// going to block after p_ut
wait_time = p_ut;
#ifdef ELAPSED_FUNC
elapsed_time = ELAPSED_FUNC(start_tv);
#endif
wait_time -= elapsed_time;
if (wait_time <= 0)
{
if (wtime >= 0)
// no character available within "wtime"
return 0;
// No character available within 'updatetime'.
did_start_blocking = TRUE;
if (trigger_cursorhold() && maxlen >= 3
&& !typebuf_changed(tb_change_cnt))
{
// Put K_CURSORHOLD in the input buffer or return it.
if (buf == NULL)
{
char_u ibuf[3];
ibuf[0] = CSI;
ibuf[1] = KS_EXTRA;
ibuf[2] = (int)KE_CURSORHOLD;
add_to_input_buf(ibuf, 3);
}
else
{
buf[0] = K_SPECIAL;
buf[1] = KS_EXTRA;
buf[2] = (int)KE_CURSORHOLD;
}
return 3;
}
// There is no character available within 'updatetime' seconds:
// flush all the swap files to disk. Also done when
// interrupted by SIGWINCH.
before_blocking();
continue;
}
}
#ifdef FEAT_JOB_CHANNEL
if (wait_time < 0 || wait_time > 100L)
{
// Checking if a job ended requires polling. Do this at least
// every 100 msec.
if (has_pending_job())
wait_time = 100L;
// If there is readahead then parse_queued_messages() timed out and
// we should call it again soon.
if (channel_any_readahead())
wait_time = 10L;
}
#endif
#ifdef FEAT_BEVAL_GUI
if (p_beval && wait_time > 100L)
// The 'balloonexpr' may indirectly invoke a callback while waiting
// for a character, need to check often.
wait_time = 100L;
#endif
// Wait for a character to be typed or another event, such as the winch
// signal or an event on the monitored file descriptors.
if (wait_func(wait_time, &interrupted, FALSE))
{
// If input was put directly in typeahead buffer bail out here.
if (typebuf_changed(tb_change_cnt))
return 0;
// We might have something to return now.
if (buf == NULL)
// "buf" is NULL, we were just waiting, not actually getting
// input.
return input_available();
len = read_from_input_buf(buf, (long)maxlen);
if (len > 0)
return len;
continue;
}
// Timed out or interrupted with no character available.
#ifndef ELAPSED_FUNC
// estimate the elapsed time
elapsed_time += wait_time;
#endif
if ((resize_func != NULL && resize_func(TRUE))
#ifdef FEAT_CLIENTSERVER
|| server_waiting()
#endif
#ifdef MESSAGE_QUEUE
|| interrupted
#endif
|| wait_time > 0
|| (wtime < 0 && !did_start_blocking))
// no character available, but something to be done, keep going
continue;
// no character available or interrupted, return zero
break;
}
return 0;
}
#endif
#if defined(FEAT_TIMERS) || defined(PROTO)
/*
* Wait for a timer to fire or "wait_func" to return non-zero.