xref: /vim-8.2.3635/src/ui.c (revision 843ee41e)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * ui.c: functions that handle the user interface.
12  * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
13  *    before the machine specific stuff (mch_*) so that we can call the GUI
14  *    stuff instead if the GUI is running.
15  * 2. Clipboard stuff.
16  * 3. Input buffer stuff.
17  */
18 
19 #include "vim.h"
20 
21     void
22 ui_write(s, len)
23     char_u  *s;
24     int	    len;
25 {
26 #ifdef FEAT_GUI
27     if (gui.in_use && !gui.dying && !gui.starting)
28     {
29 	gui_write(s, len);
30 	if (p_wd)
31 	    gui_wait_for_chars(p_wd);
32 	return;
33     }
34 #endif
35 #ifndef NO_CONSOLE
36     /* Don't output anything in silent mode ("ex -s") unless 'verbose' set */
37     if (!(silent_mode && p_verbose == 0))
38     {
39 #ifdef FEAT_MBYTE
40 	char_u	*tofree = NULL;
41 
42 	if (output_conv.vc_type != CONV_NONE)
43 	{
44 	    /* Convert characters from 'encoding' to 'termencoding'. */
45 	    tofree = string_convert(&output_conv, s, &len);
46 	    if (tofree != NULL)
47 		s = tofree;
48 	}
49 #endif
50 
51 	mch_write(s, len);
52 
53 #ifdef FEAT_MBYTE
54 	if (output_conv.vc_type != CONV_NONE)
55 	    vim_free(tofree);
56 #endif
57     }
58 #endif
59 }
60 
61 #if (defined(FEAT_GUI) && (defined(UNIX) || defined(VMS))) \
62 	|| defined(MACOS_X_UNIX) || defined(PROTO)
63 /*
64  * When executing an external program, there may be some typed characters that
65  * are not consumed by it.  Give them back to ui_inchar() and they are stored
66  * here for the next call.
67  */
68 static char_u *ta_str = NULL;
69 static int ta_off;	/* offset for next char to use when ta_str != NULL */
70 static int ta_len;	/* length of ta_str when it's not NULL*/
71 
72     void
73 ui_inchar_undo(s, len)
74     char_u	*s;
75     int		len;
76 {
77     char_u  *new;
78     int	    newlen;
79 
80     newlen = len;
81     if (ta_str != NULL)
82 	newlen += ta_len - ta_off;
83     new = alloc(newlen);
84     if (new != NULL)
85     {
86 	if (ta_str != NULL)
87 	{
88 	    mch_memmove(new, ta_str + ta_off, (size_t)(ta_len - ta_off));
89 	    mch_memmove(new + ta_len - ta_off, s, (size_t)len);
90 	    vim_free(ta_str);
91 	}
92 	else
93 	    mch_memmove(new, s, (size_t)len);
94 	ta_str = new;
95 	ta_len = newlen;
96 	ta_off = 0;
97     }
98 }
99 #endif
100 
101 /*
102  * ui_inchar(): low level input funcion.
103  * Get characters from the keyboard.
104  * Return the number of characters that are available.
105  * If "wtime" == 0 do not wait for characters.
106  * If "wtime" == -1 wait forever for characters.
107  * If "wtime" > 0 wait "wtime" milliseconds for a character.
108  *
109  * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
110  * it.  When typebuf.tb_change_cnt changes (e.g., when a message is received
111  * from a remote client) "buf" can no longer be used.  "tb_change_cnt" is NULL
112  * otherwise.
113  */
114     int
115 ui_inchar(buf, maxlen, wtime, tb_change_cnt)
116     char_u	*buf;
117     int		maxlen;
118     long	wtime;	    /* don't use "time", MIPS cannot handle it */
119     int		tb_change_cnt;
120 {
121     int		retval = 0;
122 
123 #if defined(FEAT_GUI) && (defined(UNIX) || defined(VMS))
124     /*
125      * Use the typeahead if there is any.
126      */
127     if (ta_str != NULL)
128     {
129 	if (maxlen >= ta_len - ta_off)
130 	{
131 	    mch_memmove(buf, ta_str + ta_off, (size_t)ta_len);
132 	    vim_free(ta_str);
133 	    ta_str = NULL;
134 	    return ta_len;
135 	}
136 	mch_memmove(buf, ta_str + ta_off, (size_t)maxlen);
137 	ta_off += maxlen;
138 	return maxlen;
139     }
140 #endif
141 
142 #ifdef NO_CONSOLE_INPUT
143     /* Don't wait for character input when the window hasn't been opened yet.
144      * Do try reading, this works when redirecting stdin from a file.
145      * Must return something, otherwise we'll loop forever.  If we run into
146      * this very often we probably got stuck, exit Vim. */
147     if (no_console_input())
148     {
149 	static int count = 0;
150 
151 # ifndef NO_CONSOLE
152 	retval = mch_inchar(buf, maxlen, 10L, tb_change_cnt);
153 	if (retval > 0 || typebuf_changed(tb_change_cnt))
154 	    return retval;
155 # endif
156 	if (wtime == -1 && ++count == 1000)
157 	    read_error_exit();
158 	buf[0] = CAR;
159 	return 1;
160     }
161 #endif
162 
163     /* When doing a blocking wait there is no need for CTRL-C to interrupt
164      * something, don't let it set got_int when it was mapped. */
165     if (mapped_ctrl_c && (wtime == -1 || wtime > 100L))
166 	ctrl_c_interrupts = FALSE;
167 
168 #ifdef FEAT_GUI
169     if (gui.in_use)
170     {
171 	if (gui_wait_for_chars(wtime) && !typebuf_changed(tb_change_cnt))
172 	    retval = read_from_input_buf(buf, (long)maxlen);
173     }
174 #endif
175 #ifndef NO_CONSOLE
176 # ifdef FEAT_GUI
177     else
178 # endif
179 	retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt);
180 #endif
181 
182     ctrl_c_interrupts = TRUE;
183 
184     return retval;
185 }
186 
187 /*
188  * return non-zero if a character is available
189  */
190     int
191 ui_char_avail()
192 {
193 #ifdef FEAT_GUI
194     if (gui.in_use)
195     {
196 	gui_mch_update();
197 	return input_available();
198     }
199 #endif
200 #ifndef NO_CONSOLE
201 # ifdef NO_CONSOLE_INPUT
202     if (no_console_input())
203 	return 0;
204 # endif
205     return mch_char_avail();
206 #else
207     return 0;
208 #endif
209 }
210 
211 /*
212  * Delay for the given number of milliseconds.	If ignoreinput is FALSE then we
213  * cancel the delay if a key is hit.
214  */
215     void
216 ui_delay(msec, ignoreinput)
217     long	msec;
218     int		ignoreinput;
219 {
220 #ifdef FEAT_GUI
221     if (gui.in_use && !ignoreinput)
222 	gui_wait_for_chars(msec);
223     else
224 #endif
225 	mch_delay(msec, ignoreinput);
226 }
227 
228 /*
229  * If the machine has job control, use it to suspend the program,
230  * otherwise fake it by starting a new shell.
231  * When running the GUI iconify the window.
232  */
233     void
234 ui_suspend()
235 {
236 #ifdef FEAT_GUI
237     if (gui.in_use)
238     {
239 	gui_mch_iconify();
240 	return;
241     }
242 #endif
243     mch_suspend();
244 }
245 
246 #if !defined(UNIX) || !defined(SIGTSTP) || defined(PROTO) || defined(__BEOS__)
247 /*
248  * When the OS can't really suspend, call this function to start a shell.
249  * This is never called in the GUI.
250  */
251     void
252 suspend_shell()
253 {
254     if (*p_sh == NUL)
255 	EMSG(_(e_shellempty));
256     else
257     {
258 	MSG_PUTS(_("new shell started\n"));
259 	do_shell(NULL, 0);
260     }
261 }
262 #endif
263 
264 /*
265  * Try to get the current Vim shell size.  Put the result in Rows and Columns.
266  * Use the new sizes as defaults for 'columns' and 'lines'.
267  * Return OK when size could be determined, FAIL otherwise.
268  */
269     int
270 ui_get_shellsize()
271 {
272     int	    retval;
273 
274 #ifdef FEAT_GUI
275     if (gui.in_use)
276 	retval = gui_get_shellsize();
277     else
278 #endif
279 	retval = mch_get_shellsize();
280 
281     check_shellsize();
282 
283     /* adjust the default for 'lines' and 'columns' */
284     if (retval == OK)
285     {
286 	set_number_default("lines", Rows);
287 	set_number_default("columns", Columns);
288     }
289     return retval;
290 }
291 
292 /*
293  * Set the size of the Vim shell according to Rows and Columns, if possible.
294  * The gui_set_shellsize() or mch_set_shellsize() function will try to set the
295  * new size.  If this is not possible, it will adjust Rows and Columns.
296  */
297 /*ARGSUSED*/
298     void
299 ui_set_shellsize(mustset)
300     int		mustset;	/* set by the user */
301 {
302 #ifdef FEAT_GUI
303     if (gui.in_use)
304 	gui_set_shellsize(mustset,
305 # ifdef WIN3264
306 		TRUE
307 # else
308 		FALSE
309 # endif
310 		);
311     else
312 #endif
313 	mch_set_shellsize();
314 }
315 
316 /*
317  * Called when Rows and/or Columns changed.  Adjust scroll region and mouse
318  * region.
319  */
320     void
321 ui_new_shellsize()
322 {
323     if (full_screen && !exiting)
324     {
325 #ifdef FEAT_GUI
326 	if (gui.in_use)
327 	    gui_new_shellsize();
328 	else
329 #endif
330 	    mch_new_shellsize();
331     }
332 }
333 
334     void
335 ui_breakcheck()
336 {
337 #ifdef FEAT_GUI
338     if (gui.in_use)
339 	gui_mch_update();
340     else
341 #endif
342 	mch_breakcheck();
343 }
344 
345 /*****************************************************************************
346  * Functions for copying and pasting text between applications.
347  * This is always included in a GUI version, but may also be included when the
348  * clipboard and mouse is available to a terminal version such as xterm.
349  * Note: there are some more functions in ops.c that handle selection stuff.
350  *
351  * Also note that the majority of functions here deal with the X 'primary'
352  * (visible - for Visual mode use) selection, and only that. There are no
353  * versions of these for the 'clipboard' selection, as Visual mode has no use
354  * for them.
355  */
356 
357 #if defined(FEAT_CLIPBOARD) || defined(PROTO)
358 
359 /*
360  * Selection stuff using Visual mode, for cutting and pasting text to other
361  * windows.
362  */
363 
364 /*
365  * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
366  * is included, but the clipboard can not be used, or TRUE if the clipboard can
367  * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
368  * the GUI starts.
369  */
370     void
371 clip_init(can_use)
372     int	    can_use;
373 {
374     VimClipboard *cb;
375 
376     cb = &clip_star;
377     for (;;)
378     {
379 	cb->available  = can_use;
380 	cb->owned      = FALSE;
381 	cb->start.lnum = 0;
382 	cb->start.col  = 0;
383 	cb->end.lnum   = 0;
384 	cb->end.col    = 0;
385 	cb->state      = SELECT_CLEARED;
386 
387 	if (cb == &clip_plus)
388 	    break;
389 	cb = &clip_plus;
390     }
391 }
392 
393 /*
394  * Check whether the VIsual area has changed, and if so try to become the owner
395  * of the selection, and free any old converted selection we may still have
396  * lying around.  If the VIsual mode has ended, make a copy of what was
397  * selected so we can still give it to others.	Will probably have to make sure
398  * this is called whenever VIsual mode is ended.
399  */
400     void
401 clip_update_selection()
402 {
403     pos_T    start, end;
404 
405     /* If visual mode is only due to a redo command ("."), then ignore it */
406     if (!redo_VIsual_busy && VIsual_active && (State & NORMAL))
407     {
408 	if (lt(VIsual, curwin->w_cursor))
409 	{
410 	    start = VIsual;
411 	    end = curwin->w_cursor;
412 #ifdef FEAT_MBYTE
413 	    if (has_mbyte)
414 		end.col += (*mb_ptr2len_check)(ml_get_cursor()) - 1;
415 #endif
416 	}
417 	else
418 	{
419 	    start = curwin->w_cursor;
420 	    end = VIsual;
421 	}
422 	if (!equalpos(clip_star.start, start)
423 		|| !equalpos(clip_star.end, end)
424 		|| clip_star.vmode != VIsual_mode)
425 	{
426 	    clip_clear_selection();
427 	    clip_star.start = start;
428 	    clip_star.end = end;
429 	    clip_star.vmode = VIsual_mode;
430 	    clip_free_selection(&clip_star);
431 	    clip_own_selection(&clip_star);
432 	    clip_gen_set_selection(&clip_star);
433 	}
434     }
435 }
436 
437     void
438 clip_own_selection(cbd)
439     VimClipboard	*cbd;
440 {
441     /*
442      * Also want to check somehow that we are reading from the keyboard rather
443      * than a mapping etc.
444      */
445     if (!cbd->owned && cbd->available)
446     {
447 	cbd->owned = (clip_gen_own_selection(cbd) == OK);
448 #ifdef FEAT_X11
449 	if (cbd == &clip_star)
450 	{
451 	    /* May have to show a different kind of highlighting for the selected
452 	     * area.  There is no specific redraw command for this, just redraw
453 	     * all windows on the current buffer. */
454 	    if (cbd->owned
455 		    && get_real_state() == VISUAL
456 		    && clip_isautosel()
457 		    && hl_attr(HLF_V) != hl_attr(HLF_VNC))
458 		redraw_curbuf_later(INVERTED_ALL);
459 	}
460 #endif
461     }
462 }
463 
464     void
465 clip_lose_selection(cbd)
466     VimClipboard	*cbd;
467 {
468 #ifdef FEAT_X11
469     int	    was_owned = cbd->owned;
470 #endif
471     int     visual_selection = (cbd == &clip_star);
472 
473     clip_free_selection(cbd);
474     cbd->owned = FALSE;
475     if (visual_selection)
476 	clip_clear_selection();
477     clip_gen_lose_selection(cbd);
478 #ifdef FEAT_X11
479     if (visual_selection)
480     {
481 	/* May have to show a different kind of highlighting for the selected
482 	 * area.  There is no specific redraw command for this, just redraw all
483 	 * windows on the current buffer. */
484 	if (was_owned
485 		&& get_real_state() == VISUAL
486 		&& clip_isautosel()
487 		&& hl_attr(HLF_V) != hl_attr(HLF_VNC))
488 	{
489 	    update_curbuf(INVERTED_ALL);
490 	    setcursor();
491 	    cursor_on();
492 	    out_flush();
493 # ifdef FEAT_GUI
494 	    if (gui.in_use)
495 		gui_update_cursor(TRUE, FALSE);
496 # endif
497 	}
498     }
499 #endif
500 }
501 
502     void
503 clip_copy_selection()
504 {
505     if (VIsual_active && (State & NORMAL) && clip_star.available)
506     {
507 	if (clip_isautosel())
508 	    clip_update_selection();
509 	clip_free_selection(&clip_star);
510 	clip_own_selection(&clip_star);
511 	if (clip_star.owned)
512 	    clip_get_selection(&clip_star);
513 	clip_gen_set_selection(&clip_star);
514     }
515 }
516 
517 /*
518  * Called when Visual mode is ended: update the selection.
519  */
520     void
521 clip_auto_select()
522 {
523     if (clip_isautosel())
524 	clip_copy_selection();
525 }
526 
527 /*
528  * Return TRUE if automatic selection of Visual area is desired.
529  */
530     int
531 clip_isautosel()
532 {
533     return (
534 #ifdef FEAT_GUI
535 	    gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) :
536 #endif
537 	    clip_autoselect);
538 }
539 
540 
541 /*
542  * Stuff for general mouse selection, without using Visual mode.
543  */
544 
545 static int clip_compare_pos __ARGS((int row1, int col1, int row2, int col2));
546 static void clip_invert_area __ARGS((int, int, int, int, int how));
547 static void clip_invert_rectangle __ARGS((int row, int col, int height, int width, int invert));
548 static void clip_get_word_boundaries __ARGS((VimClipboard *, int, int));
549 static int  clip_get_line_end __ARGS((int));
550 static void clip_update_modeless_selection __ARGS((VimClipboard *, int, int,
551 						    int, int));
552 
553 /* flags for clip_invert_area() */
554 #define CLIP_CLEAR	1
555 #define CLIP_SET	2
556 #define CLIP_TOGGLE	3
557 
558 /*
559  * Start, continue or end a modeless selection.  Used when editing the
560  * command-line and in the cmdline window.
561  */
562     void
563 clip_modeless(button, is_click, is_drag)
564     int		button;
565     int		is_click;
566     int		is_drag;
567 {
568     int		repeat;
569 
570     repeat = ((clip_star.mode == SELECT_MODE_CHAR
571 		|| clip_star.mode == SELECT_MODE_LINE)
572 					      && (mod_mask & MOD_MASK_2CLICK))
573 	    || (clip_star.mode == SELECT_MODE_WORD
574 					     && (mod_mask & MOD_MASK_3CLICK));
575     if (is_click && button == MOUSE_RIGHT)
576     {
577 	/* Right mouse button: If there was no selection, start one.
578 	 * Otherwise extend the existing selection. */
579 	if (clip_star.state == SELECT_CLEARED)
580 	    clip_start_selection(mouse_col, mouse_row, FALSE);
581 	clip_process_selection(button, mouse_col, mouse_row, repeat);
582     }
583     else if (is_click)
584 	clip_start_selection(mouse_col, mouse_row, repeat);
585     else if (is_drag)
586     {
587 	/* Don't try extending a selection if there isn't one.  Happens when
588 	 * button-down is in the cmdline and them moving mouse upwards. */
589 	if (clip_star.state != SELECT_CLEARED)
590 	    clip_process_selection(button, mouse_col, mouse_row, repeat);
591     }
592     else /* release */
593 	clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE);
594 }
595 
596 /*
597  * Compare two screen positions ala strcmp()
598  */
599     static int
600 clip_compare_pos(row1, col1, row2, col2)
601     int		row1;
602     int		col1;
603     int		row2;
604     int		col2;
605 {
606     if (row1 > row2) return(1);
607     if (row1 < row2) return(-1);
608     if (col1 > col2) return(1);
609     if (col1 < col2) return(-1);
610 		     return(0);
611 }
612 
613 /*
614  * Start the selection
615  */
616     void
617 clip_start_selection(col, row, repeated_click)
618     int		col;
619     int		row;
620     int		repeated_click;
621 {
622     VimClipboard	*cb = &clip_star;
623 
624     if (cb->state == SELECT_DONE)
625 	clip_clear_selection();
626 
627     row = check_row(row);
628     col = check_col(col);
629 #ifdef FEAT_MBYTE
630     col = mb_fix_col(col, row);
631 #endif
632 
633     cb->start.lnum  = row;
634     cb->start.col   = col;
635     cb->end	    = cb->start;
636     cb->origin_row  = (short_u)cb->start.lnum;
637     cb->state	    = SELECT_IN_PROGRESS;
638 
639     if (repeated_click)
640     {
641 	if (++cb->mode > SELECT_MODE_LINE)
642 	    cb->mode = SELECT_MODE_CHAR;
643     }
644     else
645 	cb->mode = SELECT_MODE_CHAR;
646 
647 #ifdef FEAT_GUI
648     /* clear the cursor until the selection is made */
649     if (gui.in_use)
650 	gui_undraw_cursor();
651 #endif
652 
653     switch (cb->mode)
654     {
655 	case SELECT_MODE_CHAR:
656 	    cb->origin_start_col = cb->start.col;
657 	    cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
658 	    break;
659 
660 	case SELECT_MODE_WORD:
661 	    clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
662 	    cb->origin_start_col = cb->word_start_col;
663 	    cb->origin_end_col	 = cb->word_end_col;
664 
665 	    clip_invert_area((int)cb->start.lnum, cb->word_start_col,
666 			    (int)cb->end.lnum, cb->word_end_col, CLIP_SET);
667 	    cb->start.col = cb->word_start_col;
668 	    cb->end.col   = cb->word_end_col;
669 	    break;
670 
671 	case SELECT_MODE_LINE:
672 	    clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum,
673 			    (int)Columns, CLIP_SET);
674 	    cb->start.col = 0;
675 	    cb->end.col   = Columns;
676 	    break;
677     }
678 
679     cb->prev = cb->start;
680 
681 #ifdef DEBUG_SELECTION
682     printf("Selection started at (%u,%u)\n", cb->start.lnum, cb->start.col);
683 #endif
684 }
685 
686 /*
687  * Continue processing the selection
688  */
689     void
690 clip_process_selection(button, col, row, repeated_click)
691     int		button;
692     int		col;
693     int		row;
694     int_u	repeated_click;
695 {
696     VimClipboard	*cb = &clip_star;
697     int			diff;
698     int			slen = 1;	/* cursor shape width */
699 
700     if (button == MOUSE_RELEASE)
701     {
702 	/* Check to make sure we have something selected */
703 	if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
704 	{
705 #ifdef FEAT_GUI
706 	    if (gui.in_use)
707 		gui_update_cursor(FALSE, FALSE);
708 #endif
709 	    cb->state = SELECT_CLEARED;
710 	    return;
711 	}
712 
713 #ifdef DEBUG_SELECTION
714 	printf("Selection ended: (%u,%u) to (%u,%u)\n", cb->start.lnum,
715 		cb->start.col, cb->end.lnum, cb->end.col);
716 #endif
717 	if (clip_isautosel()
718 		|| (
719 #ifdef FEAT_GUI
720 		    gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) :
721 #endif
722 		    clip_autoselectml))
723 	    clip_copy_modeless_selection(FALSE);
724 #ifdef FEAT_GUI
725 	if (gui.in_use)
726 	    gui_update_cursor(FALSE, FALSE);
727 #endif
728 
729 	cb->state = SELECT_DONE;
730 	return;
731     }
732 
733     row = check_row(row);
734     col = check_col(col);
735 #ifdef FEAT_MBYTE
736     col = mb_fix_col(col, row);
737 #endif
738 
739     if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click)
740 	return;
741 
742     /*
743      * When extending the selection with the right mouse button, swap the
744      * start and end if the position is before half the selection
745      */
746     if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
747     {
748 	/*
749 	 * If the click is before the start, or the click is inside the
750 	 * selection and the start is the closest side, set the origin to the
751 	 * end of the selection.
752 	 */
753 	if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
754 		|| (clip_compare_pos(row, col,
755 					   (int)cb->end.lnum, cb->end.col) < 0
756 		    && (((cb->start.lnum == cb->end.lnum
757 			    && cb->end.col - col > col - cb->start.col))
758 			|| ((diff = (cb->end.lnum - row) -
759 						   (row - cb->start.lnum)) > 0
760 			    || (diff == 0 && col < (int)(cb->start.col +
761 							 cb->end.col) / 2)))))
762 	{
763 	    cb->origin_row = (short_u)cb->end.lnum;
764 	    cb->origin_start_col = cb->end.col - 1;
765 	    cb->origin_end_col = cb->end.col;
766 	}
767 	else
768 	{
769 	    cb->origin_row = (short_u)cb->start.lnum;
770 	    cb->origin_start_col = cb->start.col;
771 	    cb->origin_end_col = cb->start.col;
772 	}
773 	if (cb->mode == SELECT_MODE_WORD && !repeated_click)
774 	    cb->mode = SELECT_MODE_CHAR;
775     }
776 
777     /* set state, for when using the right mouse button */
778     cb->state = SELECT_IN_PROGRESS;
779 
780 #ifdef DEBUG_SELECTION
781     printf("Selection extending to (%d,%d)\n", row, col);
782 #endif
783 
784     if (repeated_click && ++cb->mode > SELECT_MODE_LINE)
785 	cb->mode = SELECT_MODE_CHAR;
786 
787     switch (cb->mode)
788     {
789 	case SELECT_MODE_CHAR:
790 	    /* If we're on a different line, find where the line ends */
791 	    if (row != cb->prev.lnum)
792 		cb->word_end_col = clip_get_line_end(row);
793 
794 	    /* See if we are before or after the origin of the selection */
795 	    if (clip_compare_pos(row, col, cb->origin_row,
796 						   cb->origin_start_col) >= 0)
797 	    {
798 		if (col >= (int)cb->word_end_col)
799 		    clip_update_modeless_selection(cb, cb->origin_row,
800 			    cb->origin_start_col, row, (int)Columns);
801 		else
802 		{
803 #ifdef FEAT_MBYTE
804 		    if (has_mbyte && mb_lefthalve(row, col))
805 			slen = 2;
806 #endif
807 		    clip_update_modeless_selection(cb, cb->origin_row,
808 			    cb->origin_start_col, row, col + slen);
809 		}
810 	    }
811 	    else
812 	    {
813 #ifdef FEAT_MBYTE
814 		if (has_mbyte
815 			&& mb_lefthalve(cb->origin_row, cb->origin_start_col))
816 		    slen = 2;
817 #endif
818 		if (col >= (int)cb->word_end_col)
819 		    clip_update_modeless_selection(cb, row, cb->word_end_col,
820 			    cb->origin_row, cb->origin_start_col + slen);
821 		else
822 		    clip_update_modeless_selection(cb, row, col,
823 			    cb->origin_row, cb->origin_start_col + slen);
824 	    }
825 	    break;
826 
827 	case SELECT_MODE_WORD:
828 	    /* If we are still within the same word, do nothing */
829 	    if (row == cb->prev.lnum && col >= (int)cb->word_start_col
830 		    && col < (int)cb->word_end_col && !repeated_click)
831 		return;
832 
833 	    /* Get new word boundaries */
834 	    clip_get_word_boundaries(cb, row, col);
835 
836 	    /* Handle being after the origin point of selection */
837 	    if (clip_compare_pos(row, col, cb->origin_row,
838 		    cb->origin_start_col) >= 0)
839 		clip_update_modeless_selection(cb, cb->origin_row,
840 			cb->origin_start_col, row, cb->word_end_col);
841 	    else
842 		clip_update_modeless_selection(cb, row, cb->word_start_col,
843 			cb->origin_row, cb->origin_end_col);
844 	    break;
845 
846 	case SELECT_MODE_LINE:
847 	    if (row == cb->prev.lnum && !repeated_click)
848 		return;
849 
850 	    if (clip_compare_pos(row, col, cb->origin_row,
851 		    cb->origin_start_col) >= 0)
852 		clip_update_modeless_selection(cb, cb->origin_row, 0, row,
853 			(int)Columns);
854 	    else
855 		clip_update_modeless_selection(cb, row, 0, cb->origin_row,
856 			(int)Columns);
857 	    break;
858     }
859 
860     cb->prev.lnum = row;
861     cb->prev.col  = col;
862 
863 #ifdef DEBUG_SELECTION
864 	printf("Selection is: (%u,%u) to (%u,%u)\n", cb->start.lnum,
865 		cb->start.col, cb->end.lnum, cb->end.col);
866 #endif
867 }
868 
869 #if 0 /* not used */
870 /*
871  * Called after an Expose event to redraw the selection
872  */
873     void
874 clip_redraw_selection(x, y, w, h)
875     int	    x;
876     int	    y;
877     int	    w;
878     int	    h;
879 {
880     VimClipboard    *cb = &clip_star;
881     int		    row1, col1, row2, col2;
882     int		    row;
883     int		    start;
884     int		    end;
885 
886     if (cb->state == SELECT_CLEARED)
887 	return;
888 
889     row1 = check_row(Y_2_ROW(y));
890     col1 = check_col(X_2_COL(x));
891     row2 = check_row(Y_2_ROW(y + h - 1));
892     col2 = check_col(X_2_COL(x + w - 1));
893 
894     /* Limit the rows that need to be re-drawn */
895     if (cb->start.lnum > row1)
896 	row1 = cb->start.lnum;
897     if (cb->end.lnum < row2)
898 	row2 = cb->end.lnum;
899 
900     /* Look at each row that might need to be re-drawn */
901     for (row = row1; row <= row2; row++)
902     {
903 	/* For the first selection row, use the starting selection column */
904 	if (row == cb->start.lnum)
905 	    start = cb->start.col;
906 	else
907 	    start = 0;
908 
909 	/* For the last selection row, use the ending selection column */
910 	if (row == cb->end.lnum)
911 	    end = cb->end.col;
912 	else
913 	    end = Columns;
914 
915 	if (col1 > start)
916 	    start = col1;
917 
918 	if (col2 < end)
919 	    end = col2 + 1;
920 
921 	if (end > start)
922 	    gui_mch_invert_rectangle(row, start, 1, end - start);
923     }
924 }
925 #endif
926 
927 # if defined(FEAT_GUI) || defined(PROTO)
928 /*
929  * Redraw part of the selection if character at "row,col" is inside of it.
930  * Only used for the GUI.
931  */
932     void
933 clip_may_redraw_selection(row, col, len)
934     int		row, col;
935     int		len;
936 {
937     int		start = col;
938     int		end = col + len;
939 
940     if (clip_star.state != SELECT_CLEARED
941 	    && row >= clip_star.start.lnum
942 	    && row <= clip_star.end.lnum)
943     {
944 	if (row == clip_star.start.lnum && start < (int)clip_star.start.col)
945 	    start = clip_star.start.col;
946 	if (row == clip_star.end.lnum && end > (int)clip_star.end.col)
947 	    end = clip_star.end.col;
948 	if (end > start)
949 	    clip_invert_area(row, start, row, end, 0);
950     }
951 }
952 # endif
953 
954 /*
955  * Called from outside to clear selected region from the display
956  */
957     void
958 clip_clear_selection()
959 {
960     VimClipboard    *cb = &clip_star;
961 
962     if (cb->state == SELECT_CLEARED)
963 	return;
964 
965     clip_invert_area((int)cb->start.lnum, cb->start.col, (int)cb->end.lnum,
966 						     cb->end.col, CLIP_CLEAR);
967     cb->state = SELECT_CLEARED;
968 }
969 
970 /*
971  * Clear the selection if any lines from "row1" to "row2" are inside of it.
972  */
973     void
974 clip_may_clear_selection(row1, row2)
975     int	row1, row2;
976 {
977     if (clip_star.state == SELECT_DONE
978 	    && row2 >= clip_star.start.lnum
979 	    && row1 <= clip_star.end.lnum)
980 	clip_clear_selection();
981 }
982 
983 /*
984  * Called before the screen is scrolled up or down.  Adjusts the line numbers
985  * of the selection.  Call with big number when clearing the screen.
986  */
987     void
988 clip_scroll_selection(rows)
989     int	    rows;		/* negative for scroll down */
990 {
991     int	    lnum;
992 
993     if (clip_star.state == SELECT_CLEARED)
994 	return;
995 
996     lnum = clip_star.start.lnum - rows;
997     if (lnum <= 0)
998 	clip_star.start.lnum = 0;
999     else if (lnum >= screen_Rows)	/* scrolled off of the screen */
1000 	clip_star.state = SELECT_CLEARED;
1001     else
1002 	clip_star.start.lnum = lnum;
1003 
1004     lnum = clip_star.end.lnum - rows;
1005     if (lnum < 0)			/* scrolled off of the screen */
1006 	clip_star.state = SELECT_CLEARED;
1007     else if (lnum >= screen_Rows)
1008 	clip_star.end.lnum = screen_Rows - 1;
1009     else
1010 	clip_star.end.lnum = lnum;
1011 }
1012 
1013 /*
1014  * Invert a region of the display between a starting and ending row and column
1015  * Values for "how":
1016  * CLIP_CLEAR:  undo inversion
1017  * CLIP_SET:    set inversion
1018  * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise.
1019  * 0: invert (GUI only).
1020  */
1021     static void
1022 clip_invert_area(row1, col1, row2, col2, how)
1023     int		row1;
1024     int		col1;
1025     int		row2;
1026     int		col2;
1027     int		how;
1028 {
1029     int		invert = FALSE;
1030 
1031     if (how == CLIP_SET)
1032 	invert = TRUE;
1033 
1034     /* Swap the from and to positions so the from is always before */
1035     if (clip_compare_pos(row1, col1, row2, col2) > 0)
1036     {
1037 	int tmp_row, tmp_col;
1038 
1039 	tmp_row = row1;
1040 	tmp_col = col1;
1041 	row1	= row2;
1042 	col1	= col2;
1043 	row2	= tmp_row;
1044 	col2	= tmp_col;
1045     }
1046     else if (how == CLIP_TOGGLE)
1047 	invert = TRUE;
1048 
1049     /* If all on the same line, do it the easy way */
1050     if (row1 == row2)
1051     {
1052 	clip_invert_rectangle(row1, col1, 1, col2 - col1, invert);
1053     }
1054     else
1055     {
1056 	/* Handle a piece of the first line */
1057 	if (col1 > 0)
1058 	{
1059 	    clip_invert_rectangle(row1, col1, 1, (int)Columns - col1, invert);
1060 	    row1++;
1061 	}
1062 
1063 	/* Handle a piece of the last line */
1064 	if (col2 < Columns - 1)
1065 	{
1066 	    clip_invert_rectangle(row2, 0, 1, col2, invert);
1067 	    row2--;
1068 	}
1069 
1070 	/* Handle the rectangle thats left */
1071 	if (row2 >= row1)
1072 	    clip_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns,
1073 								      invert);
1074     }
1075 }
1076 
1077 /*
1078  * Invert or un-invert a rectangle of the screen.
1079  * "invert" is true if the result is inverted.
1080  */
1081     static void
1082 clip_invert_rectangle(row, col, height, width, invert)
1083     int		row;
1084     int		col;
1085     int		height;
1086     int		width;
1087     int		invert;
1088 {
1089 #ifdef FEAT_GUI
1090     if (gui.in_use)
1091 	gui_mch_invert_rectangle(row, col, height, width);
1092     else
1093 #endif
1094 	screen_draw_rectangle(row, col, height, width, invert);
1095 }
1096 
1097 /*
1098  * Copy the currently selected area into the '*' register so it will be
1099  * available for pasting.
1100  * When "both" is TRUE also copy to the '+' register.
1101  */
1102 /*ARGSUSED*/
1103     void
1104 clip_copy_modeless_selection(both)
1105     int		both;
1106 {
1107     char_u	*buffer;
1108     char_u	*bufp;
1109     int		row;
1110     int		start_col;
1111     int		end_col;
1112     int		line_end_col;
1113     int		add_newline_flag = FALSE;
1114     int		len;
1115 #ifdef FEAT_MBYTE
1116     char_u	*p;
1117     int		i;
1118 #endif
1119     int		row1 = clip_star.start.lnum;
1120     int		col1 = clip_star.start.col;
1121     int		row2 = clip_star.end.lnum;
1122     int		col2 = clip_star.end.col;
1123 
1124     /*
1125      * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
1126      */
1127     if (row1 > row2)
1128     {
1129 	row = row1; row1 = row2; row2 = row;
1130 	row = col1; col1 = col2; col2 = row;
1131     }
1132     else if (row1 == row2 && col1 > col2)
1133     {
1134 	row = col1; col1 = col2; col2 = row;
1135     }
1136 #ifdef FEAT_MBYTE
1137     /* correct starting point for being on right halve of double-wide char */
1138     p = ScreenLines + LineOffset[row1];
1139     if (enc_dbcs != 0)
1140 	col1 -= (*mb_head_off)(p, p + col1);
1141     else if (enc_utf8 && p[col1] == 0)
1142 	--col1;
1143 #endif
1144 
1145     /* Create a temporary buffer for storing the text */
1146     len = (row2 - row1 + 1) * Columns + 1;
1147 #ifdef FEAT_MBYTE
1148     if (enc_dbcs != 0)
1149 	len *= 2;	/* max. 2 bytes per display cell */
1150     else if (enc_utf8)
1151 	len *= 9;	/* max. 3 bytes per display cell + 2 composing chars */
1152 #endif
1153     buffer = lalloc((long_u)len, TRUE);
1154     if (buffer == NULL)	    /* out of memory */
1155 	return;
1156 
1157     /* Process each row in the selection */
1158     for (bufp = buffer, row = row1; row <= row2; row++)
1159     {
1160 	if (row == row1)
1161 	    start_col = col1;
1162 	else
1163 	    start_col = 0;
1164 
1165 	if (row == row2)
1166 	    end_col = col2;
1167 	else
1168 	    end_col = Columns;
1169 
1170 	line_end_col = clip_get_line_end(row);
1171 
1172 	/* See if we need to nuke some trailing whitespace */
1173 	if (end_col >= Columns && (row < row2 || end_col > line_end_col))
1174 	{
1175 	    /* Get rid of trailing whitespace */
1176 	    end_col = line_end_col;
1177 	    if (end_col < start_col)
1178 		end_col = start_col;
1179 
1180 	    /* If the last line extended to the end, add an extra newline */
1181 	    if (row == row2)
1182 		add_newline_flag = TRUE;
1183 	}
1184 
1185 	/* If after the first row, we need to always add a newline */
1186 	if (row > row1 && !LineWraps[row - 1])
1187 	    *bufp++ = NL;
1188 
1189 	if (row < screen_Rows && end_col <= screen_Columns)
1190 	{
1191 #ifdef FEAT_MBYTE
1192 	    if (enc_dbcs != 0)
1193 	    {
1194 		p = ScreenLines + LineOffset[row];
1195 		for (i = start_col; i < end_col; ++i)
1196 		    if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e)
1197 		    {
1198 			/* single-width double-byte char */
1199 			*bufp++ = 0x8e;
1200 			*bufp++ = ScreenLines2[LineOffset[row] + i];
1201 		    }
1202 		    else
1203 		    {
1204 			*bufp++ = p[i];
1205 			if (MB_BYTE2LEN(p[i]) == 2)
1206 			    *bufp++ = p[++i];
1207 		    }
1208 	    }
1209 	    else if (enc_utf8)
1210 	    {
1211 		int	off;
1212 
1213 		off = LineOffset[row];
1214 		for (i = start_col; i < end_col; ++i)
1215 		{
1216 		    /* The base character is either in ScreenLinesUC[] or
1217 		     * ScreenLines[]. */
1218 		    if (ScreenLinesUC[off + i] == 0)
1219 			*bufp++ = ScreenLines[off + i];
1220 		    else
1221 		    {
1222 			bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp);
1223 			if (ScreenLinesC1[off + i] != 0)
1224 			{
1225 			    /* Add one or two composing characters. */
1226 			    bufp += utf_char2bytes(ScreenLinesC1[off + i],
1227 									bufp);
1228 			    if (ScreenLinesC2[off + i] != 0)
1229 				bufp += utf_char2bytes(ScreenLinesC2[off + i],
1230 					bufp);
1231 			}
1232 		    }
1233 		    /* Skip right halve of double-wide character. */
1234 		    if (ScreenLines[off + i + 1] == 0)
1235 			++i;
1236 		}
1237 	    }
1238 	    else
1239 #endif
1240 	    {
1241 		STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col,
1242 							 end_col - start_col);
1243 		bufp += end_col - start_col;
1244 	    }
1245 	}
1246     }
1247 
1248     /* Add a newline at the end if the selection ended there */
1249     if (add_newline_flag)
1250 	*bufp++ = NL;
1251 
1252     /* First cleanup any old selection and become the owner. */
1253     clip_free_selection(&clip_star);
1254     clip_own_selection(&clip_star);
1255 
1256     /* Yank the text into the '*' register. */
1257     clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star);
1258 
1259     /* Make the register contents available to the outside world. */
1260     clip_gen_set_selection(&clip_star);
1261 
1262 #ifdef FEAT_X11
1263     if (both)
1264     {
1265 	/* Do the same for the '+' register. */
1266 	clip_free_selection(&clip_plus);
1267 	clip_own_selection(&clip_plus);
1268 	clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus);
1269 	clip_gen_set_selection(&clip_plus);
1270     }
1271 #endif
1272     vim_free(buffer);
1273 }
1274 
1275 /*
1276  * Find the starting and ending positions of the word at the given row and
1277  * column.  Only white-separated words are recognized here.
1278  */
1279 #define CHAR_CLASS(c)	(c <= ' ' ? ' ' : vim_iswordc(c))
1280 
1281     static void
1282 clip_get_word_boundaries(cb, row, col)
1283     VimClipboard	*cb;
1284     int			row;
1285     int			col;
1286 {
1287     int		start_class;
1288     int		temp_col;
1289     char_u	*p;
1290 #ifdef FEAT_MBYTE
1291     int		mboff;
1292 #endif
1293 
1294     if (row >= screen_Rows || col >= screen_Columns)
1295 	return;
1296 
1297     p = ScreenLines + LineOffset[row];
1298 #ifdef FEAT_MBYTE
1299     /* Correct for starting in the right halve of a double-wide char */
1300     if (enc_dbcs != 0)
1301 	col -= dbcs_screen_head_off(p, p + col);
1302     else if (enc_utf8 && p[col] == 0)
1303 	--col;
1304 #endif
1305     start_class = CHAR_CLASS(p[col]);
1306 
1307     temp_col = col;
1308     for ( ; temp_col > 0; temp_col--)
1309 #ifdef FEAT_MBYTE
1310 	if (enc_dbcs != 0
1311 		   && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0)
1312 	    temp_col -= mboff;
1313 	else
1314 #endif
1315 	if (CHAR_CLASS(p[temp_col - 1]) != start_class
1316 #ifdef FEAT_MBYTE
1317 		&& !(enc_utf8 && p[temp_col - 1] == 0)
1318 #endif
1319 		)
1320 	    break;
1321     cb->word_start_col = temp_col;
1322 
1323     temp_col = col;
1324     for ( ; temp_col < screen_Columns; temp_col++)
1325 #ifdef FEAT_MBYTE
1326 	if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2)
1327 	    ++temp_col;
1328 	else
1329 #endif
1330 	if (CHAR_CLASS(p[temp_col]) != start_class
1331 #ifdef FEAT_MBYTE
1332 		&& !(enc_utf8 && p[temp_col] == 0)
1333 #endif
1334 		)
1335 	    break;
1336     cb->word_end_col = temp_col;
1337 }
1338 
1339 /*
1340  * Find the column position for the last non-whitespace character on the given
1341  * line.
1342  */
1343     static int
1344 clip_get_line_end(row)
1345     int		row;
1346 {
1347     int	    i;
1348 
1349     if (row >= screen_Rows)
1350 	return 0;
1351     for (i = screen_Columns; i > 0; i--)
1352 	if (ScreenLines[LineOffset[row] + i - 1] != ' ')
1353 	    break;
1354     return i;
1355 }
1356 
1357 /*
1358  * Update the currently selected region by adding and/or subtracting from the
1359  * beginning or end and inverting the changed area(s).
1360  */
1361     static void
1362 clip_update_modeless_selection(cb, row1, col1, row2, col2)
1363     VimClipboard    *cb;
1364     int		    row1;
1365     int		    col1;
1366     int		    row2;
1367     int		    col2;
1368 {
1369     /* See if we changed at the beginning of the selection */
1370     if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
1371     {
1372 	clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col,
1373 								 CLIP_TOGGLE);
1374 	cb->start.lnum = row1;
1375 	cb->start.col  = col1;
1376     }
1377 
1378     /* See if we changed at the end of the selection */
1379     if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
1380     {
1381 	clip_invert_area((int)cb->end.lnum, cb->end.col, row2, col2,
1382 								 CLIP_TOGGLE);
1383 	cb->end.lnum = row2;
1384 	cb->end.col  = col2;
1385     }
1386 }
1387 
1388     int
1389 clip_gen_own_selection(cbd)
1390     VimClipboard	*cbd;
1391 {
1392 #ifdef FEAT_XCLIPBOARD
1393 # ifdef FEAT_GUI
1394     if (gui.in_use)
1395 	return clip_mch_own_selection(cbd);
1396     else
1397 # endif
1398 	return clip_xterm_own_selection(cbd);
1399 #else
1400     return clip_mch_own_selection(cbd);
1401 #endif
1402 }
1403 
1404     void
1405 clip_gen_lose_selection(cbd)
1406     VimClipboard	*cbd;
1407 {
1408 #ifdef FEAT_XCLIPBOARD
1409 # ifdef FEAT_GUI
1410     if (gui.in_use)
1411 	clip_mch_lose_selection(cbd);
1412     else
1413 # endif
1414 	clip_xterm_lose_selection(cbd);
1415 #else
1416     clip_mch_lose_selection(cbd);
1417 #endif
1418 }
1419 
1420     void
1421 clip_gen_set_selection(cbd)
1422     VimClipboard	*cbd;
1423 {
1424 #ifdef FEAT_XCLIPBOARD
1425 # ifdef FEAT_GUI
1426     if (gui.in_use)
1427 	clip_mch_set_selection(cbd);
1428     else
1429 # endif
1430 	clip_xterm_set_selection(cbd);
1431 #else
1432     clip_mch_set_selection(cbd);
1433 #endif
1434 }
1435 
1436     void
1437 clip_gen_request_selection(cbd)
1438     VimClipboard	*cbd;
1439 {
1440 #ifdef FEAT_XCLIPBOARD
1441 # ifdef FEAT_GUI
1442     if (gui.in_use)
1443 	clip_mch_request_selection(cbd);
1444     else
1445 # endif
1446 	clip_xterm_request_selection(cbd);
1447 #else
1448     clip_mch_request_selection(cbd);
1449 #endif
1450 }
1451 
1452 #endif /* FEAT_CLIPBOARD */
1453 
1454 /*****************************************************************************
1455  * Functions that handle the input buffer.
1456  * This is used for any GUI version, and the unix terminal version.
1457  *
1458  * For Unix, the input characters are buffered to be able to check for a
1459  * CTRL-C.  This should be done with signals, but I don't know how to do that
1460  * in a portable way for a tty in RAW mode.
1461  *
1462  * For the client-server code in the console the received keys are put in the
1463  * input buffer.
1464  */
1465 
1466 #if defined(USE_INPUT_BUF) || defined(PROTO)
1467 
1468 /*
1469  * Internal typeahead buffer.  Includes extra space for long key code
1470  * descriptions which would otherwise overflow.  The buffer is considered full
1471  * when only this extra space (or part of it) remains.
1472  */
1473 #if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) \
1474 	|| defined(FEAT_CLIENTSERVER)
1475    /*
1476     * Sun WorkShop and NetBeans stuff debugger commands into the input buffer.
1477     * This requires a larger buffer...
1478     * (Madsen) Go with this for remote input as well ...
1479     */
1480 # define INBUFLEN 4096
1481 #else
1482 # define INBUFLEN 250
1483 #endif
1484 
1485 static char_u	inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
1486 static int	inbufcount = 0;	    /* number of chars in inbuf[] */
1487 
1488 /*
1489  * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
1490  * trash_input_buf() are functions for manipulating the input buffer.  These
1491  * are used by the gui_* calls when a GUI is used to handle keyboard input.
1492  */
1493 
1494     int
1495 vim_is_input_buf_full()
1496 {
1497     return (inbufcount >= INBUFLEN);
1498 }
1499 
1500     int
1501 vim_is_input_buf_empty()
1502 {
1503     return (inbufcount == 0);
1504 }
1505 
1506 #if defined(FEAT_OLE) || defined(PROTO)
1507     int
1508 vim_free_in_input_buf()
1509 {
1510     return (INBUFLEN - inbufcount);
1511 }
1512 #endif
1513 
1514 #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_KDE) || defined(PROTO)
1515     int
1516 vim_used_in_input_buf()
1517 {
1518     return inbufcount;
1519 }
1520 #endif
1521 
1522 #if defined(FEAT_EVAL) || defined(FEAT_EX_EXTRA) || defined(PROTO)
1523 /*
1524  * Return the current contents of the input buffer and make it empty.
1525  * The returned pointer must be passed to set_input_buf() later.
1526  */
1527     char_u *
1528 get_input_buf()
1529 {
1530     garray_T	*gap;
1531 
1532     /* We use a growarray to store the data pointer and the length. */
1533     gap = (garray_T *)alloc((unsigned)sizeof(garray_T));
1534     if (gap != NULL)
1535     {
1536 	/* Add one to avoid a zero size. */
1537 	gap->ga_data = alloc((unsigned)inbufcount + 1);
1538 	if (gap->ga_data != NULL)
1539 	    mch_memmove(gap->ga_data, inbuf, (size_t)inbufcount);
1540 	gap->ga_len = inbufcount;
1541     }
1542     trash_input_buf();
1543     return (char_u *)gap;
1544 }
1545 
1546 /*
1547  * Restore the input buffer with a pointer returned from get_input_buf().
1548  * The allocated memory is freed, this only works once!
1549  */
1550     void
1551 set_input_buf(p)
1552     char_u	*p;
1553 {
1554     garray_T	*gap = (garray_T *)p;
1555 
1556     if (gap != NULL)
1557     {
1558 	if (gap->ga_data != NULL)
1559 	{
1560 	    mch_memmove(inbuf, gap->ga_data, gap->ga_len);
1561 	    inbufcount = gap->ga_len;
1562 	    vim_free(gap->ga_data);
1563 	}
1564 	vim_free(gap);
1565     }
1566 }
1567 #endif
1568 
1569 #if defined(FEAT_GUI) || defined(FEAT_MOUSE_GPM) \
1570 	|| defined(FEAT_XCLIPBOARD) || defined(VMS) \
1571 	|| defined(FEAT_SNIFF) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1572 /*
1573  * Add the given bytes to the input buffer
1574  * Special keys start with CSI.  A real CSI must have been translated to
1575  * CSI KS_EXTRA KE_CSI.  K_SPECIAL doesn't require translation.
1576  */
1577     void
1578 add_to_input_buf(s, len)
1579     char_u  *s;
1580     int	    len;
1581 {
1582     if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
1583 	return;	    /* Shouldn't ever happen! */
1584 
1585 #ifdef FEAT_HANGULIN
1586     if ((State & (INSERT|CMDLINE)) && hangul_input_state_get())
1587 	if ((len = hangul_input_process(s, len)) == 0)
1588 	    return;
1589 #endif
1590 
1591     while (len--)
1592 	inbuf[inbufcount++] = *s++;
1593 }
1594 #endif
1595 
1596 #if (defined(FEAT_XIM) && (defined(FEAT_GUI_GTK) || defined(FEAT_GUI_KDE))) \
1597 	|| (defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)) \
1598 	|| defined(PROTO)
1599 /*
1600  * Add "str[len]" to the input buffer while escaping CSI bytes.
1601  */
1602     void
1603 add_to_input_buf_csi(char_u *str, int len)
1604 {
1605     int		i;
1606     char_u	buf[2];
1607 
1608     for (i = 0; i < len; ++i)
1609     {
1610 	add_to_input_buf(str + i, 1);
1611 	if (str[i] == CSI)
1612 	{
1613 	    /* Turn CSI into K_CSI. */
1614 	    buf[0] = KS_EXTRA;
1615 	    buf[1] = (int)KE_CSI;
1616 	    add_to_input_buf(buf, 2);
1617 	}
1618     }
1619 }
1620 #endif
1621 
1622 #if defined(FEAT_HANGULIN) || defined(PROTO)
1623     void
1624 push_raw_key (s, len)
1625     char_u  *s;
1626     int	    len;
1627 {
1628     while (len--)
1629 	inbuf[inbufcount++] = *s++;
1630 }
1631 #endif
1632 
1633 #if defined(FEAT_GUI) || defined(FEAT_EVAL) || defined(FEAT_EX_EXTRA) \
1634 	|| defined(PROTO)
1635 /* Remove everything from the input buffer.  Called when ^C is found */
1636     void
1637 trash_input_buf()
1638 {
1639     inbufcount = 0;
1640 }
1641 #endif
1642 
1643 /*
1644  * Read as much data from the input buffer as possible up to maxlen, and store
1645  * it in buf.
1646  * Note: this function used to be Read() in unix.c
1647  */
1648     int
1649 read_from_input_buf(buf, maxlen)
1650     char_u  *buf;
1651     long    maxlen;
1652 {
1653     if (inbufcount == 0)	/* if the buffer is empty, fill it */
1654 	fill_input_buf(TRUE);
1655     if (maxlen > inbufcount)
1656 	maxlen = inbufcount;
1657     mch_memmove(buf, inbuf, (size_t)maxlen);
1658     inbufcount -= maxlen;
1659     if (inbufcount)
1660 	mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
1661     return (int)maxlen;
1662 }
1663 
1664     void
1665 fill_input_buf(exit_on_error)
1666     int	exit_on_error;
1667 {
1668 #if defined(UNIX) || defined(OS2) || defined(VMS) || defined(MACOS_X_UNIX)
1669     int		len;
1670     int		try;
1671     static int	did_read_something = FALSE;
1672 # ifdef FEAT_MBYTE
1673     static char_u *rest = NULL;	    /* unconverted rest of previous read */
1674     static int	restlen = 0;
1675     int		unconverted;
1676 # endif
1677 #endif
1678 
1679 #ifdef FEAT_GUI
1680     if (gui.in_use)
1681     {
1682 	gui_mch_update();
1683 	return;
1684     }
1685 #endif
1686 #if defined(UNIX) || defined(OS2) || defined(VMS) || defined(MACOS_X_UNIX)
1687     if (vim_is_input_buf_full())
1688 	return;
1689     /*
1690      * Fill_input_buf() is only called when we really need a character.
1691      * If we can't get any, but there is some in the buffer, just return.
1692      * If we can't get any, and there isn't any in the buffer, we give up and
1693      * exit Vim.
1694      */
1695 # ifdef __BEOS__
1696     /*
1697      * On the BeBox version (for now), all input is secretly performed within
1698      * beos_select() which is called from RealWaitForChar().
1699      */
1700     while (!vim_is_input_buf_full() && RealWaitForChar(read_cmd_fd, 0, NULL))
1701 	    ;
1702     len = inbufcount;
1703     inbufcount = 0;
1704 # else
1705 
1706 #  ifdef FEAT_SNIFF
1707     if (sniff_request_waiting)
1708     {
1709 	add_to_input_buf((char_u *)"\233sniff",6); /* results in K_SNIFF */
1710 	sniff_request_waiting = 0;
1711 	want_sniff_request = 0;
1712 	return;
1713     }
1714 #  endif
1715 
1716 # ifdef FEAT_MBYTE
1717     if (rest != NULL)
1718     {
1719 	/* Use remainder of previous call, starts with an invalid character
1720 	 * that may become valid when reading more. */
1721 	if (restlen > INBUFLEN - inbufcount)
1722 	    unconverted = INBUFLEN - inbufcount;
1723 	else
1724 	    unconverted = restlen;
1725 	mch_memmove(inbuf + inbufcount, rest, unconverted);
1726 	if (unconverted == restlen)
1727 	{
1728 	    vim_free(rest);
1729 	    rest = NULL;
1730 	}
1731 	else
1732 	{
1733 	    restlen -= unconverted;
1734 	    mch_memmove(rest, rest + unconverted, restlen);
1735 	}
1736 	inbufcount += unconverted;
1737     }
1738     else
1739 	unconverted = 0;
1740 #endif
1741 
1742     len = 0;	/* to avoid gcc warning */
1743     for (try = 0; try < 100; ++try)
1744     {
1745 #  ifdef VMS
1746 	len = vms_read(
1747 #  else
1748 	len = read(read_cmd_fd,
1749 #  endif
1750 	    (char *)inbuf + inbufcount, (size_t)((INBUFLEN - inbufcount)
1751 #  ifdef FEAT_MBYTE
1752 		/ input_conv.vc_factor
1753 #  endif
1754 		));
1755 #  if 0
1756 		)	/* avoid syntax highlight error */
1757 #  endif
1758 	if (len > 0 || got_int)
1759 	    break;
1760 	/*
1761 	 * If reading stdin results in an error, continue reading stderr.
1762 	 * This helps when using "foo | xargs vim".
1763 	 */
1764 	if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
1765 	{
1766 	    int m = cur_tmode;
1767 
1768 	    /* We probably set the wrong file descriptor to raw mode.  Switch
1769 	     * back to cooked mode, use another descriptor and set the mode to
1770 	     * what it was. */
1771 	    settmode(TMODE_COOK);
1772 #ifdef HAVE_DUP
1773 	    /* Use stderr for stdin, also works for shell commands. */
1774 	    close(0);
1775 	    dup(2);
1776 #else
1777 	    read_cmd_fd = 2;	/* read from stderr instead of stdin */
1778 #endif
1779 	    settmode(m);
1780 	}
1781 	if (!exit_on_error)
1782 	    return;
1783     }
1784 # endif
1785     if (len <= 0 && !got_int)
1786 	read_error_exit();
1787     if (len > 0)
1788 	did_read_something = TRUE;
1789     if (got_int)
1790     {
1791 	/* Interrupted, pretend a CTRL-C was typed. */
1792 	inbuf[0] = 3;
1793 	inbufcount = 1;
1794     }
1795     else
1796     {
1797 # ifdef FEAT_MBYTE
1798 	/*
1799 	 * May perform conversion on the input characters.
1800 	 * Include the unconverted rest of the previous call.
1801 	 * If there is an incomplete char at the end it is kept for the next
1802 	 * time, reading more bytes should make conversion possible.
1803 	 * Don't do this in the unlikely event that the input buffer is too
1804 	 * small ("rest" still contains more bytes).
1805 	 */
1806 	if (input_conv.vc_type != CONV_NONE)
1807 	{
1808 	    inbufcount -= unconverted;
1809 	    len = convert_input_safe(inbuf + inbufcount,
1810 				     len + unconverted, INBUFLEN - inbufcount,
1811 				       rest == NULL ? &rest : NULL, &restlen);
1812 	}
1813 # endif
1814 	while (len-- > 0)
1815 	{
1816 	    /*
1817 	     * if a CTRL-C was typed, remove it from the buffer and set got_int
1818 	     */
1819 	    if (inbuf[inbufcount] == 3 && ctrl_c_interrupts)
1820 	    {
1821 		/* remove everything typed before the CTRL-C */
1822 		mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
1823 		inbufcount = 0;
1824 		got_int = TRUE;
1825 	    }
1826 	    ++inbufcount;
1827 	}
1828     }
1829 #endif /* UNIX or OS2 or VMS*/
1830 }
1831 #endif /* defined(UNIX) || defined(FEAT_GUI) || defined(OS2)  || defined(VMS) */
1832 
1833 /*
1834  * Exit because of an input read error.
1835  */
1836     void
1837 read_error_exit()
1838 {
1839     if (silent_mode)	/* Normal way to exit for "ex -s" */
1840 	getout(0);
1841     STRCPY(IObuff, _("Vim: Error reading input, exiting...\n"));
1842     preserve_exit();
1843 }
1844 
1845 #if defined(CURSOR_SHAPE) || defined(PROTO)
1846 /*
1847  * May update the shape of the cursor.
1848  */
1849     void
1850 ui_cursor_shape()
1851 {
1852 # ifdef FEAT_GUI
1853     if (gui.in_use)
1854 	gui_update_cursor_later();
1855 # endif
1856 # ifdef MCH_CURSOR_SHAPE
1857     mch_update_cursor();
1858 # endif
1859 }
1860 #endif
1861 
1862 #if defined(FEAT_CLIPBOARD) || defined(FEAT_GUI) || defined(FEAT_RIGHTLEFT) \
1863 	|| defined(PROTO)
1864 /*
1865  * Check bounds for column number
1866  */
1867     int
1868 check_col(col)
1869     int	    col;
1870 {
1871     if (col < 0)
1872 	return 0;
1873     if (col >= (int)screen_Columns)
1874 	return (int)screen_Columns - 1;
1875     return col;
1876 }
1877 
1878 /*
1879  * Check bounds for row number
1880  */
1881     int
1882 check_row(row)
1883     int	    row;
1884 {
1885     if (row < 0)
1886 	return 0;
1887     if (row >= (int)screen_Rows)
1888 	return (int)screen_Rows - 1;
1889     return row;
1890 }
1891 #endif
1892 
1893 /*
1894  * Stuff for the X clipboard.  Shared between VMS and Unix.
1895  */
1896 
1897 #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(PROTO)
1898 # include <X11/Xatom.h>
1899 # include <X11/Intrinsic.h>
1900 
1901 /*
1902  * Open the application context (if it hasn't been opened yet).
1903  * Used for Motif and Athena GUI and the xterm clipboard.
1904  */
1905     void
1906 open_app_context()
1907 {
1908     if (app_context == NULL)
1909     {
1910 	XtToolkitInitialize();
1911 	app_context = XtCreateApplicationContext();
1912     }
1913 }
1914 
1915 static Atom	vim_atom;	/* Vim's own special selection format */
1916 #ifdef FEAT_MBYTE
1917 static Atom	vimenc_atom;	/* Vim's extended selection format */
1918 #endif
1919 static Atom	compound_text_atom;
1920 static Atom	text_atom;
1921 static Atom	targets_atom;
1922 
1923     void
1924 x11_setup_atoms(dpy)
1925     Display	*dpy;
1926 {
1927     vim_atom	       = XInternAtom(dpy, VIM_ATOM_NAME,   False);
1928 #ifdef FEAT_MBYTE
1929     vimenc_atom	       = XInternAtom(dpy, VIMENC_ATOM_NAME,False);
1930 #endif
1931     compound_text_atom = XInternAtom(dpy, "COMPOUND_TEXT", False);
1932     text_atom	       = XInternAtom(dpy, "TEXT",	   False);
1933     targets_atom       = XInternAtom(dpy, "TARGETS",       False);
1934     clip_star.sel_atom = XA_PRIMARY;
1935     clip_plus.sel_atom = XInternAtom(dpy, "CLIPBOARD",     False);
1936 }
1937 
1938 /*
1939  * X Selection stuff, for cutting and pasting text to other windows.
1940  */
1941 
1942 static void  clip_x11_request_selection_cb __ARGS((Widget, XtPointer, Atom *, Atom *, XtPointer, long_u *, int *));
1943 
1944 /* ARGSUSED */
1945     static void
1946 clip_x11_request_selection_cb(w, success, sel_atom, type, value, length,
1947 			      format)
1948     Widget	w;
1949     XtPointer	success;
1950     Atom	*sel_atom;
1951     Atom	*type;
1952     XtPointer	value;
1953     long_u	*length;
1954     int		*format;
1955 {
1956     int		motion_type;
1957     long_u	len;
1958     char_u	*p;
1959     char	**text_list = NULL;
1960     VimClipboard	*cbd;
1961 #ifdef FEAT_MBYTE
1962     char_u	*tmpbuf = NULL;
1963 #endif
1964 
1965     if (*sel_atom == clip_plus.sel_atom)
1966 	cbd = &clip_plus;
1967     else
1968 	cbd = &clip_star;
1969 
1970     if (value == NULL || *length == 0)
1971     {
1972 	clip_free_selection(cbd);	/* ???  [what's the query?] */
1973 	*(int *)success = FALSE;
1974 	return;
1975     }
1976     motion_type = MCHAR;
1977     p = (char_u *)value;
1978     len = *length;
1979     if (*type == vim_atom)
1980     {
1981 	motion_type = *p++;
1982 	len--;
1983     }
1984 
1985 #ifdef FEAT_MBYTE
1986     else if (*type == vimenc_atom)
1987     {
1988 	char_u		*enc;
1989 	vimconv_T	conv;
1990 	int		convlen;
1991 
1992 	motion_type = *p++;
1993 	--len;
1994 
1995 	enc = p;
1996 	p += STRLEN(p) + 1;
1997 	len -= p - enc;
1998 
1999 	/* If the encoding of the text is different from 'encoding', attempt
2000 	 * converting it. */
2001 	conv.vc_type = CONV_NONE;
2002 	convert_setup(&conv, enc, p_enc);
2003 	if (conv.vc_type != CONV_NONE)
2004 	{
2005 	    convlen = len;	/* Need to use an int here. */
2006 	    tmpbuf = string_convert(&conv, p, &convlen);
2007 	    len = convlen;
2008 	    if (tmpbuf != NULL)
2009 		p = tmpbuf;
2010 	    convert_setup(&conv, NULL, NULL);
2011 	}
2012     }
2013 #endif
2014 
2015     else if (*type == compound_text_atom || (
2016 #ifdef FEAT_MBYTE
2017 		enc_dbcs != 0 &&
2018 #endif
2019 		*type == text_atom))
2020     {
2021 	XTextProperty	text_prop;
2022 	int		n_text = 0;
2023 	int		status;
2024 
2025 	text_prop.value = (unsigned char *)value;
2026 	text_prop.encoding = *type;
2027 	text_prop.format = *format;
2028 	text_prop.nitems = STRLEN(value);
2029 	status = XmbTextPropertyToTextList(X_DISPLAY, &text_prop,
2030 							 &text_list, &n_text);
2031 	if (status != Success || n_text < 1)
2032 	{
2033 	    *(int *)success = FALSE;
2034 	    return;
2035 	}
2036 	p = (char_u *)text_list[0];
2037 	len = STRLEN(p);
2038     }
2039     clip_yank_selection(motion_type, p, (long)len, cbd);
2040 
2041     if (text_list != NULL)
2042 	XFreeStringList(text_list);
2043 #ifdef FEAT_MBYTE
2044     vim_free(tmpbuf);
2045 #endif
2046     XtFree((char *)value);
2047     *(int *)success = TRUE;
2048 }
2049 
2050     void
2051 clip_x11_request_selection(myShell, dpy, cbd)
2052     Widget	myShell;
2053     Display	*dpy;
2054     VimClipboard	*cbd;
2055 {
2056     XEvent	event;
2057     Atom	type;
2058     static int	success;
2059     int		i;
2060     int		nbytes = 0;
2061     char_u	*buffer;
2062 
2063     for (i =
2064 #ifdef FEAT_MBYTE
2065 	    0
2066 #else
2067 	    1
2068 #endif
2069 	    ; i < 5; i++)
2070     {
2071 	switch (i)
2072 	{
2073 #ifdef FEAT_MBYTE
2074 	    case 0:  type = vimenc_atom;	break;
2075 #endif
2076 	    case 1:  type = vim_atom;		break;
2077 	    case 2:  type = compound_text_atom; break;
2078 	    case 3:  type = text_atom;		break;
2079 	    default: type = XA_STRING;
2080 	}
2081 	XtGetSelectionValue(myShell, cbd->sel_atom, type,
2082 	    clip_x11_request_selection_cb, (XtPointer)&success, CurrentTime);
2083 
2084 	/* Make sure the request for the selection goes out before waiting for
2085 	 * a response. */
2086 	XFlush(dpy);
2087 
2088 	/*
2089 	 * Wait for result of selection request, otherwise if we type more
2090 	 * characters, then they will appear before the one that requested the
2091 	 * paste!  Don't worry, we will catch up with any other events later.
2092 	 */
2093 	for (;;)
2094 	{
2095 	    if (XCheckTypedEvent(dpy, SelectionNotify, &event))
2096 		break;
2097 
2098 	    /* Do we need this?  Probably not. */
2099 	    XSync(dpy, False);
2100 
2101 	    /* Bernhard Walle solved a slow paste response in an X terminal by
2102 	     * adding: usleep(10000); here. */
2103 	}
2104 
2105 	/* this is where clip_x11_request_selection_cb() is actually called */
2106 	XtDispatchEvent(&event);
2107 
2108 	if (success)
2109 	    return;
2110     }
2111 
2112     /* Final fallback position - use the X CUT_BUFFER0 store */
2113     buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0);
2114     if (nbytes > 0)
2115     {
2116 	/* Got something */
2117 	clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd);
2118 	XFree((void *)buffer);
2119 	if (p_verbose > 0)
2120 	    smsg((char_u *)_("Used CUT_BUFFER0 instead of empty selection") );
2121     }
2122 }
2123 
2124 static Boolean	clip_x11_convert_selection_cb __ARGS((Widget, Atom *, Atom *, Atom *, XtPointer *, long_u *, int *));
2125 
2126 /* ARGSUSED */
2127     static Boolean
2128 clip_x11_convert_selection_cb(w, sel_atom, target, type, value, length, format)
2129     Widget	w;
2130     Atom	*sel_atom;
2131     Atom	*target;
2132     Atom	*type;
2133     XtPointer	*value;
2134     long_u	*length;
2135     int		*format;
2136 {
2137     char_u	*string;
2138     char_u	*result;
2139     int		motion_type;
2140     VimClipboard	*cbd;
2141     int		i;
2142 
2143     if (*sel_atom == clip_plus.sel_atom)
2144 	cbd = &clip_plus;
2145     else
2146 	cbd = &clip_star;
2147 
2148     if (!cbd->owned)
2149 	return False;	    /* Shouldn't ever happen */
2150 
2151     /* requestor wants to know what target types we support */
2152     if (*target == targets_atom)
2153     {
2154 	Atom *array;
2155 
2156 	if ((array = (Atom *)XtMalloc((unsigned)(sizeof(Atom) * 6))) == NULL)
2157 	    return False;
2158 	*value = (XtPointer)array;
2159 	i = 0;
2160 	array[i++] = XA_STRING;
2161 	array[i++] = targets_atom;
2162 #ifdef FEAT_MBYTE
2163 	array[i++] = vimenc_atom;
2164 #endif
2165 	array[i++] = vim_atom;
2166 	array[i++] = text_atom;
2167 	array[i++] = compound_text_atom;
2168 	*type = XA_ATOM;
2169 	/* This used to be: *format = sizeof(Atom) * 8; but that caused
2170 	 * crashes on 64 bit machines. (Peter Derr) */
2171 	*format = 32;
2172 	*length = i;
2173 	return True;
2174     }
2175 
2176     if (       *target != XA_STRING
2177 #ifdef FEAT_MBYTE
2178 	    && *target != vimenc_atom
2179 #endif
2180 	    && *target != vim_atom
2181 	    && *target != text_atom
2182 	    && *target != compound_text_atom)
2183 	return False;
2184 
2185     clip_get_selection(cbd);
2186     motion_type = clip_convert_selection(&string, length, cbd);
2187     if (motion_type < 0)
2188 	return False;
2189 
2190     /* For our own format, the first byte contains the motion type */
2191     if (*target == vim_atom)
2192 	(*length)++;
2193 
2194 #ifdef FEAT_MBYTE
2195     /* Our own format with encoding: motion 'encoding' NUL text */
2196     if (*target == vimenc_atom)
2197 	*length += STRLEN(p_enc) + 2;
2198 #endif
2199 
2200     *value = XtMalloc((Cardinal)*length);
2201     result = (char_u *)*value;
2202     if (result == NULL)
2203     {
2204 	vim_free(string);
2205 	return False;
2206     }
2207 
2208     if (*target == XA_STRING)
2209     {
2210 	mch_memmove(result, string, (size_t)(*length));
2211 	*type = XA_STRING;
2212     }
2213     else if (*target == compound_text_atom
2214 	    || *target == text_atom)
2215     {
2216 	XTextProperty	text_prop;
2217 	char		*string_nt = (char *)alloc((unsigned)*length + 1);
2218 
2219 	/* create NUL terminated string which XmbTextListToTextProperty wants */
2220 	mch_memmove(string_nt, string, (size_t)*length);
2221 	string_nt[*length] = NUL;
2222 	XmbTextListToTextProperty(X_DISPLAY, (char **)&string_nt, 1,
2223 					      XCompoundTextStyle, &text_prop);
2224 	vim_free(string_nt);
2225 	XtFree(*value);			/* replace with COMPOUND text */
2226 	*value = (XtPointer)(text_prop.value);	/*    from plain text */
2227 	*length = text_prop.nitems;
2228 	*type = compound_text_atom;
2229     }
2230 
2231 #ifdef FEAT_MBYTE
2232     else if (*target == vimenc_atom)
2233     {
2234 	int l = STRLEN(p_enc);
2235 
2236 	result[0] = motion_type;
2237 	STRCPY(result + 1, p_enc);
2238 	mch_memmove(result + l + 2, string, (size_t)(*length - l - 2));
2239 	*type = vimenc_atom;
2240     }
2241 #endif
2242 
2243     else
2244     {
2245 	result[0] = motion_type;
2246 	mch_memmove(result + 1, string, (size_t)(*length - 1));
2247 	*type = vim_atom;
2248     }
2249     *format = 8;	    /* 8 bits per char */
2250     vim_free(string);
2251     return True;
2252 }
2253 
2254 static void  clip_x11_lose_ownership_cb __ARGS((Widget, Atom *));
2255 
2256 /* ARGSUSED */
2257     static void
2258 clip_x11_lose_ownership_cb(w, sel_atom)
2259     Widget  w;
2260     Atom    *sel_atom;
2261 {
2262     if (*sel_atom == clip_plus.sel_atom)
2263 	clip_lose_selection(&clip_plus);
2264     else
2265 	clip_lose_selection(&clip_star);
2266 }
2267 
2268     void
2269 clip_x11_lose_selection(myShell, cbd)
2270     Widget	myShell;
2271     VimClipboard	*cbd;
2272 {
2273     XtDisownSelection(myShell, cbd->sel_atom, CurrentTime);
2274 }
2275 
2276     int
2277 clip_x11_own_selection(myShell, cbd)
2278     Widget	myShell;
2279     VimClipboard	*cbd;
2280 {
2281     if (XtOwnSelection(myShell, cbd->sel_atom, CurrentTime,
2282 	    clip_x11_convert_selection_cb, clip_x11_lose_ownership_cb,
2283 							       NULL) == False)
2284 	return FAIL;
2285     return OK;
2286 }
2287 
2288 /*
2289  * Send the current selection to the clipboard.  Do nothing for X because we
2290  * will fill in the selection only when requested by another app.
2291  */
2292 /*ARGSUSED*/
2293     void
2294 clip_x11_set_selection(cbd)
2295     VimClipboard *cbd;
2296 {
2297 }
2298 #endif
2299 
2300 #if defined(FEAT_MOUSE) || defined(PROTO)
2301 
2302 /*
2303  * Move the cursor to the specified row and column on the screen.
2304  * Change current window if neccesary.	Returns an integer with the
2305  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
2306  *
2307  * The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
2308  * The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
2309  *
2310  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
2311  * if the mouse is outside the window then the text will scroll, or if the
2312  * mouse was previously on a status line, then the status line may be dragged.
2313  *
2314  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
2315  * cursor is moved unless the cursor was on a status line.
2316  * This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
2317  * IN_SEP_LINE depending on where the cursor was clicked.
2318  *
2319  * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
2320  * the mouse is on the status line of the same window.
2321  *
2322  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
2323  * the last call.
2324  *
2325  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
2326  * remembered.
2327  */
2328     int
2329 jump_to_mouse(flags, inclusive, which_button)
2330     int		flags;
2331     int		*inclusive;	/* used for inclusive operator, can be NULL */
2332     int		which_button;	/* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */
2333 {
2334     static int	on_status_line = 0;	/* #lines below bottom of window */
2335 #ifdef FEAT_VERTSPLIT
2336     static int	on_sep_line = 0;	/* on separator right of window */
2337 #endif
2338     static int	prev_row = -1;
2339     static int	prev_col = -1;
2340     static win_T *dragwin = NULL;	/* window being dragged */
2341     static int	did_drag = FALSE;	/* drag was noticed */
2342 
2343     win_T	*wp, *old_curwin;
2344     pos_T	old_cursor;
2345     int		count;
2346     int		first;
2347     int		row = mouse_row;
2348     int		col = mouse_col;
2349 #ifdef FEAT_FOLDING
2350     int		mouse_char;
2351 #endif
2352 
2353     mouse_past_bottom = FALSE;
2354     mouse_past_eol = FALSE;
2355 
2356     if (flags & MOUSE_RELEASED)
2357     {
2358 	/* On button release we may change window focus if positioned on a
2359 	 * status line and no dragging happened. */
2360 	if (dragwin != NULL && !did_drag)
2361 	    flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
2362 	dragwin = NULL;
2363 	did_drag = FALSE;
2364     }
2365 
2366     if ((flags & MOUSE_DID_MOVE)
2367 	    && prev_row == mouse_row
2368 	    && prev_col == mouse_col)
2369     {
2370 retnomove:
2371 	/* before moving the cursor for a left click wich is NOT in a status
2372 	 * line, stop Visual mode */
2373 	if (on_status_line)
2374 	    return IN_STATUS_LINE;
2375 #ifdef FEAT_VERTSPLIT
2376 	if (on_sep_line)
2377 	    return IN_SEP_LINE;
2378 #endif
2379 #ifdef FEAT_VISUAL
2380 	if (flags & MOUSE_MAY_STOP_VIS)
2381 	{
2382 	    end_visual_mode();
2383 	    redraw_curbuf_later(INVERTED);	/* delete the inversion */
2384 	}
2385 #endif
2386 #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
2387 	/* Continue a modeless selection in another window. */
2388 	if (cmdwin_type != 0 && row < W_WINROW(curwin))
2389 	    return IN_OTHER_WIN;
2390 #endif
2391 	return IN_BUFFER;
2392     }
2393 
2394     prev_row = mouse_row;
2395     prev_col = mouse_col;
2396 
2397     if (flags & MOUSE_SETPOS)
2398 	goto retnomove;				/* ugly goto... */
2399 
2400 #ifdef FEAT_FOLDING
2401     /* Remember the character under the mouse, it might be a '-' or '+' in the
2402      * fold column. */
2403     if (row >= 0 && row < Rows && col >= 0 && col <= Columns)
2404 	mouse_char = ScreenLines[LineOffset[row] + col];
2405     else
2406 	mouse_char = ' ';
2407 #endif
2408 
2409     old_curwin = curwin;
2410     old_cursor = curwin->w_cursor;
2411 
2412     if (!(flags & MOUSE_FOCUS))
2413     {
2414 	if (row < 0 || col < 0)			/* check if it makes sense */
2415 	    return IN_UNKNOWN;
2416 
2417 #ifdef FEAT_WINDOWS
2418 	/* find the window where the row is in */
2419 	wp = mouse_find_win(&row, &col);
2420 #else
2421 	wp = firstwin;
2422 #endif
2423 	dragwin = NULL;
2424 	/*
2425 	 * winpos and height may change in win_enter()!
2426 	 */
2427 	if (row >= wp->w_height)		/* In (or below) status line */
2428 	{
2429 	    on_status_line = row - wp->w_height + 1;
2430 	    dragwin = wp;
2431 	}
2432 	else
2433 	    on_status_line = 0;
2434 #ifdef FEAT_VERTSPLIT
2435 	if (col >= wp->w_width)		/* In separator line */
2436 	{
2437 	    on_sep_line = col - wp->w_width + 1;
2438 	    dragwin = wp;
2439 	}
2440 	else
2441 	    on_sep_line = 0;
2442 
2443 	/* The rightmost character of the status line might be a vertical
2444 	 * separator character if there is no connecting window to the right. */
2445 	if (on_status_line && on_sep_line)
2446 	{
2447 	    if (stl_connected(wp))
2448 		on_sep_line = 0;
2449 	    else
2450 		on_status_line = 0;
2451 	}
2452 #endif
2453 
2454 #ifdef FEAT_VISUAL
2455 	/* Before jumping to another buffer, or moving the cursor for a left
2456 	 * click, stop Visual mode. */
2457 	if (VIsual_active
2458 		&& (wp->w_buffer != curwin->w_buffer
2459 		    || (!on_status_line
2460 # ifdef FEAT_VERTSPLIT
2461 			&& !on_sep_line
2462 # endif
2463 # ifdef FEAT_FOLDING
2464 			&& (
2465 #  ifdef FEAT_RIGHTLEFT
2466 			    wp->w_p_rl ? col < W_WIDTH(wp) - wp->w_p_fdc :
2467 #  endif
2468 			    col >= wp->w_p_fdc
2469 #  ifdef FEAT_CMDWIN
2470 				  + (cmdwin_type == 0 && wp == curwin ? 0 : 1)
2471 #  endif
2472 			    )
2473 # endif
2474 			&& (flags & MOUSE_MAY_STOP_VIS))))
2475 	{
2476 	    end_visual_mode();
2477 	    redraw_curbuf_later(INVERTED);	/* delete the inversion */
2478 	}
2479 #endif
2480 #ifdef FEAT_CMDWIN
2481 	if (cmdwin_type != 0 && wp != curwin)
2482 	{
2483 	    /* A click outside the command-line window: Use modeless
2484 	     * selection if possible.  Allow dragging the status line of
2485 	     * windows just above the command-line window. */
2486 	    if (wp->w_winrow + wp->w_height
2487 		       != curwin->w_prev->w_winrow + curwin->w_prev->w_height)
2488 	    {
2489 		on_status_line = 0;
2490 		dragwin = NULL;
2491 	    }
2492 # ifdef FEAT_VERTSPLIT
2493 	    on_sep_line = 0;
2494 # endif
2495 # ifdef FEAT_CLIPBOARD
2496 	    if (on_status_line)
2497 		return IN_STATUS_LINE;
2498 	    return IN_OTHER_WIN;
2499 # else
2500 	    row = 0;
2501 	    col += wp->w_wincol;
2502 	    wp = curwin;
2503 # endif
2504 	}
2505 #endif
2506 #ifdef FEAT_WINDOWS
2507 	/* Only change window focus when not clicking on or dragging the
2508 	 * status line.  Do change focus when releasing the mouse button
2509 	 * (MOUSE_FOCUS was set above if we dragged first). */
2510 	if (dragwin == NULL || (flags & MOUSE_RELEASED))
2511 	    win_enter(wp, TRUE);		/* can make wp invalid! */
2512 # ifdef CHECK_DOUBLE_CLICK
2513 	/* set topline, to be able to check for double click ourselves */
2514 	if (curwin != old_curwin)
2515 	    set_mouse_topline(curwin);
2516 # endif
2517 #endif
2518 	if (on_status_line)			/* In (or below) status line */
2519 	{
2520 	    /* Don't use start_arrow() if we're in the same window */
2521 	    if (curwin == old_curwin)
2522 		return IN_STATUS_LINE;
2523 	    else
2524 		return IN_STATUS_LINE | CURSOR_MOVED;
2525 	}
2526 #ifdef FEAT_VERTSPLIT
2527 	if (on_sep_line)			/* In (or below) status line */
2528 	{
2529 	    /* Don't use start_arrow() if we're in the same window */
2530 	    if (curwin == old_curwin)
2531 		return IN_SEP_LINE;
2532 	    else
2533 		return IN_SEP_LINE | CURSOR_MOVED;
2534 	}
2535 #endif
2536 
2537 	curwin->w_cursor.lnum = curwin->w_topline;
2538 #ifdef FEAT_GUI
2539 	/* remember topline, needed for double click */
2540 	gui_prev_topline = curwin->w_topline;
2541 # ifdef FEAT_DIFF
2542 	gui_prev_topfill = curwin->w_topfill;
2543 # endif
2544 #endif
2545     }
2546     else if (on_status_line && which_button == MOUSE_LEFT)
2547     {
2548 #ifdef FEAT_WINDOWS
2549 	if (dragwin != NULL)
2550 	{
2551 	    /* Drag the status line */
2552 	    count = row - dragwin->w_winrow - dragwin->w_height + 1
2553 							     - on_status_line;
2554 	    win_drag_status_line(dragwin, count);
2555 	    did_drag |= count;
2556 	}
2557 #endif
2558 	return IN_STATUS_LINE;			/* Cursor didn't move */
2559     }
2560 #ifdef FEAT_VERTSPLIT
2561     else if (on_sep_line && which_button == MOUSE_LEFT)
2562     {
2563 	if (dragwin != NULL)
2564 	{
2565 	    /* Drag the separator column */
2566 	    count = col - dragwin->w_wincol - dragwin->w_width + 1
2567 								- on_sep_line;
2568 	    win_drag_vsep_line(dragwin, count);
2569 	    did_drag |= count;
2570 	}
2571 	return IN_SEP_LINE;			/* Cursor didn't move */
2572     }
2573 #endif
2574     else /* keep_window_focus must be TRUE */
2575     {
2576 #ifdef FEAT_VISUAL
2577 	/* before moving the cursor for a left click, stop Visual mode */
2578 	if (flags & MOUSE_MAY_STOP_VIS)
2579 	{
2580 	    end_visual_mode();
2581 	    redraw_curbuf_later(INVERTED);	/* delete the inversion */
2582 	}
2583 #endif
2584 
2585 #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD)
2586 	/* Continue a modeless selection in another window. */
2587 	if (cmdwin_type != 0 && row < W_WINROW(curwin))
2588 	    return IN_OTHER_WIN;
2589 #endif
2590 
2591 	row -= W_WINROW(curwin);
2592 #ifdef FEAT_VERTSPLIT
2593 	col -= W_WINCOL(curwin);
2594 #endif
2595 
2596 	/*
2597 	 * When clicking beyond the end of the window, scroll the screen.
2598 	 * Scroll by however many rows outside the window we are.
2599 	 */
2600 	if (row < 0)
2601 	{
2602 	    count = 0;
2603 	    for (first = TRUE; curwin->w_topline > 1; )
2604 	    {
2605 #ifdef FEAT_DIFF
2606 		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
2607 		    ++count;
2608 		else
2609 #endif
2610 		    count += plines(curwin->w_topline - 1);
2611 		if (!first && count > -row)
2612 		    break;
2613 		first = FALSE;
2614 #ifdef FEAT_FOLDING
2615 		hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
2616 #endif
2617 #ifdef FEAT_DIFF
2618 		if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
2619 		    ++curwin->w_topfill;
2620 		else
2621 #endif
2622 		{
2623 		    --curwin->w_topline;
2624 #ifdef FEAT_DIFF
2625 		    curwin->w_topfill = 0;
2626 #endif
2627 		}
2628 	    }
2629 #ifdef FEAT_DIFF
2630 	    check_topfill(curwin, FALSE);
2631 #endif
2632 	    curwin->w_valid &=
2633 		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2634 	    redraw_later(VALID);
2635 	    row = 0;
2636 	}
2637 	else if (row >= curwin->w_height)
2638 	{
2639 	    count = 0;
2640 	    for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count; )
2641 	    {
2642 #ifdef FEAT_DIFF
2643 		if (curwin->w_topfill > 0)
2644 		    ++count;
2645 		else
2646 #endif
2647 		    count += plines(curwin->w_topline);
2648 		if (!first && count > row - curwin->w_height + 1)
2649 		    break;
2650 		first = FALSE;
2651 #ifdef FEAT_FOLDING
2652 		if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
2653 			&& curwin->w_topline == curbuf->b_ml.ml_line_count)
2654 		    break;
2655 #endif
2656 #ifdef FEAT_DIFF
2657 		if (curwin->w_topfill > 0)
2658 		    --curwin->w_topfill;
2659 		else
2660 #endif
2661 		{
2662 		    ++curwin->w_topline;
2663 #ifdef FEAT_DIFF
2664 		    curwin->w_topfill =
2665 				   diff_check_fill(curwin, curwin->w_topline);
2666 #endif
2667 		}
2668 	    }
2669 #ifdef FEAT_DIFF
2670 	    check_topfill(curwin, FALSE);
2671 #endif
2672 	    redraw_later(VALID);
2673 	    curwin->w_valid &=
2674 		      ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
2675 	    row = curwin->w_height - 1;
2676 	}
2677 	else if (row == 0)
2678 	{
2679 	    /* When dragging the mouse, while the text has been scrolled up as
2680 	     * far as it goes, moving the mouse in the top line should scroll
2681 	     * the text down (done later when recomputing w_topline). */
2682 	    if (mouse_dragging
2683 		    && curwin->w_cursor.lnum
2684 				       == curwin->w_buffer->b_ml.ml_line_count
2685 		    && curwin->w_cursor.lnum == curwin->w_topline)
2686 		curwin->w_valid &= ~(VALID_TOPLINE);
2687 	}
2688     }
2689 
2690 #ifdef FEAT_FOLDING
2691     /* Check for position outside of the fold column. */
2692     if (
2693 # ifdef FEAT_RIGHTLEFT
2694 	    curwin->w_p_rl ? col < W_WIDTH(curwin) - curwin->w_p_fdc :
2695 # endif
2696 	    col >= curwin->w_p_fdc
2697 #  ifdef FEAT_CMDWIN
2698 				+ (cmdwin_type == 0 ? 0 : 1)
2699 #  endif
2700        )
2701 	mouse_char = ' ';
2702 #endif
2703 
2704     /* compute the position in the buffer line from the posn on the screen */
2705     if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum))
2706 	mouse_past_bottom = TRUE;
2707 
2708 #ifdef FEAT_VISUAL
2709     /* Start Visual mode before coladvance(), for when 'sel' != "old" */
2710     if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
2711     {
2712 	check_visual_highlight();
2713 	VIsual = old_cursor;
2714 	VIsual_active = TRUE;
2715 	VIsual_reselect = TRUE;
2716 	/* if 'selectmode' contains "mouse", start Select mode */
2717 	may_start_select('o');
2718 	setmouse();
2719 	if (p_smd)
2720 	    redraw_cmdline = TRUE;	/* show visual mode later */
2721     }
2722 #endif
2723 
2724     curwin->w_curswant = col;
2725     curwin->w_set_curswant = FALSE;	/* May still have been TRUE */
2726     if (coladvance(col) == FAIL)	/* Mouse click beyond end of line */
2727     {
2728 	if (inclusive != NULL)
2729 	    *inclusive = TRUE;
2730 	mouse_past_eol = TRUE;
2731     }
2732     else if (inclusive != NULL)
2733 	*inclusive = FALSE;
2734 
2735     count = IN_BUFFER;
2736     if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
2737 	    || curwin->w_cursor.col != old_cursor.col)
2738 	count |= CURSOR_MOVED;		/* Cursor has moved */
2739 
2740 #ifdef FEAT_FOLDING
2741     if (mouse_char == '+')
2742 	count |= MOUSE_FOLD_OPEN;
2743     else if (mouse_char != ' ')
2744 	count |= MOUSE_FOLD_CLOSE;
2745 #endif
2746 
2747     return count;
2748 }
2749 
2750 /*
2751  * Compute the position in the buffer line from the posn on the screen in
2752  * window "win".
2753  * Returns TRUE if the position is below the last line.
2754  */
2755     int
2756 mouse_comp_pos(win, rowp, colp, lnump)
2757     win_T	*win;
2758     int		*rowp;
2759     int		*colp;
2760     linenr_T	*lnump;
2761 {
2762     int		col = *colp;
2763     int		row = *rowp;
2764     linenr_T	lnum;
2765     int		retval = FALSE;
2766     int		off;
2767     int		count;
2768 
2769 #ifdef FEAT_RIGHTLEFT
2770     if (win->w_p_rl)
2771 	col = W_WIDTH(win) - 1 - col;
2772 #endif
2773 
2774     lnum = win->w_topline;
2775 
2776     while (row > 0)
2777     {
2778 #ifdef FEAT_DIFF
2779 	/* Don't include filler lines in "count" */
2780 	if (win->w_p_diff && !hasFoldingWin(win, lnum, NULL, NULL, TRUE, NULL))
2781 	{
2782 	    if (lnum == win->w_topline)
2783 		row -= win->w_topfill;
2784 	    else
2785 		row -= diff_check_fill(win, lnum);
2786 	    count = plines_win_nofill(win, lnum, TRUE);
2787 	}
2788 	else
2789 #endif
2790 	    count = plines_win(win, lnum, TRUE);
2791 	if (count > row)
2792 	    break;	/* Position is in this buffer line. */
2793 #ifdef FEAT_FOLDING
2794 	(void)hasFoldingWin(win, lnum, NULL, &lnum, TRUE, NULL);
2795 #endif
2796 	if (lnum == win->w_buffer->b_ml.ml_line_count)
2797 	{
2798 	    retval = TRUE;
2799 	    break;		/* past end of file */
2800 	}
2801 	row -= count;
2802 	++lnum;
2803     }
2804 
2805     if (!retval)
2806     {
2807 	/* Compute the column without wrapping. */
2808 	off = win_col_off(win) - win_col_off2(win);
2809 	if (col < off)
2810 	    col = off;
2811 	col += row * (W_WIDTH(win) - off);
2812 	/* add skip column (for long wrapping line) */
2813 	col += win->w_skipcol;
2814     }
2815 
2816     if (!win->w_p_wrap)
2817 	col += win->w_leftcol;
2818 
2819     /* skip line number and fold column in front of the line */
2820     col -= win_col_off(win);
2821     if (col < 0)
2822     {
2823 #ifdef FEAT_NETBEANS_INTG
2824 	if (usingNetbeans)
2825 	    netbeans_gutter_click(lnum);
2826 #endif
2827 	col = 0;
2828     }
2829 
2830     *colp = col;
2831     *rowp = row;
2832     *lnump = lnum;
2833     return retval;
2834 }
2835 
2836 #if defined(FEAT_WINDOWS) || defined(PROTO)
2837 /*
2838  * Find the window at screen position "*rowp" and "*colp".  The positions are
2839  * updated to become relative to the top-left of the window.
2840  */
2841 /*ARGSUSED*/
2842     win_T *
2843 mouse_find_win(rowp, colp)
2844     int		*rowp;
2845     int		*colp;
2846 {
2847     frame_T	*fp;
2848 
2849     fp = topframe;
2850     for (;;)
2851     {
2852 	if (fp->fr_layout == FR_LEAF)
2853 	    break;
2854 #ifdef FEAT_VERTSPLIT
2855 	if (fp->fr_layout == FR_ROW)
2856 	{
2857 	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
2858 	    {
2859 		if (*colp < fp->fr_width)
2860 		    break;
2861 		*colp -= fp->fr_width;
2862 	    }
2863 	}
2864 #endif
2865 	else    /* fr_layout == FR_COL */
2866 	{
2867 	    for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
2868 	    {
2869 		if (*rowp < fp->fr_height)
2870 		    break;
2871 		*rowp -= fp->fr_height;
2872 	    }
2873 	}
2874     }
2875     return fp->fr_win;
2876 }
2877 #endif
2878 
2879 #if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_GTK) || defined (FEAT_GUI_MAC) || defined (FEAT_GUI_KDE) \
2880 	|| defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) \
2881 	|| defined(FEAT_GUI_PHOTON) || defined(PROTO)
2882 /*
2883  * Translate window coordinates to buffer position without any side effects
2884  */
2885     int
2886 get_fpos_of_mouse(mpos)
2887     pos_T	*mpos;
2888 {
2889     win_T	*wp;
2890     int		row = mouse_row;
2891     int		col = mouse_col;
2892 
2893     if (row < 0 || col < 0)		/* check if it makes sense */
2894 	return IN_UNKNOWN;
2895 
2896 #ifdef FEAT_WINDOWS
2897     /* find the window where the row is in */
2898     wp = mouse_find_win(&row, &col);
2899 #else
2900     wp = firstwin;
2901 #endif
2902     /*
2903      * winpos and height may change in win_enter()!
2904      */
2905     if (row >= wp->w_height)	/* In (or below) status line */
2906 	return IN_STATUS_LINE;
2907 #ifdef FEAT_VERTSPLIT
2908     if (col >= wp->w_width)	/* In vertical separator line */
2909 	return IN_SEP_LINE;
2910 #endif
2911 
2912     if (wp != curwin)
2913 	return IN_UNKNOWN;
2914 
2915     /* compute the position in the buffer line from the posn on the screen */
2916     if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum))
2917 	return IN_STATUS_LINE; /* past bottom */
2918 
2919     mpos->col = vcol2col(wp, mpos->lnum, col);
2920 
2921     if (mpos->col > 0)
2922 	--mpos->col;
2923     return IN_BUFFER;
2924 }
2925 
2926 /*
2927  * Convert a virtual (screen) column to a character column.
2928  * The first column is one.
2929  */
2930     int
2931 vcol2col(wp, lnum, vcol)
2932     win_T	*wp;
2933     linenr_T	lnum;
2934     int		vcol;
2935 {
2936     /* try to advance to the specified column */
2937     int		col = 0;
2938     int		count = 0;
2939     char_u	*ptr;
2940 
2941     ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
2942     while (count <= vcol && *ptr != NUL)
2943     {
2944 	++col;
2945 	count += win_lbr_chartabsize(wp, ptr, count, NULL);
2946 # ifdef FEAT_MBYTE
2947 	if (has_mbyte)
2948 	    ptr += (*mb_ptr2len_check)(ptr);
2949 	else
2950 # endif
2951 	    ++ptr;
2952     }
2953     return col;
2954 }
2955 #endif
2956 
2957 #endif /* FEAT_MOUSE */
2958 
2959 #if defined(FEAT_GUI) || defined(WIN3264) || defined(PROTO)
2960 /*
2961  * Called when focus changed.  Used for the GUI or for systems where this can
2962  * be done in the console (Win32).
2963  */
2964     void
2965 ui_focus_change(in_focus)
2966     int		in_focus;	/* TRUE if focus gained. */
2967 {
2968     static time_t	last_time = (time_t)0;
2969     int			need_redraw = FALSE;
2970 
2971     /* When activated: Check if any file was modified outside of Vim.
2972      * Only do this when not done within the last two seconds (could get
2973      * several events in a row). */
2974     if (in_focus && last_time + 2 < time(NULL))
2975     {
2976 	need_redraw = check_timestamps(
2977 # ifdef FEAT_GUI
2978 		gui.in_use
2979 # else
2980 		FALSE
2981 # endif
2982 		);
2983 	last_time = time(NULL);
2984     }
2985 
2986 #ifdef FEAT_AUTOCMD
2987     /*
2988      * Fire the focus gained/lost autocommand.
2989      */
2990     need_redraw |= apply_autocmds(in_focus ? EVENT_FOCUSGAINED
2991 				: EVENT_FOCUSLOST, NULL, NULL, FALSE, curbuf);
2992 #endif
2993 
2994     if (need_redraw)
2995     {
2996 	/* Something was executed, make sure the cursor is put back where it
2997 	 * belongs. */
2998 	need_wait_return = FALSE;
2999 
3000 	if (State & CMDLINE)
3001 	    redrawcmdline();
3002 	else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE
3003 		|| State == EXTERNCMD || State == CONFIRM || exmode_active)
3004 	    repeat_message();
3005 	else if ((State & NORMAL) || (State & INSERT))
3006 	{
3007 	    if (must_redraw != 0)
3008 		update_screen(0);
3009 	    setcursor();
3010 	}
3011 	cursor_on();	    /* redrawing may have switched it off */
3012 	out_flush();
3013 # ifdef FEAT_GUI
3014 	if (gui.in_use)
3015 	{
3016 	    gui_update_cursor(FALSE, TRUE);
3017 	    gui_update_scrollbars(FALSE);
3018 	}
3019 # endif
3020     }
3021 #ifdef FEAT_TITLE
3022     /* File may have been changed from 'readonly' to 'noreadonly' */
3023     if (need_maketitle)
3024 	maketitle();
3025 #endif
3026 }
3027 #endif
3028 
3029 #if defined(USE_IM_CONTROL) || defined(PROTO)
3030 /*
3031  * Save current Input Method status to specified place.
3032  */
3033     void
3034 im_save_status(psave)
3035     long *psave;
3036 {
3037     /* Don't save when 'imdisable' is set or "xic" is NULL, IM is always
3038      * disabled then (but might start later).
3039      * Also don't save when inside a mapping, vgetc_im_active has not been set
3040      * then.
3041      * And don't save when the keys were stuffed (e.g., for a "." command).
3042      * And don't save when the GUI is running but our window doesn't have
3043      * input focus (e.g., when a find dialog is open). */
3044     if (!p_imdisable && KeyTyped && !KeyStuffed
3045 # ifdef FEAT_XIM
3046 	    && xic != NULL
3047 # endif
3048 # ifdef FEAT_GUI
3049 	    && (!gui.in_use || gui.in_focus)
3050 # endif
3051 	)
3052     {
3053 	/* Do save when IM is on, or IM is off and saved status is on. */
3054 	if (vgetc_im_active)
3055 	    *psave = B_IMODE_IM;
3056 	else if (*psave == B_IMODE_IM)
3057 	    *psave = B_IMODE_NONE;
3058     }
3059 }
3060 #endif
3061