xref: /vim-8.2.3635/src/ui.c (revision ea042677)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar  *
3071d4279SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4071d4279SBram Moolenaar  *
5071d4279SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar  */
9071d4279SBram Moolenaar 
10071d4279SBram Moolenaar /*
11071d4279SBram Moolenaar  * ui.c: functions that handle the user interface.
12071d4279SBram Moolenaar  * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
13071d4279SBram Moolenaar  *    before the machine specific stuff (mch_*) so that we can call the GUI
14071d4279SBram Moolenaar  *    stuff instead if the GUI is running.
1545fffdf1SBram Moolenaar  * 2. Input buffer stuff.
16071d4279SBram Moolenaar  */
17071d4279SBram Moolenaar 
18071d4279SBram Moolenaar #include "vim.h"
19071d4279SBram Moolenaar 
20071d4279SBram Moolenaar     void
ui_write(char_u * s,int len,int console UNUSED)214c86830fSBram Moolenaar ui_write(char_u *s, int len, int console UNUSED)
22071d4279SBram Moolenaar {
23071d4279SBram Moolenaar #ifdef FEAT_GUI
244c86830fSBram Moolenaar     if (gui.in_use && !gui.dying && !gui.starting
254c86830fSBram Moolenaar # ifndef NO_CONSOLE
264c86830fSBram Moolenaar 	    && !console
274c86830fSBram Moolenaar # endif
284c86830fSBram Moolenaar 	    )
29071d4279SBram Moolenaar     {
30071d4279SBram Moolenaar 	gui_write(s, len);
31071d4279SBram Moolenaar 	if (p_wd)
32c9e649aeSBram Moolenaar 	    gui_wait_for_chars(p_wd, typebuf.tb_change_cnt);
33071d4279SBram Moolenaar 	return;
34071d4279SBram Moolenaar     }
35071d4279SBram Moolenaar #endif
36071d4279SBram Moolenaar #ifndef NO_CONSOLE
37e38eab22SBram Moolenaar     // Don't output anything in silent mode ("ex -s") unless 'verbose' set
38071d4279SBram Moolenaar     if (!(silent_mode && p_verbose == 0))
39071d4279SBram Moolenaar     {
404f97475dSBram Moolenaar # if !defined(MSWIN)
41071d4279SBram Moolenaar 	char_u	*tofree = NULL;
42071d4279SBram Moolenaar 
43071d4279SBram Moolenaar 	if (output_conv.vc_type != CONV_NONE)
44071d4279SBram Moolenaar 	{
45e38eab22SBram Moolenaar 	    // Convert characters from 'encoding' to 'termencoding'.
46071d4279SBram Moolenaar 	    tofree = string_convert(&output_conv, s, &len);
47071d4279SBram Moolenaar 	    if (tofree != NULL)
48071d4279SBram Moolenaar 		s = tofree;
49071d4279SBram Moolenaar 	}
50071d4279SBram Moolenaar # endif
51071d4279SBram Moolenaar 
52071d4279SBram Moolenaar 	mch_write(s, len);
535ea79a25SBram Moolenaar # if defined(HAVE_FSYNC)
544c86830fSBram Moolenaar 	if (console && s[len - 1] == '\n')
555ea79a25SBram Moolenaar 	    vim_fsync(1);
565ea79a25SBram Moolenaar # endif
57071d4279SBram Moolenaar 
584f97475dSBram Moolenaar # if !defined(MSWIN)
59071d4279SBram Moolenaar 	if (output_conv.vc_type != CONV_NONE)
60071d4279SBram Moolenaar 	    vim_free(tofree);
61071d4279SBram Moolenaar # endif
62071d4279SBram Moolenaar     }
63071d4279SBram Moolenaar #endif
64071d4279SBram Moolenaar }
65071d4279SBram Moolenaar 
664f97475dSBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(PROTO) || defined(MSWIN)
67071d4279SBram Moolenaar /*
68071d4279SBram Moolenaar  * When executing an external program, there may be some typed characters that
69071d4279SBram Moolenaar  * are not consumed by it.  Give them back to ui_inchar() and they are stored
70071d4279SBram Moolenaar  * here for the next call.
71071d4279SBram Moolenaar  */
72071d4279SBram Moolenaar static char_u *ta_str = NULL;
73e38eab22SBram Moolenaar static int ta_off;	// offset for next char to use when ta_str != NULL
74e38eab22SBram Moolenaar static int ta_len;	// length of ta_str when it's not NULL
75071d4279SBram Moolenaar 
76071d4279SBram Moolenaar     void
ui_inchar_undo(char_u * s,int len)77764b23c8SBram Moolenaar ui_inchar_undo(char_u *s, int len)
78071d4279SBram Moolenaar {
79071d4279SBram Moolenaar     char_u  *new;
80071d4279SBram Moolenaar     int	    newlen;
81071d4279SBram Moolenaar 
82071d4279SBram Moolenaar     newlen = len;
83071d4279SBram Moolenaar     if (ta_str != NULL)
84071d4279SBram Moolenaar 	newlen += ta_len - ta_off;
85071d4279SBram Moolenaar     new = alloc(newlen);
86071d4279SBram Moolenaar     if (new != NULL)
87071d4279SBram Moolenaar     {
88071d4279SBram Moolenaar 	if (ta_str != NULL)
89071d4279SBram Moolenaar 	{
90071d4279SBram Moolenaar 	    mch_memmove(new, ta_str + ta_off, (size_t)(ta_len - ta_off));
91071d4279SBram Moolenaar 	    mch_memmove(new + ta_len - ta_off, s, (size_t)len);
92071d4279SBram Moolenaar 	    vim_free(ta_str);
93071d4279SBram Moolenaar 	}
94071d4279SBram Moolenaar 	else
95071d4279SBram Moolenaar 	    mch_memmove(new, s, (size_t)len);
96071d4279SBram Moolenaar 	ta_str = new;
97071d4279SBram Moolenaar 	ta_len = newlen;
98071d4279SBram Moolenaar 	ta_off = 0;
99071d4279SBram Moolenaar     }
100071d4279SBram Moolenaar }
101071d4279SBram Moolenaar #endif
102071d4279SBram Moolenaar 
103071d4279SBram Moolenaar /*
104b6101cf7SBram Moolenaar  * ui_inchar(): low level input function.
105071d4279SBram Moolenaar  * Get characters from the keyboard.
106071d4279SBram Moolenaar  * Return the number of characters that are available.
107071d4279SBram Moolenaar  * If "wtime" == 0 do not wait for characters.
108071d4279SBram Moolenaar  * If "wtime" == -1 wait forever for characters.
109071d4279SBram Moolenaar  * If "wtime" > 0 wait "wtime" milliseconds for a character.
110071d4279SBram Moolenaar  *
111071d4279SBram Moolenaar  * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
112071d4279SBram Moolenaar  * it.  When typebuf.tb_change_cnt changes (e.g., when a message is received
113071d4279SBram Moolenaar  * from a remote client) "buf" can no longer be used.  "tb_change_cnt" is NULL
114071d4279SBram Moolenaar  * otherwise.
115071d4279SBram Moolenaar  */
116071d4279SBram Moolenaar     int
ui_inchar(char_u * buf,int maxlen,long wtime,int tb_change_cnt)117764b23c8SBram Moolenaar ui_inchar(
118764b23c8SBram Moolenaar     char_u	*buf,
119764b23c8SBram Moolenaar     int		maxlen,
120e38eab22SBram Moolenaar     long	wtime,	    // don't use "time", MIPS cannot handle it
121764b23c8SBram Moolenaar     int		tb_change_cnt)
122071d4279SBram Moolenaar {
123071d4279SBram Moolenaar     int		retval = 0;
124071d4279SBram Moolenaar 
125071d4279SBram Moolenaar #if defined(FEAT_GUI) && (defined(UNIX) || defined(VMS))
126071d4279SBram Moolenaar     /*
127071d4279SBram Moolenaar      * Use the typeahead if there is any.
128071d4279SBram Moolenaar      */
129071d4279SBram Moolenaar     if (ta_str != NULL)
130071d4279SBram Moolenaar     {
131071d4279SBram Moolenaar 	if (maxlen >= ta_len - ta_off)
132071d4279SBram Moolenaar 	{
133071d4279SBram Moolenaar 	    mch_memmove(buf, ta_str + ta_off, (size_t)ta_len);
134d23a8236SBram Moolenaar 	    VIM_CLEAR(ta_str);
135071d4279SBram Moolenaar 	    return ta_len;
136071d4279SBram Moolenaar 	}
137071d4279SBram Moolenaar 	mch_memmove(buf, ta_str + ta_off, (size_t)maxlen);
138071d4279SBram Moolenaar 	ta_off += maxlen;
139071d4279SBram Moolenaar 	return maxlen;
140071d4279SBram Moolenaar     }
141071d4279SBram Moolenaar #endif
142071d4279SBram Moolenaar 
14305159a0cSBram Moolenaar #ifdef FEAT_PROFILE
144b3656edcSBram Moolenaar     if (do_profiling == PROF_YES && wtime != 0)
14505159a0cSBram Moolenaar 	prof_inchar_enter();
14605159a0cSBram Moolenaar #endif
14705159a0cSBram Moolenaar 
148071d4279SBram Moolenaar #ifdef NO_CONSOLE_INPUT
149e38eab22SBram Moolenaar     // Don't wait for character input when the window hasn't been opened yet.
150e38eab22SBram Moolenaar     // Do try reading, this works when redirecting stdin from a file.
151e38eab22SBram Moolenaar     // Must return something, otherwise we'll loop forever.  If we run into
152e38eab22SBram Moolenaar     // this very often we probably got stuck, exit Vim.
153071d4279SBram Moolenaar     if (no_console_input())
154071d4279SBram Moolenaar     {
155071d4279SBram Moolenaar 	static int count = 0;
156071d4279SBram Moolenaar 
157071d4279SBram Moolenaar # ifndef NO_CONSOLE
1581341024eSBram Moolenaar 	retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt);
15943b604cdSBram Moolenaar 	if (retval > 0 || typebuf_changed(tb_change_cnt) || wtime >= 0)
16005159a0cSBram Moolenaar 	    goto theend;
161071d4279SBram Moolenaar # endif
162071d4279SBram Moolenaar 	if (wtime == -1 && ++count == 1000)
163071d4279SBram Moolenaar 	    read_error_exit();
164071d4279SBram Moolenaar 	buf[0] = CAR;
16505159a0cSBram Moolenaar 	retval = 1;
16605159a0cSBram Moolenaar 	goto theend;
167071d4279SBram Moolenaar     }
168071d4279SBram Moolenaar #endif
169071d4279SBram Moolenaar 
170e38eab22SBram Moolenaar     // If we are going to wait for some time or block...
171c8da3119SBram Moolenaar     if (wtime == -1 || wtime > 100L)
172c8da3119SBram Moolenaar     {
173e38eab22SBram Moolenaar 	// ... allow signals to kill us.
174c8da3119SBram Moolenaar 	(void)vim_handle_signal(SIGNAL_UNBLOCK);
175c8da3119SBram Moolenaar 
176e38eab22SBram Moolenaar 	// ... there is no need for CTRL-C to interrupt something, don't let
177e38eab22SBram Moolenaar 	// it set got_int when it was mapped.
17850008697SBram Moolenaar 	if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state())
179071d4279SBram Moolenaar 	    ctrl_c_interrupts = FALSE;
180c8da3119SBram Moolenaar     }
181071d4279SBram Moolenaar 
182e40b9d47SBram Moolenaar     /*
183e40b9d47SBram Moolenaar      * Here we call gui_inchar() or mch_inchar(), the GUI or machine-dependent
184e40b9d47SBram Moolenaar      * input function.  The functionality they implement is like this:
185e40b9d47SBram Moolenaar      *
186e40b9d47SBram Moolenaar      * while (not timed out)
187e40b9d47SBram Moolenaar      * {
188e40b9d47SBram Moolenaar      *    handle-resize;
189e40b9d47SBram Moolenaar      *    parse-queued-messages;
190e40b9d47SBram Moolenaar      *    if (waited for 'updatetime')
191e40b9d47SBram Moolenaar      *       trigger-cursorhold;
192e40b9d47SBram Moolenaar      *    ui_wait_for_chars_or_timer()
193e40b9d47SBram Moolenaar      *    if (character available)
194e40b9d47SBram Moolenaar      *      break;
195e40b9d47SBram Moolenaar      * }
196e40b9d47SBram Moolenaar      *
197e40b9d47SBram Moolenaar      * ui_wait_for_chars_or_timer() does:
198e40b9d47SBram Moolenaar      *
199e40b9d47SBram Moolenaar      * while (not timed out)
200e40b9d47SBram Moolenaar      * {
201e40b9d47SBram Moolenaar      *     if (any-timer-triggered)
202e40b9d47SBram Moolenaar      *        invoke-timer-callback;
203e40b9d47SBram Moolenaar      *     wait-for-character();
204e40b9d47SBram Moolenaar      *     if (character available)
205e40b9d47SBram Moolenaar      *        break;
206e40b9d47SBram Moolenaar      * }
207e40b9d47SBram Moolenaar      *
208e40b9d47SBram Moolenaar      * wait-for-character() does:
209e40b9d47SBram Moolenaar      * while (not timed out)
210e40b9d47SBram Moolenaar      * {
211e40b9d47SBram Moolenaar      *     Wait for event;
212e40b9d47SBram Moolenaar      *     if (something on channel)
213e40b9d47SBram Moolenaar      *        read/write channel;
214e40b9d47SBram Moolenaar      *     else if (resized)
215e40b9d47SBram Moolenaar      *        handle_resize();
216e40b9d47SBram Moolenaar      *     else if (system event)
217e40b9d47SBram Moolenaar      *        deal-with-system-event;
218e40b9d47SBram Moolenaar      *     else if (character available)
219e40b9d47SBram Moolenaar      *        break;
220e40b9d47SBram Moolenaar      * }
221e40b9d47SBram Moolenaar      *
222e40b9d47SBram Moolenaar      */
223e40b9d47SBram Moolenaar 
224071d4279SBram Moolenaar #ifdef FEAT_GUI
225071d4279SBram Moolenaar     if (gui.in_use)
226c9e649aeSBram Moolenaar 	retval = gui_inchar(buf, maxlen, wtime, tb_change_cnt);
227071d4279SBram Moolenaar #endif
228071d4279SBram Moolenaar #ifndef NO_CONSOLE
229071d4279SBram Moolenaar # ifdef FEAT_GUI
230071d4279SBram Moolenaar     else
231071d4279SBram Moolenaar # endif
232071d4279SBram Moolenaar 	retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt);
233c8da3119SBram Moolenaar #endif
234c8da3119SBram Moolenaar 
23546c9c73dSBram Moolenaar     if (wtime == -1 || wtime > 100L)
236e38eab22SBram Moolenaar 	// block SIGHUP et al.
237e759a7aaSBram Moolenaar 	(void)vim_handle_signal(SIGNAL_BLOCK);
238071d4279SBram Moolenaar 
239071d4279SBram Moolenaar     ctrl_c_interrupts = TRUE;
240071d4279SBram Moolenaar 
24105159a0cSBram Moolenaar #ifdef NO_CONSOLE_INPUT
24205159a0cSBram Moolenaar theend:
24305159a0cSBram Moolenaar #endif
24405159a0cSBram Moolenaar #ifdef FEAT_PROFILE
245b3656edcSBram Moolenaar     if (do_profiling == PROF_YES && wtime != 0)
24605159a0cSBram Moolenaar 	prof_inchar_exit();
24705159a0cSBram Moolenaar #endif
248071d4279SBram Moolenaar     return retval;
249071d4279SBram Moolenaar }
250071d4279SBram Moolenaar 
25195f0b6e5SBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(FEAT_GUI) || defined(PROTO)
252e40b9d47SBram Moolenaar /*
253e40b9d47SBram Moolenaar  * Common code for mch_inchar() and gui_inchar(): Wait for a while or
254e40b9d47SBram Moolenaar  * indefinitely until characters are available, dealing with timers and
255e40b9d47SBram Moolenaar  * messages on channels.
256e40b9d47SBram Moolenaar  *
257e40b9d47SBram Moolenaar  * "buf" may be NULL if the available characters are not to be returned, only
258e40b9d47SBram Moolenaar  * check if they are available.
259e40b9d47SBram Moolenaar  *
260e40b9d47SBram Moolenaar  * Return the number of characters that are available.
261e40b9d47SBram Moolenaar  * If "wtime" == 0 do not wait for characters.
262e40b9d47SBram Moolenaar  * If "wtime" == n wait a short time for characters.
263e40b9d47SBram Moolenaar  * If "wtime" == -1 wait forever for characters.
264e40b9d47SBram Moolenaar  */
265e40b9d47SBram Moolenaar     int
inchar_loop(char_u * buf,int maxlen,long wtime,int tb_change_cnt,int (* wait_func)(long wtime,int * interrupted,int ignore_input),int (* resize_func)(int check_only))266e40b9d47SBram Moolenaar inchar_loop(
267e40b9d47SBram Moolenaar     char_u	*buf,
268e40b9d47SBram Moolenaar     int		maxlen,
269e40b9d47SBram Moolenaar     long	wtime,	    // don't use "time", MIPS cannot handle it
270e40b9d47SBram Moolenaar     int		tb_change_cnt,
271e40b9d47SBram Moolenaar     int		(*wait_func)(long wtime, int *interrupted, int ignore_input),
272e40b9d47SBram Moolenaar     int		(*resize_func)(int check_only))
273e40b9d47SBram Moolenaar {
274e40b9d47SBram Moolenaar     int		len;
275e40b9d47SBram Moolenaar     int		interrupted = FALSE;
27612dfc9eeSBram Moolenaar     int		did_call_wait_func = FALSE;
277e40b9d47SBram Moolenaar     int		did_start_blocking = FALSE;
278e40b9d47SBram Moolenaar     long	wait_time;
279e40b9d47SBram Moolenaar     long	elapsed_time = 0;
280e40b9d47SBram Moolenaar #ifdef ELAPSED_FUNC
281e40b9d47SBram Moolenaar     elapsed_T	start_tv;
282e40b9d47SBram Moolenaar 
283e40b9d47SBram Moolenaar     ELAPSED_INIT(start_tv);
284e40b9d47SBram Moolenaar #endif
285e40b9d47SBram Moolenaar 
286e38eab22SBram Moolenaar     // repeat until we got a character or waited long enough
287e40b9d47SBram Moolenaar     for (;;)
288e40b9d47SBram Moolenaar     {
289e38eab22SBram Moolenaar 	// Check if window changed size while we were busy, perhaps the ":set
290e38eab22SBram Moolenaar 	// columns=99" command was used.
291e40b9d47SBram Moolenaar 	if (resize_func != NULL)
292e40b9d47SBram Moolenaar 	    resize_func(FALSE);
293e40b9d47SBram Moolenaar 
294e40b9d47SBram Moolenaar #ifdef MESSAGE_QUEUE
295e40b9d47SBram Moolenaar 	// Only process messages when waiting.
296e40b9d47SBram Moolenaar 	if (wtime != 0)
297e40b9d47SBram Moolenaar 	{
298e40b9d47SBram Moolenaar 	    parse_queued_messages();
299e40b9d47SBram Moolenaar 	    // If input was put directly in typeahead buffer bail out here.
300e40b9d47SBram Moolenaar 	    if (typebuf_changed(tb_change_cnt))
301e40b9d47SBram Moolenaar 		return 0;
302e40b9d47SBram Moolenaar 	}
303e40b9d47SBram Moolenaar #endif
304e40b9d47SBram Moolenaar 	if (wtime < 0 && did_start_blocking)
305e40b9d47SBram Moolenaar 	    // blocking and already waited for p_ut
306e40b9d47SBram Moolenaar 	    wait_time = -1;
307e40b9d47SBram Moolenaar 	else
308e40b9d47SBram Moolenaar 	{
309e40b9d47SBram Moolenaar 	    if (wtime >= 0)
310e40b9d47SBram Moolenaar 		wait_time = wtime;
311e40b9d47SBram Moolenaar 	    else
312e40b9d47SBram Moolenaar 		// going to block after p_ut
313e40b9d47SBram Moolenaar 		wait_time = p_ut;
314e40b9d47SBram Moolenaar #ifdef ELAPSED_FUNC
315e40b9d47SBram Moolenaar 	    elapsed_time = ELAPSED_FUNC(start_tv);
316e40b9d47SBram Moolenaar #endif
317e40b9d47SBram Moolenaar 	    wait_time -= elapsed_time;
31812dfc9eeSBram Moolenaar 
31912dfc9eeSBram Moolenaar 	    // If the waiting time is now zero or less, we timed out.  However,
32012dfc9eeSBram Moolenaar 	    // loop at least once to check for characters and events.  Matters
32112dfc9eeSBram Moolenaar 	    // when "wtime" is zero.
32212dfc9eeSBram Moolenaar 	    if (wait_time <= 0 && did_call_wait_func)
323e40b9d47SBram Moolenaar 	    {
324e40b9d47SBram Moolenaar 		if (wtime >= 0)
325e40b9d47SBram Moolenaar 		    // no character available within "wtime"
326e40b9d47SBram Moolenaar 		    return 0;
327e40b9d47SBram Moolenaar 
328e40b9d47SBram Moolenaar 		// No character available within 'updatetime'.
329e40b9d47SBram Moolenaar 		did_start_blocking = TRUE;
330e40b9d47SBram Moolenaar 		if (trigger_cursorhold() && maxlen >= 3
331e40b9d47SBram Moolenaar 					    && !typebuf_changed(tb_change_cnt))
332e40b9d47SBram Moolenaar 		{
333e40b9d47SBram Moolenaar 		    // Put K_CURSORHOLD in the input buffer or return it.
334e40b9d47SBram Moolenaar 		    if (buf == NULL)
335e40b9d47SBram Moolenaar 		    {
336e40b9d47SBram Moolenaar 			char_u	ibuf[3];
337e40b9d47SBram Moolenaar 
338e40b9d47SBram Moolenaar 			ibuf[0] = CSI;
339e40b9d47SBram Moolenaar 			ibuf[1] = KS_EXTRA;
340e40b9d47SBram Moolenaar 			ibuf[2] = (int)KE_CURSORHOLD;
341e40b9d47SBram Moolenaar 			add_to_input_buf(ibuf, 3);
342e40b9d47SBram Moolenaar 		    }
343e40b9d47SBram Moolenaar 		    else
344e40b9d47SBram Moolenaar 		    {
345e40b9d47SBram Moolenaar 			buf[0] = K_SPECIAL;
346e40b9d47SBram Moolenaar 			buf[1] = KS_EXTRA;
347e40b9d47SBram Moolenaar 			buf[2] = (int)KE_CURSORHOLD;
348e40b9d47SBram Moolenaar 		    }
349e40b9d47SBram Moolenaar 		    return 3;
350e40b9d47SBram Moolenaar 		}
351e40b9d47SBram Moolenaar 
352e40b9d47SBram Moolenaar 		// There is no character available within 'updatetime' seconds:
353e40b9d47SBram Moolenaar 		// flush all the swap files to disk.  Also done when
354e40b9d47SBram Moolenaar 		// interrupted by SIGWINCH.
355e40b9d47SBram Moolenaar 		before_blocking();
356e40b9d47SBram Moolenaar 		continue;
357e40b9d47SBram Moolenaar 	    }
358e40b9d47SBram Moolenaar 	}
359e40b9d47SBram Moolenaar 
360e40b9d47SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
361e40b9d47SBram Moolenaar 	if (wait_time < 0 || wait_time > 100L)
362e40b9d47SBram Moolenaar 	{
363e40b9d47SBram Moolenaar 	    // Checking if a job ended requires polling.  Do this at least
364e40b9d47SBram Moolenaar 	    // every 100 msec.
365e40b9d47SBram Moolenaar 	    if (has_pending_job())
366e40b9d47SBram Moolenaar 		wait_time = 100L;
367e40b9d47SBram Moolenaar 
368e40b9d47SBram Moolenaar 	    // If there is readahead then parse_queued_messages() timed out and
369e40b9d47SBram Moolenaar 	    // we should call it again soon.
370e40b9d47SBram Moolenaar 	    if (channel_any_readahead())
371e40b9d47SBram Moolenaar 		wait_time = 10L;
372e40b9d47SBram Moolenaar 	}
373e40b9d47SBram Moolenaar #endif
374e40b9d47SBram Moolenaar #ifdef FEAT_BEVAL_GUI
375e40b9d47SBram Moolenaar 	if (p_beval && wait_time > 100L)
376e40b9d47SBram Moolenaar 	    // The 'balloonexpr' may indirectly invoke a callback while waiting
377e40b9d47SBram Moolenaar 	    // for a character, need to check often.
378e40b9d47SBram Moolenaar 	    wait_time = 100L;
379e40b9d47SBram Moolenaar #endif
380e40b9d47SBram Moolenaar 
381e40b9d47SBram Moolenaar 	// Wait for a character to be typed or another event, such as the winch
382e40b9d47SBram Moolenaar 	// signal or an event on the monitored file descriptors.
38312dfc9eeSBram Moolenaar 	did_call_wait_func = TRUE;
384e40b9d47SBram Moolenaar 	if (wait_func(wait_time, &interrupted, FALSE))
385e40b9d47SBram Moolenaar 	{
386e40b9d47SBram Moolenaar 	    // If input was put directly in typeahead buffer bail out here.
387e40b9d47SBram Moolenaar 	    if (typebuf_changed(tb_change_cnt))
388e40b9d47SBram Moolenaar 		return 0;
389e40b9d47SBram Moolenaar 
390e40b9d47SBram Moolenaar 	    // We might have something to return now.
391e40b9d47SBram Moolenaar 	    if (buf == NULL)
392e40b9d47SBram Moolenaar 		// "buf" is NULL, we were just waiting, not actually getting
393e40b9d47SBram Moolenaar 		// input.
394e40b9d47SBram Moolenaar 		return input_available();
395e40b9d47SBram Moolenaar 
396e40b9d47SBram Moolenaar 	    len = read_from_input_buf(buf, (long)maxlen);
397e40b9d47SBram Moolenaar 	    if (len > 0)
398e40b9d47SBram Moolenaar 		return len;
399e40b9d47SBram Moolenaar 	    continue;
400e40b9d47SBram Moolenaar 	}
401e40b9d47SBram Moolenaar 	// Timed out or interrupted with no character available.
402e40b9d47SBram Moolenaar 
403e40b9d47SBram Moolenaar #ifndef ELAPSED_FUNC
404e40b9d47SBram Moolenaar 	// estimate the elapsed time
405e40b9d47SBram Moolenaar 	elapsed_time += wait_time;
406e40b9d47SBram Moolenaar #endif
407e40b9d47SBram Moolenaar 
408e40b9d47SBram Moolenaar 	if ((resize_func != NULL && resize_func(TRUE))
4093e9d4d85SBram Moolenaar #if defined(FEAT_CLIENTSERVER) && defined(UNIX)
410e40b9d47SBram Moolenaar 		|| server_waiting()
411e40b9d47SBram Moolenaar #endif
412e40b9d47SBram Moolenaar #ifdef MESSAGE_QUEUE
413e40b9d47SBram Moolenaar 		|| interrupted
414e40b9d47SBram Moolenaar #endif
415e40b9d47SBram Moolenaar 		|| wait_time > 0
416e40b9d47SBram Moolenaar 		|| (wtime < 0 && !did_start_blocking))
417e40b9d47SBram Moolenaar 	    // no character available, but something to be done, keep going
418e40b9d47SBram Moolenaar 	    continue;
419e40b9d47SBram Moolenaar 
420e40b9d47SBram Moolenaar 	// no character available or interrupted, return zero
421e40b9d47SBram Moolenaar 	break;
422e40b9d47SBram Moolenaar     }
423e40b9d47SBram Moolenaar     return 0;
424e40b9d47SBram Moolenaar }
425e40b9d47SBram Moolenaar #endif
426e40b9d47SBram Moolenaar 
427c46af534SBram Moolenaar #if defined(FEAT_TIMERS) || defined(PROTO)
428c9e649aeSBram Moolenaar /*
429c9e649aeSBram Moolenaar  * Wait for a timer to fire or "wait_func" to return non-zero.
430c9e649aeSBram Moolenaar  * Returns OK when something was read.
431c9e649aeSBram Moolenaar  * Returns FAIL when it timed out or was interrupted.
432c9e649aeSBram Moolenaar  */
433c9e649aeSBram Moolenaar     int
ui_wait_for_chars_or_timer(long wtime,int (* wait_func)(long wtime,int * interrupted,int ignore_input),int * interrupted,int ignore_input)434c9e649aeSBram Moolenaar ui_wait_for_chars_or_timer(
435c9e649aeSBram Moolenaar     long    wtime,
436c9e649aeSBram Moolenaar     int	    (*wait_func)(long wtime, int *interrupted, int ignore_input),
437c9e649aeSBram Moolenaar     int	    *interrupted,
438c9e649aeSBram Moolenaar     int	    ignore_input)
439c9e649aeSBram Moolenaar {
440c9e649aeSBram Moolenaar     int	    due_time;
441c9e649aeSBram Moolenaar     long    remaining = wtime;
442c9e649aeSBram Moolenaar     int	    tb_change_cnt = typebuf.tb_change_cnt;
443c46af534SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
444e299bbdfSBram Moolenaar     int	    brief_wait = FALSE;
445c46af534SBram Moolenaar # endif
446c9e649aeSBram Moolenaar 
447c46af534SBram Moolenaar     // When waiting very briefly don't trigger timers.
448c9e649aeSBram Moolenaar     if (wtime >= 0 && wtime < 10L)
449c9e649aeSBram Moolenaar 	return wait_func(wtime, NULL, ignore_input);
450c9e649aeSBram Moolenaar 
451c9e649aeSBram Moolenaar     while (wtime < 0 || remaining > 0)
452c9e649aeSBram Moolenaar     {
453c46af534SBram Moolenaar 	// Trigger timers and then get the time in wtime until the next one is
454c46af534SBram Moolenaar 	// due.  Wait up to that time.
455c9e649aeSBram Moolenaar 	due_time = check_due_timer();
456c9e649aeSBram Moolenaar 	if (typebuf.tb_change_cnt != tb_change_cnt)
457c9e649aeSBram Moolenaar 	{
458e38eab22SBram Moolenaar 	    // timer may have used feedkeys()
459c9e649aeSBram Moolenaar 	    return FAIL;
460c9e649aeSBram Moolenaar 	}
461c9e649aeSBram Moolenaar 	if (due_time <= 0 || (wtime > 0 && due_time > remaining))
462c9e649aeSBram Moolenaar 	    due_time = remaining;
46328e67e0cSBram Moolenaar # if defined(FEAT_JOB_CHANNEL) || defined(FEAT_SOUND_CANBERRA)
46428e67e0cSBram Moolenaar 	if ((due_time < 0 || due_time > 10L) && (
46528e67e0cSBram Moolenaar #  if defined(FEAT_JOB_CHANNEL)
46628e67e0cSBram Moolenaar 		(
46728e67e0cSBram Moolenaar #   if defined(FEAT_GUI)
46828e67e0cSBram Moolenaar 		!gui.in_use &&
469c46af534SBram Moolenaar #   endif
47028e67e0cSBram Moolenaar 		(has_pending_job() || channel_any_readahead()))
47128e67e0cSBram Moolenaar #   ifdef FEAT_SOUND_CANBERRA
47228e67e0cSBram Moolenaar 		||
47328e67e0cSBram Moolenaar #   endif
47428e67e0cSBram Moolenaar #  endif
47528e67e0cSBram Moolenaar #  ifdef FEAT_SOUND_CANBERRA
47628e67e0cSBram Moolenaar 		    has_any_sound_callback()
47728e67e0cSBram Moolenaar #  endif
47828e67e0cSBram Moolenaar 		    ))
479c46af534SBram Moolenaar 	{
480c46af534SBram Moolenaar 	    // There is a pending job or channel, should return soon in order
481c46af534SBram Moolenaar 	    // to handle them ASAP.  Do check for input briefly.
482c46af534SBram Moolenaar 	    due_time = 10L;
4836cdce2a0SBram Moolenaar #  ifdef FEAT_JOB_CHANNEL
484c46af534SBram Moolenaar 	    brief_wait = TRUE;
4856cdce2a0SBram Moolenaar #  endif
486c46af534SBram Moolenaar 	}
487c46af534SBram Moolenaar # endif
488c9e649aeSBram Moolenaar 	if (wait_func(due_time, interrupted, ignore_input))
489c9e649aeSBram Moolenaar 	    return OK;
490c46af534SBram Moolenaar 	if ((interrupted != NULL && *interrupted)
491c46af534SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
492c46af534SBram Moolenaar 		|| brief_wait
493c46af534SBram Moolenaar # endif
494c46af534SBram Moolenaar 		)
495c46af534SBram Moolenaar 	    // Nothing available, but need to return so that side effects get
496c46af534SBram Moolenaar 	    // handled, such as handling a message on a channel.
497a338adcfSBram Moolenaar 	    return FAIL;
498c9e649aeSBram Moolenaar 	if (wtime > 0)
499c9e649aeSBram Moolenaar 	    remaining -= due_time;
500c9e649aeSBram Moolenaar     }
501c9e649aeSBram Moolenaar     return FAIL;
502c9e649aeSBram Moolenaar }
503c9e649aeSBram Moolenaar #endif
504c9e649aeSBram Moolenaar 
505071d4279SBram Moolenaar /*
506c46af534SBram Moolenaar  * Return non-zero if a character is available.
507071d4279SBram Moolenaar  */
508071d4279SBram Moolenaar     int
ui_char_avail(void)509764b23c8SBram Moolenaar ui_char_avail(void)
510071d4279SBram Moolenaar {
511071d4279SBram Moolenaar #ifdef FEAT_GUI
512071d4279SBram Moolenaar     if (gui.in_use)
513071d4279SBram Moolenaar     {
514071d4279SBram Moolenaar 	gui_mch_update();
515071d4279SBram Moolenaar 	return input_available();
516071d4279SBram Moolenaar     }
517071d4279SBram Moolenaar #endif
518071d4279SBram Moolenaar #ifndef NO_CONSOLE
519071d4279SBram Moolenaar # ifdef NO_CONSOLE_INPUT
520071d4279SBram Moolenaar     if (no_console_input())
521071d4279SBram Moolenaar 	return 0;
522071d4279SBram Moolenaar # endif
523071d4279SBram Moolenaar     return mch_char_avail();
524071d4279SBram Moolenaar #else
525071d4279SBram Moolenaar     return 0;
526071d4279SBram Moolenaar #endif
527071d4279SBram Moolenaar }
528071d4279SBram Moolenaar 
529071d4279SBram Moolenaar /*
530071d4279SBram Moolenaar  * Delay for the given number of milliseconds.	If ignoreinput is FALSE then we
531071d4279SBram Moolenaar  * cancel the delay if a key is hit.
532071d4279SBram Moolenaar  */
533071d4279SBram Moolenaar     void
ui_delay(long msec_arg,int ignoreinput)534b340baedSBram Moolenaar ui_delay(long msec_arg, int ignoreinput)
535071d4279SBram Moolenaar {
536b340baedSBram Moolenaar     long msec = msec_arg;
537b340baedSBram Moolenaar 
538b340baedSBram Moolenaar #ifdef FEAT_EVAL
539b340baedSBram Moolenaar     if (ui_delay_for_testing > 0)
540b340baedSBram Moolenaar 	msec = ui_delay_for_testing;
541b340baedSBram Moolenaar #endif
542eda1da0cSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
543eda1da0cSBram Moolenaar     ch_log(NULL, "ui_delay(%ld)", msec);
544eda1da0cSBram Moolenaar #endif
545071d4279SBram Moolenaar #ifdef FEAT_GUI
546071d4279SBram Moolenaar     if (gui.in_use && !ignoreinput)
547c9e649aeSBram Moolenaar 	gui_wait_for_chars(msec, typebuf.tb_change_cnt);
548071d4279SBram Moolenaar     else
549071d4279SBram Moolenaar #endif
5500981c872SBram Moolenaar 	mch_delay(msec, ignoreinput ? MCH_DELAY_IGNOREINPUT : 0);
551071d4279SBram Moolenaar }
552071d4279SBram Moolenaar 
553071d4279SBram Moolenaar /*
554071d4279SBram Moolenaar  * If the machine has job control, use it to suspend the program,
555071d4279SBram Moolenaar  * otherwise fake it by starting a new shell.
556071d4279SBram Moolenaar  * When running the GUI iconify the window.
557071d4279SBram Moolenaar  */
558071d4279SBram Moolenaar     void
ui_suspend(void)559764b23c8SBram Moolenaar ui_suspend(void)
560071d4279SBram Moolenaar {
561071d4279SBram Moolenaar #ifdef FEAT_GUI
562071d4279SBram Moolenaar     if (gui.in_use)
563071d4279SBram Moolenaar     {
564071d4279SBram Moolenaar 	gui_mch_iconify();
565071d4279SBram Moolenaar 	return;
566071d4279SBram Moolenaar     }
567071d4279SBram Moolenaar #endif
568071d4279SBram Moolenaar     mch_suspend();
569071d4279SBram Moolenaar }
570071d4279SBram Moolenaar 
571041c7107SBram Moolenaar #if !defined(UNIX) || !defined(SIGTSTP) || defined(PROTO)
572071d4279SBram Moolenaar /*
573071d4279SBram Moolenaar  * When the OS can't really suspend, call this function to start a shell.
574071d4279SBram Moolenaar  * This is never called in the GUI.
575071d4279SBram Moolenaar  */
576071d4279SBram Moolenaar     void
suspend_shell(void)577764b23c8SBram Moolenaar suspend_shell(void)
578071d4279SBram Moolenaar {
579071d4279SBram Moolenaar     if (*p_sh == NUL)
580f9e3e09fSBram Moolenaar 	emsg(_(e_shellempty));
581071d4279SBram Moolenaar     else
582071d4279SBram Moolenaar     {
58332526b3cSBram Moolenaar 	msg_puts(_("new shell started\n"));
584071d4279SBram Moolenaar 	do_shell(NULL, 0);
585071d4279SBram Moolenaar     }
586071d4279SBram Moolenaar }
587071d4279SBram Moolenaar #endif
588071d4279SBram Moolenaar 
589071d4279SBram Moolenaar /*
590071d4279SBram Moolenaar  * Try to get the current Vim shell size.  Put the result in Rows and Columns.
591071d4279SBram Moolenaar  * Use the new sizes as defaults for 'columns' and 'lines'.
592071d4279SBram Moolenaar  * Return OK when size could be determined, FAIL otherwise.
593071d4279SBram Moolenaar  */
594071d4279SBram Moolenaar     int
ui_get_shellsize(void)595764b23c8SBram Moolenaar ui_get_shellsize(void)
596071d4279SBram Moolenaar {
597071d4279SBram Moolenaar     int	    retval;
598071d4279SBram Moolenaar 
599071d4279SBram Moolenaar #ifdef FEAT_GUI
600071d4279SBram Moolenaar     if (gui.in_use)
601071d4279SBram Moolenaar 	retval = gui_get_shellsize();
602071d4279SBram Moolenaar     else
603071d4279SBram Moolenaar #endif
604071d4279SBram Moolenaar 	retval = mch_get_shellsize();
605071d4279SBram Moolenaar 
606071d4279SBram Moolenaar     check_shellsize();
607071d4279SBram Moolenaar 
608e38eab22SBram Moolenaar     // adjust the default for 'lines' and 'columns'
609071d4279SBram Moolenaar     if (retval == OK)
610071d4279SBram Moolenaar     {
611071d4279SBram Moolenaar 	set_number_default("lines", Rows);
612071d4279SBram Moolenaar 	set_number_default("columns", Columns);
613071d4279SBram Moolenaar     }
614071d4279SBram Moolenaar     return retval;
615071d4279SBram Moolenaar }
616071d4279SBram Moolenaar 
617071d4279SBram Moolenaar /*
618071d4279SBram Moolenaar  * Set the size of the Vim shell according to Rows and Columns, if possible.
619071d4279SBram Moolenaar  * The gui_set_shellsize() or mch_set_shellsize() function will try to set the
620071d4279SBram Moolenaar  * new size.  If this is not possible, it will adjust Rows and Columns.
621071d4279SBram Moolenaar  */
622071d4279SBram Moolenaar     void
ui_set_shellsize(int mustset UNUSED)623764b23c8SBram Moolenaar ui_set_shellsize(
624e38eab22SBram Moolenaar     int		mustset UNUSED)	// set by the user
625071d4279SBram Moolenaar {
626071d4279SBram Moolenaar #ifdef FEAT_GUI
627071d4279SBram Moolenaar     if (gui.in_use)
6288968a311SBram Moolenaar 	gui_set_shellsize(mustset, TRUE, RESIZE_BOTH);
629071d4279SBram Moolenaar     else
630071d4279SBram Moolenaar #endif
631071d4279SBram Moolenaar 	mch_set_shellsize();
632071d4279SBram Moolenaar }
633071d4279SBram Moolenaar 
634071d4279SBram Moolenaar /*
635071d4279SBram Moolenaar  * Called when Rows and/or Columns changed.  Adjust scroll region and mouse
636071d4279SBram Moolenaar  * region.
637071d4279SBram Moolenaar  */
638071d4279SBram Moolenaar     void
ui_new_shellsize(void)639764b23c8SBram Moolenaar ui_new_shellsize(void)
640071d4279SBram Moolenaar {
641071d4279SBram Moolenaar     if (full_screen && !exiting)
642071d4279SBram Moolenaar     {
643071d4279SBram Moolenaar #ifdef FEAT_GUI
644071d4279SBram Moolenaar 	if (gui.in_use)
645071d4279SBram Moolenaar 	    gui_new_shellsize();
646071d4279SBram Moolenaar 	else
647071d4279SBram Moolenaar #endif
648071d4279SBram Moolenaar 	    mch_new_shellsize();
649071d4279SBram Moolenaar     }
650071d4279SBram Moolenaar }
651071d4279SBram Moolenaar 
6526bc9305aSBram Moolenaar #if ((defined(FEAT_EVAL) || defined(FEAT_TERMINAL)) \
653fa1e90cdSBram Moolenaar 	    && (defined(FEAT_GUI) \
65416c34c37SBram Moolenaar 		|| defined(MSWIN) \
655fa1e90cdSBram Moolenaar 		|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)))) \
656fa1e90cdSBram Moolenaar 	|| defined(PROTO)
657fa1e90cdSBram Moolenaar /*
658fa1e90cdSBram Moolenaar  * Get the window position in pixels, if possible.
659fa1e90cdSBram Moolenaar  * Return FAIL when not possible.
660fa1e90cdSBram Moolenaar  */
661fa1e90cdSBram Moolenaar     int
ui_get_winpos(int * x,int * y,varnumber_T timeout UNUSED)662bd67aac2SBram Moolenaar ui_get_winpos(int *x, int *y, varnumber_T timeout UNUSED)
663fa1e90cdSBram Moolenaar {
664fa1e90cdSBram Moolenaar # ifdef FEAT_GUI
665fa1e90cdSBram Moolenaar     if (gui.in_use)
666fa1e90cdSBram Moolenaar 	return gui_mch_get_winpos(x, y);
667fa1e90cdSBram Moolenaar # endif
668afde13b6SBram Moolenaar # if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
66916c34c37SBram Moolenaar     return mch_get_winpos(x, y);
67016c34c37SBram Moolenaar # else
671fa1e90cdSBram Moolenaar #  if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
672fa1e90cdSBram Moolenaar     return term_get_winpos(x, y, timeout);
6736bc9305aSBram Moolenaar #  else
6746bc9305aSBram Moolenaar     return FAIL;
675fa1e90cdSBram Moolenaar #  endif
67616c34c37SBram Moolenaar # endif
677fa1e90cdSBram Moolenaar }
678fa1e90cdSBram Moolenaar #endif
679fa1e90cdSBram Moolenaar 
680071d4279SBram Moolenaar     void
ui_breakcheck(void)681764b23c8SBram Moolenaar ui_breakcheck(void)
682071d4279SBram Moolenaar {
683b9c31e71SBram Moolenaar     ui_breakcheck_force(FALSE);
684b9c31e71SBram Moolenaar }
685b9c31e71SBram Moolenaar 
686b9c31e71SBram Moolenaar /*
687b9c31e71SBram Moolenaar  * When "force" is true also check when the terminal is not in raw mode.
688b9c31e71SBram Moolenaar  * This is useful to read input on channels.
689b9c31e71SBram Moolenaar  */
690b9c31e71SBram Moolenaar     void
ui_breakcheck_force(int force)691b9c31e71SBram Moolenaar ui_breakcheck_force(int force)
692b9c31e71SBram Moolenaar {
69348d23bb4SBram Moolenaar     static int	recursive = FALSE;
69442335f50SBram Moolenaar     int		save_updating_screen = updating_screen;
695e3caa110SBram Moolenaar 
69648d23bb4SBram Moolenaar     // We could be called recursively if stderr is redirected, calling
69748d23bb4SBram Moolenaar     // fill_input_buf() calls settmode() when stdin isn't a tty.  settmode()
69848d23bb4SBram Moolenaar     // calls vgetorpeek() which calls ui_breakcheck() again.
69948d23bb4SBram Moolenaar     if (recursive)
70048d23bb4SBram Moolenaar 	return;
70148d23bb4SBram Moolenaar     recursive = TRUE;
70248d23bb4SBram Moolenaar 
70348d23bb4SBram Moolenaar     // We do not want gui_resize_shell() to redraw the screen here.
704e3caa110SBram Moolenaar     ++updating_screen;
705e3caa110SBram Moolenaar 
706071d4279SBram Moolenaar #ifdef FEAT_GUI
707071d4279SBram Moolenaar     if (gui.in_use)
708071d4279SBram Moolenaar 	gui_mch_update();
709071d4279SBram Moolenaar     else
710071d4279SBram Moolenaar #endif
711b9c31e71SBram Moolenaar 	mch_breakcheck(force);
712e3caa110SBram Moolenaar 
71342335f50SBram Moolenaar     if (save_updating_screen)
71442335f50SBram Moolenaar 	updating_screen = TRUE;
7150cb8ac71SBram Moolenaar     else
71668a4b04aSBram Moolenaar 	after_updating_screen(FALSE);
71748d23bb4SBram Moolenaar 
71848d23bb4SBram Moolenaar     recursive = FALSE;
719071d4279SBram Moolenaar }
720071d4279SBram Moolenaar 
721e38eab22SBram Moolenaar //////////////////////////////////////////////////////////////////////////////
722e38eab22SBram Moolenaar // Functions that handle the input buffer.
723e38eab22SBram Moolenaar // This is used for any GUI version, and the unix terminal version.
724e38eab22SBram Moolenaar //
725e38eab22SBram Moolenaar // For Unix, the input characters are buffered to be able to check for a
726e38eab22SBram Moolenaar // CTRL-C.  This should be done with signals, but I don't know how to do that
727e38eab22SBram Moolenaar // in a portable way for a tty in RAW mode.
728e38eab22SBram Moolenaar //
729e38eab22SBram Moolenaar // For the client-server code in the console the received keys are put in the
730e38eab22SBram Moolenaar // input buffer.
731071d4279SBram Moolenaar 
732071d4279SBram Moolenaar #if defined(USE_INPUT_BUF) || defined(PROTO)
733071d4279SBram Moolenaar 
734071d4279SBram Moolenaar /*
735071d4279SBram Moolenaar  * Internal typeahead buffer.  Includes extra space for long key code
736071d4279SBram Moolenaar  * descriptions which would otherwise overflow.  The buffer is considered full
737071d4279SBram Moolenaar  * when only this extra space (or part of it) remains.
738071d4279SBram Moolenaar  */
739bb1969b6SBram Moolenaar #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_CLIENTSERVER)
740071d4279SBram Moolenaar    /*
741bb1969b6SBram Moolenaar     * NetBeans stuffs debugger commands into the input buffer.
742071d4279SBram Moolenaar     * This requires a larger buffer...
743071d4279SBram Moolenaar     * (Madsen) Go with this for remote input as well ...
744071d4279SBram Moolenaar     */
745071d4279SBram Moolenaar # define INBUFLEN 4096
746071d4279SBram Moolenaar #else
747071d4279SBram Moolenaar # define INBUFLEN 250
748071d4279SBram Moolenaar #endif
749071d4279SBram Moolenaar 
750071d4279SBram Moolenaar static char_u	inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
751e38eab22SBram Moolenaar static int	inbufcount = 0;	    // number of chars in inbuf[]
752071d4279SBram Moolenaar 
753071d4279SBram Moolenaar /*
754071d4279SBram Moolenaar  * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
755071d4279SBram Moolenaar  * trash_input_buf() are functions for manipulating the input buffer.  These
756071d4279SBram Moolenaar  * are used by the gui_* calls when a GUI is used to handle keyboard input.
757071d4279SBram Moolenaar  */
758071d4279SBram Moolenaar 
759071d4279SBram Moolenaar     int
vim_is_input_buf_full(void)760764b23c8SBram Moolenaar vim_is_input_buf_full(void)
761071d4279SBram Moolenaar {
762071d4279SBram Moolenaar     return (inbufcount >= INBUFLEN);
763071d4279SBram Moolenaar }
764071d4279SBram Moolenaar 
765071d4279SBram Moolenaar     int
vim_is_input_buf_empty(void)766764b23c8SBram Moolenaar vim_is_input_buf_empty(void)
767071d4279SBram Moolenaar {
768071d4279SBram Moolenaar     return (inbufcount == 0);
769071d4279SBram Moolenaar }
770071d4279SBram Moolenaar 
771071d4279SBram Moolenaar #if defined(FEAT_OLE) || defined(PROTO)
772071d4279SBram Moolenaar     int
vim_free_in_input_buf(void)773764b23c8SBram Moolenaar vim_free_in_input_buf(void)
774071d4279SBram Moolenaar {
775071d4279SBram Moolenaar     return (INBUFLEN - inbufcount);
776071d4279SBram Moolenaar }
777071d4279SBram Moolenaar #endif
778071d4279SBram Moolenaar 
779241a8aaaSBram Moolenaar #if defined(FEAT_GUI_GTK) || defined(PROTO)
780071d4279SBram Moolenaar     int
vim_used_in_input_buf(void)781764b23c8SBram Moolenaar vim_used_in_input_buf(void)
782071d4279SBram Moolenaar {
783071d4279SBram Moolenaar     return inbufcount;
784071d4279SBram Moolenaar }
785071d4279SBram Moolenaar #endif
786071d4279SBram Moolenaar 
787071d4279SBram Moolenaar /*
788071d4279SBram Moolenaar  * Return the current contents of the input buffer and make it empty.
789071d4279SBram Moolenaar  * The returned pointer must be passed to set_input_buf() later.
790071d4279SBram Moolenaar  */
791071d4279SBram Moolenaar     char_u *
get_input_buf(void)792764b23c8SBram Moolenaar get_input_buf(void)
793071d4279SBram Moolenaar {
794071d4279SBram Moolenaar     garray_T	*gap;
795071d4279SBram Moolenaar 
796e38eab22SBram Moolenaar     // We use a growarray to store the data pointer and the length.
797c799fe20SBram Moolenaar     gap = ALLOC_ONE(garray_T);
798071d4279SBram Moolenaar     if (gap != NULL)
799071d4279SBram Moolenaar     {
800e38eab22SBram Moolenaar 	// Add one to avoid a zero size.
80118a4ba29SBram Moolenaar 	gap->ga_data = alloc(inbufcount + 1);
802071d4279SBram Moolenaar 	if (gap->ga_data != NULL)
803071d4279SBram Moolenaar 	    mch_memmove(gap->ga_data, inbuf, (size_t)inbufcount);
804071d4279SBram Moolenaar 	gap->ga_len = inbufcount;
805071d4279SBram Moolenaar     }
806071d4279SBram Moolenaar     trash_input_buf();
807071d4279SBram Moolenaar     return (char_u *)gap;
808071d4279SBram Moolenaar }
809071d4279SBram Moolenaar 
810071d4279SBram Moolenaar /*
811071d4279SBram Moolenaar  * Restore the input buffer with a pointer returned from get_input_buf().
812071d4279SBram Moolenaar  * The allocated memory is freed, this only works once!
813c41badb7SBram Moolenaar  * When "overwrite" is FALSE input typed later is kept.
814071d4279SBram Moolenaar  */
815071d4279SBram Moolenaar     void
set_input_buf(char_u * p,int overwrite)816c41badb7SBram Moolenaar set_input_buf(char_u *p, int overwrite)
817071d4279SBram Moolenaar {
818071d4279SBram Moolenaar     garray_T	*gap = (garray_T *)p;
819071d4279SBram Moolenaar 
820071d4279SBram Moolenaar     if (gap != NULL)
821071d4279SBram Moolenaar     {
822071d4279SBram Moolenaar 	if (gap->ga_data != NULL)
823071d4279SBram Moolenaar 	{
824c41badb7SBram Moolenaar 	    if (overwrite || inbufcount + gap->ga_len >= INBUFLEN)
825c41badb7SBram Moolenaar 	    {
826071d4279SBram Moolenaar 		mch_memmove(inbuf, gap->ga_data, gap->ga_len);
827071d4279SBram Moolenaar 		inbufcount = gap->ga_len;
828c41badb7SBram Moolenaar 	    }
829c41badb7SBram Moolenaar 	    else
830c41badb7SBram Moolenaar 	    {
831c41badb7SBram Moolenaar 		mch_memmove(inbuf + gap->ga_len, inbuf, inbufcount);
832c41badb7SBram Moolenaar 		mch_memmove(inbuf, gap->ga_data, gap->ga_len);
833c41badb7SBram Moolenaar 		inbufcount += gap->ga_len;
834c41badb7SBram Moolenaar 	    }
835071d4279SBram Moolenaar 	    vim_free(gap->ga_data);
836071d4279SBram Moolenaar 	}
837071d4279SBram Moolenaar 	vim_free(gap);
838071d4279SBram Moolenaar     }
839071d4279SBram Moolenaar }
840071d4279SBram Moolenaar 
841071d4279SBram Moolenaar /*
842071d4279SBram Moolenaar  * Add the given bytes to the input buffer
843071d4279SBram Moolenaar  * Special keys start with CSI.  A real CSI must have been translated to
844071d4279SBram Moolenaar  * CSI KS_EXTRA KE_CSI.  K_SPECIAL doesn't require translation.
845071d4279SBram Moolenaar  */
846071d4279SBram Moolenaar     void
add_to_input_buf(char_u * s,int len)847764b23c8SBram Moolenaar add_to_input_buf(char_u *s, int len)
848071d4279SBram Moolenaar {
849071d4279SBram Moolenaar     if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
850e38eab22SBram Moolenaar 	return;	    // Shouldn't ever happen!
851071d4279SBram Moolenaar 
852071d4279SBram Moolenaar     while (len--)
853071d4279SBram Moolenaar 	inbuf[inbufcount++] = *s++;
854071d4279SBram Moolenaar }
855071d4279SBram Moolenaar 
856071d4279SBram Moolenaar /*
857071d4279SBram Moolenaar  * Add "str[len]" to the input buffer while escaping CSI bytes.
858071d4279SBram Moolenaar  */
859071d4279SBram Moolenaar     void
add_to_input_buf_csi(char_u * str,int len)860071d4279SBram Moolenaar add_to_input_buf_csi(char_u *str, int len)
861071d4279SBram Moolenaar {
862071d4279SBram Moolenaar     int		i;
863071d4279SBram Moolenaar     char_u	buf[2];
864071d4279SBram Moolenaar 
865071d4279SBram Moolenaar     for (i = 0; i < len; ++i)
866071d4279SBram Moolenaar     {
867071d4279SBram Moolenaar 	add_to_input_buf(str + i, 1);
868071d4279SBram Moolenaar 	if (str[i] == CSI)
869071d4279SBram Moolenaar 	{
870e38eab22SBram Moolenaar 	    // Turn CSI into K_CSI.
871071d4279SBram Moolenaar 	    buf[0] = KS_EXTRA;
872071d4279SBram Moolenaar 	    buf[1] = (int)KE_CSI;
873071d4279SBram Moolenaar 	    add_to_input_buf(buf, 2);
874071d4279SBram Moolenaar 	}
875071d4279SBram Moolenaar     }
876071d4279SBram Moolenaar }
877071d4279SBram Moolenaar 
878e38eab22SBram Moolenaar /*
879e38eab22SBram Moolenaar  * Remove everything from the input buffer.  Called when ^C is found.
880e38eab22SBram Moolenaar  */
881071d4279SBram Moolenaar     void
trash_input_buf(void)882764b23c8SBram Moolenaar trash_input_buf(void)
883071d4279SBram Moolenaar {
884071d4279SBram Moolenaar     inbufcount = 0;
885071d4279SBram Moolenaar }
886071d4279SBram Moolenaar 
887071d4279SBram Moolenaar /*
888071d4279SBram Moolenaar  * Read as much data from the input buffer as possible up to maxlen, and store
889071d4279SBram Moolenaar  * it in buf.
890071d4279SBram Moolenaar  */
891071d4279SBram Moolenaar     int
read_from_input_buf(char_u * buf,long maxlen)892764b23c8SBram Moolenaar read_from_input_buf(char_u *buf, long maxlen)
893071d4279SBram Moolenaar {
894e38eab22SBram Moolenaar     if (inbufcount == 0)	// if the buffer is empty, fill it
895071d4279SBram Moolenaar 	fill_input_buf(TRUE);
896071d4279SBram Moolenaar     if (maxlen > inbufcount)
897071d4279SBram Moolenaar 	maxlen = inbufcount;
898071d4279SBram Moolenaar     mch_memmove(buf, inbuf, (size_t)maxlen);
899071d4279SBram Moolenaar     inbufcount -= maxlen;
900071d4279SBram Moolenaar     if (inbufcount)
901071d4279SBram Moolenaar 	mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
902071d4279SBram Moolenaar     return (int)maxlen;
903071d4279SBram Moolenaar }
904071d4279SBram Moolenaar 
905071d4279SBram Moolenaar     void
fill_input_buf(int exit_on_error UNUSED)906764b23c8SBram Moolenaar fill_input_buf(int exit_on_error UNUSED)
907071d4279SBram Moolenaar {
908d057301bSBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(MACOS_X)
909071d4279SBram Moolenaar     int		len;
910071d4279SBram Moolenaar     int		try;
911071d4279SBram Moolenaar     static int	did_read_something = FALSE;
912e38eab22SBram Moolenaar     static char_u *rest = NULL;	    // unconverted rest of previous read
913071d4279SBram Moolenaar     static int	restlen = 0;
914071d4279SBram Moolenaar     int		unconverted;
915071d4279SBram Moolenaar #endif
916071d4279SBram Moolenaar 
917071d4279SBram Moolenaar #ifdef FEAT_GUI
91854ee775eSBram Moolenaar     if (gui.in_use
91954ee775eSBram Moolenaar # ifdef NO_CONSOLE_INPUT
920e38eab22SBram Moolenaar     // Don't use the GUI input when the window hasn't been opened yet.
921e38eab22SBram Moolenaar     // We get here from ui_inchar() when we should try reading from stdin.
92254ee775eSBram Moolenaar 	    && !no_console_input()
92354ee775eSBram Moolenaar # endif
92454ee775eSBram Moolenaar        )
925071d4279SBram Moolenaar     {
926071d4279SBram Moolenaar 	gui_mch_update();
927071d4279SBram Moolenaar 	return;
928071d4279SBram Moolenaar     }
929071d4279SBram Moolenaar #endif
930d057301bSBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(MACOS_X)
931071d4279SBram Moolenaar     if (vim_is_input_buf_full())
932071d4279SBram Moolenaar 	return;
933071d4279SBram Moolenaar     /*
934071d4279SBram Moolenaar      * Fill_input_buf() is only called when we really need a character.
935071d4279SBram Moolenaar      * If we can't get any, but there is some in the buffer, just return.
936071d4279SBram Moolenaar      * If we can't get any, and there isn't any in the buffer, we give up and
937071d4279SBram Moolenaar      * exit Vim.
938071d4279SBram Moolenaar      */
939071d4279SBram Moolenaar     if (rest != NULL)
940071d4279SBram Moolenaar     {
941e38eab22SBram Moolenaar 	// Use remainder of previous call, starts with an invalid character
942e38eab22SBram Moolenaar 	// that may become valid when reading more.
943071d4279SBram Moolenaar 	if (restlen > INBUFLEN - inbufcount)
944071d4279SBram Moolenaar 	    unconverted = INBUFLEN - inbufcount;
945071d4279SBram Moolenaar 	else
946071d4279SBram Moolenaar 	    unconverted = restlen;
947071d4279SBram Moolenaar 	mch_memmove(inbuf + inbufcount, rest, unconverted);
948071d4279SBram Moolenaar 	if (unconverted == restlen)
949d23a8236SBram Moolenaar 	    VIM_CLEAR(rest);
950071d4279SBram Moolenaar 	else
951071d4279SBram Moolenaar 	{
952071d4279SBram Moolenaar 	    restlen -= unconverted;
953071d4279SBram Moolenaar 	    mch_memmove(rest, rest + unconverted, restlen);
954071d4279SBram Moolenaar 	}
955071d4279SBram Moolenaar 	inbufcount += unconverted;
956071d4279SBram Moolenaar     }
957071d4279SBram Moolenaar     else
958071d4279SBram Moolenaar 	unconverted = 0;
959071d4279SBram Moolenaar 
960e38eab22SBram Moolenaar     len = 0;	// to avoid gcc warning
961071d4279SBram Moolenaar     for (try = 0; try < 100; ++try)
962071d4279SBram Moolenaar     {
9634e601e3cSBram Moolenaar 	size_t readlen = (size_t)((INBUFLEN - inbufcount)
964264b74faSBram Moolenaar 						       / input_conv.vc_factor);
9654e601e3cSBram Moolenaar #  ifdef VMS
9664994373cSBram Moolenaar 	len = vms_read((char *)inbuf + inbufcount, readlen);
9674e601e3cSBram Moolenaar #  else
9684e601e3cSBram Moolenaar 	len = read(read_cmd_fd, (char *)inbuf + inbufcount, readlen);
969071d4279SBram Moolenaar #  endif
9707ca86fe8SBram Moolenaar #  ifdef FEAT_JOB_CHANNEL
9717ca86fe8SBram Moolenaar 	if (len > 0)
9727ca86fe8SBram Moolenaar 	{
9737ca86fe8SBram Moolenaar 	    inbuf[inbufcount + len] = NUL;
9747ca86fe8SBram Moolenaar 	    ch_log(NULL, "raw key input: \"%s\"", inbuf + inbufcount);
9757ca86fe8SBram Moolenaar 	}
9767ca86fe8SBram Moolenaar #  endif
9775313dcb7SBram Moolenaar 
978071d4279SBram Moolenaar 	if (len > 0 || got_int)
979071d4279SBram Moolenaar 	    break;
980071d4279SBram Moolenaar 	/*
981071d4279SBram Moolenaar 	 * If reading stdin results in an error, continue reading stderr.
982071d4279SBram Moolenaar 	 * This helps when using "foo | xargs vim".
983071d4279SBram Moolenaar 	 */
984071d4279SBram Moolenaar 	if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
985071d4279SBram Moolenaar 	{
986071d4279SBram Moolenaar 	    int m = cur_tmode;
987071d4279SBram Moolenaar 
988e38eab22SBram Moolenaar 	    // We probably set the wrong file descriptor to raw mode.  Switch
989e38eab22SBram Moolenaar 	    // back to cooked mode, use another descriptor and set the mode to
990e38eab22SBram Moolenaar 	    // what it was.
991071d4279SBram Moolenaar 	    settmode(TMODE_COOK);
992071d4279SBram Moolenaar #ifdef HAVE_DUP
993e38eab22SBram Moolenaar 	    // Use stderr for stdin, also works for shell commands.
994071d4279SBram Moolenaar 	    close(0);
99542335f50SBram Moolenaar 	    vim_ignored = dup(2);
996071d4279SBram Moolenaar #else
997e38eab22SBram Moolenaar 	    read_cmd_fd = 2;	// read from stderr instead of stdin
998071d4279SBram Moolenaar #endif
999071d4279SBram Moolenaar 	    settmode(m);
1000071d4279SBram Moolenaar 	}
1001071d4279SBram Moolenaar 	if (!exit_on_error)
1002071d4279SBram Moolenaar 	    return;
1003071d4279SBram Moolenaar     }
1004071d4279SBram Moolenaar     if (len <= 0 && !got_int)
1005071d4279SBram Moolenaar 	read_error_exit();
1006071d4279SBram Moolenaar     if (len > 0)
1007071d4279SBram Moolenaar 	did_read_something = TRUE;
1008071d4279SBram Moolenaar     if (got_int)
1009071d4279SBram Moolenaar     {
1010e38eab22SBram Moolenaar 	// Interrupted, pretend a CTRL-C was typed.
1011071d4279SBram Moolenaar 	inbuf[0] = 3;
1012071d4279SBram Moolenaar 	inbufcount = 1;
1013071d4279SBram Moolenaar     }
1014071d4279SBram Moolenaar     else
1015071d4279SBram Moolenaar     {
1016071d4279SBram Moolenaar 	/*
1017071d4279SBram Moolenaar 	 * May perform conversion on the input characters.
1018071d4279SBram Moolenaar 	 * Include the unconverted rest of the previous call.
1019071d4279SBram Moolenaar 	 * If there is an incomplete char at the end it is kept for the next
1020071d4279SBram Moolenaar 	 * time, reading more bytes should make conversion possible.
1021071d4279SBram Moolenaar 	 * Don't do this in the unlikely event that the input buffer is too
1022071d4279SBram Moolenaar 	 * small ("rest" still contains more bytes).
1023071d4279SBram Moolenaar 	 */
1024071d4279SBram Moolenaar 	if (input_conv.vc_type != CONV_NONE)
1025071d4279SBram Moolenaar 	{
1026071d4279SBram Moolenaar 	    inbufcount -= unconverted;
1027071d4279SBram Moolenaar 	    len = convert_input_safe(inbuf + inbufcount,
1028071d4279SBram Moolenaar 				     len + unconverted, INBUFLEN - inbufcount,
1029071d4279SBram Moolenaar 				       rest == NULL ? &rest : NULL, &restlen);
1030071d4279SBram Moolenaar 	}
1031071d4279SBram Moolenaar 	while (len-- > 0)
1032071d4279SBram Moolenaar 	{
1033339c1bdbSBram Moolenaar 	    // If a CTRL-C was typed, remove it from the buffer and set
1034339c1bdbSBram Moolenaar 	    // got_int.  Also recognize CTRL-C with modifyOtherKeys set, in two
1035339c1bdbSBram Moolenaar 	    // forms.
10369645e2d9SBram Moolenaar 	    if (ctrl_c_interrupts && (inbuf[inbufcount] == 3
1037339c1bdbSBram Moolenaar 			|| (len >= 10 && STRNCMP(inbuf + inbufcount,
103802faa944SBram Moolenaar 						   "\033[27;5;99~", 10) == 0)
103902faa944SBram Moolenaar 			|| (len >= 7 && STRNCMP(inbuf + inbufcount,
104002faa944SBram Moolenaar 						       "\033[99;5u", 7) == 0)))
1041071d4279SBram Moolenaar 	    {
1042e38eab22SBram Moolenaar 		// remove everything typed before the CTRL-C
1043071d4279SBram Moolenaar 		mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
1044071d4279SBram Moolenaar 		inbufcount = 0;
1045071d4279SBram Moolenaar 		got_int = TRUE;
1046071d4279SBram Moolenaar 	    }
1047071d4279SBram Moolenaar 	    ++inbufcount;
1048071d4279SBram Moolenaar 	}
1049071d4279SBram Moolenaar     }
105074ee5e23SBram Moolenaar #endif // UNIX || VMS || MACOS_X
1051071d4279SBram Moolenaar }
105274ee5e23SBram Moolenaar #endif // USE_INPUT_BUF
1053071d4279SBram Moolenaar 
1054071d4279SBram Moolenaar /*
1055071d4279SBram Moolenaar  * Exit because of an input read error.
1056071d4279SBram Moolenaar  */
1057071d4279SBram Moolenaar     void
read_error_exit(void)1058764b23c8SBram Moolenaar read_error_exit(void)
1059071d4279SBram Moolenaar {
1060e38eab22SBram Moolenaar     if (silent_mode)	// Normal way to exit for "ex -s"
1061071d4279SBram Moolenaar 	getout(0);
1062071d4279SBram Moolenaar     STRCPY(IObuff, _("Vim: Error reading input, exiting...\n"));
1063071d4279SBram Moolenaar     preserve_exit();
1064071d4279SBram Moolenaar }
1065071d4279SBram Moolenaar 
1066071d4279SBram Moolenaar #if defined(CURSOR_SHAPE) || defined(PROTO)
1067071d4279SBram Moolenaar /*
1068071d4279SBram Moolenaar  * May update the shape of the cursor.
1069071d4279SBram Moolenaar  */
1070071d4279SBram Moolenaar     void
ui_cursor_shape_forced(int forced)10713cd43cccSBram Moolenaar ui_cursor_shape_forced(int forced)
1072071d4279SBram Moolenaar {
1073071d4279SBram Moolenaar # ifdef FEAT_GUI
1074071d4279SBram Moolenaar     if (gui.in_use)
1075071d4279SBram Moolenaar 	gui_update_cursor_later();
1076293ee4d4SBram Moolenaar     else
1077071d4279SBram Moolenaar # endif
10783cd43cccSBram Moolenaar 	term_cursor_mode(forced);
1079293ee4d4SBram Moolenaar 
1080071d4279SBram Moolenaar # ifdef MCH_CURSOR_SHAPE
1081071d4279SBram Moolenaar     mch_update_cursor();
1082071d4279SBram Moolenaar # endif
1083f5963f71SBram Moolenaar 
1084f5963f71SBram Moolenaar # ifdef FEAT_CONCEAL
1085*ea042677SBram Moolenaar     conceal_check_cursor_line(FALSE);
1086f5963f71SBram Moolenaar # endif
1087071d4279SBram Moolenaar }
10883cd43cccSBram Moolenaar 
10893cd43cccSBram Moolenaar     void
ui_cursor_shape(void)10903cd43cccSBram Moolenaar ui_cursor_shape(void)
10913cd43cccSBram Moolenaar {
10923cd43cccSBram Moolenaar     ui_cursor_shape_forced(FALSE);
10933cd43cccSBram Moolenaar }
1094071d4279SBram Moolenaar #endif
1095071d4279SBram Moolenaar 
1096071d4279SBram Moolenaar /*
1097071d4279SBram Moolenaar  * Check bounds for column number
1098071d4279SBram Moolenaar  */
1099071d4279SBram Moolenaar     int
check_col(int col)1100764b23c8SBram Moolenaar check_col(int col)
1101071d4279SBram Moolenaar {
1102071d4279SBram Moolenaar     if (col < 0)
1103071d4279SBram Moolenaar 	return 0;
1104071d4279SBram Moolenaar     if (col >= (int)screen_Columns)
1105071d4279SBram Moolenaar 	return (int)screen_Columns - 1;
1106071d4279SBram Moolenaar     return col;
1107071d4279SBram Moolenaar }
1108071d4279SBram Moolenaar 
1109071d4279SBram Moolenaar /*
1110071d4279SBram Moolenaar  * Check bounds for row number
1111071d4279SBram Moolenaar  */
1112071d4279SBram Moolenaar     int
check_row(int row)1113764b23c8SBram Moolenaar check_row(int row)
1114071d4279SBram Moolenaar {
1115071d4279SBram Moolenaar     if (row < 0)
1116071d4279SBram Moolenaar 	return 0;
1117071d4279SBram Moolenaar     if (row >= (int)screen_Rows)
1118071d4279SBram Moolenaar 	return (int)screen_Rows - 1;
1119071d4279SBram Moolenaar     return row;
1120071d4279SBram Moolenaar }
1121071d4279SBram Moolenaar 
1122071d4279SBram Moolenaar /*
1123071d4279SBram Moolenaar  * Called when focus changed.  Used for the GUI or for systems where this can
1124071d4279SBram Moolenaar  * be done in the console (Win32).
1125071d4279SBram Moolenaar  */
1126071d4279SBram Moolenaar     void
ui_focus_change(int in_focus)1127764b23c8SBram Moolenaar ui_focus_change(
1128e38eab22SBram Moolenaar     int		in_focus)	// TRUE if focus gained.
1129071d4279SBram Moolenaar {
1130071d4279SBram Moolenaar     static time_t	last_time = (time_t)0;
1131071d4279SBram Moolenaar     int			need_redraw = FALSE;
1132071d4279SBram Moolenaar 
1133e38eab22SBram Moolenaar     // When activated: Check if any file was modified outside of Vim.
1134e38eab22SBram Moolenaar     // Only do this when not done within the last two seconds (could get
1135e38eab22SBram Moolenaar     // several events in a row).
1136071d4279SBram Moolenaar     if (in_focus && last_time + 2 < time(NULL))
1137071d4279SBram Moolenaar     {
1138071d4279SBram Moolenaar 	need_redraw = check_timestamps(
1139071d4279SBram Moolenaar # ifdef FEAT_GUI
1140071d4279SBram Moolenaar 		gui.in_use
1141071d4279SBram Moolenaar # else
1142071d4279SBram Moolenaar 		FALSE
1143071d4279SBram Moolenaar # endif
1144071d4279SBram Moolenaar 		);
1145071d4279SBram Moolenaar 	last_time = time(NULL);
1146071d4279SBram Moolenaar     }
1147071d4279SBram Moolenaar 
1148071d4279SBram Moolenaar     /*
1149071d4279SBram Moolenaar      * Fire the focus gained/lost autocommand.
1150071d4279SBram Moolenaar      */
1151071d4279SBram Moolenaar     need_redraw |= apply_autocmds(in_focus ? EVENT_FOCUSGAINED
1152071d4279SBram Moolenaar 				: EVENT_FOCUSLOST, NULL, NULL, FALSE, curbuf);
1153071d4279SBram Moolenaar 
1154071d4279SBram Moolenaar     if (need_redraw)
1155071d4279SBram Moolenaar     {
1156e38eab22SBram Moolenaar 	// Something was executed, make sure the cursor is put back where it
1157e38eab22SBram Moolenaar 	// belongs.
1158071d4279SBram Moolenaar 	need_wait_return = FALSE;
1159071d4279SBram Moolenaar 
1160071d4279SBram Moolenaar 	if (State & CMDLINE)
1161071d4279SBram Moolenaar 	    redrawcmdline();
1162071d4279SBram Moolenaar 	else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE
1163071d4279SBram Moolenaar 		|| State == EXTERNCMD || State == CONFIRM || exmode_active)
1164071d4279SBram Moolenaar 	    repeat_message();
1165071d4279SBram Moolenaar 	else if ((State & NORMAL) || (State & INSERT))
1166071d4279SBram Moolenaar 	{
1167071d4279SBram Moolenaar 	    if (must_redraw != 0)
1168071d4279SBram Moolenaar 		update_screen(0);
1169071d4279SBram Moolenaar 	    setcursor();
1170071d4279SBram Moolenaar 	}
1171e38eab22SBram Moolenaar 	cursor_on();	    // redrawing may have switched it off
1172a338adcfSBram Moolenaar 	out_flush_cursor(FALSE, TRUE);
1173071d4279SBram Moolenaar # ifdef FEAT_GUI
1174071d4279SBram Moolenaar 	if (gui.in_use)
1175071d4279SBram Moolenaar 	    gui_update_scrollbars(FALSE);
1176071d4279SBram Moolenaar # endif
1177071d4279SBram Moolenaar     }
1178071d4279SBram Moolenaar #ifdef FEAT_TITLE
1179e38eab22SBram Moolenaar     // File may have been changed from 'readonly' to 'noreadonly'
1180071d4279SBram Moolenaar     if (need_maketitle)
1181071d4279SBram Moolenaar 	maketitle();
1182071d4279SBram Moolenaar #endif
1183071d4279SBram Moolenaar }
1184071d4279SBram Moolenaar 
1185f2bd8ef2SBram Moolenaar #if defined(HAVE_INPUT_METHOD) || defined(PROTO)
1186071d4279SBram Moolenaar /*
1187071d4279SBram Moolenaar  * Save current Input Method status to specified place.
1188071d4279SBram Moolenaar  */
1189071d4279SBram Moolenaar     void
im_save_status(long * psave)1190764b23c8SBram Moolenaar im_save_status(long *psave)
1191071d4279SBram Moolenaar {
1192e38eab22SBram Moolenaar     // Don't save when 'imdisable' is set or "xic" is NULL, IM is always
1193e38eab22SBram Moolenaar     // disabled then (but might start later).
1194e38eab22SBram Moolenaar     // Also don't save when inside a mapping, vgetc_im_active has not been set
1195e38eab22SBram Moolenaar     // then.
1196e38eab22SBram Moolenaar     // And don't save when the keys were stuffed (e.g., for a "." command).
1197e38eab22SBram Moolenaar     // And don't save when the GUI is running but our window doesn't have
1198e38eab22SBram Moolenaar     // input focus (e.g., when a find dialog is open).
1199071d4279SBram Moolenaar     if (!p_imdisable && KeyTyped && !KeyStuffed
1200071d4279SBram Moolenaar # ifdef FEAT_XIM
1201071d4279SBram Moolenaar 	    && xic != NULL
1202071d4279SBram Moolenaar # endif
1203071d4279SBram Moolenaar # ifdef FEAT_GUI
1204071d4279SBram Moolenaar 	    && (!gui.in_use || gui.in_focus)
1205071d4279SBram Moolenaar # endif
1206071d4279SBram Moolenaar 	)
1207071d4279SBram Moolenaar     {
1208e38eab22SBram Moolenaar 	// Do save when IM is on, or IM is off and saved status is on.
1209071d4279SBram Moolenaar 	if (vgetc_im_active)
1210071d4279SBram Moolenaar 	    *psave = B_IMODE_IM;
1211071d4279SBram Moolenaar 	else if (*psave == B_IMODE_IM)
1212071d4279SBram Moolenaar 	    *psave = B_IMODE_NONE;
1213071d4279SBram Moolenaar     }
1214071d4279SBram Moolenaar }
1215071d4279SBram Moolenaar #endif
1216