xref: /vim-8.2.3635/src/gui.c (revision 2e693a88)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved		by Bram Moolenaar
4  *				GUI/Motif support by Robert Webb
5  *
6  * Do ":help uganda"  in Vim to read copying and usage conditions.
7  * Do ":help credits" in Vim to see a list of people who contributed.
8  * See README.txt for an overview of the Vim source code.
9  */
10 
11 #include "vim.h"
12 
13 /* Structure containing all the GUI information */
14 gui_T gui;
15 
16 #if !defined(FEAT_GUI_GTK)
17 static void set_guifontwide(char_u *font_name);
18 #endif
19 static void gui_check_pos(void);
20 static void gui_reset_scroll_region(void);
21 static void gui_outstr(char_u *, int);
22 static int gui_screenchar(int off, int flags, guicolor_T fg, guicolor_T bg, int back);
23 static int gui_outstr_nowrap(char_u *s, int len, int flags, guicolor_T fg, guicolor_T bg, int back);
24 static void gui_delete_lines(int row, int count);
25 static void gui_insert_lines(int row, int count);
26 static int gui_xy2colrow(int x, int y, int *colp);
27 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
28 static int gui_has_tabline(void);
29 #endif
30 static void gui_do_scrollbar(win_T *wp, int which, int enable);
31 static void gui_update_horiz_scrollbar(int);
32 static void gui_set_fg_color(char_u *name);
33 static void gui_set_bg_color(char_u *name);
34 static win_T *xy2win(int x, int y);
35 
36 #ifdef GUI_MAY_FORK
37 static void gui_do_fork(void);
38 
39 static int gui_read_child_pipe(int fd);
40 
41 /* Return values for gui_read_child_pipe */
42 enum {
43     GUI_CHILD_IO_ERROR,
44     GUI_CHILD_OK,
45     GUI_CHILD_FAILED
46 };
47 #endif
48 
49 static void gui_attempt_start(void);
50 
51 static int can_update_cursor = TRUE; /* can display the cursor */
52 static int disable_flush = 0;	/* If > 0, gui_mch_flush() is disabled. */
53 
54 /*
55  * The Athena scrollbars can move the thumb to after the end of the scrollbar,
56  * this makes the thumb indicate the part of the text that is shown.  Motif
57  * can't do this.
58  */
59 #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MAC)
60 # define SCROLL_PAST_END
61 #endif
62 
63 /*
64  * gui_start -- Called when user wants to start the GUI.
65  *
66  * Careful: This function can be called recursively when there is a ":gui"
67  * command in the .gvimrc file.  Only the first call should fork, not the
68  * recursive call.
69  */
70     void
71 gui_start(char_u *arg UNUSED)
72 {
73     char_u	*old_term;
74     static int	recursive = 0;
75 #if defined(GUI_MAY_SPAWN) && defined(EXPERIMENTAL_GUI_CMD)
76     char	*msg = NULL;
77 #endif
78 
79     old_term = vim_strsave(T_NAME);
80 
81     settmode(TMODE_COOK);		/* stop RAW mode */
82     if (full_screen)
83 	cursor_on();			/* needed for ":gui" in .vimrc */
84     full_screen = FALSE;
85 
86     ++recursive;
87 
88 #ifdef GUI_MAY_FORK
89     /*
90      * Quit the current process and continue in the child.
91      * Makes "gvim file" disconnect from the shell it was started in.
92      * Don't do this when Vim was started with "-f" or the 'f' flag is present
93      * in 'guioptions'.
94      * Don't do this when there is a running job, we can only get the status
95      * of a child from the parent.
96      */
97     if (gui.dofork && !vim_strchr(p_go, GO_FORG) && recursive <= 1
98 # ifdef FEAT_JOB_CHANNEL
99 	    && !job_any_running()
100 # endif
101 	    )
102     {
103 	gui_do_fork();
104     }
105     else
106 #endif
107 #ifdef GUI_MAY_SPAWN
108     if (gui.dospawn
109 # ifdef EXPERIMENTAL_GUI_CMD
110 	    && gui.dofork
111 # endif
112 	    && !vim_strchr(p_go, GO_FORG)
113 	    && !anyBufIsChanged()
114 # ifdef FEAT_JOB_CHANNEL
115 	    && !job_any_running()
116 # endif
117 	    )
118     {
119 # ifdef EXPERIMENTAL_GUI_CMD
120 	msg =
121 # endif
122 	    gui_mch_do_spawn(arg);
123     }
124     else
125 #endif
126     {
127 #ifdef FEAT_GUI_GTK
128 	/* If there is 'f' in 'guioptions' and specify -g argument,
129 	 * gui_mch_init_check() was not called yet.  */
130 	if (gui_mch_init_check() != OK)
131 	    getout_preserve_modified(1);
132 #endif
133 	gui_attempt_start();
134     }
135 
136     if (!gui.in_use)			/* failed to start GUI */
137     {
138 	/* Back to old term settings
139 	 *
140 	 * FIXME: If we got here because a child process failed and flagged to
141 	 * the parent to resume, and X11 is enabled with FEAT_TITLE, this will
142 	 * hit an X11 I/O error and do a longjmp(), leaving recursive
143 	 * permanently set to 1. This is probably not as big a problem as it
144 	 * sounds, because gui_mch_init() in both gui_x11.c and gui_gtk_x11.c
145 	 * return "OK" unconditionally, so it would be very difficult to
146 	 * actually hit this case.
147 	 */
148 	termcapinit(old_term);
149 	settmode(TMODE_RAW);		/* restart RAW mode */
150 #ifdef FEAT_TITLE
151 	set_title_defaults();		/* set 'title' and 'icon' again */
152 #endif
153 #if defined(GUI_MAY_SPAWN) && defined(EXPERIMENTAL_GUI_CMD)
154 	if (msg)
155 	    emsg(msg);
156 #endif
157     }
158 
159     vim_free(old_term);
160 
161     /* If the GUI started successfully, trigger the GUIEnter event, otherwise
162      * the GUIFailed event. */
163     gui_mch_update();
164     apply_autocmds(gui.in_use ? EVENT_GUIENTER : EVENT_GUIFAILED,
165 						   NULL, NULL, FALSE, curbuf);
166     --recursive;
167 }
168 
169 /*
170  * Set_termname() will call gui_init() to start the GUI.
171  * Set the "starting" flag, to indicate that the GUI will start.
172  *
173  * We don't want to open the GUI shell until after we've read .gvimrc,
174  * otherwise we don't know what font we will use, and hence we don't know
175  * what size the shell should be.  So if there are errors in the .gvimrc
176  * file, they will have to go to the terminal: Set full_screen to FALSE.
177  * full_screen will be set to TRUE again by a successful termcapinit().
178  */
179     static void
180 gui_attempt_start(void)
181 {
182     static int recursive = 0;
183 
184     ++recursive;
185     gui.starting = TRUE;
186 
187 #ifdef FEAT_GUI_GTK
188     gui.event_time = GDK_CURRENT_TIME;
189 #endif
190 
191     termcapinit((char_u *)"builtin_gui");
192     gui.starting = recursive - 1;
193 
194 #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
195     if (gui.in_use)
196     {
197 # ifdef FEAT_EVAL
198 	Window	x11_window;
199 	Display	*x11_display;
200 
201 	if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
202 	    set_vim_var_nr(VV_WINDOWID, (long)x11_window);
203 # endif
204 
205 	/* Display error messages in a dialog now. */
206 	display_errors();
207     }
208 #endif
209     --recursive;
210 }
211 
212 #ifdef GUI_MAY_FORK
213 
214 /* for waitpid() */
215 # if defined(HAVE_SYS_WAIT_H) || defined(HAVE_UNION_WAIT)
216 #  include <sys/wait.h>
217 # endif
218 
219 /*
220  * Create a new process, by forking. In the child, start the GUI, and in
221  * the parent, exit.
222  *
223  * If something goes wrong, this will return with gui.in_use still set
224  * to FALSE, in which case the caller should continue execution without
225  * the GUI.
226  *
227  * If the child fails to start the GUI, then the child will exit and the
228  * parent will return. If the child succeeds, then the parent will exit
229  * and the child will return.
230  */
231     static void
232 gui_do_fork(void)
233 {
234     int		pipefd[2];	/* pipe between parent and child */
235     int		pipe_error;
236     int		status;
237     int		exit_status;
238     pid_t	pid = -1;
239 
240     /* Setup a pipe between the child and the parent, so that the parent
241      * knows when the child has done the setsid() call and is allowed to
242      * exit. */
243     pipe_error = (pipe(pipefd) < 0);
244     pid = fork();
245     if (pid < 0)	    /* Fork error */
246     {
247 	emsg(_("E851: Failed to create a new process for the GUI"));
248 	return;
249     }
250     else if (pid > 0)	    /* Parent */
251     {
252 	/* Give the child some time to do the setsid(), otherwise the
253 	 * exit() may kill the child too (when starting gvim from inside a
254 	 * gvim). */
255 	if (!pipe_error)
256 	{
257 	    /* The read returns when the child closes the pipe (or when
258 	     * the child dies for some reason). */
259 	    close(pipefd[1]);
260 	    status = gui_read_child_pipe(pipefd[0]);
261 	    if (status == GUI_CHILD_FAILED)
262 	    {
263 		/* The child failed to start the GUI, so the caller must
264 		 * continue. There may be more error information written
265 		 * to stderr by the child. */
266 # ifdef __NeXT__
267 		wait4(pid, &exit_status, 0, (struct rusage *)0);
268 # else
269 		waitpid(pid, &exit_status, 0);
270 # endif
271 		emsg(_("E852: The child process failed to start the GUI"));
272 		return;
273 	    }
274 	    else if (status == GUI_CHILD_IO_ERROR)
275 	    {
276 		pipe_error = TRUE;
277 	    }
278 	    /* else GUI_CHILD_OK: parent exit */
279 	}
280 
281 	if (pipe_error)
282 	    ui_delay(300L, TRUE);
283 
284 	/* When swapping screens we may need to go to the next line, e.g.,
285 	 * after a hit-enter prompt and using ":gui". */
286 	if (newline_on_exit)
287 	    mch_errmsg("\r\n");
288 
289 	/*
290 	 * The parent must skip the normal exit() processing, the child
291 	 * will do it.  For example, GTK messes up signals when exiting.
292 	 */
293 	_exit(0);
294     }
295     /* Child */
296 
297 #ifdef FEAT_GUI_GTK
298     /* Call gtk_init_check() here after fork(). See gui_init_check(). */
299     if (gui_mch_init_check() != OK)
300 	getout_preserve_modified(1);
301 #endif
302 
303 # if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
304     /*
305      * Change our process group.  On some systems/shells a CTRL-C in the
306      * shell where Vim was started would otherwise kill gvim!
307      */
308 #  if defined(HAVE_SETSID)
309     (void)setsid();
310 #  else
311     (void)setpgid(0, 0);
312 #  endif
313 # endif
314     if (!pipe_error)
315 	close(pipefd[0]);
316 
317 # if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
318     /* Tell the session manager our new PID */
319     gui_mch_forked();
320 # endif
321 
322     /* Try to start the GUI */
323     gui_attempt_start();
324 
325     /* Notify the parent */
326     if (!pipe_error)
327     {
328 	if (gui.in_use)
329 	    write_eintr(pipefd[1], "ok", 3);
330 	else
331 	    write_eintr(pipefd[1], "fail", 5);
332 	close(pipefd[1]);
333     }
334 
335     /* If we failed to start the GUI, exit now. */
336     if (!gui.in_use)
337 	getout_preserve_modified(1);
338 }
339 
340 /*
341  * Read from a pipe assumed to be connected to the child process (this
342  * function is called from the parent).
343  * Return GUI_CHILD_OK if the child successfully started the GUI,
344  * GUY_CHILD_FAILED if the child failed, or GUI_CHILD_IO_ERROR if there was
345  * some other error.
346  *
347  * The file descriptor will be closed before the function returns.
348  */
349     static int
350 gui_read_child_pipe(int fd)
351 {
352     long	bytes_read;
353 #define READ_BUFFER_SIZE 10
354     char	buffer[READ_BUFFER_SIZE];
355 
356     bytes_read = read_eintr(fd, buffer, READ_BUFFER_SIZE - 1);
357 #undef READ_BUFFER_SIZE
358     close(fd);
359     if (bytes_read < 0)
360 	return GUI_CHILD_IO_ERROR;
361     buffer[bytes_read] = NUL;
362     if (strcmp(buffer, "ok") == 0)
363 	return GUI_CHILD_OK;
364     return GUI_CHILD_FAILED;
365 }
366 
367 #endif /* GUI_MAY_FORK */
368 
369 /*
370  * Call this when vim starts up, whether or not the GUI is started
371  */
372     void
373 gui_prepare(int *argc, char **argv)
374 {
375     gui.in_use = FALSE;		    /* No GUI yet (maybe later) */
376     gui.starting = FALSE;	    /* No GUI yet (maybe later) */
377     gui_mch_prepare(argc, argv);
378 }
379 
380 /*
381  * Try initializing the GUI and check if it can be started.
382  * Used from main() to check early if "vim -g" can start the GUI.
383  * Used from gui_init() to prepare for starting the GUI.
384  * Returns FAIL or OK.
385  */
386     int
387 gui_init_check(void)
388 {
389     static int result = MAYBE;
390 
391     if (result != MAYBE)
392     {
393 	if (result == FAIL)
394 	    emsg(_("E229: Cannot start the GUI"));
395 	return result;
396     }
397 
398     gui.shell_created = FALSE;
399     gui.dying = FALSE;
400     gui.in_focus = TRUE;		/* so the guicursor setting works */
401     gui.dragged_sb = SBAR_NONE;
402     gui.dragged_wp = NULL;
403     gui.pointer_hidden = FALSE;
404     gui.col = 0;
405     gui.row = 0;
406     gui.num_cols = Columns;
407     gui.num_rows = Rows;
408 
409     gui.cursor_is_valid = FALSE;
410     gui.scroll_region_top = 0;
411     gui.scroll_region_bot = Rows - 1;
412     gui.scroll_region_left = 0;
413     gui.scroll_region_right = Columns - 1;
414     gui.highlight_mask = HL_NORMAL;
415     gui.char_width = 1;
416     gui.char_height = 1;
417     gui.char_ascent = 0;
418     gui.border_width = 0;
419 
420     gui.norm_font = NOFONT;
421 #ifndef FEAT_GUI_GTK
422     gui.bold_font = NOFONT;
423     gui.ital_font = NOFONT;
424     gui.boldital_font = NOFONT;
425 # ifdef FEAT_XFONTSET
426     gui.fontset = NOFONTSET;
427 # endif
428 #endif
429     gui.wide_font = NOFONT;
430 #ifndef FEAT_GUI_GTK
431     gui.wide_bold_font = NOFONT;
432     gui.wide_ital_font = NOFONT;
433     gui.wide_boldital_font = NOFONT;
434 #endif
435 
436 #ifdef FEAT_MENU
437 # ifndef FEAT_GUI_GTK
438 #  ifdef FONTSET_ALWAYS
439     gui.menu_fontset = NOFONTSET;
440 #  else
441     gui.menu_font = NOFONT;
442 #  endif
443 # endif
444     gui.menu_is_active = TRUE;	    /* default: include menu */
445 # ifndef FEAT_GUI_GTK
446     gui.menu_height = MENU_DEFAULT_HEIGHT;
447     gui.menu_width = 0;
448 # endif
449 #endif
450 #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
451     gui.toolbar_height = 0;
452 #endif
453 #if defined(FEAT_FOOTER) && defined(FEAT_GUI_MOTIF)
454     gui.footer_height = 0;
455 #endif
456 #ifdef FEAT_BEVAL_TIP
457     gui.tooltip_fontset = NOFONTSET;
458 #endif
459 
460     gui.scrollbar_width = gui.scrollbar_height = SB_DEFAULT_WIDTH;
461     gui.prev_wrap = -1;
462 
463 #if defined(ALWAYS_USE_GUI) || defined(VIMDLL)
464     result = OK;
465 #else
466 # ifdef FEAT_GUI_GTK
467     /*
468      * Note: Don't call gtk_init_check() before fork, it will be called after
469      * the fork. When calling it before fork, it make vim hang for a while.
470      * See gui_do_fork().
471      * Use a simpler check if the GUI window can probably be opened.
472      */
473     result = gui.dofork ? gui_mch_early_init_check(TRUE) : gui_mch_init_check();
474 # else
475     result = gui_mch_init_check();
476 # endif
477 #endif
478     return result;
479 }
480 
481 /*
482  * This is the call which starts the GUI.
483  */
484     void
485 gui_init(void)
486 {
487     win_T	*wp;
488     static int	recursive = 0;
489 
490     /*
491      * It's possible to use ":gui" in a .gvimrc file.  The first halve of this
492      * function will then be executed at the first call, the rest by the
493      * recursive call.  This allow the shell to be opened halfway reading a
494      * gvimrc file.
495      */
496     if (!recursive)
497     {
498 	++recursive;
499 
500 	clip_init(TRUE);
501 
502 	/* If can't initialize, don't try doing the rest */
503 	if (gui_init_check() == FAIL)
504 	{
505 	    --recursive;
506 	    clip_init(FALSE);
507 	    return;
508 	}
509 
510 	/*
511 	 * Reset 'paste'.  It's useful in the terminal, but not in the GUI.  It
512 	 * breaks the Paste toolbar button.
513 	 */
514 	set_option_value((char_u *)"paste", 0L, NULL, 0);
515 
516 	/*
517 	 * Set up system-wide default menus.
518 	 */
519 #if defined(SYS_MENU_FILE) && defined(FEAT_MENU)
520 	if (vim_strchr(p_go, GO_NOSYSMENU) == NULL)
521 	{
522 	    sys_menu = TRUE;
523 	    do_source((char_u *)SYS_MENU_FILE, FALSE, DOSO_NONE);
524 	    sys_menu = FALSE;
525 	}
526 #endif
527 
528 	/*
529 	 * Switch on the mouse by default, unless the user changed it already.
530 	 * This can then be changed in the .gvimrc.
531 	 */
532 	if (!option_was_set((char_u *)"mouse"))
533 	    set_string_option_direct((char_u *)"mouse", -1,
534 					   (char_u *)"a", OPT_FREE, SID_NONE);
535 
536 	/*
537 	 * If -U option given, use only the initializations from that file and
538 	 * nothing else.  Skip all initializations for "-U NONE" or "-u NORC".
539 	 */
540 	if (use_gvimrc != NULL)
541 	{
542 	    if (STRCMP(use_gvimrc, "NONE") != 0
543 		    && STRCMP(use_gvimrc, "NORC") != 0
544 		    && do_source(use_gvimrc, FALSE, DOSO_NONE) != OK)
545 		semsg(_("E230: Cannot read from \"%s\""), use_gvimrc);
546 	}
547 	else
548 	{
549 	    /*
550 	     * Get system wide defaults for gvim, only when file name defined.
551 	     */
552 #ifdef SYS_GVIMRC_FILE
553 	    do_source((char_u *)SYS_GVIMRC_FILE, FALSE, DOSO_NONE);
554 #endif
555 
556 	    /*
557 	     * Try to read GUI initialization commands from the following
558 	     * places:
559 	     * - environment variable GVIMINIT
560 	     * - the user gvimrc file (~/.gvimrc)
561 	     * - the second user gvimrc file ($VIM/.gvimrc for Dos)
562 	     * - the third user gvimrc file ($VIM/.gvimrc for Amiga)
563 	     * The first that exists is used, the rest is ignored.
564 	     */
565 	    if (process_env((char_u *)"GVIMINIT", FALSE) == FAIL
566 		 && do_source((char_u *)USR_GVIMRC_FILE, TRUE,
567 							  DOSO_GVIMRC) == FAIL
568 #ifdef USR_GVIMRC_FILE2
569 		 && do_source((char_u *)USR_GVIMRC_FILE2, TRUE,
570 							  DOSO_GVIMRC) == FAIL
571 #endif
572 #ifdef USR_GVIMRC_FILE3
573 		 && do_source((char_u *)USR_GVIMRC_FILE3, TRUE,
574 							  DOSO_GVIMRC) == FAIL
575 #endif
576 				)
577 	    {
578 #ifdef USR_GVIMRC_FILE4
579 		(void)do_source((char_u *)USR_GVIMRC_FILE4, TRUE, DOSO_GVIMRC);
580 #endif
581 	    }
582 
583 	    /*
584 	     * Read initialization commands from ".gvimrc" in current
585 	     * directory.  This is only done if the 'exrc' option is set.
586 	     * Because of security reasons we disallow shell and write
587 	     * commands now, except for unix if the file is owned by the user
588 	     * or 'secure' option has been reset in environment of global
589 	     * ".gvimrc".
590 	     * Only do this if GVIMRC_FILE is not the same as USR_GVIMRC_FILE,
591 	     * USR_GVIMRC_FILE2, USR_GVIMRC_FILE3 or SYS_GVIMRC_FILE.
592 	     */
593 	    if (p_exrc)
594 	    {
595 #ifdef UNIX
596 		{
597 		    stat_T s;
598 
599 		    /* if ".gvimrc" file is not owned by user, set 'secure'
600 		     * mode */
601 		    if (mch_stat(GVIMRC_FILE, &s) || s.st_uid != getuid())
602 			secure = p_secure;
603 		}
604 #else
605 		secure = p_secure;
606 #endif
607 
608 		if (       fullpathcmp((char_u *)USR_GVIMRC_FILE,
609 				(char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
610 #ifdef SYS_GVIMRC_FILE
611 			&& fullpathcmp((char_u *)SYS_GVIMRC_FILE,
612 				(char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
613 #endif
614 #ifdef USR_GVIMRC_FILE2
615 			&& fullpathcmp((char_u *)USR_GVIMRC_FILE2,
616 				(char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
617 #endif
618 #ifdef USR_GVIMRC_FILE3
619 			&& fullpathcmp((char_u *)USR_GVIMRC_FILE3,
620 				(char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
621 #endif
622 #ifdef USR_GVIMRC_FILE4
623 			&& fullpathcmp((char_u *)USR_GVIMRC_FILE4,
624 				(char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
625 #endif
626 			)
627 		    do_source((char_u *)GVIMRC_FILE, TRUE, DOSO_GVIMRC);
628 
629 		if (secure == 2)
630 		    need_wait_return = TRUE;
631 		secure = 0;
632 	    }
633 	}
634 
635 	if (need_wait_return || msg_didany)
636 	    wait_return(TRUE);
637 
638 	--recursive;
639     }
640 
641     /* If recursive call opened the shell, return here from the first call */
642     if (gui.in_use)
643 	return;
644 
645     /*
646      * Create the GUI shell.
647      */
648     gui.in_use = TRUE;		/* Must be set after menus have been set up */
649     if (gui_mch_init() == FAIL)
650 	goto error;
651 
652     /* Avoid a delay for an error message that was printed in the terminal
653      * where Vim was started. */
654     emsg_on_display = FALSE;
655     msg_scrolled = 0;
656     clear_sb_text(TRUE);
657     need_wait_return = FALSE;
658     msg_didany = FALSE;
659 
660     /*
661      * Check validity of any generic resources that may have been loaded.
662      */
663     if (gui.border_width < 0)
664 	gui.border_width = 0;
665 
666     /*
667      * Set up the fonts.  First use a font specified with "-fn" or "-font".
668      */
669     if (font_argument != NULL)
670 	set_option_value((char_u *)"gfn", 0L, (char_u *)font_argument, 0);
671     if (
672 #ifdef FEAT_XFONTSET
673 	    (*p_guifontset == NUL
674 	     || gui_init_font(p_guifontset, TRUE) == FAIL) &&
675 #endif
676 	    gui_init_font(*p_guifont == NUL ? hl_get_font_name()
677 						  : p_guifont, FALSE) == FAIL)
678     {
679 	emsg(_("E665: Cannot start GUI, no valid font found"));
680 	goto error2;
681     }
682     if (gui_get_wide_font() == FAIL)
683 	emsg(_("E231: 'guifontwide' invalid"));
684 
685     gui.num_cols = Columns;
686     gui.num_rows = Rows;
687     gui_reset_scroll_region();
688 
689     /* Create initial scrollbars */
690     FOR_ALL_WINDOWS(wp)
691     {
692 	gui_create_scrollbar(&wp->w_scrollbars[SBAR_LEFT], SBAR_LEFT, wp);
693 	gui_create_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], SBAR_RIGHT, wp);
694     }
695     gui_create_scrollbar(&gui.bottom_sbar, SBAR_BOTTOM, NULL);
696 
697 #ifdef FEAT_MENU
698     gui_create_initial_menus(root_menu);
699 #endif
700 #ifdef FEAT_SIGN_ICONS
701     sign_gui_started();
702 #endif
703 
704     /* Configure the desired menu and scrollbars */
705     gui_init_which_components(NULL);
706 
707     /* All components of the GUI have been created now */
708     gui.shell_created = TRUE;
709 
710 #ifdef FEAT_GUI_MSWIN
711     // Set the shell size, adjusted for the screen size.  For GTK this only
712     // works after the shell has been opened, thus it is further down.
713     // If the window is already maximized (e.g. when --windowid is passed in),
714     // we want to use the system-provided dimensions by passing FALSE to
715     // mustset. Otherwise, we want to initialize with the default rows/columns.
716     if (gui_mch_maximized())
717 	gui_set_shellsize(FALSE, TRUE, RESIZE_BOTH);
718     else
719 	gui_set_shellsize(TRUE, TRUE, RESIZE_BOTH);
720 #else
721 # ifndef FEAT_GUI_GTK
722     gui_set_shellsize(FALSE, TRUE, RESIZE_BOTH);
723 # endif
724 #endif
725 #if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
726     /* Need to set the size of the menubar after all the menus have been
727      * created. */
728     gui_mch_compute_menu_height((Widget)0);
729 #endif
730 
731     /*
732      * Actually open the GUI shell.
733      */
734     if (gui_mch_open() != FAIL)
735     {
736 #ifdef FEAT_TITLE
737 	maketitle();
738 	resettitle();
739 #endif
740 	init_gui_options();
741 #ifdef FEAT_ARABIC
742 	/* Our GUI can't do bidi. */
743 	p_tbidi = FALSE;
744 #endif
745 #if defined(FEAT_GUI_GTK)
746 	/* Give GTK+ a chance to put all widget's into place. */
747 	gui_mch_update();
748 
749 # ifdef FEAT_MENU
750 	/* If there is no 'm' in 'guioptions' we need to remove the menu now.
751 	 * It was still there to make F10 work. */
752 	if (vim_strchr(p_go, GO_MENUS) == NULL)
753 	{
754 	    --gui.starting;
755 	    gui_mch_enable_menu(FALSE);
756 	    ++gui.starting;
757 	    gui_mch_update();
758 	}
759 # endif
760 
761 	/* Now make sure the shell fits on the screen. */
762 	if (gui_mch_maximized())
763 	    gui_set_shellsize(FALSE, TRUE, RESIZE_BOTH);
764 	else
765 	    gui_set_shellsize(TRUE, TRUE, RESIZE_BOTH);
766 #endif
767 	/* When 'lines' was set while starting up the topframe may have to be
768 	 * resized. */
769 	win_new_shellsize();
770 
771 #ifdef FEAT_BEVAL_GUI
772 	/* Always create the Balloon Evaluation area, but disable it when
773 	 * 'ballooneval' is off. */
774 	if (balloonEval != NULL)
775 	{
776 # ifdef FEAT_VARTABS
777 	    vim_free(balloonEval->vts);
778 # endif
779 	    vim_free(balloonEval);
780 	}
781 	balloonEvalForTerm = FALSE;
782 # ifdef FEAT_GUI_GTK
783 	balloonEval = gui_mch_create_beval_area(gui.drawarea, NULL,
784 						     &general_beval_cb, NULL);
785 # else
786 #  if defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
787 	{
788 	    extern Widget	textArea;
789 	    balloonEval = gui_mch_create_beval_area(textArea, NULL,
790 						     &general_beval_cb, NULL);
791 	}
792 #  else
793 #   ifdef FEAT_GUI_MSWIN
794 	balloonEval = gui_mch_create_beval_area(NULL, NULL,
795 						     &general_beval_cb, NULL);
796 #   endif
797 #  endif
798 # endif
799 	if (!p_beval)
800 	    gui_mch_disable_beval_area(balloonEval);
801 #endif
802 
803 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
804 	if (!im_xim_isvalid_imactivate())
805 	    emsg(_("E599: Value of 'imactivatekey' is invalid"));
806 #endif
807 	/* When 'cmdheight' was set during startup it may not have taken
808 	 * effect yet. */
809 	if (p_ch != 1L)
810 	    command_height();
811 
812 	return;
813     }
814 
815 error2:
816 #ifdef FEAT_GUI_X11
817     /* undo gui_mch_init() */
818     gui_mch_uninit();
819 #endif
820 
821 error:
822     gui.in_use = FALSE;
823     clip_init(FALSE);
824 }
825 
826 
827     void
828 gui_exit(int rc)
829 {
830     /* don't free the fonts, it leads to a BUS error
831      * [email protected] Jul 99 */
832     free_highlight_fonts();
833     gui.in_use = FALSE;
834     gui_mch_exit(rc);
835 }
836 
837 #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_MSWIN) \
838 	|| defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(PROTO)
839 # define NEED_GUI_UPDATE_SCREEN 1
840 /*
841  * Called when the GUI shell is closed by the user.  If there are no changed
842  * files Vim exits, otherwise there will be a dialog to ask the user what to
843  * do.
844  * When this function returns, Vim should NOT exit!
845  */
846     void
847 gui_shell_closed(void)
848 {
849     cmdmod_T	    save_cmdmod;
850 
851     save_cmdmod = cmdmod;
852 
853     /* Only exit when there are no changed files */
854     exiting = TRUE;
855 # ifdef FEAT_BROWSE
856     cmdmod.browse = TRUE;
857 # endif
858 # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
859     cmdmod.confirm = TRUE;
860 # endif
861     /* If there are changed buffers, present the user with a dialog if
862      * possible, otherwise give an error message. */
863     if (!check_changed_any(FALSE, FALSE))
864 	getout(0);
865 
866     exiting = FALSE;
867     cmdmod = save_cmdmod;
868     gui_update_screen();	/* redraw, window may show changed buffer */
869 }
870 #endif
871 
872 /*
873  * Set the font.  "font_list" is a comma separated list of font names.  The
874  * first font name that works is used.  If none is found, use the default
875  * font.
876  * If "fontset" is TRUE, the "font_list" is used as one name for the fontset.
877  * Return OK when able to set the font.  When it failed FAIL is returned and
878  * the fonts are unchanged.
879  */
880     int
881 gui_init_font(char_u *font_list, int fontset UNUSED)
882 {
883 #define FONTLEN 320
884     char_u	font_name[FONTLEN];
885     int		font_list_empty = FALSE;
886     int		ret = FAIL;
887 
888     if (!gui.in_use)
889 	return FAIL;
890 
891     font_name[0] = NUL;
892     if (*font_list == NUL)
893 	font_list_empty = TRUE;
894     else
895     {
896 #ifdef FEAT_XFONTSET
897 	/* When using a fontset, the whole list of fonts is one name. */
898 	if (fontset)
899 	    ret = gui_mch_init_font(font_list, TRUE);
900 	else
901 #endif
902 	    while (*font_list != NUL)
903 	    {
904 		/* Isolate one comma separated font name. */
905 		(void)copy_option_part(&font_list, font_name, FONTLEN, ",");
906 
907 		/* Careful!!!  The Win32 version of gui_mch_init_font(), when
908 		 * called with "*" will change p_guifont to the selected font
909 		 * name, which frees the old value.  This makes font_list
910 		 * invalid.  Thus when OK is returned here, font_list must no
911 		 * longer be used! */
912 		if (gui_mch_init_font(font_name, FALSE) == OK)
913 		{
914 #if !defined(FEAT_GUI_GTK)
915 		    /* If it's a Unicode font, try setting 'guifontwide' to a
916 		     * similar double-width font. */
917 		    if ((p_guifontwide == NULL || *p_guifontwide == NUL)
918 				&& strstr((char *)font_name, "10646") != NULL)
919 			set_guifontwide(font_name);
920 #endif
921 		    ret = OK;
922 		    break;
923 		}
924 	    }
925     }
926 
927     if (ret != OK
928 	    && STRCMP(font_list, "*") != 0
929 	    && (font_list_empty || gui.norm_font == NOFONT))
930     {
931 	/*
932 	 * Couldn't load any font in 'font_list', keep the current font if
933 	 * there is one.  If 'font_list' is empty, or if there is no current
934 	 * font, tell gui_mch_init_font() to try to find a font we can load.
935 	 */
936 	ret = gui_mch_init_font(NULL, FALSE);
937     }
938 
939     if (ret == OK)
940     {
941 #ifndef FEAT_GUI_GTK
942 	/* Set normal font as current font */
943 # ifdef FEAT_XFONTSET
944 	if (gui.fontset != NOFONTSET)
945 	    gui_mch_set_fontset(gui.fontset);
946 	else
947 # endif
948 	    gui_mch_set_font(gui.norm_font);
949 #endif
950 	gui_set_shellsize(FALSE, TRUE, RESIZE_BOTH);
951     }
952 
953     return ret;
954 }
955 
956 #ifndef FEAT_GUI_GTK
957 /*
958  * Try setting 'guifontwide' to a font twice as wide as "name".
959  */
960     static void
961 set_guifontwide(char_u *name)
962 {
963     int		i = 0;
964     char_u	wide_name[FONTLEN + 10]; /* room for 2 * width and '*' */
965     char_u	*wp = NULL;
966     char_u	*p;
967     GuiFont	font;
968 
969     wp = wide_name;
970     for (p = name; *p != NUL; ++p)
971     {
972 	*wp++ = *p;
973 	if (*p == '-')
974 	{
975 	    ++i;
976 	    if (i == 6)		/* font type: change "--" to "-*-" */
977 	    {
978 		if (p[1] == '-')
979 		    *wp++ = '*';
980 	    }
981 	    else if (i == 12)	/* found the width */
982 	    {
983 		++p;
984 		i = getdigits(&p);
985 		if (i != 0)
986 		{
987 		    /* Double the width specification. */
988 		    sprintf((char *)wp, "%d%s", i * 2, p);
989 		    font = gui_mch_get_font(wide_name, FALSE);
990 		    if (font != NOFONT)
991 		    {
992 			gui_mch_free_font(gui.wide_font);
993 			gui.wide_font = font;
994 			set_string_option_direct((char_u *)"gfw", -1,
995 						      wide_name, OPT_FREE, 0);
996 		    }
997 		}
998 		break;
999 	    }
1000 	}
1001     }
1002 }
1003 #endif /* !FEAT_GUI_GTK */
1004 
1005 /*
1006  * Get the font for 'guifontwide'.
1007  * Return FAIL for an invalid font name.
1008  */
1009     int
1010 gui_get_wide_font(void)
1011 {
1012     GuiFont	font = NOFONT;
1013     char_u	font_name[FONTLEN];
1014     char_u	*p;
1015 
1016     if (!gui.in_use)	    /* Can't allocate font yet, assume it's OK. */
1017 	return OK;	    /* Will give an error message later. */
1018 
1019     if (p_guifontwide != NULL && *p_guifontwide != NUL)
1020     {
1021 	for (p = p_guifontwide; *p != NUL; )
1022 	{
1023 	    /* Isolate one comma separated font name. */
1024 	    (void)copy_option_part(&p, font_name, FONTLEN, ",");
1025 	    font = gui_mch_get_font(font_name, FALSE);
1026 	    if (font != NOFONT)
1027 		break;
1028 	}
1029 	if (font == NOFONT)
1030 	    return FAIL;
1031     }
1032 
1033     gui_mch_free_font(gui.wide_font);
1034 #ifdef FEAT_GUI_GTK
1035     /* Avoid unnecessary overhead if 'guifontwide' is equal to 'guifont'. */
1036     if (font != NOFONT && gui.norm_font != NOFONT
1037 			 && pango_font_description_equal(font, gui.norm_font))
1038     {
1039 	gui.wide_font = NOFONT;
1040 	gui_mch_free_font(font);
1041     }
1042     else
1043 #endif
1044 	gui.wide_font = font;
1045 #ifdef FEAT_GUI_MSWIN
1046     gui_mch_wide_font_changed();
1047 #else
1048     /*
1049      * TODO: setup wide_bold_font, wide_ital_font and wide_boldital_font to
1050      * support those fonts for 'guifontwide'.
1051      */
1052 #endif
1053     return OK;
1054 }
1055 
1056     static void
1057 gui_set_cursor(int row, int col)
1058 {
1059     gui.row = row;
1060     gui.col = col;
1061 }
1062 
1063 /*
1064  * gui_check_pos - check if the cursor is on the screen.
1065  */
1066     static void
1067 gui_check_pos(void)
1068 {
1069     if (gui.row >= screen_Rows)
1070 	gui.row = screen_Rows - 1;
1071     if (gui.col >= screen_Columns)
1072 	gui.col = screen_Columns - 1;
1073     if (gui.cursor_row >= screen_Rows || gui.cursor_col >= screen_Columns)
1074 	gui.cursor_is_valid = FALSE;
1075 }
1076 
1077 /*
1078  * Redraw the cursor if necessary or when forced.
1079  * Careful: The contents of ScreenLines[] must match what is on the screen,
1080  * otherwise this goes wrong.  May need to call out_flush() first.
1081  */
1082     void
1083 gui_update_cursor(
1084     int		force,		/* when TRUE, update even when not moved */
1085     int		clear_selection)/* clear selection under cursor */
1086 {
1087     int		cur_width = 0;
1088     int		cur_height = 0;
1089     int		old_hl_mask;
1090     cursorentry_T *shape;
1091     int		id;
1092 #ifdef FEAT_TERMINAL
1093     guicolor_T	shape_fg = INVALCOLOR;
1094     guicolor_T	shape_bg = INVALCOLOR;
1095 #endif
1096     guicolor_T	cfg, cbg, cc;	/* cursor fore-/background color */
1097     int		cattr;		/* cursor attributes */
1098     int		attr;
1099     attrentry_T *aep = NULL;
1100 
1101     /* Don't update the cursor when halfway busy scrolling or the screen size
1102      * doesn't match 'columns' and 'lines.  ScreenLines[] isn't valid then. */
1103     if (!can_update_cursor || screen_Columns != gui.num_cols
1104 					       || screen_Rows != gui.num_rows)
1105 	return;
1106 
1107     gui_check_pos();
1108     if (!gui.cursor_is_valid || force
1109 		    || gui.row != gui.cursor_row || gui.col != gui.cursor_col)
1110     {
1111 	gui_undraw_cursor();
1112 	if (gui.row < 0)
1113 	    return;
1114 #ifdef HAVE_INPUT_METHOD
1115 	if (gui.row != gui.cursor_row || gui.col != gui.cursor_col)
1116 	    im_set_position(gui.row, gui.col);
1117 #endif
1118 	gui.cursor_row = gui.row;
1119 	gui.cursor_col = gui.col;
1120 
1121 	/* Only write to the screen after ScreenLines[] has been initialized */
1122 	if (!screen_cleared || ScreenLines == NULL)
1123 	    return;
1124 
1125 	/* Clear the selection if we are about to write over it */
1126 	if (clear_selection)
1127 	    clip_may_clear_selection(gui.row, gui.row);
1128 	/* Check that the cursor is inside the shell (resizing may have made
1129 	 * it invalid) */
1130 	if (gui.row >= screen_Rows || gui.col >= screen_Columns)
1131 	    return;
1132 
1133 	gui.cursor_is_valid = TRUE;
1134 
1135 	/*
1136 	 * How the cursor is drawn depends on the current mode.
1137 	 * When in a terminal window use the shape/color specified there.
1138 	 */
1139 #ifdef FEAT_TERMINAL
1140 	if (terminal_is_active())
1141 	    shape = term_get_cursor_shape(&shape_fg, &shape_bg);
1142 	else
1143 #endif
1144 	    shape = &shape_table[get_shape_idx(FALSE)];
1145 	if (State & LANGMAP)
1146 	    id = shape->id_lm;
1147 	else
1148 	    id = shape->id;
1149 
1150 	/* get the colors and attributes for the cursor.  Default is inverted */
1151 	cfg = INVALCOLOR;
1152 	cbg = INVALCOLOR;
1153 	cattr = HL_INVERSE;
1154 	gui_mch_set_blinking(shape->blinkwait,
1155 			     shape->blinkon,
1156 			     shape->blinkoff);
1157 	if (shape->blinkwait == 0 || shape->blinkon == 0
1158 						       || shape->blinkoff == 0)
1159 	    gui_mch_stop_blink(FALSE);
1160 #ifdef FEAT_TERMINAL
1161 	if (shape_bg != INVALCOLOR)
1162 	{
1163 	    cattr = 0;
1164 	    cfg = shape_fg;
1165 	    cbg = shape_bg;
1166 	}
1167 	else
1168 #endif
1169 	if (id > 0)
1170 	{
1171 	    cattr = syn_id2colors(id, &cfg, &cbg);
1172 #if defined(HAVE_INPUT_METHOD) || defined(FEAT_HANGULIN)
1173 	    {
1174 		static int iid;
1175 		guicolor_T fg, bg;
1176 
1177 		if (
1178 # if defined(FEAT_GUI_GTK) && defined(FEAT_XIM) && !defined(FEAT_HANGULIN)
1179 			preedit_get_status()
1180 # else
1181 			im_get_status()
1182 # endif
1183 			)
1184 		{
1185 		    iid = syn_name2id((char_u *)"CursorIM");
1186 		    if (iid > 0)
1187 		    {
1188 			syn_id2colors(iid, &fg, &bg);
1189 			if (bg != INVALCOLOR)
1190 			    cbg = bg;
1191 			if (fg != INVALCOLOR)
1192 			    cfg = fg;
1193 		    }
1194 		}
1195 	    }
1196 #endif
1197 	}
1198 
1199 	/*
1200 	 * Get the attributes for the character under the cursor.
1201 	 * When no cursor color was given, use the character color.
1202 	 */
1203 	attr = ScreenAttrs[LineOffset[gui.row] + gui.col];
1204 	if (attr > HL_ALL)
1205 	    aep = syn_gui_attr2entry(attr);
1206 	if (aep != NULL)
1207 	{
1208 	    attr = aep->ae_attr;
1209 	    if (cfg == INVALCOLOR)
1210 		cfg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.bg_color
1211 					    : aep->ae_u.gui.fg_color);
1212 	    if (cbg == INVALCOLOR)
1213 		cbg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.fg_color
1214 					    : aep->ae_u.gui.bg_color);
1215 	}
1216 	if (cfg == INVALCOLOR)
1217 	    cfg = (attr & HL_INVERSE) ? gui.back_pixel : gui.norm_pixel;
1218 	if (cbg == INVALCOLOR)
1219 	    cbg = (attr & HL_INVERSE) ? gui.norm_pixel : gui.back_pixel;
1220 
1221 #ifdef FEAT_XIM
1222 	if (aep != NULL)
1223 	{
1224 	    xim_bg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.fg_color
1225 						: aep->ae_u.gui.bg_color);
1226 	    xim_fg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.bg_color
1227 						: aep->ae_u.gui.fg_color);
1228 	    if (xim_bg_color == INVALCOLOR)
1229 		xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
1230 						   : gui.back_pixel;
1231 	    if (xim_fg_color == INVALCOLOR)
1232 		xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
1233 						   : gui.norm_pixel;
1234 	}
1235 	else
1236 	{
1237 	    xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
1238 					       : gui.back_pixel;
1239 	    xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
1240 					       : gui.norm_pixel;
1241 	}
1242 #endif
1243 
1244 	attr &= ~HL_INVERSE;
1245 	if (cattr & HL_INVERSE)
1246 	{
1247 	    cc = cbg;
1248 	    cbg = cfg;
1249 	    cfg = cc;
1250 	}
1251 	cattr &= ~HL_INVERSE;
1252 
1253 	/*
1254 	 * When we don't have window focus, draw a hollow cursor.
1255 	 */
1256 	if (!gui.in_focus)
1257 	{
1258 	    gui_mch_draw_hollow_cursor(cbg);
1259 	    return;
1260 	}
1261 
1262 	old_hl_mask = gui.highlight_mask;
1263 	if (shape->shape == SHAPE_BLOCK
1264 #ifdef FEAT_HANGULIN
1265 		|| composing_hangul
1266 #endif
1267 	   )
1268 	{
1269 	    /*
1270 	     * Draw the text character with the cursor colors.	Use the
1271 	     * character attributes plus the cursor attributes.
1272 	     */
1273 	    gui.highlight_mask = (cattr | attr);
1274 #ifdef FEAT_HANGULIN
1275 	    if (composing_hangul)
1276 	    {
1277 		char_u *comp_buf;
1278 		int comp_len;
1279 
1280 		comp_buf = hangul_composing_buffer_get(&comp_len);
1281 		if (comp_buf)
1282 		{
1283 		    (void)gui_outstr_nowrap(comp_buf, comp_len,
1284 					    GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR,
1285 					    cfg, cbg, 0);
1286 		    vim_free(comp_buf);
1287 		}
1288 	    }
1289 	    else
1290 #endif
1291 		(void)gui_screenchar(LineOffset[gui.row] + gui.col,
1292 			GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR, cfg, cbg, 0);
1293 	}
1294 	else
1295 	{
1296 #if defined(FEAT_RIGHTLEFT)
1297 	    int	    col_off = FALSE;
1298 #endif
1299 	    /*
1300 	     * First draw the partial cursor, then overwrite with the text
1301 	     * character, using a transparent background.
1302 	     */
1303 	    if (shape->shape == SHAPE_VER)
1304 	    {
1305 		cur_height = gui.char_height;
1306 		cur_width = (gui.char_width * shape->percentage + 99) / 100;
1307 	    }
1308 	    else
1309 	    {
1310 		cur_height = (gui.char_height * shape->percentage + 99) / 100;
1311 		cur_width = gui.char_width;
1312 	    }
1313 	    if (has_mbyte && (*mb_off2cells)(LineOffset[gui.row] + gui.col,
1314 				    LineOffset[gui.row] + screen_Columns) > 1)
1315 	    {
1316 		/* Double wide character. */
1317 		if (shape->shape != SHAPE_VER)
1318 		    cur_width += gui.char_width;
1319 #ifdef FEAT_RIGHTLEFT
1320 		if (CURSOR_BAR_RIGHT)
1321 		{
1322 		    /* gui.col points to the left halve of the character but
1323 		     * the vertical line needs to be on the right halve.
1324 		     * A double-wide horizontal line is also drawn from the
1325 		     * right halve in gui_mch_draw_part_cursor(). */
1326 		    col_off = TRUE;
1327 		    ++gui.col;
1328 		}
1329 #endif
1330 	    }
1331 	    gui_mch_draw_part_cursor(cur_width, cur_height, cbg);
1332 #if defined(FEAT_RIGHTLEFT)
1333 	    if (col_off)
1334 		--gui.col;
1335 #endif
1336 
1337 #ifndef FEAT_GUI_MSWIN	    /* doesn't seem to work for MSWindows */
1338 	    gui.highlight_mask = ScreenAttrs[LineOffset[gui.row] + gui.col];
1339 	    (void)gui_screenchar(LineOffset[gui.row] + gui.col,
1340 		    GUI_MON_TRS_CURSOR | GUI_MON_NOCLEAR,
1341 		    (guicolor_T)0, (guicolor_T)0, 0);
1342 #endif
1343 	}
1344 	gui.highlight_mask = old_hl_mask;
1345     }
1346 }
1347 
1348 #if defined(FEAT_MENU) || defined(PROTO)
1349     void
1350 gui_position_menu(void)
1351 {
1352 # if !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF)
1353     if (gui.menu_is_active && gui.in_use)
1354 	gui_mch_set_menu_pos(0, 0, gui.menu_width, gui.menu_height);
1355 # endif
1356 }
1357 #endif
1358 
1359 /*
1360  * Position the various GUI components (text area, menu).  The vertical
1361  * scrollbars are NOT handled here.  See gui_update_scrollbars().
1362  */
1363     static void
1364 gui_position_components(int total_width UNUSED)
1365 {
1366     int	    text_area_x;
1367     int	    text_area_y;
1368     int	    text_area_width;
1369     int	    text_area_height;
1370 
1371     /* avoid that moving components around generates events */
1372     ++hold_gui_events;
1373 
1374     text_area_x = 0;
1375     if (gui.which_scrollbars[SBAR_LEFT])
1376 	text_area_x += gui.scrollbar_width;
1377 
1378     text_area_y = 0;
1379 #if defined(FEAT_MENU) && !(defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON))
1380     gui.menu_width = total_width;
1381     if (gui.menu_is_active)
1382 	text_area_y += gui.menu_height;
1383 #endif
1384 #if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_MSWIN)
1385     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
1386 	text_area_y = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
1387 #endif
1388 
1389 # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
1390 	|| defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC))
1391     if (gui_has_tabline())
1392 	text_area_y += gui.tabline_height;
1393 #endif
1394 
1395 #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
1396     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
1397     {
1398 # ifdef FEAT_GUI_ATHENA
1399 	gui_mch_set_toolbar_pos(0, text_area_y,
1400 				gui.menu_width, gui.toolbar_height);
1401 # endif
1402 	text_area_y += gui.toolbar_height;
1403     }
1404 #endif
1405 
1406     text_area_width = gui.num_cols * gui.char_width + gui.border_offset * 2;
1407     text_area_height = gui.num_rows * gui.char_height + gui.border_offset * 2;
1408 
1409     gui_mch_set_text_area_pos(text_area_x,
1410 			      text_area_y,
1411 			      text_area_width,
1412 			      text_area_height
1413 #if defined(FEAT_XIM) && !defined(FEAT_GUI_GTK)
1414 				  + xim_get_status_area_height()
1415 #endif
1416 			      );
1417 #ifdef FEAT_MENU
1418     gui_position_menu();
1419 #endif
1420     if (gui.which_scrollbars[SBAR_BOTTOM])
1421 	gui_mch_set_scrollbar_pos(&gui.bottom_sbar,
1422 				  text_area_x,
1423 				  text_area_y + text_area_height,
1424 				  text_area_width,
1425 				  gui.scrollbar_height);
1426     gui.left_sbar_x = 0;
1427     gui.right_sbar_x = text_area_x + text_area_width;
1428 
1429     --hold_gui_events;
1430 }
1431 
1432 /*
1433  * Get the width of the widgets and decorations to the side of the text area.
1434  */
1435     int
1436 gui_get_base_width(void)
1437 {
1438     int	    base_width;
1439 
1440     base_width = 2 * gui.border_offset;
1441     if (gui.which_scrollbars[SBAR_LEFT])
1442 	base_width += gui.scrollbar_width;
1443     if (gui.which_scrollbars[SBAR_RIGHT])
1444 	base_width += gui.scrollbar_width;
1445     return base_width;
1446 }
1447 
1448 /*
1449  * Get the height of the widgets and decorations above and below the text area.
1450  */
1451     int
1452 gui_get_base_height(void)
1453 {
1454     int	    base_height;
1455 
1456     base_height = 2 * gui.border_offset;
1457     if (gui.which_scrollbars[SBAR_BOTTOM])
1458 	base_height += gui.scrollbar_height;
1459 #ifdef FEAT_GUI_GTK
1460     /* We can't take the sizes properly into account until anything is
1461      * realized.  Therefore we recalculate all the values here just before
1462      * setting the size. (--mdcki) */
1463 #else
1464 # ifdef FEAT_MENU
1465     if (gui.menu_is_active)
1466 	base_height += gui.menu_height;
1467 # endif
1468 # ifdef FEAT_TOOLBAR
1469     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
1470 #  if defined(FEAT_GUI_MSWIN) && defined(FEAT_TOOLBAR)
1471 	base_height += (TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT);
1472 #  else
1473 	base_height += gui.toolbar_height;
1474 #  endif
1475 # endif
1476 # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
1477 	|| defined(FEAT_GUI_MOTIF))
1478     if (gui_has_tabline())
1479 	base_height += gui.tabline_height;
1480 # endif
1481 # ifdef FEAT_FOOTER
1482     if (vim_strchr(p_go, GO_FOOTER) != NULL)
1483 	base_height += gui.footer_height;
1484 # endif
1485 # if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
1486     base_height += gui_mch_text_area_extra_height();
1487 # endif
1488 #endif
1489     return base_height;
1490 }
1491 
1492 /*
1493  * Should be called after the GUI shell has been resized.  Its arguments are
1494  * the new width and height of the shell in pixels.
1495  */
1496     void
1497 gui_resize_shell(int pixel_width, int pixel_height)
1498 {
1499     static int	busy = FALSE;
1500 
1501     if (!gui.shell_created)	    /* ignore when still initializing */
1502 	return;
1503 
1504     /*
1505      * Can't resize the screen while it is being redrawn.  Remember the new
1506      * size and handle it later.
1507      */
1508     if (updating_screen || busy)
1509     {
1510 	new_pixel_width = pixel_width;
1511 	new_pixel_height = pixel_height;
1512 	return;
1513     }
1514 
1515 again:
1516     new_pixel_width = 0;
1517     new_pixel_height = 0;
1518     busy = TRUE;
1519 
1520     /* Flush pending output before redrawing */
1521     out_flush();
1522 
1523     gui.num_cols = (pixel_width - gui_get_base_width()) / gui.char_width;
1524     gui.num_rows = (pixel_height - gui_get_base_height()) / gui.char_height;
1525 
1526     gui_position_components(pixel_width);
1527     gui_reset_scroll_region();
1528 
1529     /*
1530      * At the "more" and ":confirm" prompt there is no redraw, put the cursor
1531      * at the last line here (why does it have to be one row too low?).
1532      */
1533     if (State == ASKMORE || State == CONFIRM)
1534 	gui.row = gui.num_rows;
1535 
1536     /* Only comparing Rows and Columns may be sufficient, but let's stay on
1537      * the safe side. */
1538     if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns
1539 	    || gui.num_rows != Rows || gui.num_cols != Columns)
1540 	shell_resized();
1541 
1542     gui_update_scrollbars(TRUE);
1543     gui_update_cursor(FALSE, TRUE);
1544 #if defined(FEAT_XIM) && !defined(FEAT_GUI_GTK)
1545     xim_set_status_area();
1546 #endif
1547 
1548     busy = FALSE;
1549 
1550     /* We may have been called again while redrawing the screen.
1551      * Need to do it all again with the latest size then.  But only if the size
1552      * actually changed. */
1553     if (new_pixel_height)
1554     {
1555 	if (pixel_width == new_pixel_width && pixel_height == new_pixel_height)
1556 	{
1557 	    new_pixel_width = 0;
1558 	    new_pixel_height = 0;
1559 	}
1560 	else
1561 	{
1562 	    pixel_width = new_pixel_width;
1563 	    pixel_height = new_pixel_height;
1564 	    goto again;
1565 	}
1566     }
1567 }
1568 
1569 /*
1570  * Check if gui_resize_shell() must be called.
1571  */
1572     void
1573 gui_may_resize_shell(void)
1574 {
1575     if (new_pixel_height)
1576 	/* careful: gui_resize_shell() may postpone the resize again if we
1577 	 * were called indirectly by it */
1578 	gui_resize_shell(new_pixel_width, new_pixel_height);
1579 }
1580 
1581     int
1582 gui_get_shellsize(void)
1583 {
1584     Rows = gui.num_rows;
1585     Columns = gui.num_cols;
1586     return OK;
1587 }
1588 
1589 /*
1590  * Set the size of the Vim shell according to Rows and Columns.
1591  * If "fit_to_display" is TRUE then the size may be reduced to fit the window
1592  * on the screen.
1593  * When "mustset" is TRUE the size was set by the user. When FALSE a UI
1594  * component was added or removed (e.g., a scrollbar).
1595  */
1596     void
1597 gui_set_shellsize(
1598     int		mustset UNUSED,
1599     int		fit_to_display,
1600     int		direction)		/* RESIZE_HOR, RESIZE_VER */
1601 {
1602     int		base_width;
1603     int		base_height;
1604     int		width;
1605     int		height;
1606     int		min_width;
1607     int		min_height;
1608     int		screen_w;
1609     int		screen_h;
1610 #ifdef FEAT_GUI_GTK
1611     int		un_maximize = mustset;
1612     int		did_adjust = 0;
1613 #endif
1614     int		x = -1, y = -1;
1615 
1616     if (!gui.shell_created)
1617 	return;
1618 
1619 #if defined(MSWIN) || defined(FEAT_GUI_GTK)
1620     /* If not setting to a user specified size and maximized, calculate the
1621      * number of characters that fit in the maximized window. */
1622     if (!mustset && (vim_strchr(p_go, GO_KEEPWINSIZE) != NULL
1623 						       || gui_mch_maximized()))
1624     {
1625 	gui_mch_newfont();
1626 	return;
1627     }
1628 #endif
1629 
1630     base_width = gui_get_base_width();
1631     base_height = gui_get_base_height();
1632     if (fit_to_display)
1633 	/* Remember the original window position. */
1634 	(void)gui_mch_get_winpos(&x, &y);
1635 
1636     width = Columns * gui.char_width + base_width;
1637     height = Rows * gui.char_height + base_height;
1638 
1639     if (fit_to_display)
1640     {
1641 	gui_mch_get_screen_dimensions(&screen_w, &screen_h);
1642 	if ((direction & RESIZE_HOR) && width > screen_w)
1643 	{
1644 	    Columns = (screen_w - base_width) / gui.char_width;
1645 	    if (Columns < MIN_COLUMNS)
1646 		Columns = MIN_COLUMNS;
1647 	    width = Columns * gui.char_width + base_width;
1648 #ifdef FEAT_GUI_GTK
1649 	    ++did_adjust;
1650 #endif
1651 	}
1652 	if ((direction & RESIZE_VERT) && height > screen_h)
1653 	{
1654 	    Rows = (screen_h - base_height) / gui.char_height;
1655 	    check_shellsize();
1656 	    height = Rows * gui.char_height + base_height;
1657 #ifdef FEAT_GUI_GTK
1658 	    ++did_adjust;
1659 #endif
1660 	}
1661 #ifdef FEAT_GUI_GTK
1662 	if (did_adjust == 2 || (width + gui.char_width >= screen_w
1663 				     && height + gui.char_height >= screen_h))
1664 	    /* don't unmaximize if at maximum size */
1665 	    un_maximize = FALSE;
1666 #endif
1667     }
1668     limit_screen_size();
1669     gui.num_cols = Columns;
1670     gui.num_rows = Rows;
1671 
1672     min_width = base_width + MIN_COLUMNS * gui.char_width;
1673     min_height = base_height + MIN_LINES * gui.char_height;
1674     min_height += tabline_height() * gui.char_height;
1675 
1676 #ifdef FEAT_GUI_GTK
1677     if (un_maximize)
1678     {
1679 	/* If the window size is smaller than the screen unmaximize the
1680 	 * window, otherwise resizing won't work. */
1681 	gui_mch_get_screen_dimensions(&screen_w, &screen_h);
1682 	if ((width + gui.char_width < screen_w
1683 				   || height + gui.char_height * 2 < screen_h)
1684 		&& gui_mch_maximized())
1685 	    gui_mch_unmaximize();
1686     }
1687 #endif
1688 
1689     gui_mch_set_shellsize(width, height, min_width, min_height,
1690 					  base_width, base_height, direction);
1691 
1692     if (fit_to_display && x >= 0 && y >= 0)
1693     {
1694 	/* Some window managers put the Vim window left of/above the screen.
1695 	 * Only change the position if it wasn't already negative before
1696 	 * (happens on MS-Windows with a secondary monitor). */
1697 	gui_mch_update();
1698 	if (gui_mch_get_winpos(&x, &y) == OK && (x < 0 || y < 0))
1699 	    gui_mch_set_winpos(x < 0 ? 0 : x, y < 0 ? 0 : y);
1700     }
1701 
1702     gui_position_components(width);
1703     gui_update_scrollbars(TRUE);
1704     gui_reset_scroll_region();
1705 }
1706 
1707 /*
1708  * Called when Rows and/or Columns has changed.
1709  */
1710     void
1711 gui_new_shellsize(void)
1712 {
1713     gui_reset_scroll_region();
1714 }
1715 
1716 /*
1717  * Make scroll region cover whole screen.
1718  */
1719     static void
1720 gui_reset_scroll_region(void)
1721 {
1722     gui.scroll_region_top = 0;
1723     gui.scroll_region_bot = gui.num_rows - 1;
1724     gui.scroll_region_left = 0;
1725     gui.scroll_region_right = gui.num_cols - 1;
1726 }
1727 
1728     static void
1729 gui_start_highlight(int mask)
1730 {
1731     if (mask > HL_ALL)		    /* highlight code */
1732 	gui.highlight_mask = mask;
1733     else			    /* mask */
1734 	gui.highlight_mask |= mask;
1735 }
1736 
1737     void
1738 gui_stop_highlight(int mask)
1739 {
1740     if (mask > HL_ALL)		    /* highlight code */
1741 	gui.highlight_mask = HL_NORMAL;
1742     else			    /* mask */
1743 	gui.highlight_mask &= ~mask;
1744 }
1745 
1746 /*
1747  * Clear a rectangular region of the screen from text pos (row1, col1) to
1748  * (row2, col2) inclusive.
1749  */
1750     void
1751 gui_clear_block(
1752     int	    row1,
1753     int	    col1,
1754     int	    row2,
1755     int	    col2)
1756 {
1757     /* Clear the selection if we are about to write over it */
1758     clip_may_clear_selection(row1, row2);
1759 
1760     gui_mch_clear_block(row1, col1, row2, col2);
1761 
1762     /* Invalidate cursor if it was in this block */
1763     if (       gui.cursor_row >= row1 && gui.cursor_row <= row2
1764 	    && gui.cursor_col >= col1 && gui.cursor_col <= col2)
1765 	gui.cursor_is_valid = FALSE;
1766 }
1767 
1768 /*
1769  * Write code to update the cursor later.  This avoids the need to flush the
1770  * output buffer before calling gui_update_cursor().
1771  */
1772     void
1773 gui_update_cursor_later(void)
1774 {
1775     OUT_STR(IF_EB("\033|s", ESC_STR "|s"));
1776 }
1777 
1778     void
1779 gui_write(
1780     char_u	*s,
1781     int		len)
1782 {
1783     char_u	*p;
1784     int		arg1 = 0, arg2 = 0;
1785     int		force_cursor = FALSE;	/* force cursor update */
1786     int		force_scrollbar = FALSE;
1787     static win_T	*old_curwin = NULL;
1788 
1789 /* #define DEBUG_GUI_WRITE */
1790 #ifdef DEBUG_GUI_WRITE
1791     {
1792 	int i;
1793 	char_u *str;
1794 
1795 	printf("gui_write(%d):\n    ", len);
1796 	for (i = 0; i < len; i++)
1797 	    if (s[i] == ESC)
1798 	    {
1799 		if (i != 0)
1800 		    printf("\n    ");
1801 		printf("<ESC>");
1802 	    }
1803 	    else
1804 	    {
1805 		str = transchar_byte(s[i]);
1806 		if (str[0] && str[1])
1807 		    printf("<%s>", (char *)str);
1808 		else
1809 		    printf("%s", (char *)str);
1810 	    }
1811 	printf("\n");
1812     }
1813 #endif
1814     while (len)
1815     {
1816 	if (s[0] == ESC && s[1] == '|')
1817 	{
1818 	    p = s + 2;
1819 	    if (VIM_ISDIGIT(*p) || (*p == '-' && VIM_ISDIGIT(*(p + 1))))
1820 	    {
1821 		arg1 = getdigits(&p);
1822 		if (p > s + len)
1823 		    break;
1824 		if (*p == ';')
1825 		{
1826 		    ++p;
1827 		    arg2 = getdigits(&p);
1828 		    if (p > s + len)
1829 			break;
1830 		}
1831 	    }
1832 	    switch (*p)
1833 	    {
1834 		case 'C':	/* Clear screen */
1835 		    clip_scroll_selection(9999);
1836 		    gui_mch_clear_all();
1837 		    gui.cursor_is_valid = FALSE;
1838 		    force_scrollbar = TRUE;
1839 		    break;
1840 		case 'M':	/* Move cursor */
1841 		    gui_set_cursor(arg1, arg2);
1842 		    break;
1843 		case 's':	/* force cursor (shape) update */
1844 		    force_cursor = TRUE;
1845 		    break;
1846 		case 'R':	/* Set scroll region */
1847 		    if (arg1 < arg2)
1848 		    {
1849 			gui.scroll_region_top = arg1;
1850 			gui.scroll_region_bot = arg2;
1851 		    }
1852 		    else
1853 		    {
1854 			gui.scroll_region_top = arg2;
1855 			gui.scroll_region_bot = arg1;
1856 		    }
1857 		    break;
1858 		case 'V':	/* Set vertical scroll region */
1859 		    if (arg1 < arg2)
1860 		    {
1861 			gui.scroll_region_left = arg1;
1862 			gui.scroll_region_right = arg2;
1863 		    }
1864 		    else
1865 		    {
1866 			gui.scroll_region_left = arg2;
1867 			gui.scroll_region_right = arg1;
1868 		    }
1869 		    break;
1870 		case 'd':	/* Delete line */
1871 		    gui_delete_lines(gui.row, 1);
1872 		    break;
1873 		case 'D':	/* Delete lines */
1874 		    gui_delete_lines(gui.row, arg1);
1875 		    break;
1876 		case 'i':	/* Insert line */
1877 		    gui_insert_lines(gui.row, 1);
1878 		    break;
1879 		case 'I':	/* Insert lines */
1880 		    gui_insert_lines(gui.row, arg1);
1881 		    break;
1882 		case '$':	/* Clear to end-of-line */
1883 		    gui_clear_block(gui.row, gui.col, gui.row,
1884 							    (int)Columns - 1);
1885 		    break;
1886 		case 'h':	/* Turn on highlighting */
1887 		    gui_start_highlight(arg1);
1888 		    break;
1889 		case 'H':	/* Turn off highlighting */
1890 		    gui_stop_highlight(arg1);
1891 		    break;
1892 		case 'f':	/* flash the window (visual bell) */
1893 		    gui_mch_flash(arg1 == 0 ? 20 : arg1);
1894 		    break;
1895 		default:
1896 		    p = s + 1;	/* Skip the ESC */
1897 		    break;
1898 	    }
1899 	    len -= (int)(++p - s);
1900 	    s = p;
1901 	}
1902 	else if (
1903 #ifdef EBCDIC
1904 		CtrlChar(s[0]) != 0	/* Ctrl character */
1905 #else
1906 		s[0] < 0x20		/* Ctrl character */
1907 #endif
1908 #ifdef FEAT_SIGN_ICONS
1909 		&& s[0] != SIGN_BYTE
1910 # ifdef FEAT_NETBEANS_INTG
1911 		&& s[0] != MULTISIGN_BYTE
1912 # endif
1913 #endif
1914 		)
1915 	{
1916 	    if (s[0] == '\n')		/* NL */
1917 	    {
1918 		gui.col = 0;
1919 		if (gui.row < gui.scroll_region_bot)
1920 		    gui.row++;
1921 		else
1922 		    gui_delete_lines(gui.scroll_region_top, 1);
1923 	    }
1924 	    else if (s[0] == '\r')	/* CR */
1925 	    {
1926 		gui.col = 0;
1927 	    }
1928 	    else if (s[0] == '\b')	/* Backspace */
1929 	    {
1930 		if (gui.col)
1931 		    --gui.col;
1932 	    }
1933 	    else if (s[0] == Ctrl_L)	/* cursor-right */
1934 	    {
1935 		++gui.col;
1936 	    }
1937 	    else if (s[0] == Ctrl_G)	/* Beep */
1938 	    {
1939 		gui_mch_beep();
1940 	    }
1941 	    /* Other Ctrl character: shouldn't happen! */
1942 
1943 	    --len;	/* Skip this char */
1944 	    ++s;
1945 	}
1946 	else
1947 	{
1948 	    p = s;
1949 	    while (len > 0 && (
1950 #ifdef EBCDIC
1951 			CtrlChar(*p) == 0
1952 #else
1953 			*p >= 0x20
1954 #endif
1955 #ifdef FEAT_SIGN_ICONS
1956 			|| *p == SIGN_BYTE
1957 # ifdef FEAT_NETBEANS_INTG
1958 			|| *p == MULTISIGN_BYTE
1959 # endif
1960 #endif
1961 			))
1962 	    {
1963 		len--;
1964 		p++;
1965 	    }
1966 	    gui_outstr(s, (int)(p - s));
1967 	    s = p;
1968 	}
1969     }
1970 
1971     /* Postponed update of the cursor (won't work if "can_update_cursor" isn't
1972      * set). */
1973     if (force_cursor)
1974 	gui_update_cursor(TRUE, TRUE);
1975 
1976     /* When switching to another window the dragging must have stopped.
1977      * Required for GTK, dragged_sb isn't reset. */
1978     if (old_curwin != curwin)
1979 	gui.dragged_sb = SBAR_NONE;
1980 
1981     /* Update the scrollbars after clearing the screen or when switched
1982      * to another window.
1983      * Update the horizontal scrollbar always, it's difficult to check all
1984      * situations where it might change. */
1985     if (force_scrollbar || old_curwin != curwin)
1986 	gui_update_scrollbars(force_scrollbar);
1987     else
1988 	gui_update_horiz_scrollbar(FALSE);
1989     old_curwin = curwin;
1990 
1991     /*
1992      * We need to make sure this is cleared since Athena doesn't tell us when
1993      * he is done dragging.  Do the same for GTK.
1994      */
1995 #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK)
1996     gui.dragged_sb = SBAR_NONE;
1997 #endif
1998 
1999     gui_may_flush();		    /* In case vim decides to take a nap */
2000 }
2001 
2002 /*
2003  * When ScreenLines[] is invalid, updating the cursor should not be done, it
2004  * produces wrong results.  Call gui_dont_update_cursor() before that code and
2005  * gui_can_update_cursor() afterwards.
2006  */
2007     void
2008 gui_dont_update_cursor(int undraw)
2009 {
2010     if (gui.in_use)
2011     {
2012 	/* Undraw the cursor now, we probably can't do it after the change. */
2013 	if (undraw)
2014 	    gui_undraw_cursor();
2015 	can_update_cursor = FALSE;
2016     }
2017 }
2018 
2019     void
2020 gui_can_update_cursor(void)
2021 {
2022     can_update_cursor = TRUE;
2023     /* No need to update the cursor right now, there is always more output
2024      * after scrolling. */
2025 }
2026 
2027 /*
2028  * Disable issuing gui_mch_flush().
2029  */
2030     void
2031 gui_disable_flush(void)
2032 {
2033     ++disable_flush;
2034 }
2035 
2036 /*
2037  * Enable issuing gui_mch_flush().
2038  */
2039     void
2040 gui_enable_flush(void)
2041 {
2042     --disable_flush;
2043 }
2044 
2045 /*
2046  * Issue gui_mch_flush() if it is not disabled.
2047  */
2048     void
2049 gui_may_flush(void)
2050 {
2051     if (disable_flush == 0)
2052 	gui_mch_flush();
2053 }
2054 
2055     static void
2056 gui_outstr(char_u *s, int len)
2057 {
2058     int	    this_len;
2059     int	    cells;
2060 
2061     if (len == 0)
2062 	return;
2063 
2064     if (len < 0)
2065 	len = (int)STRLEN(s);
2066 
2067     while (len > 0)
2068     {
2069 	if (has_mbyte)
2070 	{
2071 	    /* Find out how many chars fit in the current line. */
2072 	    cells = 0;
2073 	    for (this_len = 0; this_len < len; )
2074 	    {
2075 		cells += (*mb_ptr2cells)(s + this_len);
2076 		if (gui.col + cells > Columns)
2077 		    break;
2078 		this_len += (*mb_ptr2len)(s + this_len);
2079 	    }
2080 	    if (this_len > len)
2081 		this_len = len;	    /* don't include following composing char */
2082 	}
2083 	else
2084 	    if (gui.col + len > Columns)
2085 	    this_len = Columns - gui.col;
2086 	else
2087 	    this_len = len;
2088 
2089 	(void)gui_outstr_nowrap(s, this_len,
2090 					  0, (guicolor_T)0, (guicolor_T)0, 0);
2091 	s += this_len;
2092 	len -= this_len;
2093 	/* fill up for a double-width char that doesn't fit. */
2094 	if (len > 0 && gui.col < Columns)
2095 	    (void)gui_outstr_nowrap((char_u *)" ", 1,
2096 					  0, (guicolor_T)0, (guicolor_T)0, 0);
2097 	/* The cursor may wrap to the next line. */
2098 	if (gui.col >= Columns)
2099 	{
2100 	    gui.col = 0;
2101 	    gui.row++;
2102 	}
2103     }
2104 }
2105 
2106 /*
2107  * Output one character (may be one or two display cells).
2108  * Caller must check for valid "off".
2109  * Returns FAIL or OK, just like gui_outstr_nowrap().
2110  */
2111     static int
2112 gui_screenchar(
2113     int		off,	    /* Offset from start of screen */
2114     int		flags,
2115     guicolor_T	fg,	    /* colors for cursor */
2116     guicolor_T	bg,	    /* colors for cursor */
2117     int		back)	    /* backup this many chars when using bold trick */
2118 {
2119     char_u	buf[MB_MAXBYTES + 1];
2120 
2121     /* Don't draw right halve of a double-width UTF-8 char. "cannot happen" */
2122     if (enc_utf8 && ScreenLines[off] == 0)
2123 	return OK;
2124 
2125     if (enc_utf8 && ScreenLinesUC[off] != 0)
2126 	/* Draw UTF-8 multi-byte character. */
2127 	return gui_outstr_nowrap(buf, utfc_char2bytes(off, buf),
2128 							 flags, fg, bg, back);
2129 
2130     if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
2131     {
2132 	buf[0] = ScreenLines[off];
2133 	buf[1] = ScreenLines2[off];
2134 	return gui_outstr_nowrap(buf, 2, flags, fg, bg, back);
2135     }
2136 
2137     /* Draw non-multi-byte character or DBCS character. */
2138     return gui_outstr_nowrap(ScreenLines + off,
2139 	    enc_dbcs ? (*mb_ptr2len)(ScreenLines + off) : 1,
2140 							 flags, fg, bg, back);
2141 }
2142 
2143 #ifdef FEAT_GUI_GTK
2144 /*
2145  * Output the string at the given screen position.  This is used in place
2146  * of gui_screenchar() where possible because Pango needs as much context
2147  * as possible to work nicely.  It's a lot faster as well.
2148  */
2149     static int
2150 gui_screenstr(
2151     int		off,	    /* Offset from start of screen */
2152     int		len,	    /* string length in screen cells */
2153     int		flags,
2154     guicolor_T	fg,	    /* colors for cursor */
2155     guicolor_T	bg,	    /* colors for cursor */
2156     int		back)	    /* backup this many chars when using bold trick */
2157 {
2158     char_u  *buf;
2159     int	    outlen = 0;
2160     int	    i;
2161     int	    retval;
2162 
2163     if (len <= 0) /* "cannot happen"? */
2164 	return OK;
2165 
2166     if (enc_utf8)
2167     {
2168 	buf = alloc(len * MB_MAXBYTES + 1);
2169 	if (buf == NULL)
2170 	    return OK; /* not much we could do here... */
2171 
2172 	for (i = off; i < off + len; ++i)
2173 	{
2174 	    if (ScreenLines[i] == 0)
2175 		continue; /* skip second half of double-width char */
2176 
2177 	    if (ScreenLinesUC[i] == 0)
2178 		buf[outlen++] = ScreenLines[i];
2179 	    else
2180 		outlen += utfc_char2bytes(i, buf + outlen);
2181 	}
2182 
2183 	buf[outlen] = NUL; /* only to aid debugging */
2184 	retval = gui_outstr_nowrap(buf, outlen, flags, fg, bg, back);
2185 	vim_free(buf);
2186 
2187 	return retval;
2188     }
2189     else if (enc_dbcs == DBCS_JPNU)
2190     {
2191 	buf = alloc(len * 2 + 1);
2192 	if (buf == NULL)
2193 	    return OK; /* not much we could do here... */
2194 
2195 	for (i = off; i < off + len; ++i)
2196 	{
2197 	    buf[outlen++] = ScreenLines[i];
2198 
2199 	    /* handle double-byte single-width char */
2200 	    if (ScreenLines[i] == 0x8e)
2201 		buf[outlen++] = ScreenLines2[i];
2202 	    else if (MB_BYTE2LEN(ScreenLines[i]) == 2)
2203 		buf[outlen++] = ScreenLines[++i];
2204 	}
2205 
2206 	buf[outlen] = NUL; /* only to aid debugging */
2207 	retval = gui_outstr_nowrap(buf, outlen, flags, fg, bg, back);
2208 	vim_free(buf);
2209 
2210 	return retval;
2211     }
2212     else
2213     {
2214 	return gui_outstr_nowrap(&ScreenLines[off], len,
2215 				 flags, fg, bg, back);
2216     }
2217 }
2218 #endif /* FEAT_GUI_GTK */
2219 
2220 /*
2221  * Output the given string at the current cursor position.  If the string is
2222  * too long to fit on the line, then it is truncated.
2223  * "flags":
2224  * GUI_MON_IS_CURSOR should only be used when this function is being called to
2225  * actually draw (an inverted) cursor.
2226  * GUI_MON_TRS_CURSOR is used to draw the cursor text with a transparent
2227  * background.
2228  * GUI_MON_NOCLEAR is used to avoid clearing the selection when drawing over
2229  * it.
2230  * Returns OK, unless "back" is non-zero and using the bold trick, then return
2231  * FAIL (the caller should start drawing "back" chars back).
2232  */
2233     static int
2234 gui_outstr_nowrap(
2235     char_u	*s,
2236     int		len,
2237     int		flags,
2238     guicolor_T	fg,	    /* colors for cursor */
2239     guicolor_T	bg,	    /* colors for cursor */
2240     int		back)	    /* backup this many chars when using bold trick */
2241 {
2242     long_u	highlight_mask;
2243     long_u	hl_mask_todo;
2244     guicolor_T	fg_color;
2245     guicolor_T	bg_color;
2246     guicolor_T	sp_color;
2247 #if !defined(FEAT_GUI_GTK)
2248     GuiFont	font = NOFONT;
2249     GuiFont	wide_font = NOFONT;
2250 # ifdef FEAT_XFONTSET
2251     GuiFontset	fontset = NOFONTSET;
2252 # endif
2253 #endif
2254     attrentry_T	*aep = NULL;
2255     int		draw_flags;
2256     int		col = gui.col;
2257 #ifdef FEAT_SIGN_ICONS
2258     int		draw_sign = FALSE;
2259     int		signcol = 0;
2260     char_u	extra[18];
2261 # ifdef FEAT_NETBEANS_INTG
2262     int		multi_sign = FALSE;
2263 # endif
2264 #endif
2265 
2266     if (len < 0)
2267 	len = (int)STRLEN(s);
2268     if (len == 0)
2269 	return OK;
2270 
2271 #ifdef FEAT_SIGN_ICONS
2272     if (*s == SIGN_BYTE
2273 # ifdef FEAT_NETBEANS_INTG
2274 	  || *s == MULTISIGN_BYTE
2275 # endif
2276        )
2277     {
2278 # ifdef FEAT_NETBEANS_INTG
2279 	if (*s == MULTISIGN_BYTE)
2280 	    multi_sign = TRUE;
2281 # endif
2282 	/* draw spaces instead */
2283 	if (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) == 'u' &&
2284 		(curwin->w_p_nu || curwin->w_p_rnu))
2285 	{
2286 	    sprintf((char *)extra, "%*c ", number_width(curwin), ' ');
2287 	    s = extra;
2288 	}
2289 	else
2290 	    s = (char_u *)"  ";
2291 	if (len == 1 && col > 0)
2292 	    --col;
2293 	len = (int)STRLEN(s);
2294 	if (len > 2)
2295 	    // right align sign icon in the number column
2296 	    signcol = col + len - 3;
2297 	else
2298 	    signcol = col;
2299 	draw_sign = TRUE;
2300 	highlight_mask = 0;
2301     }
2302     else
2303 #endif
2304     if (gui.highlight_mask > HL_ALL)
2305     {
2306 	aep = syn_gui_attr2entry(gui.highlight_mask);
2307 	if (aep == NULL)	    /* highlighting not set */
2308 	    highlight_mask = 0;
2309 	else
2310 	    highlight_mask = aep->ae_attr;
2311     }
2312     else
2313 	highlight_mask = gui.highlight_mask;
2314     hl_mask_todo = highlight_mask;
2315 
2316 #if !defined(FEAT_GUI_GTK)
2317     /* Set the font */
2318     if (aep != NULL && aep->ae_u.gui.font != NOFONT)
2319 	font = aep->ae_u.gui.font;
2320 # ifdef FEAT_XFONTSET
2321     else if (aep != NULL && aep->ae_u.gui.fontset != NOFONTSET)
2322 	fontset = aep->ae_u.gui.fontset;
2323 # endif
2324     else
2325     {
2326 # ifdef FEAT_XFONTSET
2327 	if (gui.fontset != NOFONTSET)
2328 	    fontset = gui.fontset;
2329 	else
2330 # endif
2331 	    if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
2332 	{
2333 	    if ((hl_mask_todo & HL_ITALIC) && gui.boldital_font != NOFONT)
2334 	    {
2335 		font = gui.boldital_font;
2336 		hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT | HL_ITALIC);
2337 	    }
2338 	    else if (gui.bold_font != NOFONT)
2339 	    {
2340 		font = gui.bold_font;
2341 		hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT);
2342 	    }
2343 	    else
2344 		font = gui.norm_font;
2345 	}
2346 	else if ((hl_mask_todo & HL_ITALIC) && gui.ital_font != NOFONT)
2347 	{
2348 	    font = gui.ital_font;
2349 	    hl_mask_todo &= ~HL_ITALIC;
2350 	}
2351 	else
2352 	    font = gui.norm_font;
2353 
2354 	/*
2355 	 * Choose correct wide_font by font.  wide_font should be set with font
2356 	 * at same time in above block.  But it will make many "ifdef" nasty
2357 	 * blocks.  So we do it here.
2358 	 */
2359 	if (font == gui.boldital_font && gui.wide_boldital_font)
2360 	    wide_font = gui.wide_boldital_font;
2361 	else if (font == gui.bold_font && gui.wide_bold_font)
2362 	    wide_font = gui.wide_bold_font;
2363 	else if (font == gui.ital_font && gui.wide_ital_font)
2364 	    wide_font = gui.wide_ital_font;
2365 	else if (font == gui.norm_font && gui.wide_font)
2366 	    wide_font = gui.wide_font;
2367     }
2368 # ifdef FEAT_XFONTSET
2369     if (fontset != NOFONTSET)
2370 	gui_mch_set_fontset(fontset);
2371     else
2372 # endif
2373 	gui_mch_set_font(font);
2374 #endif
2375 
2376     draw_flags = 0;
2377 
2378     /* Set the color */
2379     bg_color = gui.back_pixel;
2380     if ((flags & GUI_MON_IS_CURSOR) && gui.in_focus)
2381     {
2382 	draw_flags |= DRAW_CURSOR;
2383 	fg_color = fg;
2384 	bg_color = bg;
2385 	sp_color = fg;
2386     }
2387     else if (aep != NULL)
2388     {
2389 	fg_color = aep->ae_u.gui.fg_color;
2390 	if (fg_color == INVALCOLOR)
2391 	    fg_color = gui.norm_pixel;
2392 	bg_color = aep->ae_u.gui.bg_color;
2393 	if (bg_color == INVALCOLOR)
2394 	    bg_color = gui.back_pixel;
2395 	sp_color = aep->ae_u.gui.sp_color;
2396 	if (sp_color == INVALCOLOR)
2397 	    sp_color = fg_color;
2398     }
2399     else
2400     {
2401 	fg_color = gui.norm_pixel;
2402 	sp_color = fg_color;
2403     }
2404 
2405     if (highlight_mask & (HL_INVERSE | HL_STANDOUT))
2406     {
2407 #if defined(AMIGA)
2408 	gui_mch_set_colors(bg_color, fg_color);
2409 #else
2410 	gui_mch_set_fg_color(bg_color);
2411 	gui_mch_set_bg_color(fg_color);
2412 #endif
2413     }
2414     else
2415     {
2416 #if defined(AMIGA)
2417 	gui_mch_set_colors(fg_color, bg_color);
2418 #else
2419 	gui_mch_set_fg_color(fg_color);
2420 	gui_mch_set_bg_color(bg_color);
2421 #endif
2422     }
2423     gui_mch_set_sp_color(sp_color);
2424 
2425     /* Clear the selection if we are about to write over it */
2426     if (!(flags & GUI_MON_NOCLEAR))
2427 	clip_may_clear_selection(gui.row, gui.row);
2428 
2429 
2430     /* If there's no bold font, then fake it */
2431     if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
2432 	draw_flags |= DRAW_BOLD;
2433 
2434     /*
2435      * When drawing bold or italic characters the spill-over from the left
2436      * neighbor may be destroyed.  Let the caller backup to start redrawing
2437      * just after a blank.
2438      */
2439     if (back != 0 && ((draw_flags & DRAW_BOLD) || (highlight_mask & HL_ITALIC)))
2440 	return FAIL;
2441 
2442 #if defined(FEAT_GUI_GTK)
2443     /* If there's no italic font, then fake it.
2444      * For GTK2, we don't need a different font for italic style. */
2445     if (hl_mask_todo & HL_ITALIC)
2446 	draw_flags |= DRAW_ITALIC;
2447 
2448     /* Do we underline the text? */
2449     if (hl_mask_todo & HL_UNDERLINE)
2450 	draw_flags |= DRAW_UNDERL;
2451 
2452 #else
2453     /* Do we underline the text? */
2454     if ((hl_mask_todo & HL_UNDERLINE) || (hl_mask_todo & HL_ITALIC))
2455 	draw_flags |= DRAW_UNDERL;
2456 #endif
2457     /* Do we undercurl the text? */
2458     if (hl_mask_todo & HL_UNDERCURL)
2459 	draw_flags |= DRAW_UNDERC;
2460 
2461     /* Do we strikethrough the text? */
2462     if (hl_mask_todo & HL_STRIKETHROUGH)
2463 	draw_flags |= DRAW_STRIKE;
2464 
2465     /* Do we draw transparently? */
2466     if (flags & GUI_MON_TRS_CURSOR)
2467 	draw_flags |= DRAW_TRANSP;
2468 
2469     /*
2470      * Draw the text.
2471      */
2472 #ifdef FEAT_GUI_GTK
2473     /* The value returned is the length in display cells */
2474     len = gui_gtk2_draw_string(gui.row, col, s, len, draw_flags);
2475 #else
2476     if (enc_utf8)
2477     {
2478 	int	start;		/* index of bytes to be drawn */
2479 	int	cells;		/* cellwidth of bytes to be drawn */
2480 	int	thislen;	/* length of bytes to be drawn */
2481 	int	cn;		/* cellwidth of current char */
2482 	int	i;		/* index of current char */
2483 	int	c;		/* current char value */
2484 	int	cl;		/* byte length of current char */
2485 	int	comping;	/* current char is composing */
2486 	int	scol = col;	/* screen column */
2487 	int	curr_wide = FALSE;  /* use 'guifontwide' */
2488 	int	prev_wide = FALSE;
2489 	int	wide_changed;
2490 # ifdef MSWIN
2491 	int	sep_comp = FALSE;   /* Don't separate composing chars. */
2492 # else
2493 	int	sep_comp = TRUE;    /* Separate composing chars. */
2494 # endif
2495 
2496 	/* Break the string at a composing character, it has to be drawn on
2497 	 * top of the previous character. */
2498 	start = 0;
2499 	cells = 0;
2500 	for (i = 0; i < len; i += cl)
2501 	{
2502 	    c = utf_ptr2char(s + i);
2503 	    cn = utf_char2cells(c);
2504 	    comping = utf_iscomposing(c);
2505 	    if (!comping)	/* count cells from non-composing chars */
2506 		cells += cn;
2507 	    if (!comping || sep_comp)
2508 	    {
2509 		if (cn > 1
2510 # ifdef FEAT_XFONTSET
2511 			&& fontset == NOFONTSET
2512 # endif
2513 			&& wide_font != NOFONT)
2514 		    curr_wide = TRUE;
2515 		else
2516 		    curr_wide = FALSE;
2517 	    }
2518 	    cl = utf_ptr2len(s + i);
2519 	    if (cl == 0)	/* hit end of string */
2520 		len = i + cl;	/* len must be wrong "cannot happen" */
2521 
2522 	    wide_changed = curr_wide != prev_wide;
2523 
2524 	    /* Print the string so far if it's the last character or there is
2525 	     * a composing character. */
2526 	    if (i + cl >= len || (comping && sep_comp && i > start)
2527 		    || wide_changed
2528 # if defined(FEAT_GUI_X11)
2529 		    || (cn > 1
2530 #  ifdef FEAT_XFONTSET
2531 			/* No fontset: At least draw char after wide char at
2532 			 * right position. */
2533 			&& fontset == NOFONTSET
2534 #  endif
2535 		       )
2536 # endif
2537 	       )
2538 	    {
2539 		if ((comping && sep_comp) || wide_changed)
2540 		    thislen = i - start;
2541 		else
2542 		    thislen = i - start + cl;
2543 		if (thislen > 0)
2544 		{
2545 		    if (prev_wide)
2546 			gui_mch_set_font(wide_font);
2547 		    gui_mch_draw_string(gui.row, scol, s + start, thislen,
2548 								  draw_flags);
2549 		    if (prev_wide)
2550 			gui_mch_set_font(font);
2551 		    start += thislen;
2552 		}
2553 		scol += cells;
2554 		cells = 0;
2555 		/* Adjust to not draw a character which width is changed
2556 		 * against with last one. */
2557 		if (wide_changed && !(comping && sep_comp))
2558 		{
2559 		    scol -= cn;
2560 		    cl = 0;
2561 		}
2562 
2563 # if defined(FEAT_GUI_X11)
2564 		/* No fontset: draw a space to fill the gap after a wide char
2565 		 * */
2566 		if (cn > 1 && (draw_flags & DRAW_TRANSP) == 0
2567 #  ifdef FEAT_XFONTSET
2568 			&& fontset == NOFONTSET
2569 #  endif
2570 			&& !wide_changed)
2571 		    gui_mch_draw_string(gui.row, scol - 1, (char_u *)" ",
2572 							       1, draw_flags);
2573 # endif
2574 	    }
2575 	    /* Draw a composing char on top of the previous char. */
2576 	    if (comping && sep_comp)
2577 	    {
2578 # if defined(__APPLE_CC__) && TARGET_API_MAC_CARBON
2579 		/* Carbon ATSUI autodraws composing char over previous char */
2580 		gui_mch_draw_string(gui.row, scol, s + i, cl,
2581 						    draw_flags | DRAW_TRANSP);
2582 # else
2583 		gui_mch_draw_string(gui.row, scol - cn, s + i, cl,
2584 						    draw_flags | DRAW_TRANSP);
2585 # endif
2586 		start = i + cl;
2587 	    }
2588 	    prev_wide = curr_wide;
2589 	}
2590 	/* The stuff below assumes "len" is the length in screen columns. */
2591 	len = scol - col;
2592     }
2593     else
2594     {
2595 	gui_mch_draw_string(gui.row, col, s, len, draw_flags);
2596 	if (enc_dbcs == DBCS_JPNU)
2597 	{
2598 	    /* Get the length in display cells, this can be different from the
2599 	     * number of bytes for "euc-jp". */
2600 	    len = mb_string2cells(s, len);
2601 	}
2602     }
2603 #endif /* !FEAT_GUI_GTK */
2604 
2605     if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
2606 	gui.col = col + len;
2607 
2608     /* May need to invert it when it's part of the selection. */
2609     if (flags & GUI_MON_NOCLEAR)
2610 	clip_may_redraw_selection(gui.row, col, len);
2611 
2612     if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
2613     {
2614 	/* Invalidate the old physical cursor position if we wrote over it */
2615 	if (gui.cursor_row == gui.row
2616 		&& gui.cursor_col >= col
2617 		&& gui.cursor_col < col + len)
2618 	    gui.cursor_is_valid = FALSE;
2619     }
2620 
2621 #ifdef FEAT_SIGN_ICONS
2622     if (draw_sign)
2623 	/* Draw the sign on top of the spaces. */
2624 	gui_mch_drawsign(gui.row, signcol, gui.highlight_mask);
2625 # if defined(FEAT_NETBEANS_INTG) && (defined(FEAT_GUI_X11) \
2626 	|| defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MSWIN))
2627     if (multi_sign)
2628 	netbeans_draw_multisign_indicator(gui.row);
2629 # endif
2630 #endif
2631 
2632     return OK;
2633 }
2634 
2635 /*
2636  * Un-draw the cursor.	Actually this just redraws the character at the given
2637  * position.  The character just before it too, for when it was in bold.
2638  */
2639     void
2640 gui_undraw_cursor(void)
2641 {
2642     if (gui.cursor_is_valid)
2643     {
2644 #ifdef FEAT_HANGULIN
2645 	if (composing_hangul
2646 		    && gui.col == gui.cursor_col && gui.row == gui.cursor_row)
2647 	{
2648 	    char_u *comp_buf;
2649 	    int comp_len;
2650 
2651 	    comp_buf = hangul_composing_buffer_get(&comp_len);
2652 	    if (comp_buf)
2653 	    {
2654 		(void)gui_outstr_nowrap(comp_buf, comp_len,
2655 					GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR,
2656 					gui.norm_pixel, gui.back_pixel, 0);
2657 		vim_free(comp_buf);
2658 	    }
2659 	}
2660 	else
2661 	{
2662 #endif
2663 	if (gui_redraw_block(gui.cursor_row, gui.cursor_col,
2664 			      gui.cursor_row, gui.cursor_col, GUI_MON_NOCLEAR)
2665 		&& gui.cursor_col > 0)
2666 	    (void)gui_redraw_block(gui.cursor_row, gui.cursor_col - 1,
2667 			 gui.cursor_row, gui.cursor_col - 1, GUI_MON_NOCLEAR);
2668 #ifdef FEAT_HANGULIN
2669 	    if (composing_hangul)
2670 		(void)gui_redraw_block(gui.cursor_row, gui.cursor_col + 1,
2671 			gui.cursor_row, gui.cursor_col + 1, GUI_MON_NOCLEAR);
2672 	}
2673 #endif
2674 	/* Cursor_is_valid is reset when the cursor is undrawn, also reset it
2675 	 * here in case it wasn't needed to undraw it. */
2676 	gui.cursor_is_valid = FALSE;
2677     }
2678 }
2679 
2680     void
2681 gui_redraw(
2682     int		x,
2683     int		y,
2684     int		w,
2685     int		h)
2686 {
2687     int		row1, col1, row2, col2;
2688 
2689     row1 = Y_2_ROW(y);
2690     col1 = X_2_COL(x);
2691     row2 = Y_2_ROW(y + h - 1);
2692     col2 = X_2_COL(x + w - 1);
2693 
2694     (void)gui_redraw_block(row1, col1, row2, col2, GUI_MON_NOCLEAR);
2695 
2696     /*
2697      * We may need to redraw the cursor, but don't take it upon us to change
2698      * its location after a scroll.
2699      * (maybe be more strict even and test col too?)
2700      * These things may be outside the update/clipping region and reality may
2701      * not reflect Vims internal ideas if these operations are clipped away.
2702      */
2703     if (gui.row == gui.cursor_row)
2704 	gui_update_cursor(TRUE, TRUE);
2705 }
2706 
2707 /*
2708  * Draw a rectangular block of characters, from row1 to row2 (inclusive) and
2709  * from col1 to col2 (inclusive).
2710  * Return TRUE when the character before the first drawn character has
2711  * different attributes (may have to be redrawn too).
2712  */
2713     int
2714 gui_redraw_block(
2715     int		row1,
2716     int		col1,
2717     int		row2,
2718     int		col2,
2719     int		flags)	/* flags for gui_outstr_nowrap() */
2720 {
2721     int		old_row, old_col;
2722     long_u	old_hl_mask;
2723     int		off;
2724     sattr_T	first_attr;
2725     int		idx, len;
2726     int		back, nback;
2727     int		retval = FALSE;
2728     int		orig_col1, orig_col2;
2729 
2730     /* Don't try to update when ScreenLines is not valid */
2731     if (!screen_cleared || ScreenLines == NULL)
2732 	return retval;
2733 
2734     /* Don't try to draw outside the shell! */
2735     /* Check everything, strange values may be caused by a big border width */
2736     col1 = check_col(col1);
2737     col2 = check_col(col2);
2738     row1 = check_row(row1);
2739     row2 = check_row(row2);
2740 
2741     /* Remember where our cursor was */
2742     old_row = gui.row;
2743     old_col = gui.col;
2744     old_hl_mask = gui.highlight_mask;
2745     orig_col1 = col1;
2746     orig_col2 = col2;
2747 
2748     for (gui.row = row1; gui.row <= row2; gui.row++)
2749     {
2750 	/* When only half of a double-wide character is in the block, include
2751 	 * the other half. */
2752 	col1 = orig_col1;
2753 	col2 = orig_col2;
2754 	off = LineOffset[gui.row];
2755 	if (enc_dbcs != 0)
2756 	{
2757 	    if (col1 > 0)
2758 		col1 -= dbcs_screen_head_off(ScreenLines + off,
2759 						    ScreenLines + off + col1);
2760 	    col2 += dbcs_screen_tail_off(ScreenLines + off,
2761 						    ScreenLines + off + col2);
2762 	}
2763 	else if (enc_utf8)
2764 	{
2765 	    if (ScreenLines[off + col1] == 0)
2766 	    {
2767 		if (col1 > 0)
2768 		    --col1;
2769 		else
2770 		{
2771 		    // FIXME: how can the first character ever be zero?
2772 		    // Make this IEMSGN when it no longer breaks Travis CI.
2773 		    vim_snprintf((char *)IObuff, IOSIZE,
2774 			    "INTERNAL ERROR: NUL in ScreenLines in row %ld",
2775 			    (long)gui.row);
2776 		    msg((char *)IObuff);
2777 		}
2778 	    }
2779 #ifdef FEAT_GUI_GTK
2780 	    if (col2 + 1 < Columns && ScreenLines[off + col2 + 1] == 0)
2781 		++col2;
2782 #endif
2783 	}
2784 	gui.col = col1;
2785 	off = LineOffset[gui.row] + gui.col;
2786 	len = col2 - col1 + 1;
2787 
2788 	/* Find how many chars back this highlighting starts, or where a space
2789 	 * is.  Needed for when the bold trick is used */
2790 	for (back = 0; back < col1; ++back)
2791 	    if (ScreenAttrs[off - 1 - back] != ScreenAttrs[off]
2792 		    || ScreenLines[off - 1 - back] == ' ')
2793 		break;
2794 	retval = (col1 > 0 && ScreenAttrs[off - 1] != 0 && back == 0
2795 					      && ScreenLines[off - 1] != ' ');
2796 
2797 	/* Break it up in strings of characters with the same attributes. */
2798 	/* Print UTF-8 characters individually. */
2799 	while (len > 0)
2800 	{
2801 	    first_attr = ScreenAttrs[off];
2802 	    gui.highlight_mask = first_attr;
2803 #if !defined(FEAT_GUI_GTK)
2804 	    if (enc_utf8 && ScreenLinesUC[off] != 0)
2805 	    {
2806 		/* output multi-byte character separately */
2807 		nback = gui_screenchar(off, flags,
2808 					  (guicolor_T)0, (guicolor_T)0, back);
2809 		if (gui.col < Columns && ScreenLines[off + 1] == 0)
2810 		    idx = 2;
2811 		else
2812 		    idx = 1;
2813 	    }
2814 	    else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
2815 	    {
2816 		/* output double-byte, single-width character separately */
2817 		nback = gui_screenchar(off, flags,
2818 					  (guicolor_T)0, (guicolor_T)0, back);
2819 		idx = 1;
2820 	    }
2821 	    else
2822 #endif
2823 	    {
2824 #ifdef FEAT_GUI_GTK
2825 		for (idx = 0; idx < len; ++idx)
2826 		{
2827 		    if (enc_utf8 && ScreenLines[off + idx] == 0)
2828 			continue; /* skip second half of double-width char */
2829 		    if (ScreenAttrs[off + idx] != first_attr)
2830 			break;
2831 		}
2832 		/* gui_screenstr() takes care of multibyte chars */
2833 		nback = gui_screenstr(off, idx, flags,
2834 				      (guicolor_T)0, (guicolor_T)0, back);
2835 #else
2836 		for (idx = 0; idx < len && ScreenAttrs[off + idx] == first_attr;
2837 									idx++)
2838 		{
2839 		    /* Stop at a multi-byte Unicode character. */
2840 		    if (enc_utf8 && ScreenLinesUC[off + idx] != 0)
2841 			break;
2842 		    if (enc_dbcs == DBCS_JPNU)
2843 		    {
2844 			/* Stop at a double-byte single-width char. */
2845 			if (ScreenLines[off + idx] == 0x8e)
2846 			    break;
2847 			if (len > 1 && (*mb_ptr2len)(ScreenLines
2848 							    + off + idx) == 2)
2849 			    ++idx;  /* skip second byte of double-byte char */
2850 		    }
2851 		}
2852 		nback = gui_outstr_nowrap(ScreenLines + off, idx, flags,
2853 					  (guicolor_T)0, (guicolor_T)0, back);
2854 #endif
2855 	    }
2856 	    if (nback == FAIL)
2857 	    {
2858 		/* Must back up to start drawing where a bold or italic word
2859 		 * starts. */
2860 		off -= back;
2861 		len += back;
2862 		gui.col -= back;
2863 	    }
2864 	    else
2865 	    {
2866 		off += idx;
2867 		len -= idx;
2868 	    }
2869 	    back = 0;
2870 	}
2871     }
2872 
2873     /* Put the cursor back where it was */
2874     gui.row = old_row;
2875     gui.col = old_col;
2876     gui.highlight_mask = (int)old_hl_mask;
2877 
2878     return retval;
2879 }
2880 
2881     static void
2882 gui_delete_lines(int row, int count)
2883 {
2884     if (count <= 0)
2885 	return;
2886 
2887     if (row + count > gui.scroll_region_bot)
2888 	/* Scrolled out of region, just blank the lines out */
2889 	gui_clear_block(row, gui.scroll_region_left,
2890 			      gui.scroll_region_bot, gui.scroll_region_right);
2891     else
2892     {
2893 	gui_mch_delete_lines(row, count);
2894 
2895 	/* If the cursor was in the deleted lines it's now gone.  If the
2896 	 * cursor was in the scrolled lines adjust its position. */
2897 	if (gui.cursor_row >= row
2898 		&& gui.cursor_col >= gui.scroll_region_left
2899 		&& gui.cursor_col <= gui.scroll_region_right)
2900 	{
2901 	    if (gui.cursor_row < row + count)
2902 		gui.cursor_is_valid = FALSE;
2903 	    else if (gui.cursor_row <= gui.scroll_region_bot)
2904 		gui.cursor_row -= count;
2905 	}
2906     }
2907 }
2908 
2909     static void
2910 gui_insert_lines(int row, int count)
2911 {
2912     if (count <= 0)
2913 	return;
2914 
2915     if (row + count > gui.scroll_region_bot)
2916 	/* Scrolled out of region, just blank the lines out */
2917 	gui_clear_block(row, gui.scroll_region_left,
2918 			      gui.scroll_region_bot, gui.scroll_region_right);
2919     else
2920     {
2921 	gui_mch_insert_lines(row, count);
2922 
2923 	if (gui.cursor_row >= gui.row
2924 		&& gui.cursor_col >= gui.scroll_region_left
2925 		&& gui.cursor_col <= gui.scroll_region_right)
2926 	{
2927 	    if (gui.cursor_row <= gui.scroll_region_bot - count)
2928 		gui.cursor_row += count;
2929 	    else if (gui.cursor_row <= gui.scroll_region_bot)
2930 		gui.cursor_is_valid = FALSE;
2931 	}
2932     }
2933 }
2934 
2935 #ifdef FEAT_TIMERS
2936 /*
2937  * Passed to ui_wait_for_chars_or_timer(), ignoring extra arguments.
2938  */
2939     static int
2940 gui_wait_for_chars_3(
2941     long wtime,
2942     int *interrupted UNUSED,
2943     int ignore_input UNUSED)
2944 {
2945     return gui_mch_wait_for_chars(wtime);
2946 }
2947 #endif
2948 
2949 /*
2950  * Returns OK if a character was found to be available within the given time,
2951  * or FAIL otherwise.
2952  */
2953     static int
2954 gui_wait_for_chars_or_timer(
2955 	long wtime,
2956 	int *interrupted UNUSED,
2957 	int ignore_input UNUSED)
2958 {
2959 #ifdef FEAT_TIMERS
2960     return ui_wait_for_chars_or_timer(wtime, gui_wait_for_chars_3,
2961 						    interrupted, ignore_input);
2962 #else
2963     return gui_mch_wait_for_chars(wtime);
2964 #endif
2965 }
2966 
2967 /*
2968  * The main GUI input routine.	Waits for a character from the keyboard.
2969  * "wtime" == -1    Wait forever.
2970  * "wtime" == 0	    Don't wait.
2971  * "wtime" > 0	    Wait wtime milliseconds for a character.
2972  *
2973  * Returns the number of characters read or zero when timed out or interrupted.
2974  * "buf" may be NULL, in which case a non-zero number is returned if characters
2975  * are available.
2976  */
2977     static int
2978 gui_wait_for_chars_buf(
2979     char_u	*buf,
2980     int		maxlen,
2981     long	wtime,	    // don't use "time", MIPS cannot handle it
2982     int		tb_change_cnt)
2983 {
2984     int	    retval;
2985 
2986 #ifdef FEAT_MENU
2987     // If we're going to wait a bit, update the menus and mouse shape for the
2988     // current State.
2989     if (wtime != 0)
2990 	gui_update_menus(0);
2991 #endif
2992 
2993     gui_mch_update();
2994     if (input_available())	// Got char, return immediately
2995     {
2996 	if (buf != NULL && !typebuf_changed(tb_change_cnt))
2997 	    return read_from_input_buf(buf, (long)maxlen);
2998 	return 0;
2999     }
3000     if (wtime == 0)		// Don't wait for char
3001 	return FAIL;
3002 
3003     // Before waiting, flush any output to the screen.
3004     gui_mch_flush();
3005 
3006     // Blink while waiting for a character.
3007     gui_mch_start_blink();
3008 
3009     // Common function to loop until "wtime" is met, while handling timers and
3010     // other callbacks.
3011     retval = inchar_loop(buf, maxlen, wtime, tb_change_cnt,
3012 			 gui_wait_for_chars_or_timer, NULL);
3013 
3014     gui_mch_stop_blink(TRUE);
3015 
3016     return retval;
3017 }
3018 
3019 /*
3020  * Wait for a character from the keyboard without actually reading it.
3021  * Also deals with timers.
3022  * wtime == -1	    Wait forever.
3023  * wtime == 0	    Don't wait.
3024  * wtime > 0	    Wait wtime milliseconds for a character.
3025  * Returns OK if a character was found to be available within the given time,
3026  * or FAIL otherwise.
3027  */
3028     int
3029 gui_wait_for_chars(long wtime, int tb_change_cnt)
3030 {
3031     return gui_wait_for_chars_buf(NULL, 0, wtime, tb_change_cnt);
3032 }
3033 
3034 /*
3035  * Equivalent of mch_inchar() for the GUI.
3036  */
3037     int
3038 gui_inchar(
3039     char_u  *buf,
3040     int	    maxlen,
3041     long    wtime,		/* milli seconds */
3042     int	    tb_change_cnt)
3043 {
3044     return gui_wait_for_chars_buf(buf, maxlen, wtime, tb_change_cnt);
3045 }
3046 
3047 /*
3048  * Fill p[4] with mouse coordinates encoded for check_termcode().
3049  */
3050     static void
3051 fill_mouse_coord(char_u *p, int col, int row)
3052 {
3053     p[0] = (char_u)(col / 128 + ' ' + 1);
3054     p[1] = (char_u)(col % 128 + ' ' + 1);
3055     p[2] = (char_u)(row / 128 + ' ' + 1);
3056     p[3] = (char_u)(row % 128 + ' ' + 1);
3057 }
3058 
3059 /*
3060  * Generic mouse support function.  Add a mouse event to the input buffer with
3061  * the given properties.
3062  *  button	    --- may be any of MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT,
3063  *			MOUSE_X1, MOUSE_X2
3064  *			MOUSE_DRAG, or MOUSE_RELEASE.
3065  *			MOUSE_4 and MOUSE_5 are used for vertical scroll wheel,
3066  *			MOUSE_6 and MOUSE_7 for horizontal scroll wheel.
3067  *  x, y	    --- Coordinates of mouse in pixels.
3068  *  repeated_click  --- TRUE if this click comes only a short time after a
3069  *			previous click.
3070  *  modifiers	    --- Bit field which may be any of the following modifiers
3071  *			or'ed together: MOUSE_SHIFT | MOUSE_CTRL | MOUSE_ALT.
3072  * This function will ignore drag events where the mouse has not moved to a new
3073  * character.
3074  */
3075     void
3076 gui_send_mouse_event(
3077     int	    button,
3078     int	    x,
3079     int	    y,
3080     int	    repeated_click,
3081     int_u   modifiers)
3082 {
3083     static int	    prev_row = 0, prev_col = 0;
3084     static int	    prev_button = -1;
3085     static int	    num_clicks = 1;
3086     char_u	    string[10];
3087     enum key_extra  button_char;
3088     int		    row, col;
3089 #ifdef FEAT_CLIPBOARD
3090     int		    checkfor;
3091     int		    did_clip = FALSE;
3092 #endif
3093 
3094     /*
3095      * Scrolling may happen at any time, also while a selection is present.
3096      */
3097     switch (button)
3098     {
3099 	case MOUSE_X1:
3100 	    button_char = KE_X1MOUSE;
3101 	    goto button_set;
3102 	case MOUSE_X2:
3103 	    button_char = KE_X2MOUSE;
3104 	    goto button_set;
3105 	case MOUSE_4:
3106 	    button_char = KE_MOUSEDOWN;
3107 	    goto button_set;
3108 	case MOUSE_5:
3109 	    button_char = KE_MOUSEUP;
3110 	    goto button_set;
3111 	case MOUSE_6:
3112 	    button_char = KE_MOUSELEFT;
3113 	    goto button_set;
3114 	case MOUSE_7:
3115 	    button_char = KE_MOUSERIGHT;
3116 button_set:
3117 	    {
3118 		/* Don't put events in the input queue now. */
3119 		if (hold_gui_events)
3120 		    return;
3121 
3122 		string[3] = CSI;
3123 		string[4] = KS_EXTRA;
3124 		string[5] = (int)button_char;
3125 
3126 		/* Pass the pointer coordinates of the scroll event so that we
3127 		 * know which window to scroll. */
3128 		row = gui_xy2colrow(x, y, &col);
3129 		string[6] = (char_u)(col / 128 + ' ' + 1);
3130 		string[7] = (char_u)(col % 128 + ' ' + 1);
3131 		string[8] = (char_u)(row / 128 + ' ' + 1);
3132 		string[9] = (char_u)(row % 128 + ' ' + 1);
3133 
3134 		if (modifiers == 0)
3135 		    add_to_input_buf(string + 3, 7);
3136 		else
3137 		{
3138 		    string[0] = CSI;
3139 		    string[1] = KS_MODIFIER;
3140 		    string[2] = 0;
3141 		    if (modifiers & MOUSE_SHIFT)
3142 			string[2] |= MOD_MASK_SHIFT;
3143 		    if (modifiers & MOUSE_CTRL)
3144 			string[2] |= MOD_MASK_CTRL;
3145 		    if (modifiers & MOUSE_ALT)
3146 			string[2] |= MOD_MASK_ALT;
3147 		    add_to_input_buf(string, 10);
3148 		}
3149 		return;
3150 	    }
3151     }
3152 
3153 #ifdef FEAT_CLIPBOARD
3154     /* If a clipboard selection is in progress, handle it */
3155     if (clip_star.state == SELECT_IN_PROGRESS)
3156     {
3157 	clip_process_selection(button, X_2_COL(x), Y_2_ROW(y), repeated_click);
3158 	return;
3159     }
3160 
3161     /* Determine which mouse settings to look for based on the current mode */
3162     switch (get_real_state())
3163     {
3164 	case NORMAL_BUSY:
3165 	case OP_PENDING:
3166 # ifdef FEAT_TERMINAL
3167 	case TERMINAL:
3168 # endif
3169 	case NORMAL:		checkfor = MOUSE_NORMAL;	break;
3170 	case VISUAL:		checkfor = MOUSE_VISUAL;	break;
3171 	case SELECTMODE:	checkfor = MOUSE_VISUAL;	break;
3172 	case REPLACE:
3173 	case REPLACE+LANGMAP:
3174 	case VREPLACE:
3175 	case VREPLACE+LANGMAP:
3176 	case INSERT:
3177 	case INSERT+LANGMAP:	checkfor = MOUSE_INSERT;	break;
3178 	case ASKMORE:
3179 	case HITRETURN:		/* At the more- and hit-enter prompt pass the
3180 				   mouse event for a click on or below the
3181 				   message line. */
3182 				if (Y_2_ROW(y) >= msg_row)
3183 				    checkfor = MOUSE_NORMAL;
3184 				else
3185 				    checkfor = MOUSE_RETURN;
3186 				break;
3187 
3188 	    /*
3189 	     * On the command line, use the clipboard selection on all lines
3190 	     * but the command line.  But not when pasting.
3191 	     */
3192 	case CMDLINE:
3193 	case CMDLINE+LANGMAP:
3194 	    if (Y_2_ROW(y) < cmdline_row && button != MOUSE_MIDDLE)
3195 		checkfor = MOUSE_NONE;
3196 	    else
3197 		checkfor = MOUSE_COMMAND;
3198 	    break;
3199 
3200 	default:
3201 	    checkfor = MOUSE_NONE;
3202 	    break;
3203     };
3204 
3205     /*
3206      * Allow clipboard selection of text on the command line in "normal"
3207      * modes.  Don't do this when dragging the status line, or extending a
3208      * Visual selection.
3209      */
3210     if ((State == NORMAL || State == NORMAL_BUSY || (State & INSERT))
3211 	    && Y_2_ROW(y) >= topframe->fr_height + firstwin->w_winrow
3212 	    && button != MOUSE_DRAG
3213 # ifdef FEAT_MOUSESHAPE
3214 	    && !drag_status_line
3215 	    && !drag_sep_line
3216 # endif
3217 	    )
3218 	checkfor = MOUSE_NONE;
3219 
3220     /*
3221      * Use modeless selection when holding CTRL and SHIFT pressed.
3222      */
3223     if ((modifiers & MOUSE_CTRL) && (modifiers & MOUSE_SHIFT))
3224 	checkfor = MOUSE_NONEF;
3225 
3226     /*
3227      * In Ex mode, always use modeless selection.
3228      */
3229     if (exmode_active)
3230 	checkfor = MOUSE_NONE;
3231 
3232     /*
3233      * If the mouse settings say to not use the mouse, use the modeless
3234      * selection.  But if Visual is active, assume that only the Visual area
3235      * will be selected.
3236      * Exception: On the command line, both the selection is used and a mouse
3237      * key is send.
3238      */
3239     if (!mouse_has(checkfor) || checkfor == MOUSE_COMMAND)
3240     {
3241 	/* Don't do modeless selection in Visual mode. */
3242 	if (checkfor != MOUSE_NONEF && VIsual_active && (State & NORMAL))
3243 	    return;
3244 
3245 	/*
3246 	 * When 'mousemodel' is "popup", shift-left is translated to right.
3247 	 * But not when also using Ctrl.
3248 	 */
3249 	if (mouse_model_popup() && button == MOUSE_LEFT
3250 		&& (modifiers & MOUSE_SHIFT) && !(modifiers & MOUSE_CTRL))
3251 	{
3252 	    button = MOUSE_RIGHT;
3253 	    modifiers &= ~ MOUSE_SHIFT;
3254 	}
3255 
3256 	/* If the selection is done, allow the right button to extend it.
3257 	 * If the selection is cleared, allow the right button to start it
3258 	 * from the cursor position. */
3259 	if (button == MOUSE_RIGHT)
3260 	{
3261 	    if (clip_star.state == SELECT_CLEARED)
3262 	    {
3263 		if (State & CMDLINE)
3264 		{
3265 		    col = msg_col;
3266 		    row = msg_row;
3267 		}
3268 		else
3269 		{
3270 		    col = curwin->w_wcol;
3271 		    row = curwin->w_wrow + W_WINROW(curwin);
3272 		}
3273 		clip_start_selection(col, row, FALSE);
3274 	    }
3275 	    clip_process_selection(button, X_2_COL(x), Y_2_ROW(y),
3276 							      repeated_click);
3277 	    did_clip = TRUE;
3278 	}
3279 	/* Allow the left button to start the selection */
3280 	else if (button == MOUSE_LEFT)
3281 	{
3282 	    clip_start_selection(X_2_COL(x), Y_2_ROW(y), repeated_click);
3283 	    did_clip = TRUE;
3284 	}
3285 
3286 	/* Always allow pasting */
3287 	if (button != MOUSE_MIDDLE)
3288 	{
3289 	    if (!mouse_has(checkfor) || button == MOUSE_RELEASE)
3290 		return;
3291 	    if (checkfor != MOUSE_COMMAND)
3292 		button = MOUSE_LEFT;
3293 	}
3294 	repeated_click = FALSE;
3295     }
3296 
3297     if (clip_star.state != SELECT_CLEARED && !did_clip)
3298 	clip_clear_selection(&clip_star);
3299 #endif
3300 
3301     /* Don't put events in the input queue now. */
3302     if (hold_gui_events)
3303 	return;
3304 
3305     row = gui_xy2colrow(x, y, &col);
3306 
3307     /*
3308      * If we are dragging and the mouse hasn't moved far enough to be on a
3309      * different character, then don't send an event to vim.
3310      */
3311     if (button == MOUSE_DRAG)
3312     {
3313 	if (row == prev_row && col == prev_col)
3314 	    return;
3315 	/* Dragging above the window, set "row" to -1 to cause a scroll. */
3316 	if (y < 0)
3317 	    row = -1;
3318     }
3319 
3320     /*
3321      * If topline has changed (window scrolled) since the last click, reset
3322      * repeated_click, because we don't want starting Visual mode when
3323      * clicking on a different character in the text.
3324      */
3325     if (curwin->w_topline != gui_prev_topline
3326 #ifdef FEAT_DIFF
3327 	    || curwin->w_topfill != gui_prev_topfill
3328 #endif
3329 	    )
3330 	repeated_click = FALSE;
3331 
3332     string[0] = CSI;	/* this sequence is recognized by check_termcode() */
3333     string[1] = KS_MOUSE;
3334     string[2] = KE_FILLER;
3335     if (button != MOUSE_DRAG && button != MOUSE_RELEASE)
3336     {
3337 	if (repeated_click)
3338 	{
3339 	    /*
3340 	     * Handle multiple clicks.	They only count if the mouse is still
3341 	     * pointing at the same character.
3342 	     */
3343 	    if (button != prev_button || row != prev_row || col != prev_col)
3344 		num_clicks = 1;
3345 	    else if (++num_clicks > 4)
3346 		num_clicks = 1;
3347 	}
3348 	else
3349 	    num_clicks = 1;
3350 	prev_button = button;
3351 	gui_prev_topline = curwin->w_topline;
3352 #ifdef FEAT_DIFF
3353 	gui_prev_topfill = curwin->w_topfill;
3354 #endif
3355 
3356 	string[3] = (char_u)(button | 0x20);
3357 	SET_NUM_MOUSE_CLICKS(string[3], num_clicks);
3358     }
3359     else
3360 	string[3] = (char_u)button;
3361 
3362     string[3] |= modifiers;
3363     fill_mouse_coord(string + 4, col, row);
3364     add_to_input_buf(string, 8);
3365 
3366     if (row < 0)
3367 	prev_row = 0;
3368     else
3369 	prev_row = row;
3370     prev_col = col;
3371 
3372     /*
3373      * We need to make sure this is cleared since Athena doesn't tell us when
3374      * he is done dragging.  Neither does GTK+ 2 -- at least for now.
3375      */
3376 #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK)
3377     gui.dragged_sb = SBAR_NONE;
3378 #endif
3379 }
3380 
3381 /*
3382  * Convert x and y coordinate to column and row in text window.
3383  * Corrects for multi-byte character.
3384  * returns column in "*colp" and row as return value;
3385  */
3386     static int
3387 gui_xy2colrow(int x, int y, int *colp)
3388 {
3389     int		col = check_col(X_2_COL(x));
3390     int		row = check_row(Y_2_ROW(y));
3391 
3392     *colp = mb_fix_col(col, row);
3393     return row;
3394 }
3395 
3396 #if defined(FEAT_MENU) || defined(PROTO)
3397 /*
3398  * Callback function for when a menu entry has been selected.
3399  */
3400     void
3401 gui_menu_cb(vimmenu_T *menu)
3402 {
3403     char_u  bytes[sizeof(long_u)];
3404 
3405     /* Don't put events in the input queue now. */
3406     if (hold_gui_events)
3407 	return;
3408 
3409     bytes[0] = CSI;
3410     bytes[1] = KS_MENU;
3411     bytes[2] = KE_FILLER;
3412     add_to_input_buf(bytes, 3);
3413     add_long_to_buf((long_u)menu, bytes);
3414     add_to_input_buf_csi(bytes, sizeof(long_u));
3415 }
3416 #endif
3417 
3418 static int	prev_which_scrollbars[3];
3419 
3420 /*
3421  * Set which components are present.
3422  * If "oldval" is not NULL, "oldval" is the previous value, the new value is
3423  * in p_go.
3424  */
3425     void
3426 gui_init_which_components(char_u *oldval UNUSED)
3427 {
3428 #ifdef FEAT_GUI_DARKTHEME
3429     static int	prev_dark_theme = -1;
3430     int		using_dark_theme = FALSE;
3431 #endif
3432 #ifdef FEAT_MENU
3433     static int	prev_menu_is_active = -1;
3434 #endif
3435 #ifdef FEAT_TOOLBAR
3436     static int	prev_toolbar = -1;
3437     int		using_toolbar = FALSE;
3438 #endif
3439 #ifdef FEAT_GUI_TABLINE
3440     int		using_tabline;
3441 #endif
3442 #ifdef FEAT_FOOTER
3443     static int	prev_footer = -1;
3444     int		using_footer = FALSE;
3445 #endif
3446 #if defined(FEAT_MENU)
3447     static int	prev_tearoff = -1;
3448     int		using_tearoff = FALSE;
3449 #endif
3450 
3451     char_u	*p;
3452     int		i;
3453 #ifdef FEAT_MENU
3454     int		grey_old, grey_new;
3455     char_u	*temp;
3456 #endif
3457     win_T	*wp;
3458     int		need_set_size;
3459     int		fix_size;
3460 
3461 #ifdef FEAT_MENU
3462     if (oldval != NULL && gui.in_use)
3463     {
3464 	/*
3465 	 * Check if the menu's go from grey to non-grey or vise versa.
3466 	 */
3467 	grey_old = (vim_strchr(oldval, GO_GREY) != NULL);
3468 	grey_new = (vim_strchr(p_go, GO_GREY) != NULL);
3469 	if (grey_old != grey_new)
3470 	{
3471 	    temp = p_go;
3472 	    p_go = oldval;
3473 	    gui_update_menus(MENU_ALL_MODES);
3474 	    p_go = temp;
3475 	}
3476     }
3477     gui.menu_is_active = FALSE;
3478 #endif
3479 
3480     for (i = 0; i < 3; i++)
3481 	gui.which_scrollbars[i] = FALSE;
3482     for (p = p_go; *p; p++)
3483 	switch (*p)
3484 	{
3485 	    case GO_LEFT:
3486 		gui.which_scrollbars[SBAR_LEFT] = TRUE;
3487 		break;
3488 	    case GO_RIGHT:
3489 		gui.which_scrollbars[SBAR_RIGHT] = TRUE;
3490 		break;
3491 	    case GO_VLEFT:
3492 		if (win_hasvertsplit())
3493 		    gui.which_scrollbars[SBAR_LEFT] = TRUE;
3494 		break;
3495 	    case GO_VRIGHT:
3496 		if (win_hasvertsplit())
3497 		    gui.which_scrollbars[SBAR_RIGHT] = TRUE;
3498 		break;
3499 	    case GO_BOT:
3500 		gui.which_scrollbars[SBAR_BOTTOM] = TRUE;
3501 		break;
3502 #ifdef FEAT_GUI_DARKTHEME
3503 	    case GO_DARKTHEME:
3504 		using_dark_theme = TRUE;
3505 		break;
3506 #endif
3507 #ifdef FEAT_MENU
3508 	    case GO_MENUS:
3509 		gui.menu_is_active = TRUE;
3510 		break;
3511 #endif
3512 	    case GO_GREY:
3513 		/* make menu's have grey items, ignored here */
3514 		break;
3515 #ifdef FEAT_TOOLBAR
3516 	    case GO_TOOLBAR:
3517 		using_toolbar = TRUE;
3518 		break;
3519 #endif
3520 #ifdef FEAT_FOOTER
3521 	    case GO_FOOTER:
3522 		using_footer = TRUE;
3523 		break;
3524 #endif
3525 	    case GO_TEAROFF:
3526 #if defined(FEAT_MENU)
3527 		using_tearoff = TRUE;
3528 #endif
3529 		break;
3530 	    default:
3531 		/* Ignore options that are not supported */
3532 		break;
3533 	}
3534 
3535     if (gui.in_use)
3536     {
3537 	need_set_size = 0;
3538 	fix_size = FALSE;
3539 
3540 #ifdef FEAT_GUI_DARKTHEME
3541 	if (using_dark_theme != prev_dark_theme)
3542 	{
3543 	    gui_mch_set_dark_theme(using_dark_theme);
3544 	    prev_dark_theme = using_dark_theme;
3545 	}
3546 #endif
3547 
3548 #ifdef FEAT_GUI_TABLINE
3549 	/* Update the GUI tab line, it may appear or disappear.  This may
3550 	 * cause the non-GUI tab line to disappear or appear. */
3551 	using_tabline = gui_has_tabline();
3552 	if (!gui_mch_showing_tabline() != !using_tabline)
3553 	{
3554 	    /* We don't want a resize event change "Rows" here, save and
3555 	     * restore it.  Resizing is handled below. */
3556 	    i = Rows;
3557 	    gui_update_tabline();
3558 	    Rows = i;
3559 	    need_set_size |= RESIZE_VERT;
3560 	    if (using_tabline)
3561 		fix_size = TRUE;
3562 	    if (!gui_use_tabline())
3563 		redraw_tabline = TRUE;    /* may draw non-GUI tab line */
3564 	}
3565 #endif
3566 
3567 	for (i = 0; i < 3; i++)
3568 	{
3569 	    /* The scrollbar needs to be updated when it is shown/unshown and
3570 	     * when switching tab pages.  But the size only changes when it's
3571 	     * shown/unshown.  Thus we need two places to remember whether a
3572 	     * scrollbar is there or not. */
3573 	    if (gui.which_scrollbars[i] != prev_which_scrollbars[i]
3574 		    || gui.which_scrollbars[i]
3575 					!= curtab->tp_prev_which_scrollbars[i])
3576 	    {
3577 		if (i == SBAR_BOTTOM)
3578 		    gui_mch_enable_scrollbar(&gui.bottom_sbar,
3579 						     gui.which_scrollbars[i]);
3580 		else
3581 		{
3582 		    FOR_ALL_WINDOWS(wp)
3583 			gui_do_scrollbar(wp, i, gui.which_scrollbars[i]);
3584 		}
3585 		if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
3586 		{
3587 		    if (i == SBAR_BOTTOM)
3588 			need_set_size |= RESIZE_VERT;
3589 		    else
3590 			need_set_size |= RESIZE_HOR;
3591 		    if (gui.which_scrollbars[i])
3592 			fix_size = TRUE;
3593 		}
3594 	    }
3595 	    curtab->tp_prev_which_scrollbars[i] = gui.which_scrollbars[i];
3596 	    prev_which_scrollbars[i] = gui.which_scrollbars[i];
3597 	}
3598 
3599 #ifdef FEAT_MENU
3600 	if (gui.menu_is_active != prev_menu_is_active)
3601 	{
3602 	    /* We don't want a resize event change "Rows" here, save and
3603 	     * restore it.  Resizing is handled below. */
3604 	    i = Rows;
3605 	    gui_mch_enable_menu(gui.menu_is_active);
3606 	    Rows = i;
3607 	    prev_menu_is_active = gui.menu_is_active;
3608 	    need_set_size |= RESIZE_VERT;
3609 	    if (gui.menu_is_active)
3610 		fix_size = TRUE;
3611 	}
3612 #endif
3613 
3614 #ifdef FEAT_TOOLBAR
3615 	if (using_toolbar != prev_toolbar)
3616 	{
3617 	    gui_mch_show_toolbar(using_toolbar);
3618 	    prev_toolbar = using_toolbar;
3619 	    need_set_size |= RESIZE_VERT;
3620 	    if (using_toolbar)
3621 		fix_size = TRUE;
3622 	}
3623 #endif
3624 #ifdef FEAT_FOOTER
3625 	if (using_footer != prev_footer)
3626 	{
3627 	    gui_mch_enable_footer(using_footer);
3628 	    prev_footer = using_footer;
3629 	    need_set_size |= RESIZE_VERT;
3630 	    if (using_footer)
3631 		fix_size = TRUE;
3632 	}
3633 #endif
3634 #if defined(FEAT_MENU) && !(defined(MSWIN) && !defined(FEAT_TEAROFF))
3635 	if (using_tearoff != prev_tearoff)
3636 	{
3637 	    gui_mch_toggle_tearoffs(using_tearoff);
3638 	    prev_tearoff = using_tearoff;
3639 	}
3640 #endif
3641 	if (need_set_size != 0)
3642 	{
3643 #ifdef FEAT_GUI_GTK
3644 	    long    prev_Columns = Columns;
3645 	    long    prev_Rows = Rows;
3646 #endif
3647 	    /* Adjust the size of the window to make the text area keep the
3648 	     * same size and to avoid that part of our window is off-screen
3649 	     * and a scrollbar can't be used, for example. */
3650 	    gui_set_shellsize(FALSE, fix_size, need_set_size);
3651 
3652 #ifdef FEAT_GUI_GTK
3653 	    /* GTK has the annoying habit of sending us resize events when
3654 	     * changing the window size ourselves.  This mostly happens when
3655 	     * waiting for a character to arrive, quite unpredictably, and may
3656 	     * change Columns and Rows when we don't want it.  Wait for a
3657 	     * character here to avoid this effect.
3658 	     * If you remove this, please test this command for resizing
3659 	     * effects (with optional left scrollbar): ":vsp|q|vsp|q|vsp|q".
3660 	     * Don't do this while starting up though.
3661 	     * Don't change Rows when adding menu/toolbar/tabline.
3662 	     * Don't change Columns when adding vertical toolbar. */
3663 	    if (!gui.starting && need_set_size != (RESIZE_VERT | RESIZE_HOR))
3664 		(void)char_avail();
3665 	    if ((need_set_size & RESIZE_VERT) == 0)
3666 		Rows = prev_Rows;
3667 	    if ((need_set_size & RESIZE_HOR) == 0)
3668 		Columns = prev_Columns;
3669 #endif
3670 	}
3671 	/* When the console tabline appears or disappears the window positions
3672 	 * change. */
3673 	if (firstwin->w_winrow != tabline_height())
3674 	    shell_new_rows();	/* recompute window positions and heights */
3675     }
3676 }
3677 
3678 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
3679 /*
3680  * Return TRUE if the GUI is taking care of the tabline.
3681  * It may still be hidden if 'showtabline' is zero.
3682  */
3683     int
3684 gui_use_tabline(void)
3685 {
3686     return gui.in_use && vim_strchr(p_go, GO_TABLINE) != NULL;
3687 }
3688 
3689 /*
3690  * Return TRUE if the GUI is showing the tabline.
3691  * This uses 'showtabline'.
3692  */
3693     static int
3694 gui_has_tabline(void)
3695 {
3696     if (!gui_use_tabline()
3697 	    || p_stal == 0
3698 	    || (p_stal == 1 && first_tabpage->tp_next == NULL))
3699 	return FALSE;
3700     return TRUE;
3701 }
3702 
3703 /*
3704  * Update the tabline.
3705  * This may display/undisplay the tabline and update the labels.
3706  */
3707     void
3708 gui_update_tabline(void)
3709 {
3710     int	    showit = gui_has_tabline();
3711     int	    shown = gui_mch_showing_tabline();
3712 
3713     if (!gui.starting && starting == 0)
3714     {
3715 	/* Updating the tabline uses direct GUI commands, flush
3716 	 * outstanding instructions first. (esp. clear screen) */
3717 	out_flush();
3718 
3719 	if (!showit != !shown)
3720 	    gui_mch_show_tabline(showit);
3721 	if (showit != 0)
3722 	    gui_mch_update_tabline();
3723 
3724 	/* When the tabs change from hidden to shown or from shown to
3725 	 * hidden the size of the text area should remain the same. */
3726 	if (!showit != !shown)
3727 	    gui_set_shellsize(FALSE, showit, RESIZE_VERT);
3728     }
3729 }
3730 
3731 /*
3732  * Get the label or tooltip for tab page "tp" into NameBuff[].
3733  */
3734     void
3735 get_tabline_label(
3736     tabpage_T	*tp,
3737     int		tooltip)	/* TRUE: get tooltip */
3738 {
3739     int		modified = FALSE;
3740     char_u	buf[40];
3741     int		wincount;
3742     win_T	*wp;
3743     char_u	**opt;
3744 
3745     /* Use 'guitablabel' or 'guitabtooltip' if it's set. */
3746     opt = (tooltip ? &p_gtt : &p_gtl);
3747     if (**opt != NUL)
3748     {
3749 	int	use_sandbox = FALSE;
3750 	int	save_called_emsg = called_emsg;
3751 	char_u	res[MAXPATHL];
3752 	tabpage_T *save_curtab;
3753 	char_u	*opt_name = (char_u *)(tooltip ? "guitabtooltip"
3754 							     : "guitablabel");
3755 
3756 	called_emsg = FALSE;
3757 
3758 	printer_page_num = tabpage_index(tp);
3759 # ifdef FEAT_EVAL
3760 	set_vim_var_nr(VV_LNUM, printer_page_num);
3761 	use_sandbox = was_set_insecurely(opt_name, 0);
3762 # endif
3763 	/* It's almost as going to the tabpage, but without autocommands. */
3764 	curtab->tp_firstwin = firstwin;
3765 	curtab->tp_lastwin = lastwin;
3766 	curtab->tp_curwin = curwin;
3767 	save_curtab = curtab;
3768 	curtab = tp;
3769 	topframe = curtab->tp_topframe;
3770 	firstwin = curtab->tp_firstwin;
3771 	lastwin = curtab->tp_lastwin;
3772 	curwin = curtab->tp_curwin;
3773 	curbuf = curwin->w_buffer;
3774 
3775 	/* Can't use NameBuff directly, build_stl_str_hl() uses it. */
3776 	build_stl_str_hl(curwin, res, MAXPATHL, *opt, use_sandbox,
3777 						 0, (int)Columns, NULL, NULL);
3778 	STRCPY(NameBuff, res);
3779 
3780 	/* Back to the original curtab. */
3781 	curtab = save_curtab;
3782 	topframe = curtab->tp_topframe;
3783 	firstwin = curtab->tp_firstwin;
3784 	lastwin = curtab->tp_lastwin;
3785 	curwin = curtab->tp_curwin;
3786 	curbuf = curwin->w_buffer;
3787 
3788 	if (called_emsg)
3789 	    set_string_option_direct(opt_name, -1,
3790 					   (char_u *)"", OPT_FREE, SID_ERROR);
3791 	called_emsg |= save_called_emsg;
3792     }
3793 
3794     /* If 'guitablabel'/'guitabtooltip' is not set or the result is empty then
3795      * use a default label. */
3796     if (**opt == NUL || *NameBuff == NUL)
3797     {
3798 	/* Get the buffer name into NameBuff[] and shorten it. */
3799 	get_trans_bufname(tp == curtab ? curbuf : tp->tp_curwin->w_buffer);
3800 	if (!tooltip)
3801 	    shorten_dir(NameBuff);
3802 
3803 	wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
3804 	for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
3805 	    if (bufIsChanged(wp->w_buffer))
3806 		modified = TRUE;
3807 	if (modified || wincount > 1)
3808 	{
3809 	    if (wincount > 1)
3810 		vim_snprintf((char *)buf, sizeof(buf), "%d", wincount);
3811 	    else
3812 		buf[0] = NUL;
3813 	    if (modified)
3814 		STRCAT(buf, "+");
3815 	    STRCAT(buf, " ");
3816 	    STRMOVE(NameBuff + STRLEN(buf), NameBuff);
3817 	    mch_memmove(NameBuff, buf, STRLEN(buf));
3818 	}
3819     }
3820 }
3821 
3822 /*
3823  * Send the event for clicking to select tab page "nr".
3824  * Returns TRUE if it was done, FALSE when skipped because we are already at
3825  * that tab page or the cmdline window is open.
3826  */
3827     int
3828 send_tabline_event(int nr)
3829 {
3830     char_u string[3];
3831 
3832     if (nr == tabpage_index(curtab))
3833 	return FALSE;
3834 
3835     /* Don't put events in the input queue now. */
3836     if (hold_gui_events
3837 # ifdef FEAT_CMDWIN
3838 	    || cmdwin_type != 0
3839 # endif
3840 	    )
3841     {
3842 	/* Set it back to the current tab page. */
3843 	gui_mch_set_curtab(tabpage_index(curtab));
3844 	return FALSE;
3845     }
3846 
3847     string[0] = CSI;
3848     string[1] = KS_TABLINE;
3849     string[2] = KE_FILLER;
3850     add_to_input_buf(string, 3);
3851     string[0] = nr;
3852     add_to_input_buf_csi(string, 1);
3853     return TRUE;
3854 }
3855 
3856 /*
3857  * Send a tabline menu event
3858  */
3859     void
3860 send_tabline_menu_event(int tabidx, int event)
3861 {
3862     char_u	    string[3];
3863 
3864     // Don't put events in the input queue now.
3865     if (hold_gui_events)
3866 	return;
3867 
3868     // Cannot close the last tabpage.
3869     if (event == TABLINE_MENU_CLOSE && first_tabpage->tp_next == NULL)
3870 	return;
3871 
3872     string[0] = CSI;
3873     string[1] = KS_TABMENU;
3874     string[2] = KE_FILLER;
3875     add_to_input_buf(string, 3);
3876     string[0] = tabidx;
3877     string[1] = (char_u)(long)event;
3878     add_to_input_buf_csi(string, 2);
3879 }
3880 
3881 #endif
3882 
3883 /*
3884  * Scrollbar stuff:
3885  */
3886 
3887 /*
3888  * Remove all scrollbars.  Used before switching to another tab page.
3889  */
3890     void
3891 gui_remove_scrollbars(void)
3892 {
3893     int	    i;
3894     win_T   *wp;
3895 
3896     for (i = 0; i < 3; i++)
3897     {
3898 	if (i == SBAR_BOTTOM)
3899 	    gui_mch_enable_scrollbar(&gui.bottom_sbar, FALSE);
3900 	else
3901 	{
3902 	    FOR_ALL_WINDOWS(wp)
3903 		gui_do_scrollbar(wp, i, FALSE);
3904 	}
3905 	curtab->tp_prev_which_scrollbars[i] = -1;
3906     }
3907 }
3908 
3909     void
3910 gui_create_scrollbar(scrollbar_T *sb, int type, win_T *wp)
3911 {
3912     static int	sbar_ident = 0;
3913 
3914     sb->ident = sbar_ident++;	/* No check for too big, but would it happen? */
3915     sb->wp = wp;
3916     sb->type = type;
3917     sb->value = 0;
3918 #ifdef FEAT_GUI_ATHENA
3919     sb->pixval = 0;
3920 #endif
3921     sb->size = 1;
3922     sb->max = 1;
3923     sb->top = 0;
3924     sb->height = 0;
3925     sb->width = 0;
3926     sb->status_height = 0;
3927     gui_mch_create_scrollbar(sb, (wp == NULL) ? SBAR_HORIZ : SBAR_VERT);
3928 }
3929 
3930 /*
3931  * Find the scrollbar with the given index.
3932  */
3933     scrollbar_T *
3934 gui_find_scrollbar(long ident)
3935 {
3936     win_T	*wp;
3937 
3938     if (gui.bottom_sbar.ident == ident)
3939 	return &gui.bottom_sbar;
3940     FOR_ALL_WINDOWS(wp)
3941     {
3942 	if (wp->w_scrollbars[SBAR_LEFT].ident == ident)
3943 	    return &wp->w_scrollbars[SBAR_LEFT];
3944 	if (wp->w_scrollbars[SBAR_RIGHT].ident == ident)
3945 	    return &wp->w_scrollbars[SBAR_RIGHT];
3946     }
3947     return NULL;
3948 }
3949 
3950 /*
3951  * For most systems: Put a code in the input buffer for a dragged scrollbar.
3952  *
3953  * For Win32, Macintosh and GTK+ 2:
3954  * Scrollbars seem to grab focus and vim doesn't read the input queue until
3955  * you stop dragging the scrollbar.  We get here each time the scrollbar is
3956  * dragged another pixel, but as far as the rest of vim goes, it thinks
3957  * we're just hanging in the call to DispatchMessage() in
3958  * process_message().  The DispatchMessage() call that hangs was passed a
3959  * mouse button click event in the scrollbar window. -- webb.
3960  *
3961  * Solution: Do the scrolling right here.  But only when allowed.
3962  * Ignore the scrollbars while executing an external command or when there
3963  * are still characters to be processed.
3964  */
3965     void
3966 gui_drag_scrollbar(scrollbar_T *sb, long value, int still_dragging)
3967 {
3968     win_T	*wp;
3969     int		sb_num;
3970 #ifdef USE_ON_FLY_SCROLL
3971     colnr_T	old_leftcol = curwin->w_leftcol;
3972     linenr_T	old_topline = curwin->w_topline;
3973 # ifdef FEAT_DIFF
3974     int		old_topfill = curwin->w_topfill;
3975 # endif
3976 #else
3977     char_u	bytes[sizeof(long_u)];
3978     int		byte_count;
3979 #endif
3980 
3981     if (sb == NULL)
3982 	return;
3983 
3984     /* Don't put events in the input queue now. */
3985     if (hold_gui_events)
3986 	return;
3987 
3988 #ifdef FEAT_CMDWIN
3989     if (cmdwin_type != 0 && sb->wp != curwin)
3990 	return;
3991 #endif
3992 
3993     if (still_dragging)
3994     {
3995 	if (sb->wp == NULL)
3996 	    gui.dragged_sb = SBAR_BOTTOM;
3997 	else if (sb == &sb->wp->w_scrollbars[SBAR_LEFT])
3998 	    gui.dragged_sb = SBAR_LEFT;
3999 	else
4000 	    gui.dragged_sb = SBAR_RIGHT;
4001 	gui.dragged_wp = sb->wp;
4002     }
4003     else
4004     {
4005 	gui.dragged_sb = SBAR_NONE;
4006 #ifdef FEAT_GUI_GTK
4007 	/* Keep the "dragged_wp" value until after the scrolling, for when the
4008 	 * mouse button is released.  GTK2 doesn't send the button-up event. */
4009 	gui.dragged_wp = NULL;
4010 #endif
4011     }
4012 
4013     /* Vertical sbar info is kept in the first sbar (the left one) */
4014     if (sb->wp != NULL)
4015 	sb = &sb->wp->w_scrollbars[0];
4016 
4017     /*
4018      * Check validity of value
4019      */
4020     if (value < 0)
4021 	value = 0;
4022 #ifdef SCROLL_PAST_END
4023     else if (value > sb->max)
4024 	value = sb->max;
4025 #else
4026     if (value > sb->max - sb->size + 1)
4027 	value = sb->max - sb->size + 1;
4028 #endif
4029 
4030     sb->value = value;
4031 
4032 #ifdef USE_ON_FLY_SCROLL
4033     /* When not allowed to do the scrolling right now, return.
4034      * This also checked input_available(), but that causes the first click in
4035      * a scrollbar to be ignored when Vim doesn't have focus. */
4036     if (dont_scroll)
4037 	return;
4038 #endif
4039     /* Disallow scrolling the current window when the completion popup menu is
4040      * visible. */
4041     if ((sb->wp == NULL || sb->wp == curwin) && pum_visible())
4042 	return;
4043 
4044 #ifdef FEAT_RIGHTLEFT
4045     if (sb->wp == NULL && curwin->w_p_rl)
4046     {
4047 	value = sb->max + 1 - sb->size - value;
4048 	if (value < 0)
4049 	    value = 0;
4050     }
4051 #endif
4052 
4053     if (sb->wp != NULL)		/* vertical scrollbar */
4054     {
4055 	sb_num = 0;
4056 	for (wp = firstwin; wp != sb->wp && wp != NULL; wp = wp->w_next)
4057 	    sb_num++;
4058 	if (wp == NULL)
4059 	    return;
4060 
4061 #ifdef USE_ON_FLY_SCROLL
4062 	current_scrollbar = sb_num;
4063 	scrollbar_value = value;
4064 	if (State & NORMAL)
4065 	{
4066 	    gui_do_scroll();
4067 	    setcursor();
4068 	}
4069 	else if (State & INSERT)
4070 	{
4071 	    ins_scroll();
4072 	    setcursor();
4073 	}
4074 	else if (State & CMDLINE)
4075 	{
4076 	    if (msg_scrolled == 0)
4077 	    {
4078 		gui_do_scroll();
4079 		redrawcmdline();
4080 	    }
4081 	}
4082 # ifdef FEAT_FOLDING
4083 	/* Value may have been changed for closed fold. */
4084 	sb->value = sb->wp->w_topline - 1;
4085 # endif
4086 
4087 	/* When dragging one scrollbar and there is another one at the other
4088 	 * side move the thumb of that one too. */
4089 	if (gui.which_scrollbars[SBAR_RIGHT] && gui.which_scrollbars[SBAR_LEFT])
4090 	    gui_mch_set_scrollbar_thumb(
4091 		    &sb->wp->w_scrollbars[
4092 			    sb == &sb->wp->w_scrollbars[SBAR_RIGHT]
4093 						    ? SBAR_LEFT : SBAR_RIGHT],
4094 		    sb->value, sb->size, sb->max);
4095 
4096 #else
4097 	bytes[0] = CSI;
4098 	bytes[1] = KS_VER_SCROLLBAR;
4099 	bytes[2] = KE_FILLER;
4100 	bytes[3] = (char_u)sb_num;
4101 	byte_count = 4;
4102 #endif
4103     }
4104     else
4105     {
4106 #ifdef USE_ON_FLY_SCROLL
4107 	scrollbar_value = value;
4108 
4109 	if (State & NORMAL)
4110 	    gui_do_horiz_scroll(scrollbar_value, FALSE);
4111 	else if (State & INSERT)
4112 	    ins_horscroll();
4113 	else if (State & CMDLINE)
4114 	{
4115 	    if (msg_scrolled == 0)
4116 	    {
4117 		gui_do_horiz_scroll(scrollbar_value, FALSE);
4118 		redrawcmdline();
4119 	    }
4120 	}
4121 	if (old_leftcol != curwin->w_leftcol)
4122 	{
4123 	    updateWindow(curwin);   /* update window, status and cmdline */
4124 	    setcursor();
4125 	}
4126 #else
4127 	bytes[0] = CSI;
4128 	bytes[1] = KS_HOR_SCROLLBAR;
4129 	bytes[2] = KE_FILLER;
4130 	byte_count = 3;
4131 #endif
4132     }
4133 
4134 #ifdef USE_ON_FLY_SCROLL
4135     /*
4136      * synchronize other windows, as necessary according to 'scrollbind'
4137      */
4138     if (curwin->w_p_scb
4139 	    && ((sb->wp == NULL && curwin->w_leftcol != old_leftcol)
4140 		|| (sb->wp == curwin && (curwin->w_topline != old_topline
4141 # ifdef FEAT_DIFF
4142 					   || curwin->w_topfill != old_topfill
4143 # endif
4144 			))))
4145     {
4146 	do_check_scrollbind(TRUE);
4147 	/* need to update the window right here */
4148 	FOR_ALL_WINDOWS(wp)
4149 	    if (wp->w_redr_type > 0)
4150 		updateWindow(wp);
4151 	setcursor();
4152     }
4153     out_flush_cursor(FALSE, TRUE);
4154 #else
4155     add_to_input_buf(bytes, byte_count);
4156     add_long_to_buf((long_u)value, bytes);
4157     add_to_input_buf_csi(bytes, sizeof(long_u));
4158 #endif
4159 }
4160 
4161 /*
4162  * Scrollbar stuff:
4163  */
4164 
4165 /*
4166  * Called when something in the window layout has changed.
4167  */
4168     void
4169 gui_may_update_scrollbars(void)
4170 {
4171     if (gui.in_use && starting == 0)
4172     {
4173 	out_flush();
4174 	gui_init_which_components(NULL);
4175 	gui_update_scrollbars(TRUE);
4176     }
4177     need_mouse_correct = TRUE;
4178 }
4179 
4180     void
4181 gui_update_scrollbars(
4182     int		force)	    /* Force all scrollbars to get updated */
4183 {
4184     win_T	*wp;
4185     scrollbar_T	*sb;
4186     long	val, size, max;		/* need 32 bits here */
4187     int		which_sb;
4188     int		h, y;
4189     static win_T *prev_curwin = NULL;
4190 
4191     /* Update the horizontal scrollbar */
4192     gui_update_horiz_scrollbar(force);
4193 
4194 #ifndef MSWIN
4195     /* Return straight away if there is neither a left nor right scrollbar.
4196      * On MS-Windows this is required anyway for scrollwheel messages. */
4197     if (!gui.which_scrollbars[SBAR_LEFT] && !gui.which_scrollbars[SBAR_RIGHT])
4198 	return;
4199 #endif
4200 
4201     /*
4202      * Don't want to update a scrollbar while we're dragging it.  But if we
4203      * have both a left and right scrollbar, and we drag one of them, we still
4204      * need to update the other one.
4205      */
4206     if (!force && (gui.dragged_sb == SBAR_LEFT || gui.dragged_sb == SBAR_RIGHT)
4207 	    && gui.which_scrollbars[SBAR_LEFT]
4208 	    && gui.which_scrollbars[SBAR_RIGHT])
4209     {
4210 	/*
4211 	 * If we have two scrollbars and one of them is being dragged, just
4212 	 * copy the scrollbar position from the dragged one to the other one.
4213 	 */
4214 	which_sb = SBAR_LEFT + SBAR_RIGHT - gui.dragged_sb;
4215 	if (gui.dragged_wp != NULL)
4216 	    gui_mch_set_scrollbar_thumb(
4217 		    &gui.dragged_wp->w_scrollbars[which_sb],
4218 		    gui.dragged_wp->w_scrollbars[0].value,
4219 		    gui.dragged_wp->w_scrollbars[0].size,
4220 		    gui.dragged_wp->w_scrollbars[0].max);
4221     }
4222 
4223     /* avoid that moving components around generates events */
4224     ++hold_gui_events;
4225 
4226     for (wp = firstwin; wp != NULL; wp = W_NEXT(wp))
4227     {
4228 	if (wp->w_buffer == NULL)	/* just in case */
4229 	    continue;
4230 	/* Skip a scrollbar that is being dragged. */
4231 	if (!force && (gui.dragged_sb == SBAR_LEFT
4232 					     || gui.dragged_sb == SBAR_RIGHT)
4233 		&& gui.dragged_wp == wp)
4234 	    continue;
4235 
4236 #ifdef SCROLL_PAST_END
4237 	max = wp->w_buffer->b_ml.ml_line_count - 1;
4238 #else
4239 	max = wp->w_buffer->b_ml.ml_line_count + wp->w_height - 2;
4240 #endif
4241 	if (max < 0)			/* empty buffer */
4242 	    max = 0;
4243 	val = wp->w_topline - 1;
4244 	size = wp->w_height;
4245 #ifdef SCROLL_PAST_END
4246 	if (val > max)			/* just in case */
4247 	    val = max;
4248 #else
4249 	if (size > max + 1)		/* just in case */
4250 	    size = max + 1;
4251 	if (val > max - size + 1)
4252 	    val = max - size + 1;
4253 #endif
4254 	if (val < 0)			/* minimal value is 0 */
4255 	    val = 0;
4256 
4257 	/*
4258 	 * Scrollbar at index 0 (the left one) contains all the information.
4259 	 * It would be the same info for left and right so we just store it for
4260 	 * one of them.
4261 	 */
4262 	sb = &wp->w_scrollbars[0];
4263 
4264 	/*
4265 	 * Note: no check for valid w_botline.	If it's not valid the
4266 	 * scrollbars will be updated later anyway.
4267 	 */
4268 	if (size < 1 || wp->w_botline - 2 > max)
4269 	{
4270 	    /*
4271 	     * This can happen during changing files.  Just don't update the
4272 	     * scrollbar for now.
4273 	     */
4274 	    sb->height = 0;	    /* Force update next time */
4275 	    if (gui.which_scrollbars[SBAR_LEFT])
4276 		gui_do_scrollbar(wp, SBAR_LEFT, FALSE);
4277 	    if (gui.which_scrollbars[SBAR_RIGHT])
4278 		gui_do_scrollbar(wp, SBAR_RIGHT, FALSE);
4279 	    continue;
4280 	}
4281 	if (force || sb->height != wp->w_height
4282 	    || sb->top != wp->w_winrow
4283 	    || sb->status_height != wp->w_status_height
4284 	    || sb->width != wp->w_width
4285 	    || prev_curwin != curwin)
4286 	{
4287 	    /* Height, width or position of scrollbar has changed.  For
4288 	     * vertical split: curwin changed. */
4289 	    sb->height = wp->w_height;
4290 	    sb->top = wp->w_winrow;
4291 	    sb->status_height = wp->w_status_height;
4292 	    sb->width = wp->w_width;
4293 
4294 	    /* Calculate height and position in pixels */
4295 	    h = (sb->height + sb->status_height) * gui.char_height;
4296 	    y = sb->top * gui.char_height + gui.border_offset;
4297 #if defined(FEAT_MENU) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF) && !defined(FEAT_GUI_PHOTON)
4298 	    if (gui.menu_is_active)
4299 		y += gui.menu_height;
4300 #endif
4301 
4302 #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_ATHENA))
4303 	    if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
4304 # ifdef FEAT_GUI_ATHENA
4305 		y += gui.toolbar_height;
4306 # else
4307 #  ifdef FEAT_GUI_MSWIN
4308 		y += TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
4309 #  endif
4310 # endif
4311 #endif
4312 
4313 #if defined(FEAT_GUI_TABLINE) && defined(FEAT_GUI_MSWIN)
4314 	    if (gui_has_tabline())
4315 		y += gui.tabline_height;
4316 #endif
4317 
4318 	    if (wp->w_winrow == 0)
4319 	    {
4320 		/* Height of top scrollbar includes width of top border */
4321 		h += gui.border_offset;
4322 		y -= gui.border_offset;
4323 	    }
4324 	    if (gui.which_scrollbars[SBAR_LEFT])
4325 	    {
4326 		gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_LEFT],
4327 					  gui.left_sbar_x, y,
4328 					  gui.scrollbar_width, h);
4329 		gui_do_scrollbar(wp, SBAR_LEFT, TRUE);
4330 	    }
4331 	    if (gui.which_scrollbars[SBAR_RIGHT])
4332 	    {
4333 		gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_RIGHT],
4334 					  gui.right_sbar_x, y,
4335 					  gui.scrollbar_width, h);
4336 		gui_do_scrollbar(wp, SBAR_RIGHT, TRUE);
4337 	    }
4338 	}
4339 
4340 	/* Reduce the number of calls to gui_mch_set_scrollbar_thumb() by
4341 	 * checking if the thumb moved at least a pixel.  Only do this for
4342 	 * Athena, most other GUIs require the update anyway to make the
4343 	 * arrows work. */
4344 #ifdef FEAT_GUI_ATHENA
4345 	if (max == 0)
4346 	    y = 0;
4347 	else
4348 	    y = (val * (sb->height + 2) * gui.char_height + max / 2) / max;
4349 	if (force || sb->pixval != y || sb->size != size || sb->max != max)
4350 #else
4351 	if (force || sb->value != val || sb->size != size || sb->max != max)
4352 #endif
4353 	{
4354 	    /* Thumb of scrollbar has moved */
4355 	    sb->value = val;
4356 #ifdef FEAT_GUI_ATHENA
4357 	    sb->pixval = y;
4358 #endif
4359 	    sb->size = size;
4360 	    sb->max = max;
4361 	    if (gui.which_scrollbars[SBAR_LEFT]
4362 		    && (gui.dragged_sb != SBAR_LEFT || gui.dragged_wp != wp))
4363 		gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_LEFT],
4364 					    val, size, max);
4365 	    if (gui.which_scrollbars[SBAR_RIGHT]
4366 		    && (gui.dragged_sb != SBAR_RIGHT || gui.dragged_wp != wp))
4367 		gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_RIGHT],
4368 					    val, size, max);
4369 	}
4370     }
4371     prev_curwin = curwin;
4372     --hold_gui_events;
4373 }
4374 
4375 /*
4376  * Enable or disable a scrollbar.
4377  * Check for scrollbars for vertically split windows which are not enabled
4378  * sometimes.
4379  */
4380     static void
4381 gui_do_scrollbar(
4382     win_T	*wp,
4383     int		which,	    /* SBAR_LEFT or SBAR_RIGHT */
4384     int		enable)	    /* TRUE to enable scrollbar */
4385 {
4386     int		midcol = curwin->w_wincol + curwin->w_width / 2;
4387     int		has_midcol = (wp->w_wincol <= midcol
4388 				     && wp->w_wincol + wp->w_width >= midcol);
4389 
4390     /* Only enable scrollbars that contain the middle column of the current
4391      * window. */
4392     if (gui.which_scrollbars[SBAR_RIGHT] != gui.which_scrollbars[SBAR_LEFT])
4393     {
4394 	/* Scrollbars only on one side.  Don't enable scrollbars that don't
4395 	 * contain the middle column of the current window. */
4396 	if (!has_midcol)
4397 	    enable = FALSE;
4398     }
4399     else
4400     {
4401 	/* Scrollbars on both sides.  Don't enable scrollbars that neither
4402 	 * contain the middle column of the current window nor are on the far
4403 	 * side. */
4404 	if (midcol > Columns / 2)
4405 	{
4406 	    if (which == SBAR_LEFT ? wp->w_wincol != 0 : !has_midcol)
4407 		enable = FALSE;
4408 	}
4409 	else
4410 	{
4411 	    if (which == SBAR_RIGHT ? wp->w_wincol + wp->w_width != Columns
4412 								: !has_midcol)
4413 		enable = FALSE;
4414 	}
4415     }
4416     gui_mch_enable_scrollbar(&wp->w_scrollbars[which], enable);
4417 }
4418 
4419 /*
4420  * Scroll a window according to the values set in the globals current_scrollbar
4421  * and scrollbar_value.  Return TRUE if the cursor in the current window moved
4422  * or FALSE otherwise.
4423  */
4424     int
4425 gui_do_scroll(void)
4426 {
4427     win_T	*wp, *save_wp;
4428     int		i;
4429     long	nlines;
4430     pos_T	old_cursor;
4431     linenr_T	old_topline;
4432 #ifdef FEAT_DIFF
4433     int		old_topfill;
4434 #endif
4435 
4436     for (wp = firstwin, i = 0; i < current_scrollbar; wp = W_NEXT(wp), i++)
4437 	if (wp == NULL)
4438 	    break;
4439     if (wp == NULL)
4440 	/* Couldn't find window */
4441 	return FALSE;
4442 
4443     /*
4444      * Compute number of lines to scroll.  If zero, nothing to do.
4445      */
4446     nlines = (long)scrollbar_value + 1 - (long)wp->w_topline;
4447     if (nlines == 0)
4448 	return FALSE;
4449 
4450     save_wp = curwin;
4451     old_topline = wp->w_topline;
4452 #ifdef FEAT_DIFF
4453     old_topfill = wp->w_topfill;
4454 #endif
4455     old_cursor = wp->w_cursor;
4456     curwin = wp;
4457     curbuf = wp->w_buffer;
4458     if (nlines < 0)
4459 	scrolldown(-nlines, gui.dragged_wp == NULL);
4460     else
4461 	scrollup(nlines, gui.dragged_wp == NULL);
4462     /* Reset dragged_wp after using it.  "dragged_sb" will have been reset for
4463      * the mouse-up event already, but we still want it to behave like when
4464      * dragging.  But not the next click in an arrow. */
4465     if (gui.dragged_sb == SBAR_NONE)
4466 	gui.dragged_wp = NULL;
4467 
4468     if (old_topline != wp->w_topline
4469 #ifdef FEAT_DIFF
4470 	    || old_topfill != wp->w_topfill
4471 #endif
4472 	    )
4473     {
4474 	if (get_scrolloff_value() != 0)
4475 	{
4476 	    cursor_correct();		/* fix window for 'so' */
4477 	    update_topline();		/* avoid up/down jump */
4478 	}
4479 	if (old_cursor.lnum != wp->w_cursor.lnum)
4480 	    coladvance(wp->w_curswant);
4481 	wp->w_scbind_pos = wp->w_topline;
4482     }
4483 
4484     /* Make sure wp->w_leftcol and wp->w_skipcol are correct. */
4485     validate_cursor();
4486 
4487     curwin = save_wp;
4488     curbuf = save_wp->w_buffer;
4489 
4490     /*
4491      * Don't call updateWindow() when nothing has changed (it will overwrite
4492      * the status line!).
4493      */
4494     if (old_topline != wp->w_topline
4495 	    || wp->w_redr_type != 0
4496 #ifdef FEAT_DIFF
4497 	    || old_topfill != wp->w_topfill
4498 #endif
4499 	    )
4500     {
4501 	int type = VALID;
4502 
4503 	if (pum_visible())
4504 	{
4505 	    type = NOT_VALID;
4506 	    wp->w_lines_valid = 0;
4507 	}
4508 
4509 	/* Don't set must_redraw here, it may cause the popup menu to
4510 	 * disappear when losing focus after a scrollbar drag. */
4511 	if (wp->w_redr_type < type)
4512 	    wp->w_redr_type = type;
4513 	mch_disable_flush();
4514 	updateWindow(wp);   /* update window, status line, and cmdline */
4515 	mch_enable_flush();
4516     }
4517 
4518     /* May need to redraw the popup menu. */
4519     if (pum_visible())
4520 	pum_redraw();
4521 
4522     return (wp == curwin && !EQUAL_POS(curwin->w_cursor, old_cursor));
4523 }
4524 
4525 
4526 /*
4527  * Horizontal scrollbar stuff:
4528  */
4529 
4530 /*
4531  * Return length of line "lnum" for horizontal scrolling.
4532  */
4533     static colnr_T
4534 scroll_line_len(linenr_T lnum)
4535 {
4536     char_u	*p;
4537     colnr_T	col;
4538     int		w;
4539 
4540     p = ml_get(lnum);
4541     col = 0;
4542     if (*p != NUL)
4543 	for (;;)
4544 	{
4545 	    w = chartabsize(p, col);
4546 	    MB_PTR_ADV(p);
4547 	    if (*p == NUL)		/* don't count the last character */
4548 		break;
4549 	    col += w;
4550 	}
4551     return col;
4552 }
4553 
4554 /* Remember which line is currently the longest, so that we don't have to
4555  * search for it when scrolling horizontally. */
4556 static linenr_T longest_lnum = 0;
4557 
4558 /*
4559  * Find longest visible line number.  If this is not possible (or not desired,
4560  * by setting 'h' in "guioptions") then the current line number is returned.
4561  */
4562     static linenr_T
4563 gui_find_longest_lnum(void)
4564 {
4565     linenr_T ret = 0;
4566 
4567     /* Calculate maximum for horizontal scrollbar.  Check for reasonable
4568      * line numbers, topline and botline can be invalid when displaying is
4569      * postponed. */
4570     if (vim_strchr(p_go, GO_HORSCROLL) == NULL
4571 	    && curwin->w_topline <= curwin->w_cursor.lnum
4572 	    && curwin->w_botline > curwin->w_cursor.lnum
4573 	    && curwin->w_botline <= curbuf->b_ml.ml_line_count + 1)
4574     {
4575 	linenr_T    lnum;
4576 	colnr_T	    n;
4577 	long	    max = 0;
4578 
4579 	/* Use maximum of all visible lines.  Remember the lnum of the
4580 	 * longest line, closest to the cursor line.  Used when scrolling
4581 	 * below. */
4582 	for (lnum = curwin->w_topline; lnum < curwin->w_botline; ++lnum)
4583 	{
4584 	    n = scroll_line_len(lnum);
4585 	    if (n > (colnr_T)max)
4586 	    {
4587 		max = n;
4588 		ret = lnum;
4589 	    }
4590 	    else if (n == (colnr_T)max
4591 		    && abs((int)(lnum - curwin->w_cursor.lnum))
4592 		       < abs((int)(ret - curwin->w_cursor.lnum)))
4593 		ret = lnum;
4594 	}
4595     }
4596     else
4597 	/* Use cursor line only. */
4598 	ret = curwin->w_cursor.lnum;
4599 
4600     return ret;
4601 }
4602 
4603     static void
4604 gui_update_horiz_scrollbar(int force)
4605 {
4606     long	value, size, max;	/* need 32 bit ints here */
4607 
4608     if (!gui.which_scrollbars[SBAR_BOTTOM])
4609 	return;
4610 
4611     if (!force && gui.dragged_sb == SBAR_BOTTOM)
4612 	return;
4613 
4614     if (!force && curwin->w_p_wrap && gui.prev_wrap)
4615 	return;
4616 
4617     /*
4618      * It is possible for the cursor to be invalid if we're in the middle of
4619      * something (like changing files).  If so, don't do anything for now.
4620      */
4621     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
4622     {
4623 	gui.bottom_sbar.value = -1;
4624 	return;
4625     }
4626 
4627     size = curwin->w_width;
4628     if (curwin->w_p_wrap)
4629     {
4630 	value = 0;
4631 #ifdef SCROLL_PAST_END
4632 	max = 0;
4633 #else
4634 	max = curwin->w_width - 1;
4635 #endif
4636     }
4637     else
4638     {
4639 	value = curwin->w_leftcol;
4640 
4641 	longest_lnum = gui_find_longest_lnum();
4642 	max = scroll_line_len(longest_lnum);
4643 
4644 	if (virtual_active())
4645 	{
4646 	    /* May move the cursor even further to the right. */
4647 	    if (curwin->w_virtcol >= (colnr_T)max)
4648 		max = curwin->w_virtcol;
4649 	}
4650 
4651 #ifndef SCROLL_PAST_END
4652 	max += curwin->w_width - 1;
4653 #endif
4654 	/* The line number isn't scrolled, thus there is less space when
4655 	 * 'number' or 'relativenumber' is set (also for 'foldcolumn'). */
4656 	size -= curwin_col_off();
4657 #ifndef SCROLL_PAST_END
4658 	max -= curwin_col_off();
4659 #endif
4660     }
4661 
4662 #ifndef SCROLL_PAST_END
4663     if (value > max - size + 1)
4664 	value = max - size + 1;	    /* limit the value to allowable range */
4665 #endif
4666 
4667 #ifdef FEAT_RIGHTLEFT
4668     if (curwin->w_p_rl)
4669     {
4670 	value = max + 1 - size - value;
4671 	if (value < 0)
4672 	{
4673 	    size += value;
4674 	    value = 0;
4675 	}
4676     }
4677 #endif
4678     if (!force && value == gui.bottom_sbar.value && size == gui.bottom_sbar.size
4679 						&& max == gui.bottom_sbar.max)
4680 	return;
4681 
4682     gui.bottom_sbar.value = value;
4683     gui.bottom_sbar.size = size;
4684     gui.bottom_sbar.max = max;
4685     gui.prev_wrap = curwin->w_p_wrap;
4686 
4687     gui_mch_set_scrollbar_thumb(&gui.bottom_sbar, value, size, max);
4688 }
4689 
4690 /*
4691  * Do a horizontal scroll.  Return TRUE if the cursor moved, FALSE otherwise.
4692  */
4693     int
4694 gui_do_horiz_scroll(long_u leftcol, int compute_longest_lnum)
4695 {
4696     /* no wrapping, no scrolling */
4697     if (curwin->w_p_wrap)
4698 	return FALSE;
4699 
4700     if (curwin->w_leftcol == (colnr_T)leftcol)
4701 	return FALSE;
4702 
4703     curwin->w_leftcol = (colnr_T)leftcol;
4704 
4705     /* When the line of the cursor is too short, move the cursor to the
4706      * longest visible line. */
4707     if (vim_strchr(p_go, GO_HORSCROLL) == NULL
4708 	    && !virtual_active()
4709 	    && (colnr_T)leftcol > scroll_line_len(curwin->w_cursor.lnum))
4710     {
4711 	if (compute_longest_lnum)
4712 	{
4713 	    curwin->w_cursor.lnum = gui_find_longest_lnum();
4714 	    curwin->w_cursor.col = 0;
4715 	}
4716 	/* Do a sanity check on "longest_lnum", just in case. */
4717 	else if (longest_lnum >= curwin->w_topline
4718 		&& longest_lnum < curwin->w_botline)
4719 	{
4720 	    curwin->w_cursor.lnum = longest_lnum;
4721 	    curwin->w_cursor.col = 0;
4722 	}
4723     }
4724 
4725     return leftcol_changed();
4726 }
4727 
4728 /*
4729  * Check that none of the colors are the same as the background color
4730  */
4731     void
4732 gui_check_colors(void)
4733 {
4734     if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == INVALCOLOR)
4735     {
4736 	gui_set_bg_color((char_u *)"White");
4737 	if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == INVALCOLOR)
4738 	    gui_set_fg_color((char_u *)"Black");
4739     }
4740 }
4741 
4742     static void
4743 gui_set_fg_color(char_u *name)
4744 {
4745     gui.norm_pixel = gui_get_color(name);
4746     hl_set_fg_color_name(vim_strsave(name));
4747 }
4748 
4749     static void
4750 gui_set_bg_color(char_u *name)
4751 {
4752     gui.back_pixel = gui_get_color(name);
4753     hl_set_bg_color_name(vim_strsave(name));
4754 }
4755 
4756 /*
4757  * Allocate a color by name.
4758  * Returns INVALCOLOR and gives an error message when failed.
4759  */
4760     guicolor_T
4761 gui_get_color(char_u *name)
4762 {
4763     guicolor_T	t;
4764 
4765     if (*name == NUL)
4766 	return INVALCOLOR;
4767     t = gui_mch_get_color(name);
4768 
4769     if (t == INVALCOLOR
4770 #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
4771 	    && gui.in_use
4772 #endif
4773 	    )
4774 	semsg(_("E254: Cannot allocate color %s"), name);
4775     return t;
4776 }
4777 
4778 /*
4779  * Return the grey value of a color (range 0-255).
4780  */
4781     int
4782 gui_get_lightness(guicolor_T pixel)
4783 {
4784     long_u	rgb = (long_u)gui_mch_get_rgb(pixel);
4785 
4786     return  (int)(  (((rgb >> 16) & 0xff) * 299)
4787 		   + (((rgb >> 8) & 0xff) * 587)
4788 		   +  ((rgb	  & 0xff) * 114)) / 1000;
4789 }
4790 
4791 #if defined(FEAT_GUI_X11) || defined(PROTO)
4792     void
4793 gui_new_scrollbar_colors(void)
4794 {
4795     win_T	*wp;
4796 
4797     /* Nothing to do if GUI hasn't started yet. */
4798     if (!gui.in_use)
4799 	return;
4800 
4801     FOR_ALL_WINDOWS(wp)
4802     {
4803 	gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_LEFT]));
4804 	gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_RIGHT]));
4805     }
4806     gui_mch_set_scrollbar_colors(&gui.bottom_sbar);
4807 }
4808 #endif
4809 
4810 /*
4811  * Call this when focus has changed.
4812  */
4813     void
4814 gui_focus_change(int in_focus)
4815 {
4816 /*
4817  * Skip this code to avoid drawing the cursor when debugging and switching
4818  * between the debugger window and gvim.
4819  */
4820 #if 1
4821     gui.in_focus = in_focus;
4822     out_flush_cursor(TRUE, FALSE);
4823 
4824 # ifdef FEAT_XIM
4825     xim_set_focus(in_focus);
4826 # endif
4827 
4828     /* Put events in the input queue only when allowed.
4829      * ui_focus_change() isn't called directly, because it invokes
4830      * autocommands and that must not happen asynchronously. */
4831     if (!hold_gui_events)
4832     {
4833 	char_u  bytes[3];
4834 
4835 	bytes[0] = CSI;
4836 	bytes[1] = KS_EXTRA;
4837 	bytes[2] = in_focus ? (int)KE_FOCUSGAINED : (int)KE_FOCUSLOST;
4838 	add_to_input_buf(bytes, 3);
4839     }
4840 #endif
4841 }
4842 
4843 /*
4844  * When mouse moved: apply 'mousefocus'.
4845  * Also updates the mouse pointer shape.
4846  */
4847     static void
4848 gui_mouse_focus(int x, int y)
4849 {
4850     win_T	*wp;
4851     char_u	st[8];
4852 
4853 #ifdef FEAT_MOUSESHAPE
4854     /* Get window pointer, and update mouse shape as well. */
4855     wp = xy2win(x, y);
4856 #endif
4857 
4858     /* Only handle this when 'mousefocus' set and ... */
4859     if (p_mousef
4860 	    && !hold_gui_events		/* not holding events */
4861 	    && (State & (NORMAL|INSERT))/* Normal/Visual/Insert mode */
4862 	    && State != HITRETURN	/* but not hit-return prompt */
4863 	    && msg_scrolled == 0	/* no scrolled message */
4864 	    && !need_mouse_correct	/* not moving the pointer */
4865 	    && gui.in_focus)		/* gvim in focus */
4866     {
4867 	/* Don't move the mouse when it's left or right of the Vim window */
4868 	if (x < 0 || x > Columns * gui.char_width)
4869 	    return;
4870 #ifndef FEAT_MOUSESHAPE
4871 	wp = xy2win(x, y);
4872 #endif
4873 	if (wp == curwin || wp == NULL)
4874 	    return;	/* still in the same old window, or none at all */
4875 
4876 	/* Ignore position in the tab pages line. */
4877 	if (Y_2_ROW(y) < tabline_height())
4878 	    return;
4879 
4880 	/*
4881 	 * format a mouse click on status line input
4882 	 * ala gui_send_mouse_event(0, x, y, 0, 0);
4883 	 * Trick: Use a column number -1, so that get_pseudo_mouse_code() will
4884 	 * generate a K_LEFTMOUSE_NM key code.
4885 	 */
4886 	if (finish_op)
4887 	{
4888 	    /* abort the current operator first */
4889 	    st[0] = ESC;
4890 	    add_to_input_buf(st, 1);
4891 	}
4892 	st[0] = CSI;
4893 	st[1] = KS_MOUSE;
4894 	st[2] = KE_FILLER;
4895 	st[3] = (char_u)MOUSE_LEFT;
4896 	fill_mouse_coord(st + 4,
4897 		wp->w_wincol == 0 ? -1 : wp->w_wincol + MOUSE_COLOFF,
4898 		wp->w_height + W_WINROW(wp));
4899 
4900 	add_to_input_buf(st, 8);
4901 	st[3] = (char_u)MOUSE_RELEASE;
4902 	add_to_input_buf(st, 8);
4903 #ifdef FEAT_GUI_GTK
4904 	/* Need to wake up the main loop */
4905 	if (gtk_main_level() > 0)
4906 	    gtk_main_quit();
4907 #endif
4908     }
4909 }
4910 
4911 /*
4912  * Called when the mouse moved (but not when dragging).
4913  */
4914     void
4915 gui_mouse_moved(int x, int y)
4916 {
4917     // Ignore this while still starting up.
4918     if (!gui.in_use || gui.starting)
4919 	return;
4920 
4921     // apply 'mousefocus' and pointer shape
4922     gui_mouse_focus(x, y);
4923 
4924 #ifdef FEAT_TEXT_PROP
4925     if (popup_visible)
4926 	// Generate a mouse-moved event, so that the popup can perhaps be
4927 	// closed, just like in the terminal.
4928 	gui_send_mouse_event(MOUSE_DRAG, x, y, FALSE, 0);
4929 #endif
4930 }
4931 
4932 /*
4933  * Called when mouse should be moved to window with focus.
4934  */
4935     void
4936 gui_mouse_correct(void)
4937 {
4938     int		x, y;
4939     win_T	*wp = NULL;
4940 
4941     need_mouse_correct = FALSE;
4942 
4943     if (!(gui.in_use && p_mousef))
4944 	return;
4945 
4946     gui_mch_getmouse(&x, &y);
4947     /* Don't move the mouse when it's left or right of the Vim window */
4948     if (x < 0 || x > Columns * gui.char_width)
4949 	return;
4950     if (y >= 0 && Y_2_ROW(y) >= tabline_height())
4951 	wp = xy2win(x, y);
4952     if (wp != curwin && wp != NULL)	/* If in other than current window */
4953     {
4954 	validate_cline_row();
4955 	gui_mch_setmouse((int)W_ENDCOL(curwin) * gui.char_width - 3,
4956 		(W_WINROW(curwin) + curwin->w_wrow) * gui.char_height
4957 						     + (gui.char_height) / 2);
4958     }
4959 }
4960 
4961 /*
4962  * Find window where the mouse pointer "x" / "y" coordinate is in.
4963  * As a side effect update the shape of the mouse pointer.
4964  */
4965     static win_T *
4966 xy2win(int x, int y)
4967 {
4968     int		row;
4969     int		col;
4970     win_T	*wp;
4971 
4972     row = Y_2_ROW(y);
4973     col = X_2_COL(x);
4974     if (row < 0 || col < 0)		/* before first window */
4975 	return NULL;
4976     wp = mouse_find_win(&row, &col, FALSE);
4977     if (wp == NULL)
4978 	return NULL;
4979 #ifdef FEAT_MOUSESHAPE
4980     if (State == HITRETURN || State == ASKMORE)
4981     {
4982 	if (Y_2_ROW(y) >= msg_row)
4983 	    update_mouseshape(SHAPE_IDX_MOREL);
4984 	else
4985 	    update_mouseshape(SHAPE_IDX_MORE);
4986     }
4987     else if (row > wp->w_height)	/* below status line */
4988 	update_mouseshape(SHAPE_IDX_CLINE);
4989     else if (!(State & CMDLINE) && wp->w_vsep_width > 0 && col == wp->w_width
4990 	    && (row != wp->w_height || !stl_connected(wp)) && msg_scrolled == 0)
4991 	update_mouseshape(SHAPE_IDX_VSEP);
4992     else if (!(State & CMDLINE) && wp->w_status_height > 0
4993 				  && row == wp->w_height && msg_scrolled == 0)
4994 	update_mouseshape(SHAPE_IDX_STATUS);
4995     else
4996 	update_mouseshape(-2);
4997 #endif
4998     return wp;
4999 }
5000 
5001 /*
5002  * ":gui" and ":gvim": Change from the terminal version to the GUI version.
5003  * File names may be given to redefine the args list.
5004  */
5005     void
5006 ex_gui(exarg_T *eap)
5007 {
5008     char_u	*arg = eap->arg;
5009 
5010     /*
5011      * Check for "-f" argument: foreground, don't fork.
5012      * Also don't fork when started with "gvim -f".
5013      * Do fork when using "gui -b".
5014      */
5015     if (arg[0] == '-'
5016 	    && (arg[1] == 'f' || arg[1] == 'b')
5017 	    && (arg[2] == NUL || VIM_ISWHITE(arg[2])))
5018     {
5019 	gui.dofork = (arg[1] == 'b');
5020 	eap->arg = skipwhite(eap->arg + 2);
5021     }
5022     if (!gui.in_use)
5023     {
5024 #if defined(VIMDLL) && !defined(EXPERIMENTAL_GUI_CMD)
5025 	emsg(_(e_nogvim));
5026 	return;
5027 #else
5028 	/* Clear the command.  Needed for when forking+exiting, to avoid part
5029 	 * of the argument ending up after the shell prompt. */
5030 	msg_clr_eos_force();
5031 # ifdef GUI_MAY_SPAWN
5032 	if (!ends_excmd(*eap->arg))
5033 	    gui_start(eap->arg);
5034 	else
5035 # endif
5036 	    gui_start(NULL);
5037 # ifdef FEAT_JOB_CHANNEL
5038 	channel_gui_register_all();
5039 # endif
5040 #endif
5041     }
5042     if (!ends_excmd(*eap->arg))
5043 	ex_next(eap);
5044 }
5045 
5046 #if ((defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \
5047 	    || defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_PHOTON)) \
5048 	    && defined(FEAT_TOOLBAR)) || defined(PROTO)
5049 /*
5050  * This is shared between Athena, Motif and GTK.
5051  */
5052 
5053 /*
5054  * Callback function for do_in_runtimepath().
5055  */
5056     static void
5057 gfp_setname(char_u *fname, void *cookie)
5058 {
5059     char_u	*gfp_buffer = cookie;
5060 
5061     if (STRLEN(fname) >= MAXPATHL)
5062 	*gfp_buffer = NUL;
5063     else
5064 	STRCPY(gfp_buffer, fname);
5065 }
5066 
5067 /*
5068  * Find the path of bitmap "name" with extension "ext" in 'runtimepath'.
5069  * Return FAIL for failure and OK if buffer[MAXPATHL] contains the result.
5070  */
5071     int
5072 gui_find_bitmap(char_u *name, char_u *buffer, char *ext)
5073 {
5074     if (STRLEN(name) > MAXPATHL - 14)
5075 	return FAIL;
5076     vim_snprintf((char *)buffer, MAXPATHL, "bitmaps/%s.%s", name, ext);
5077     if (do_in_runtimepath(buffer, 0, gfp_setname, buffer) == FAIL
5078 							    || *buffer == NUL)
5079 	return FAIL;
5080     return OK;
5081 }
5082 
5083 # if !defined(FEAT_GUI_GTK) || defined(PROTO)
5084 /*
5085  * Given the name of the "icon=" argument, try finding the bitmap file for the
5086  * icon.  If it is an absolute path name, use it as it is.  Otherwise append
5087  * "ext" and search for it in 'runtimepath'.
5088  * The result is put in "buffer[MAXPATHL]".  If something fails "buffer"
5089  * contains "name".
5090  */
5091     void
5092 gui_find_iconfile(char_u *name, char_u *buffer, char *ext)
5093 {
5094     char_u	buf[MAXPATHL + 1];
5095 
5096     expand_env(name, buffer, MAXPATHL);
5097     if (!mch_isFullName(buffer) && gui_find_bitmap(buffer, buf, ext) == OK)
5098 	STRCPY(buffer, buf);
5099 }
5100 # endif
5101 #endif
5102 
5103 #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(PROTO)
5104     void
5105 display_errors(void)
5106 {
5107     char_u	*p;
5108 
5109     if (isatty(2))
5110 	fflush(stderr);
5111     else if (error_ga.ga_data != NULL)
5112     {
5113 	/* avoid putting up a message box with blanks only */
5114 	for (p = (char_u *)error_ga.ga_data; *p != NUL; ++p)
5115 	    if (!isspace(*p))
5116 	    {
5117 		/* Truncate a very long message, it will go off-screen. */
5118 		if (STRLEN(p) > 2000)
5119 		    STRCPY(p + 2000 - 14, "...(truncated)");
5120 		(void)do_dialog(VIM_ERROR, (char_u *)_("Error"),
5121 				       p, (char_u *)_("&Ok"), 1, NULL, FALSE);
5122 		break;
5123 	    }
5124 	ga_clear(&error_ga);
5125     }
5126 }
5127 #endif
5128 
5129 #if defined(NO_CONSOLE_INPUT) || defined(PROTO)
5130 /*
5131  * Return TRUE if still starting up and there is no place to enter text.
5132  * For GTK and X11 we check if stderr is not a tty, which means we were
5133  * (probably) started from the desktop.  Also check stdin, "vim >& file" does
5134  * allow typing on stdin.
5135  */
5136     int
5137 no_console_input(void)
5138 {
5139     return ((!gui.in_use || gui.starting)
5140 # ifndef NO_CONSOLE
5141 	    && !isatty(0) && !isatty(2)
5142 # endif
5143 	    );
5144 }
5145 #endif
5146 
5147 #if defined(FIND_REPLACE_DIALOG) \
5148 	|| defined(NEED_GUI_UPDATE_SCREEN) \
5149 	|| defined(PROTO)
5150 /*
5151  * Update the current window and the screen.
5152  */
5153     void
5154 gui_update_screen(void)
5155 {
5156 # ifdef FEAT_CONCEAL
5157     linenr_T	conceal_old_cursor_line = 0;
5158     linenr_T	conceal_new_cursor_line = 0;
5159     int		conceal_update_lines = FALSE;
5160 # endif
5161 
5162     update_topline();
5163     validate_cursor();
5164 
5165     /* Trigger CursorMoved if the cursor moved. */
5166     if (!finish_op && (has_cursormoved()
5167 # ifdef FEAT_TEXT_PROP
5168 		|| popup_visible
5169 # endif
5170 # ifdef FEAT_CONCEAL
5171 		|| curwin->w_p_cole > 0
5172 # endif
5173 		) && !EQUAL_POS(last_cursormoved, curwin->w_cursor))
5174     {
5175 	if (has_cursormoved())
5176 	    apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf);
5177 #ifdef FEAT_TEXT_PROP
5178 	if (popup_visible)
5179 	    popup_check_cursor_pos();
5180 #endif
5181 # ifdef FEAT_CONCEAL
5182 	if (curwin->w_p_cole > 0)
5183 	{
5184 	    conceal_old_cursor_line = last_cursormoved.lnum;
5185 	    conceal_new_cursor_line = curwin->w_cursor.lnum;
5186 	    conceal_update_lines = TRUE;
5187 	}
5188 # endif
5189 	last_cursormoved = curwin->w_cursor;
5190     }
5191 
5192 # ifdef FEAT_CONCEAL
5193     if (conceal_update_lines
5194 	    && (conceal_old_cursor_line != conceal_new_cursor_line
5195 		|| conceal_cursor_line(curwin)
5196 		|| need_cursor_line_redraw))
5197     {
5198 	if (conceal_old_cursor_line != conceal_new_cursor_line)
5199 	    redrawWinline(curwin, conceal_old_cursor_line);
5200 	redrawWinline(curwin, conceal_new_cursor_line);
5201 	curwin->w_valid &= ~VALID_CROW;
5202 	need_cursor_line_redraw = FALSE;
5203     }
5204 # endif
5205     update_screen(0);	/* may need to update the screen */
5206     setcursor();
5207     out_flush_cursor(TRUE, FALSE);
5208 }
5209 #endif
5210 
5211 #if defined(FIND_REPLACE_DIALOG) || defined(PROTO)
5212 /*
5213  * Get the text to use in a find/replace dialog.  Uses the last search pattern
5214  * if the argument is empty.
5215  * Returns an allocated string.
5216  */
5217     char_u *
5218 get_find_dialog_text(
5219     char_u	*arg,
5220     int		*wwordp,	/* return: TRUE if \< \> found */
5221     int		*mcasep)	/* return: TRUE if \C found */
5222 {
5223     char_u	*text;
5224 
5225     if (*arg == NUL)
5226 	text = last_search_pat();
5227     else
5228 	text = arg;
5229     if (text != NULL)
5230     {
5231 	text = vim_strsave(text);
5232 	if (text != NULL)
5233 	{
5234 	    int len = (int)STRLEN(text);
5235 	    int i;
5236 
5237 	    /* Remove "\V" */
5238 	    if (len >= 2 && STRNCMP(text, "\\V", 2) == 0)
5239 	    {
5240 		mch_memmove(text, text + 2, (size_t)(len - 1));
5241 		len -= 2;
5242 	    }
5243 
5244 	    /* Recognize "\c" and "\C" and remove. */
5245 	    if (len >= 2 && *text == '\\' && (text[1] == 'c' || text[1] == 'C'))
5246 	    {
5247 		*mcasep = (text[1] == 'C');
5248 		mch_memmove(text, text + 2, (size_t)(len - 1));
5249 		len -= 2;
5250 	    }
5251 
5252 	    /* Recognize "\<text\>" and remove. */
5253 	    if (len >= 4
5254 		    && STRNCMP(text, "\\<", 2) == 0
5255 		    && STRNCMP(text + len - 2, "\\>", 2) == 0)
5256 	    {
5257 		*wwordp = TRUE;
5258 		mch_memmove(text, text + 2, (size_t)(len - 4));
5259 		text[len - 4] = NUL;
5260 	    }
5261 
5262 	    /* Recognize "\/" or "\?" and remove. */
5263 	    for (i = 0; i + 1 < len; ++i)
5264 		if (text[i] == '\\' && (text[i + 1] == '/'
5265 						       || text[i + 1] == '?'))
5266 		{
5267 		    mch_memmove(text + i, text + i + 1, (size_t)(len - i));
5268 		    --len;
5269 		}
5270 	}
5271     }
5272     return text;
5273 }
5274 
5275 /*
5276  * Handle the press of a button in the find-replace dialog.
5277  * Return TRUE when something was added to the input buffer.
5278  */
5279     int
5280 gui_do_findrepl(
5281     int		flags,		/* one of FRD_REPLACE, FRD_FINDNEXT, etc. */
5282     char_u	*find_text,
5283     char_u	*repl_text,
5284     int		down)		/* Search downwards. */
5285 {
5286     garray_T	ga;
5287     int		i;
5288     int		type = (flags & FRD_TYPE_MASK);
5289     char_u	*p;
5290     regmatch_T	regmatch;
5291     int		save_did_emsg = did_emsg;
5292     static int  busy = FALSE;
5293 
5294     /* When the screen is being updated we should not change buffers and
5295      * windows structures, it may cause freed memory to be used.  Also don't
5296      * do this recursively (pressing "Find" quickly several times. */
5297     if (updating_screen || busy)
5298 	return FALSE;
5299 
5300     /* refuse replace when text cannot be changed */
5301     if ((type == FRD_REPLACE || type == FRD_REPLACEALL) && text_locked())
5302 	return FALSE;
5303 
5304     busy = TRUE;
5305 
5306     ga_init2(&ga, 1, 100);
5307     if (type == FRD_REPLACEALL)
5308 	ga_concat(&ga, (char_u *)"%s/");
5309 
5310     ga_concat(&ga, (char_u *)"\\V");
5311     if (flags & FRD_MATCH_CASE)
5312 	ga_concat(&ga, (char_u *)"\\C");
5313     else
5314 	ga_concat(&ga, (char_u *)"\\c");
5315     if (flags & FRD_WHOLE_WORD)
5316 	ga_concat(&ga, (char_u *)"\\<");
5317     /* escape / and \ */
5318     p = vim_strsave_escaped(find_text, (char_u *)"/\\");
5319     if (p != NULL)
5320         ga_concat(&ga, p);
5321     vim_free(p);
5322     if (flags & FRD_WHOLE_WORD)
5323 	ga_concat(&ga, (char_u *)"\\>");
5324 
5325     if (type == FRD_REPLACEALL)
5326     {
5327 	ga_concat(&ga, (char_u *)"/");
5328 						/* escape / and \ */
5329 	p = vim_strsave_escaped(repl_text, (char_u *)"/\\");
5330 	if (p != NULL)
5331 	    ga_concat(&ga, p);
5332 	vim_free(p);
5333 	ga_concat(&ga, (char_u *)"/g");
5334     }
5335     ga_append(&ga, NUL);
5336 
5337     if (type == FRD_REPLACE)
5338     {
5339 	/* Do the replacement when the text at the cursor matches.  Thus no
5340 	 * replacement is done if the cursor was moved! */
5341 	regmatch.regprog = vim_regcomp(ga.ga_data, RE_MAGIC + RE_STRING);
5342 	regmatch.rm_ic = 0;
5343 	if (regmatch.regprog != NULL)
5344 	{
5345 	    p = ml_get_cursor();
5346 	    if (vim_regexec_nl(&regmatch, p, (colnr_T)0)
5347 						   && regmatch.startp[0] == p)
5348 	    {
5349 		/* Clear the command line to remove any old "No match"
5350 		 * error. */
5351 		msg_end_prompt();
5352 
5353 		if (u_save_cursor() == OK)
5354 		{
5355 		    /* A button was pressed thus undo should be synced. */
5356 		    u_sync(FALSE);
5357 
5358 		    del_bytes((long)(regmatch.endp[0] - regmatch.startp[0]),
5359 								FALSE, FALSE);
5360 		    ins_str(repl_text);
5361 		}
5362 	    }
5363 	    else
5364 		msg(_("No match at cursor, finding next"));
5365 	    vim_regfree(regmatch.regprog);
5366 	}
5367     }
5368 
5369     if (type == FRD_REPLACEALL)
5370     {
5371 	/* A button was pressed, thus undo should be synced. */
5372 	u_sync(FALSE);
5373 	do_cmdline_cmd(ga.ga_data);
5374     }
5375     else
5376     {
5377 	int searchflags = SEARCH_MSG + SEARCH_MARK;
5378 
5379 	/* Search for the next match.
5380 	 * Don't skip text under cursor for single replace. */
5381 	if (type == FRD_REPLACE)
5382 	    searchflags += SEARCH_START;
5383 	i = msg_scroll;
5384 	if (down)
5385 	{
5386 	    (void)do_search(NULL, '/', ga.ga_data, 1L, searchflags, NULL, NULL);
5387 	}
5388 	else
5389 	{
5390 	    /* We need to escape '?' if and only if we are searching in the up
5391 	     * direction */
5392 	    p = vim_strsave_escaped(ga.ga_data, (char_u *)"?");
5393 	    if (p != NULL)
5394 	        (void)do_search(NULL, '?', p, 1L, searchflags, NULL, NULL);
5395 	    vim_free(p);
5396 	}
5397 
5398 	msg_scroll = i;	    /* don't let an error message set msg_scroll */
5399     }
5400 
5401     /* Don't want to pass did_emsg to other code, it may cause disabling
5402      * syntax HL if we were busy redrawing. */
5403     did_emsg = save_did_emsg;
5404 
5405     if (State & (NORMAL | INSERT))
5406     {
5407 	gui_update_screen();		/* update the screen */
5408 	msg_didout = 0;			/* overwrite any message */
5409 	need_wait_return = FALSE;	/* don't wait for return */
5410     }
5411 
5412     vim_free(ga.ga_data);
5413     busy = FALSE;
5414     return (ga.ga_len > 0);
5415 }
5416 
5417 #endif
5418 
5419 #if defined(HAVE_DROP_FILE) || defined(PROTO)
5420 /*
5421  * Jump to the window at specified point (x, y).
5422  */
5423     static void
5424 gui_wingoto_xy(int x, int y)
5425 {
5426     int		row = Y_2_ROW(y);
5427     int		col = X_2_COL(x);
5428     win_T	*wp;
5429 
5430     if (row >= 0 && col >= 0)
5431     {
5432 	wp = mouse_find_win(&row, &col, FAIL_POPUP);
5433 	if (wp != NULL && wp != curwin)
5434 	    win_goto(wp);
5435     }
5436 }
5437 
5438 /*
5439  * Function passed to handle_drop() for the actions to be done after the
5440  * argument list has been updated.
5441  */
5442     static void
5443 drop_callback(void *cookie)
5444 {
5445     char_u	*p = cookie;
5446 
5447     /* If Shift held down, change to first file's directory.  If the first
5448      * item is a directory, change to that directory (and let the explorer
5449      * plugin show the contents). */
5450     if (p != NULL)
5451     {
5452 	if (mch_isdir(p))
5453 	{
5454 	    if (mch_chdir((char *)p) == 0)
5455 		shorten_fnames(TRUE);
5456 	}
5457 	else if (vim_chdirfile(p, "drop") == OK)
5458 	    shorten_fnames(TRUE);
5459 	vim_free(p);
5460     }
5461 
5462     /* Update the screen display */
5463     update_screen(NOT_VALID);
5464 # ifdef FEAT_MENU
5465     gui_update_menus(0);
5466 # endif
5467 #ifdef FEAT_TITLE
5468     maketitle();
5469 #endif
5470     setcursor();
5471     out_flush_cursor(FALSE, FALSE);
5472 }
5473 
5474 /*
5475  * Process file drop.  Mouse cursor position, key modifiers, name of files
5476  * and count of files are given.  Argument "fnames[count]" has full pathnames
5477  * of dropped files, they will be freed in this function, and caller can't use
5478  * fnames after call this function.
5479  */
5480     void
5481 gui_handle_drop(
5482     int		x UNUSED,
5483     int		y UNUSED,
5484     int_u	modifiers,
5485     char_u	**fnames,
5486     int		count)
5487 {
5488     int		i;
5489     char_u	*p;
5490     static int	entered = FALSE;
5491 
5492     /*
5493      * This function is called by event handlers.  Just in case we get a
5494      * second event before the first one is handled, ignore the second one.
5495      * Not sure if this can ever happen, just in case.
5496      */
5497     if (entered)
5498 	return;
5499     entered = TRUE;
5500 
5501     /*
5502      * When the cursor is at the command line, add the file names to the
5503      * command line, don't edit the files.
5504      */
5505     if (State & CMDLINE)
5506     {
5507 	shorten_filenames(fnames, count);
5508 	for (i = 0; i < count; ++i)
5509 	{
5510 	    if (fnames[i] != NULL)
5511 	    {
5512 		if (i > 0)
5513 		    add_to_input_buf((char_u*)" ", 1);
5514 
5515 		/* We don't know what command is used thus we can't be sure
5516 		 * about which characters need to be escaped.  Only escape the
5517 		 * most common ones. */
5518 # ifdef BACKSLASH_IN_FILENAME
5519 		p = vim_strsave_escaped(fnames[i], (char_u *)" \t\"|");
5520 # else
5521 		p = vim_strsave_escaped(fnames[i], (char_u *)"\\ \t\"|");
5522 # endif
5523 		if (p != NULL)
5524 		    add_to_input_buf_csi(p, (int)STRLEN(p));
5525 		vim_free(p);
5526 		vim_free(fnames[i]);
5527 	    }
5528 	}
5529 	vim_free(fnames);
5530     }
5531     else
5532     {
5533 	/* Go to the window under mouse cursor, then shorten given "fnames" by
5534 	 * current window, because a window can have local current dir. */
5535 	gui_wingoto_xy(x, y);
5536 	shorten_filenames(fnames, count);
5537 
5538 	/* If Shift held down, remember the first item. */
5539 	if ((modifiers & MOUSE_SHIFT) != 0)
5540 	    p = vim_strsave(fnames[0]);
5541 	else
5542 	    p = NULL;
5543 
5544 	/* Handle the drop, :edit or :split to get to the file.  This also
5545 	 * frees fnames[].  Skip this if there is only one item, it's a
5546 	 * directory and Shift is held down. */
5547 	if (count == 1 && (modifiers & MOUSE_SHIFT) != 0
5548 						     && mch_isdir(fnames[0]))
5549 	{
5550 	    vim_free(fnames[0]);
5551 	    vim_free(fnames);
5552 	}
5553 	else
5554 	    handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0,
5555 		    drop_callback, (void *)p);
5556     }
5557 
5558     entered = FALSE;
5559 }
5560 #endif
5561