home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / gui.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-17  |  107.1 KB  |  4,478 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  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_MBYTE) && !defined(HAVE_GTK2)
  17. static void set_guifontwide __ARGS((char_u *font_name));
  18. #endif
  19. static void gui_check_pos __ARGS((void));
  20. static void gui_position_components __ARGS((int));
  21. static void gui_outstr __ARGS((char_u *, int));
  22. static int gui_screenchar __ARGS((int off, int flags, guicolor_T fg, guicolor_T bg, int back));
  23. #ifdef HAVE_GTK2
  24. static int gui_screenstr __ARGS((int off, int len, int flags, guicolor_T fg, guicolor_T bg, int back));
  25. #endif
  26. static void gui_delete_lines __ARGS((int row, int count));
  27. static void gui_insert_lines __ARGS((int row, int count));
  28. static void fill_mouse_coord __ARGS((char_u *p, int col, int row));
  29. static void gui_do_scrollbar __ARGS((win_T *wp, int which, int enable));
  30. static void gui_update_horiz_scrollbar __ARGS((int));
  31. static win_T *xy2win __ARGS((int x, int y));
  32.  
  33. static int can_update_cursor = TRUE; /* can display the cursor */
  34.  
  35. /*
  36.  * The Athena scrollbars can move the thumb to after the end of the scrollbar,
  37.  * this makes the thumb indicate the part of the text that is shown.  Motif
  38.  * can't do this.
  39.  */
  40. #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MAC)
  41. # define SCROLL_PAST_END
  42. #endif
  43.  
  44. /*
  45.  * gui_start -- Called when user wants to start the GUI.
  46.  *
  47.  * Careful: This function can be called recursively when there is a ":gui"
  48.  * command in the .gvimrc file.  Only the first call should fork, not the
  49.  * recursive call.
  50.  */
  51.     void
  52. gui_start()
  53. {
  54.     char_u    *old_term;
  55. #if defined(UNIX) && !defined(__BEOS__) && !defined(MACOS_X)
  56. # define MAY_FORK
  57.     int        dofork = TRUE;
  58. #endif
  59.     static int    recursive = 0;
  60.  
  61.     old_term = vim_strsave(T_NAME);
  62.  
  63.     /*
  64.      * Set_termname() will call gui_init() to start the GUI.
  65.      * Set the "starting" flag, to indicate that the GUI will start.
  66.      *
  67.      * We don't want to open the GUI shell until after we've read .gvimrc,
  68.      * otherwise we don't know what font we will use, and hence we don't know
  69.      * what size the shell should be.  So if there are errors in the .gvimrc
  70.      * file, they will have to go to the terminal: Set full_screen to FALSE.
  71.      * full_screen will be set to TRUE again by a successful termcapinit().
  72.      */
  73.     settmode(TMODE_COOK);        /* stop RAW mode */
  74.     if (full_screen)
  75.     cursor_on();            /* needed for ":gui" in .vimrc */
  76.     gui.starting = TRUE;
  77.     full_screen = FALSE;
  78.  
  79. #ifdef MAY_FORK
  80.     if (!gui.dofork || vim_strchr(p_go, GO_FORG) || recursive)
  81.     dofork = FALSE;
  82. #endif
  83.     ++recursive;
  84.  
  85.     termcapinit((char_u *)"builtin_gui");
  86.     gui.starting = recursive - 1;
  87.  
  88.     if (!gui.in_use)            /* failed to start GUI */
  89.     {
  90.     termcapinit(old_term);        /* back to old term settings */
  91.     settmode(TMODE_RAW);        /* restart RAW mode */
  92. #ifdef FEAT_TITLE
  93.     set_title_defaults();        /* set 'title' and 'icon' again */
  94. #endif
  95.     }
  96.  
  97.     vim_free(old_term);
  98.  
  99. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
  100.     if (gui.in_use)
  101.     /* Display error messages in a dialog now. */
  102.     display_errors();
  103. #endif
  104.  
  105. #if defined(MAY_FORK) && !defined(__QNXNTO__)
  106.     /*
  107.      * Quit the current process and continue in the child.
  108.      * Makes "gvim file" disconnect from the shell it was started in.
  109.      * Don't do this when Vim was started with "-f" or the 'f' flag is present
  110.      * in 'guioptions'.
  111.      */
  112.     if (gui.in_use && dofork)
  113.     {
  114.     int    pipefd[2];    /* pipe between parent and child */
  115.     int    pipe_error;
  116.     char    dummy;
  117.     pid_t    pid = -1;
  118.  
  119.     /* Setup a pipe between the child and the parent, so that the parent
  120.      * knows when the child has done the setsid() call and is allowed to
  121.      * exit. */
  122.     pipe_error = (pipe(pipefd) < 0);
  123.     pid = fork();
  124.     if (pid > 0)        /* Parent */
  125.     {
  126.         /* Give the child some time to do the setsid(), otherwise the
  127.          * exit() may kill the child too (when starting gvim from inside a
  128.          * gvim). */
  129.         if (pipe_error)
  130.         ui_delay(300L, TRUE);
  131.         else
  132.         {
  133.         /* The read returns when the child closes the pipe (or when
  134.          * the child dies for some reason). */
  135.         close(pipefd[1]);
  136.         (void)read(pipefd[0], &dummy, (size_t)1);
  137.         close(pipefd[0]);
  138.         }
  139.  
  140.         /* When swapping screens we may need to go to the next line, e.g.,
  141.          * after a hit-enter prompt and using ":gui". */
  142.         if (newline_on_exit)
  143.         mch_errmsg("\r\n");
  144.  
  145.         /*
  146.          * The parent must skip the normal exit() processing, the child
  147.          * will do it.  For example, GTK messes up signals when exiting.
  148.          */
  149.         _exit(0);
  150.     }
  151.  
  152. # if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
  153.     /*
  154.      * Change our process group.  On some systems/shells a CTRL-C in the
  155.      * shell where Vim was started would otherwise kill gvim!
  156.      */
  157.     if (pid == 0)        /* child */
  158. #  if defined(HAVE_SETSID)
  159.         (void)setsid();
  160. #  else
  161.         (void)setpgid(0, 0);
  162. #  endif
  163. # endif
  164.     if (!pipe_error)
  165.     {
  166.         close(pipefd[0]);
  167.         close(pipefd[1]);
  168.     }
  169.  
  170. # if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
  171.     /* Tell the session manager our new PID */
  172.     gui_mch_forked();
  173. # endif
  174.     }
  175. #else
  176. # if defined(__QNXNTO__)
  177.     if (gui.in_use && dofork)
  178.     procmgr_daemon(0, PROCMGR_DAEMON_KEEPUMASK | PROCMGR_DAEMON_NOCHDIR |
  179.         PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL);
  180. # endif
  181. #endif
  182.  
  183. #ifdef FEAT_AUTOCMD
  184.     /* If the GUI started successfully, trigger the GUIEnter event */
  185.     if (gui.in_use)
  186.     apply_autocmds(EVENT_GUIENTER, NULL, NULL, FALSE, curbuf);
  187. #endif
  188.  
  189.     --recursive;
  190. }
  191.  
  192. /*
  193.  * Call this when vim starts up, whether or not the GUI is started
  194.  */
  195.     void
  196. gui_prepare(argc, argv)
  197.     int        *argc;
  198.     char    **argv;
  199. {
  200.     gui.in_use = FALSE;            /* No GUI yet (maybe later) */
  201.     gui.starting = FALSE;        /* No GUI yet (maybe later) */
  202.     gui_mch_prepare(argc, argv);
  203. }
  204.  
  205. /*
  206.  * Try initializing the GUI and check if it can be started.
  207.  * Used from main() to check early if "vim -g" can start the GUI.
  208.  * Used from gui_init() to prepare for starting the GUI.
  209.  * Returns FAIL or OK.
  210.  */
  211.     int
  212. gui_init_check()
  213. {
  214.     static int result = MAYBE;
  215.  
  216.     if (result != MAYBE)
  217.     {
  218.     if (result == FAIL)
  219.         EMSG(_("E229: Cannot start the GUI"));
  220.     return result;
  221.     }
  222.  
  223.     gui.shell_created = FALSE;
  224.     gui.dying = FALSE;
  225.     gui.in_focus = TRUE;        /* so the guicursor setting works */
  226.     gui.dragged_sb = SBAR_NONE;
  227.     gui.dragged_wp = NULL;
  228.     gui.pointer_hidden = FALSE;
  229.     gui.col = 0;
  230.     gui.row = 0;
  231.     gui.num_cols = Columns;
  232.     gui.num_rows = Rows;
  233.  
  234.     gui.cursor_is_valid = FALSE;
  235.     gui.scroll_region_top = 0;
  236.     gui.scroll_region_bot = Rows - 1;
  237.     gui.scroll_region_left = 0;
  238.     gui.scroll_region_right = Columns - 1;
  239.     gui.highlight_mask = HL_NORMAL;
  240.     gui.char_width = 1;
  241.     gui.char_height = 1;
  242.     gui.char_ascent = 0;
  243.     gui.border_width = 0;
  244.  
  245.     gui.norm_font = NOFONT;
  246. #ifndef HAVE_GTK2
  247.     gui.bold_font = NOFONT;
  248.     gui.ital_font = NOFONT;
  249.     gui.boldital_font = NOFONT;
  250. # ifdef FEAT_XFONTSET
  251.     gui.fontset = NOFONTSET;
  252. # endif
  253. #endif
  254.  
  255. #ifdef FEAT_MENU
  256. # ifndef HAVE_GTK2
  257. #  ifdef FONTSET_ALWAYS
  258.     gui.menu_fontset = NOFONTSET;
  259. #  else
  260.     gui.menu_font = NOFONT;
  261. #  endif
  262. # endif
  263.     gui.menu_is_active = TRUE;        /* default: include menu */
  264. # ifndef FEAT_GUI_GTK
  265.     gui.menu_height = MENU_DEFAULT_HEIGHT;
  266.     gui.menu_width = 0;
  267. # endif
  268. #endif
  269. #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
  270.     gui.toolbar_height = 0;
  271. #endif
  272. #if defined(FEAT_FOOTER) && defined(FEAT_GUI_MOTIF)
  273.     gui.footer_height = 0;
  274. #endif
  275. #ifdef FEAT_BEVAL_TIP
  276.     gui.tooltip_fontset = NOFONTSET;
  277. #endif
  278.  
  279.     gui.scrollbar_width = gui.scrollbar_height = SB_DEFAULT_WIDTH;
  280.     gui.prev_wrap = -1;
  281.  
  282. #ifdef ALWAYS_USE_GUI
  283.     result = OK;
  284. #else
  285.     result = gui_mch_init_check();
  286. #endif
  287.     return result;
  288. }
  289.  
  290. /*
  291.  * This is the call which starts the GUI.
  292.  */
  293.     void
  294. gui_init()
  295. {
  296.     win_T    *wp;
  297.     static int    recursive = 0;
  298.  
  299.     /*
  300.      * It's possible to use ":gui" in a .gvimrc file.  The first halve of this
  301.      * function will then be executed at the first call, the rest by the
  302.      * recursive call.  This allow the shell to be opened halfway reading a
  303.      * gvimrc file.
  304.      */
  305.     if (!recursive)
  306.     {
  307.     ++recursive;
  308.  
  309.     clip_init(TRUE);
  310.  
  311.     /* If can't initialize, don't try doing the rest */
  312.     if (gui_init_check() == FAIL)
  313.     {
  314.         --recursive;
  315.         clip_init(FALSE);
  316.         return;
  317.     }
  318.  
  319.     /*
  320.      * Set up system-wide default menus.
  321.      */
  322. #if defined(SYS_MENU_FILE) && defined(FEAT_MENU)
  323.     if (vim_strchr(p_go, GO_NOSYSMENU) == NULL)
  324.     {
  325.         sys_menu = TRUE;
  326.         do_source((char_u *)SYS_MENU_FILE, FALSE, FALSE);
  327.         sys_menu = FALSE;
  328.     }
  329. #endif
  330.  
  331.     /*
  332.      * Switch on the mouse by default, unless the user changed it already.
  333.      * This can then be changed in the .gvimrc.
  334.      */
  335.     if (!option_was_set((char_u *)"mouse"))
  336.         set_string_option_direct((char_u *)"mouse", -1,
  337.                              (char_u *)"a", OPT_FREE);
  338.  
  339.     /*
  340.      * If -U option given, use only the initializations from that file and
  341.      * nothing else.  Skip all initializations for "-U NONE" or "-u NORC".
  342.      */
  343.     if (use_gvimrc != NULL)
  344.     {
  345.         if (STRCMP(use_gvimrc, "NONE") != 0
  346.             && STRCMP(use_gvimrc, "NORC") != 0
  347.             && do_source(use_gvimrc, FALSE, FALSE) != OK)
  348.         EMSG2(_("E230: Cannot read from \"%s\""), use_gvimrc);
  349.     }
  350.     else
  351.     {
  352.         /*
  353.          * Get system wide defaults for gvim, only when file name defined.
  354.          */
  355. #ifdef SYS_GVIMRC_FILE
  356.         do_source((char_u *)SYS_GVIMRC_FILE, FALSE, FALSE);
  357. #endif
  358.  
  359.         /*
  360.          * Try to read GUI initialization commands from the following
  361.          * places:
  362.          * - environment variable GVIMINIT
  363.          * - the user gvimrc file (~/.gvimrc)
  364.          * - the second user gvimrc file ($VIM/.gvimrc for Dos)
  365.          * - the third user gvimrc file ($VIM/.gvimrc for Amiga)
  366.          * The first that exists is used, the rest is ignored.
  367.          */
  368.         if (process_env((char_u *)"GVIMINIT", FALSE) == FAIL
  369.          && do_source((char_u *)USR_GVIMRC_FILE, TRUE, FALSE) == FAIL
  370. #ifdef USR_GVIMRC_FILE2
  371.          && do_source((char_u *)USR_GVIMRC_FILE2, TRUE, FALSE) == FAIL
  372. #endif
  373.                 )
  374.         {
  375. #ifdef USR_GVIMRC_FILE3
  376.         (void)do_source((char_u *)USR_GVIMRC_FILE3, TRUE, FALSE);
  377. #endif
  378.         }
  379.  
  380.         /*
  381.          * Read initialization commands from ".gvimrc" in current
  382.          * directory.  This is only done if the 'exrc' option is set.
  383.          * Because of security reasons we disallow shell and write
  384.          * commands now, except for unix if the file is owned by the user
  385.          * or 'secure' option has been reset in environment of global
  386.          * ".gvimrc".
  387.          * Only do this if GVIMRC_FILE is not the same as USR_GVIMRC_FILE,
  388.          * USR_GVIMRC_FILE2, USR_GVIMRC_FILE3 or SYS_GVIMRC_FILE.
  389.          */
  390.         if (p_exrc)
  391.         {
  392. #ifdef UNIX
  393.         {
  394.             struct stat s;
  395.  
  396.             /* if ".gvimrc" file is not owned by user, set 'secure'
  397.              * mode */
  398.             if (mch_stat(GVIMRC_FILE, &s) || s.st_uid != getuid())
  399.             secure = p_secure;
  400.         }
  401. #else
  402.         secure = p_secure;
  403. #endif
  404.  
  405.         if (       fullpathcmp((char_u *)USR_GVIMRC_FILE,
  406.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  407. #ifdef SYS_GVIMRC_FILE
  408.             && fullpathcmp((char_u *)SYS_GVIMRC_FILE,
  409.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  410. #endif
  411. #ifdef USR_GVIMRC_FILE2
  412.             && fullpathcmp((char_u *)USR_GVIMRC_FILE2,
  413.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  414. #endif
  415. #ifdef USR_GVIMRC_FILE3
  416.             && fullpathcmp((char_u *)USR_GVIMRC_FILE3,
  417.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  418. #endif
  419.             )
  420.             do_source((char_u *)GVIMRC_FILE, TRUE, FALSE);
  421.  
  422.         if (secure == 2)
  423.             need_wait_return = TRUE;
  424.         secure = 0;
  425.         }
  426.     }
  427.  
  428.     if (need_wait_return || msg_didany)
  429.         wait_return(TRUE);
  430.  
  431.     --recursive;
  432.     }
  433.  
  434.     /* If recursive call opened the shell, return here from the first call */
  435.     if (gui.in_use)
  436.     return;
  437.  
  438.     /*
  439.      * Create the GUI shell.
  440.      */
  441.     gui.in_use = TRUE;        /* Must be set after menus have been set up */
  442.     if (gui_mch_init() == FAIL)
  443.     goto error;
  444.  
  445.     /* Avoid a delay for an error message that was printed in the terminal
  446.      * where Vim was started. */
  447.     emsg_on_display = FALSE;
  448.     msg_scrolled = 0;
  449.     need_wait_return = FALSE;
  450.     msg_didany = FALSE;
  451.  
  452.     /*
  453.      * Check validity of any generic resources that may have been loaded.
  454.      */
  455.     if (gui.border_width < 0)
  456.     gui.border_width = 0;
  457.  
  458.     /*
  459.      * Set up the fonts.  First use a font specified with "-fn" or "-font".
  460.      */
  461.     if (font_argument != NULL)
  462.     set_option_value((char_u *)"gfn", 0L, (char_u *)font_argument, 0);
  463.     if (
  464. #ifdef FEAT_XFONTSET
  465.         (*p_guifontset == NUL
  466.          || gui_init_font(p_guifontset, TRUE) == FAIL) &&
  467. #endif
  468.         gui_init_font(*p_guifont == NUL ? hl_get_font_name()
  469.                           : p_guifont, FALSE) == FAIL)
  470.     goto error2;
  471. #ifdef FEAT_MBYTE
  472.     if (gui_get_wide_font() == FAIL)
  473.     EMSG(_("E231: 'guifontwide' invalid"));
  474. #endif
  475.  
  476.     gui.num_cols = Columns;
  477.     gui.num_rows = Rows;
  478.     gui_reset_scroll_region();
  479.  
  480.     /* Create initial scrollbars */
  481.     FOR_ALL_WINDOWS(wp)
  482.     {
  483.     gui_create_scrollbar(&wp->w_scrollbars[SBAR_LEFT], SBAR_LEFT, wp);
  484.     gui_create_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], SBAR_RIGHT, wp);
  485.     }
  486.     gui_create_scrollbar(&gui.bottom_sbar, SBAR_BOTTOM, NULL);
  487.  
  488. #ifdef FEAT_MENU
  489.     gui_create_initial_menus(root_menu);
  490. #endif
  491. #ifdef FEAT_SUN_WORKSHOP
  492.     if (usingSunWorkShop)
  493.     workshop_init();
  494. #endif
  495. #ifdef FEAT_SIGN_ICONS
  496.     sign_gui_started();
  497. #endif
  498.  
  499.     /* Configure the desired menu and scrollbars */
  500.     gui_init_which_components(NULL);
  501.  
  502.     /* All components of the GUI have been created now */
  503.     gui.shell_created = TRUE;
  504.  
  505. #ifndef FEAT_GUI_GTK
  506.     /* Set the shell size, adjusted for the screen size.  For GTK this only
  507.      * works after the shell has been opened, thus it is further down. */
  508.     gui_set_shellsize(FALSE, TRUE);
  509. #endif
  510. #if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
  511.     /* Need to set the size of the menubar after all the menus have been
  512.      * created. */
  513.     gui_mch_compute_menu_height((Widget)0);
  514. #endif
  515.  
  516.     /*
  517.      * Actually open the GUI shell.
  518.      */
  519.     if (gui_mch_open() != FAIL)
  520.     {
  521. #ifdef FEAT_TITLE
  522.     maketitle();
  523.     resettitle();
  524. #endif
  525.     init_gui_options();
  526. #ifdef FEAT_ARABIC
  527.     /* Our GUI can't do bidi. */
  528.     p_tbidi = FALSE;
  529. #endif
  530. #ifdef FEAT_GUI_GTK
  531.     /* Give GTK+ a chance to put all widget's into place. */
  532.     gui_mch_update();
  533.     /* Now make sure the shell fits on the screen. */
  534.     gui_set_shellsize(FALSE, TRUE);
  535. #endif
  536. #ifdef FEAT_NETBEANS_INTG
  537.     if (starting == 0 && usingNetbeans)
  538.         /* Tell the client that it can start sending commands. */
  539.         netbeans_startup_done();
  540. #endif
  541.     return;
  542.     }
  543.  
  544. error2:
  545. #ifdef FEAT_GUI_X11
  546.     /* undo gui_mch_init() */
  547.     gui_mch_uninit();
  548. #endif
  549.  
  550. error:
  551.     gui.in_use = FALSE;
  552.     clip_init(FALSE);
  553. }
  554.  
  555.  
  556.     void
  557. gui_exit(rc)
  558.     int        rc;
  559. {
  560. #ifndef __BEOS__
  561.     /* don't free the fonts, it leads to a BUS error
  562.      * richard@whitequeen.com Jul 99 */
  563.     free_highlight_fonts();
  564. #endif
  565.     gui.in_use = FALSE;
  566.     gui_mch_exit(rc);
  567. }
  568.  
  569. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_MSWIN) \
  570.     || defined(FEAT_GUI_PHOTON) || defined(PROTO)
  571. /*
  572.  * Called when the GUI shell is closed by the user.  If there are no changed
  573.  * files Vim exits, otherwise there will be a dialog to ask the user what to
  574.  * do.
  575.  * When this function returns, Vim should NOT exit!
  576.  */
  577.     void
  578. gui_shell_closed()
  579. {
  580.     cmdmod_T        save_cmdmod;
  581.  
  582.     save_cmdmod = cmdmod;
  583.  
  584.     /* Only exit when there are no changed files */
  585.     exiting = TRUE;
  586. # ifdef FEAT_BROWSE
  587.     cmdmod.browse = TRUE;
  588. # endif
  589. # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  590.     cmdmod.confirm = TRUE;
  591. # endif
  592.     /* If there are changed buffers, present the user with a dialog if
  593.      * possible, otherwise give an error message. */
  594.     if (!check_changed_any(FALSE))
  595.     getout(0);
  596.  
  597.     exiting = FALSE;
  598.     cmdmod = save_cmdmod;
  599.     setcursor();        /* position cursor */
  600.     out_flush();
  601. }
  602. #endif
  603.  
  604. /*
  605.  * Set the font.  "font_list" is a a comma separated list of font names.  The
  606.  * first font name that works is used.  If none is found, use the default
  607.  * font.
  608.  * If "fontset" is TRUE, the "font_list" is used as one name for the fontset.
  609.  * Return OK when able to set the font.  When it failed FAIL is returned and
  610.  * the fonts are unchanged.
  611.  */
  612. /*ARGSUSED*/
  613.     int
  614. gui_init_font(font_list, fontset)
  615.     char_u    *font_list;
  616.     int        fontset;
  617. {
  618. #define FONTLEN 320
  619.     char_u    font_name[FONTLEN];
  620.     int        font_list_empty = FALSE;
  621.     int        ret = FAIL;
  622.  
  623.     if (!gui.in_use)
  624.     return FAIL;
  625.  
  626.     font_name[0] = NUL;
  627.     if (*font_list == NUL)
  628.     font_list_empty = TRUE;
  629.     else
  630.     {
  631. #ifdef FEAT_XFONTSET
  632.     /* When using a fontset, the whole list of fonts is one name. */
  633.     if (fontset)
  634.         ret = gui_mch_init_font(font_list, TRUE);
  635.     else
  636. #endif
  637.         while (*font_list != NUL)
  638.         {
  639.         /* Isolate one comma separated font name. */
  640.         (void)copy_option_part(&font_list, font_name, FONTLEN, ",");
  641.  
  642.         /* Careful!!!  The Win32 version of gui_mch_init_font(), when
  643.          * called with "*" will change p_guifont to the selected font
  644.          * name, which frees the old value.  This makes font_list
  645.          * invalid.  Thus when OK is returned here, font_list must no
  646.          * longer be used! */
  647.         if (gui_mch_init_font(font_name, FALSE) == OK)
  648.         {
  649. #if defined(FEAT_MBYTE) && !defined(HAVE_GTK2)
  650.             /* If it's a Unicode font, try setting 'guifontwide' to a
  651.              * similar double-width font. */
  652.             if ((p_guifontwide == NULL || *p_guifontwide == NUL)
  653.                 && strstr((char *)font_name, "10646") != NULL)
  654.             set_guifontwide(font_name);
  655. #endif
  656.             ret = OK;
  657.             break;
  658.         }
  659.         }
  660.     }
  661.  
  662.     if (ret != OK
  663.         && STRCMP(font_list, "*") != 0
  664.         && (font_list_empty || gui.norm_font == NOFONT))
  665.     {
  666.     /*
  667.      * Couldn't load any font in 'font_list', keep the current font if
  668.      * there is one.  If 'font_list' is empty, or if there is no current
  669.      * font, tell gui_mch_init_font() to try to find a font we can load.
  670.      */
  671.     ret = gui_mch_init_font(NULL, FALSE);
  672.     }
  673.  
  674.     if (ret == OK)
  675.     {
  676. #ifndef HAVE_GTK2
  677.     /* Set normal font as current font */
  678. # ifdef FEAT_XFONTSET
  679.     if (gui.fontset != NOFONTSET)
  680.         gui_mch_set_fontset(gui.fontset);
  681.     else
  682. # endif
  683.         gui_mch_set_font(gui.norm_font);
  684. #endif
  685.     gui_set_shellsize(FALSE,
  686. #ifdef MSWIN
  687.         TRUE
  688. #else
  689.         FALSE
  690. #endif
  691.         );
  692.     }
  693.  
  694.     return ret;
  695. }
  696.  
  697. #if defined(FEAT_MBYTE) || defined(PROTO)
  698. # ifndef HAVE_GTK2
  699. /*
  700.  * Try setting 'guifontwide' to a font twice as wide as "name".
  701.  */
  702.     static void
  703. set_guifontwide(name)
  704.     char_u    *name;
  705. {
  706.     int        i = 0;
  707.     char_u    wide_name[FONTLEN + 10]; /* room for 2 * width and '*' */
  708.     char_u    *wp = NULL;
  709.     char_u    *p;
  710.     GuiFont    font;
  711.  
  712.     wp = wide_name;
  713.     for (p = name; *p != NUL; ++p)
  714.     {
  715.     *wp++ = *p;
  716.     if (*p == '-')
  717.     {
  718.         ++i;
  719.         if (i == 6)        /* font type: change "--" to "-*-" */
  720.         {
  721.         if (p[1] == '-')
  722.             *wp++ = '*';
  723.         }
  724.         else if (i == 12)    /* found the width */
  725.         {
  726.         ++p;
  727.         i = getdigits(&p);
  728.         if (i != 0)
  729.         {
  730.             /* Double the width specification. */
  731.             sprintf((char *)wp, "%d%s", i * 2, p);
  732.             font = gui_mch_get_font(wide_name, FALSE);
  733.             if (font != NOFONT)
  734.             {
  735.             gui.wide_font = font;
  736.             set_string_option_direct((char_u *)"gfw", -1,
  737.                              wide_name, OPT_FREE);
  738.             }
  739.         }
  740.         break;
  741.         }
  742.     }
  743.     }
  744. }
  745. # endif /* !HAVE_GTK2 */
  746.  
  747. /*
  748.  * Get the font for 'guifontwide'.
  749.  * Return FAIL for an invalid font name.
  750.  */
  751.     int
  752. gui_get_wide_font()
  753. {
  754.     GuiFont    font = NOFONT;
  755.     char_u    font_name[FONTLEN];
  756.     char_u    *p;
  757.  
  758.     if (!gui.in_use)        /* Can't allocate font yet, assume it's OK. */
  759.     return OK;        /* Will give an error message later. */
  760.  
  761.     if (p_guifontwide != NULL && *p_guifontwide != NUL)
  762.     {
  763.     for (p = p_guifontwide; *p != NUL; )
  764.     {
  765.         /* Isolate one comma separated font name. */
  766.         (void)copy_option_part(&p, font_name, FONTLEN, ",");
  767.         font = gui_mch_get_font(font_name, FALSE);
  768.         if (font != NOFONT)
  769.         break;
  770.     }
  771.     if (font == NOFONT)
  772.         return FAIL;
  773.     }
  774.  
  775.     gui_mch_free_font(gui.wide_font);
  776. #ifdef HAVE_GTK2
  777.     /* Avoid unnecessary overhead if 'guifontwide' is equal to 'guifont'. */
  778.     if (font != NOFONT && gui.norm_font != NOFONT
  779.              && pango_font_description_equal(font, gui.norm_font))
  780.     {
  781.     gui.wide_font = NOFONT;
  782.     gui_mch_free_font(font);
  783.     }
  784.     else
  785. #endif
  786.     gui.wide_font = font;
  787.     return OK;
  788. }
  789. #endif
  790.  
  791.     void
  792. gui_set_cursor(row, col)
  793.     int        row;
  794.     int        col;
  795. {
  796.     gui.row = row;
  797.     gui.col = col;
  798. }
  799.  
  800. /*
  801.  * gui_check_pos - check if the cursor is on the screen.
  802.  */
  803.     static void
  804. gui_check_pos()
  805. {
  806.     if (gui.row >= screen_Rows)
  807.     gui.row = screen_Rows - 1;
  808.     if (gui.col >= screen_Columns)
  809.     gui.col = screen_Columns - 1;
  810.     if (gui.cursor_row >= screen_Rows || gui.cursor_col >= screen_Columns)
  811.     gui.cursor_is_valid = FALSE;
  812. }
  813.  
  814. /*
  815.  * Redraw the cursor if necessary or when forced.
  816.  * Careful: The contents of ScreenLines[] must match what is on the screen,
  817.  * otherwise this goes wrong.  May need to call out_flush() first.
  818.  */
  819.     void
  820. gui_update_cursor(force, clear_selection)
  821.     int        force;        /* when TRUE, update even when not moved */
  822.     int        clear_selection;/* clear selection under cursor */
  823. {
  824.     int        cur_width = 0;
  825.     int        cur_height = 0;
  826.     int        old_hl_mask;
  827.     int        idx;
  828.     int        id;
  829.     guicolor_T    cfg, cbg, cc;    /* cursor fore-/background color */
  830.     int        cattr;        /* cursor attributes */
  831.     int        attr;
  832.     attrentry_T *aep = NULL;
  833.  
  834.     /* Don't update the cursor when halfway busy scrolling.
  835.      * ScreenLines[] isn't valid then. */
  836.     if (!can_update_cursor)
  837.     return;
  838.  
  839.     gui_check_pos();
  840.     if (!gui.cursor_is_valid || force
  841.             || gui.row != gui.cursor_row || gui.col != gui.cursor_col)
  842.     {
  843.     gui_undraw_cursor();
  844.     if (gui.row < 0)
  845.         return;
  846. #ifdef USE_IM_CONTROL
  847.     if (gui.row != gui.cursor_row || gui.col != gui.cursor_col)
  848.         im_set_position(gui.row, gui.col);
  849. #endif
  850.     gui.cursor_row = gui.row;
  851.     gui.cursor_col = gui.col;
  852.  
  853.     /* Only write to the screen after ScreenLines[] has been initialized */
  854.     if (!screen_cleared || ScreenLines == NULL)
  855.         return;
  856.  
  857.     /* Clear the selection if we are about to write over it */
  858.     if (clear_selection)
  859.         clip_may_clear_selection(gui.row, gui.row);
  860.     /* Check that the cursor is inside the shell (resizing may have made
  861.      * it invalid) */
  862.     if (gui.row >= screen_Rows || gui.col >= screen_Columns)
  863.         return;
  864.  
  865.     gui.cursor_is_valid = TRUE;
  866.  
  867.     /*
  868.      * How the cursor is drawn depends on the current mode.
  869.      */
  870.     idx = get_shape_idx(FALSE);
  871.     if (State & LANGMAP)
  872.         id = shape_table[idx].id_lm;
  873.     else
  874.         id = shape_table[idx].id;
  875.  
  876.     /* get the colors and attributes for the cursor.  Default is inverted */
  877.     cfg = INVALCOLOR;
  878.     cbg = INVALCOLOR;
  879.     cattr = HL_INVERSE;
  880.     gui_mch_set_blinking(shape_table[idx].blinkwait,
  881.                  shape_table[idx].blinkon,
  882.                  shape_table[idx].blinkoff);
  883.     if (id > 0)
  884.     {
  885.         cattr = syn_id2colors(id, &cfg, &cbg);
  886. #if defined(USE_IM_CONTROL) || defined(FEAT_HANGULIN)
  887.         {
  888.         static int iid;
  889.         guicolor_T fg, bg;
  890.  
  891.         if (im_get_status())
  892.         {
  893.             iid = syn_name2id((char_u *)"CursorIM");
  894.             if (iid > 0)
  895.             {
  896.             syn_id2colors(iid, &fg, &bg);
  897.             if (bg != INVALCOLOR)
  898.                 cbg = bg;
  899.             if (fg != INVALCOLOR)
  900.                 cfg = fg;
  901.             }
  902.         }
  903.         }
  904. #endif
  905.     }
  906.  
  907.     /*
  908.      * Get the attributes for the character under the cursor.
  909.      * When no cursor color was given, use the character color.
  910.      */
  911.     attr = ScreenAttrs[LineOffset[gui.row] + gui.col];
  912.     if (attr > HL_ALL)
  913.         aep = syn_gui_attr2entry(attr);
  914.     if (aep != NULL)
  915.     {
  916.         attr = aep->ae_attr;
  917.         if (cfg == INVALCOLOR)
  918.         cfg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.bg_color
  919.                         : aep->ae_u.gui.fg_color);
  920.         if (cbg == INVALCOLOR)
  921.         cbg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.fg_color
  922.                         : aep->ae_u.gui.bg_color);
  923.     }
  924.     if (cfg == INVALCOLOR)
  925.         cfg = (attr & HL_INVERSE) ? gui.back_pixel : gui.norm_pixel;
  926.     if (cbg == INVALCOLOR)
  927.         cbg = (attr & HL_INVERSE) ? gui.norm_pixel : gui.back_pixel;
  928.  
  929. #ifdef FEAT_XIM
  930.     if (aep != NULL)
  931.     {
  932.         xim_bg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.fg_color
  933.                         : aep->ae_u.gui.bg_color);
  934.         xim_fg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.bg_color
  935.                         : aep->ae_u.gui.fg_color);
  936.         if (xim_bg_color == INVALCOLOR)
  937.         xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
  938.                            : gui.back_pixel;
  939.         if (xim_fg_color == INVALCOLOR)
  940.         xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
  941.                            : gui.norm_pixel;
  942.     }
  943.     else
  944.     {
  945.         xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
  946.                            : gui.back_pixel;
  947.         xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
  948.                            : gui.norm_pixel;
  949.     }
  950. #endif
  951.  
  952.     attr &= ~HL_INVERSE;
  953.     if (cattr & HL_INVERSE)
  954.     {
  955.         cc = cbg;
  956.         cbg = cfg;
  957.         cfg = cc;
  958.     }
  959.     cattr &= ~HL_INVERSE;
  960.  
  961.     /*
  962.      * When we don't have window focus, draw a hollow cursor.
  963.      */
  964.     if (!gui.in_focus)
  965.     {
  966.         gui_mch_draw_hollow_cursor(cbg);
  967.         return;
  968.     }
  969.  
  970.     old_hl_mask = gui.highlight_mask;
  971.     if (shape_table[idx].shape == SHAPE_BLOCK
  972. #ifdef FEAT_HANGULIN
  973.         || composing_hangul
  974. #endif
  975.        )
  976.     {
  977.         /*
  978.          * Draw the text character with the cursor colors.    Use the
  979.          * character attributes plus the cursor attributes.
  980.          */
  981.         gui.highlight_mask = (cattr | attr);
  982. #ifdef FEAT_HANGULIN
  983.         if (composing_hangul)
  984.         (void)gui_outstr_nowrap(composing_hangul_buffer, 2,
  985.             GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR, cfg, cbg, 0);
  986.         else
  987. #endif
  988.         (void)gui_screenchar(LineOffset[gui.row] + gui.col,
  989.             GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR, cfg, cbg, 0);
  990.     }
  991.     else
  992.     {
  993. #if defined(FEAT_MBYTE) && defined(FEAT_RIGHTLEFT)
  994.         int        col_off = FALSE;
  995. #endif
  996.         /*
  997.          * First draw the partial cursor, then overwrite with the text
  998.          * character, using a transparent background.
  999.          */
  1000.         if (shape_table[idx].shape == SHAPE_VER)
  1001.         {
  1002.         cur_height = gui.char_height;
  1003.         cur_width = (gui.char_width * shape_table[idx].percentage
  1004.                                   + 99) / 100;
  1005.         }
  1006.         else
  1007.         {
  1008.         cur_height = (gui.char_height * shape_table[idx].percentage
  1009.                                   + 99) / 100;
  1010.         cur_width = gui.char_width;
  1011.         }
  1012. #ifdef FEAT_MBYTE
  1013.         if (has_mbyte && (*mb_off2cells)(LineOffset[gui.row] + gui.col) > 1)
  1014.         {
  1015.         /* Double wide character. */
  1016.         if (shape_table[idx].shape != SHAPE_VER)
  1017.             cur_width += gui.char_width;
  1018. # ifdef FEAT_RIGHTLEFT
  1019.         if (CURSOR_BAR_RIGHT)
  1020.         {
  1021.             /* gui.col points to the left halve of the character but
  1022.              * the vertical line needs to be on the right halve.
  1023.              * A double-wide horizontal line is also drawn from the
  1024.              * right halve in gui_mch_draw_part_cursor(). */
  1025.             col_off = TRUE;
  1026.             ++gui.col;
  1027.         }
  1028. # endif
  1029.         }
  1030. #endif
  1031.         gui_mch_draw_part_cursor(cur_width, cur_height, cbg);
  1032. #if defined(FEAT_MBYTE) && defined(FEAT_RIGHTLEFT)
  1033.         if (col_off)
  1034.         --gui.col;
  1035. #endif
  1036.  
  1037. #ifndef FEAT_GUI_MSWIN        /* doesn't seem to work for MSWindows */
  1038.         gui.highlight_mask = ScreenAttrs[LineOffset[gui.row] + gui.col];
  1039.         (void)gui_screenchar(LineOffset[gui.row] + gui.col,
  1040.             GUI_MON_TRS_CURSOR | GUI_MON_NOCLEAR,
  1041.             (guicolor_T)0, (guicolor_T)0, 0);
  1042. #endif
  1043.     }
  1044.     gui.highlight_mask = old_hl_mask;
  1045.     }
  1046. }
  1047.  
  1048. #if defined(FEAT_MENU) || defined(PROTO)
  1049.     void
  1050. gui_position_menu()
  1051. {
  1052. # if !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF)
  1053.     if (gui.menu_is_active && gui.in_use)
  1054.     gui_mch_set_menu_pos(0, 0, gui.menu_width, gui.menu_height);
  1055. # endif
  1056. }
  1057. #endif
  1058.  
  1059. /*
  1060.  * Position the various GUI components (text area, menu).  The vertical
  1061.  * scrollbars are NOT handled here.  See gui_update_scrollbars().
  1062.  */
  1063. /*ARGSUSED*/
  1064.     static void
  1065. gui_position_components(total_width)
  1066.     int        total_width;
  1067. {
  1068.     int        text_area_x;
  1069.     int        text_area_y;
  1070.     int        text_area_width;
  1071.     int        text_area_height;
  1072.  
  1073.     /* avoid that moving components around generates events */
  1074.     ++hold_gui_events;
  1075.  
  1076.     text_area_x = 0;
  1077.     if (gui.which_scrollbars[SBAR_LEFT])
  1078.     text_area_x += gui.scrollbar_width;
  1079.  
  1080.     text_area_y = 0;
  1081. #if defined(FEAT_MENU) && !(defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON))
  1082.     gui.menu_width = total_width;
  1083.     if (gui.menu_is_active)
  1084.     text_area_y += gui.menu_height;
  1085. #endif
  1086. #if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_MSWIN)
  1087.     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  1088.     text_area_y = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
  1089. #endif
  1090.  
  1091. #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
  1092.     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  1093.     {
  1094. # ifdef FEAT_GUI_ATHENA
  1095.     gui_mch_set_toolbar_pos(0, text_area_y,
  1096.                 gui.menu_width, gui.toolbar_height);
  1097. # endif
  1098.     text_area_y += gui.toolbar_height;
  1099.     }
  1100. #endif
  1101.  
  1102.     text_area_width = gui.num_cols * gui.char_width + gui.border_offset * 2;
  1103.     text_area_height = gui.num_rows * gui.char_height + gui.border_offset * 2;
  1104.  
  1105.     gui_mch_set_text_area_pos(text_area_x,
  1106.                   text_area_y,
  1107.                   text_area_width,
  1108.                   text_area_height
  1109. #if defined(FEAT_XIM) && !defined(HAVE_GTK2)
  1110.                   + xim_get_status_area_height()
  1111. #endif
  1112.                   );
  1113. #ifdef FEAT_MENU
  1114.     gui_position_menu();
  1115. #endif
  1116.     if (gui.which_scrollbars[SBAR_BOTTOM])
  1117.     gui_mch_set_scrollbar_pos(&gui.bottom_sbar,
  1118.                   text_area_x,
  1119.                   text_area_y + text_area_height,
  1120.                   text_area_width,
  1121.                   gui.scrollbar_height);
  1122.     gui.left_sbar_x = 0;
  1123.     gui.right_sbar_x = text_area_x + text_area_width;
  1124.  
  1125.     --hold_gui_events;
  1126. }
  1127.  
  1128.     int
  1129. gui_get_base_width()
  1130. {
  1131.     int        base_width;
  1132.  
  1133.     base_width = 2 * gui.border_offset;
  1134.     if (gui.which_scrollbars[SBAR_LEFT])
  1135.     base_width += gui.scrollbar_width;
  1136.     if (gui.which_scrollbars[SBAR_RIGHT])
  1137.     base_width += gui.scrollbar_width;
  1138.     return base_width;
  1139. }
  1140.  
  1141.     int
  1142. gui_get_base_height()
  1143. {
  1144.     int        base_height;
  1145.  
  1146.     base_height = 2 * gui.border_offset;
  1147.     if (gui.which_scrollbars[SBAR_BOTTOM])
  1148.     base_height += gui.scrollbar_height;
  1149. #ifdef FEAT_GUI_GTK
  1150.     /* We can't take the sizes properly into account until anything is
  1151.      * realized.  Therefore we recalculate all the values here just before
  1152.      * setting the size. (--mdcki) */
  1153. #else
  1154. # ifdef FEAT_MENU
  1155.     if (gui.menu_is_active)
  1156.     base_height += gui.menu_height;
  1157. # endif
  1158. # ifdef FEAT_TOOLBAR
  1159.     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  1160. #  if defined(FEAT_GUI_MSWIN) && defined(FEAT_TOOLBAR)
  1161.     base_height += (TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT);
  1162. #  else
  1163.     base_height += gui.toolbar_height;
  1164. #  endif
  1165. # endif
  1166. # ifdef FEAT_FOOTER
  1167.     if (vim_strchr(p_go, GO_FOOTER) != NULL)
  1168.     base_height += gui.footer_height;
  1169. # endif
  1170. # if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
  1171.     base_height += gui_mch_text_area_extra_height();
  1172. # endif
  1173. #endif
  1174.     return base_height;
  1175. }
  1176.  
  1177. /*
  1178.  * Should be called after the GUI shell has been resized.  Its arguments are
  1179.  * the new width and height of the shell in pixels.
  1180.  */
  1181.     void
  1182. gui_resize_shell(pixel_width, pixel_height)
  1183.     int        pixel_width;
  1184.     int        pixel_height;
  1185. {
  1186.     static int    busy = FALSE;
  1187.  
  1188.     if (!gui.shell_created)        /* ignore when still initializing */
  1189.     return;
  1190.  
  1191.     /*
  1192.      * Can't resize the screen while it is being redrawn.  Remember the new
  1193.      * size and handle it later.
  1194.      */
  1195.     if (updating_screen || busy)
  1196.     {
  1197.     new_pixel_width = pixel_width;
  1198.     new_pixel_height = pixel_height;
  1199.     return;
  1200.     }
  1201.  
  1202. again:
  1203.     busy = TRUE;
  1204.  
  1205. #ifdef FEAT_GUI_BEOS
  1206.     vim_lock_screen();
  1207. #endif
  1208.  
  1209.     /* Flush pending output before redrawing */
  1210.     out_flush();
  1211.  
  1212.     gui.num_cols = (pixel_width - gui_get_base_width()) / gui.char_width;
  1213.     gui.num_rows = (pixel_height - gui_get_base_height()
  1214. #if !defined(FEAT_GUI_PHOTON) && !defined(FEAT_GUI_MSWIN)
  1215.                     + (gui.char_height / 2)
  1216. #endif
  1217.                     ) / gui.char_height;
  1218.  
  1219.     gui_position_components(pixel_width);
  1220.  
  1221.     gui_reset_scroll_region();
  1222.     /*
  1223.      * At the "more" and ":confirm" prompt there is no redraw, put the cursor
  1224.      * at the last line here (why does it have to be one row too low?).
  1225.      */
  1226.     if (State == ASKMORE || State == CONFIRM)
  1227.     gui.row = gui.num_rows;
  1228.  
  1229.     if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns)
  1230.     shell_resized();
  1231.  
  1232. #ifdef FEAT_GUI_BEOS
  1233.     vim_unlock_screen();
  1234. #endif
  1235.  
  1236.     gui_update_scrollbars(TRUE);
  1237.     gui_update_cursor(FALSE, TRUE);
  1238. #if defined(FEAT_XIM) && !defined(HAVE_GTK2)
  1239.     xim_set_status_area();
  1240. #endif
  1241.  
  1242.     busy = FALSE;
  1243.     /*
  1244.      * We could have been called again while redrawing the screen.
  1245.      * Need to do it all again with the latest size then.
  1246.      */
  1247.     if (new_pixel_height)
  1248.     {
  1249.     pixel_width = new_pixel_width;
  1250.     pixel_height = new_pixel_height;
  1251.     new_pixel_width = 0;
  1252.     new_pixel_height = 0;
  1253.     goto again;
  1254.     }
  1255. }
  1256.  
  1257. /*
  1258.  * Check if gui_resize_shell() must be called.
  1259.  */
  1260.     void
  1261. gui_may_resize_shell()
  1262. {
  1263.     int        h, w;
  1264.  
  1265.     if (new_pixel_height)
  1266.     {
  1267.     /* careful: gui_resize_shell() may postpone the resize again if we
  1268.      * were called indirectly by it */
  1269.     w = new_pixel_width;
  1270.     h = new_pixel_height;
  1271.     new_pixel_width = 0;
  1272.     new_pixel_height = 0;
  1273.     gui_resize_shell(w, h);
  1274.     }
  1275. }
  1276.  
  1277.     int
  1278. gui_get_shellsize()
  1279. {
  1280.     Rows = gui.num_rows;
  1281.     Columns = gui.num_cols;
  1282.     return OK;
  1283. }
  1284.  
  1285. /*
  1286.  * Set the size of the Vim shell according to Rows and Columns.
  1287.  */
  1288. /*ARGSUSED*/
  1289.     void
  1290. gui_set_shellsize(mustset, fit_to_display)
  1291.     int        mustset;        /* set by the user */
  1292.     int        fit_to_display;
  1293. {
  1294.     int        base_width;
  1295.     int        base_height;
  1296.     int        width;
  1297.     int        height;
  1298.     int        min_width;
  1299.     int        min_height;
  1300.     int        screen_w;
  1301.     int        screen_h;
  1302.  
  1303.     if (!gui.shell_created)
  1304.     return;
  1305.  
  1306. #ifdef MSWIN
  1307.     /* If not setting to a user specified size and maximized, calculate the
  1308.      * number of characters that fit in the maximized window. */
  1309.     if (!mustset && gui_mch_maximized())
  1310.     {
  1311.     gui_mch_newfont();
  1312.     return;
  1313.     }
  1314. #endif
  1315.  
  1316.     base_width = gui_get_base_width();
  1317.     base_height = gui_get_base_height();
  1318. #ifdef USE_SUN_WORKSHOP
  1319.     if (!mustset && usingSunWorkShop
  1320.                 && workshop_get_width_height(&width, &height))
  1321.     {
  1322.     Columns = (width - base_width + gui.char_width - 1) / gui.char_width;
  1323.     Rows = (height - base_height + gui.char_height - 1) / gui.char_height;
  1324.     }
  1325.     else
  1326. #endif
  1327.     {
  1328.     width = Columns * gui.char_width + base_width;
  1329.     height = Rows * gui.char_height + base_height;
  1330.     }
  1331.  
  1332.     if (fit_to_display)
  1333.     {
  1334.     gui_mch_get_screen_dimensions(&screen_w, &screen_h);
  1335.     if (width > screen_w)
  1336.     {
  1337.         Columns = (screen_w - base_width) / gui.char_width;
  1338.         if (Columns < MIN_COLUMNS)
  1339.         Columns = MIN_COLUMNS;
  1340.         width = Columns * gui.char_width + base_width;
  1341.     }
  1342.     if (height > screen_h)
  1343.     {
  1344.         Rows = (screen_h - base_height) / gui.char_height;
  1345.         check_shellsize();
  1346.         height = Rows * gui.char_height + base_height;
  1347.     }
  1348.     }
  1349.     gui.num_cols = Columns;
  1350.     gui.num_rows = Rows;
  1351.  
  1352.     min_width = base_width + MIN_COLUMNS * gui.char_width;
  1353.     min_height = base_height + MIN_LINES * gui.char_height;
  1354.  
  1355.     gui_mch_set_shellsize(width, height, min_width, min_height,
  1356.                              base_width, base_height);
  1357.     gui_position_components(width);
  1358.     gui_update_scrollbars(TRUE);
  1359.     gui_reset_scroll_region();
  1360. }
  1361.  
  1362. /*
  1363.  * Called when Rows and/or Columns has changed.
  1364.  */
  1365.     void
  1366. gui_new_shellsize()
  1367. {
  1368.     gui_reset_scroll_region();
  1369. }
  1370.  
  1371. /*
  1372.  * Make scroll region cover whole screen.
  1373.  */
  1374.     void
  1375. gui_reset_scroll_region()
  1376. {
  1377.     gui.scroll_region_top = 0;
  1378.     gui.scroll_region_bot = gui.num_rows - 1;
  1379.     gui.scroll_region_left = 0;
  1380.     gui.scroll_region_right = gui.num_cols - 1;
  1381. }
  1382.  
  1383.     void
  1384. gui_start_highlight(mask)
  1385.     int        mask;
  1386. {
  1387.     if (mask > HL_ALL)            /* highlight code */
  1388.     gui.highlight_mask = mask;
  1389.     else                /* mask */
  1390.     gui.highlight_mask |= mask;
  1391. }
  1392.  
  1393.     void
  1394. gui_stop_highlight(mask)
  1395.     int        mask;
  1396. {
  1397.     if (mask > HL_ALL)            /* highlight code */
  1398.     gui.highlight_mask = HL_NORMAL;
  1399.     else                /* mask */
  1400.     gui.highlight_mask &= ~mask;
  1401. }
  1402.  
  1403. /*
  1404.  * Clear a rectangular region of the screen from text pos (row1, col1) to
  1405.  * (row2, col2) inclusive.
  1406.  */
  1407.     void
  1408. gui_clear_block(row1, col1, row2, col2)
  1409.     int        row1;
  1410.     int        col1;
  1411.     int        row2;
  1412.     int        col2;
  1413. {
  1414.     /* Clear the selection if we are about to write over it */
  1415.     clip_may_clear_selection(row1, row2);
  1416.  
  1417.     gui_mch_clear_block(row1, col1, row2, col2);
  1418.  
  1419.     /* Invalidate cursor if it was in this block */
  1420.     if (       gui.cursor_row >= row1 && gui.cursor_row <= row2
  1421.         && gui.cursor_col >= col1 && gui.cursor_col <= col2)
  1422.     gui.cursor_is_valid = FALSE;
  1423. }
  1424.  
  1425. /*
  1426.  * Write code to update the cursor later.  This avoids the need to flush the
  1427.  * output buffer before calling gui_update_cursor().
  1428.  */
  1429.     void
  1430. gui_update_cursor_later()
  1431. {
  1432.     OUT_STR(IF_EB("\033|s", ESC_STR "|s"));
  1433. }
  1434.  
  1435.     void
  1436. gui_write(s, len)
  1437.     char_u    *s;
  1438.     int        len;
  1439. {
  1440.     char_u    *p;
  1441.     int        arg1 = 0, arg2 = 0;
  1442.     /* this doesn't make sense, disabled until someone can explain why it
  1443.      * would be needed */
  1444. #if 0 && (defined(RISCOS) || defined(WIN16))
  1445.     int        force_cursor = TRUE;    /* JK230798, stop Vim being smart or
  1446.                        our redraw speed will suffer */
  1447. #else
  1448.     int        force_cursor = FALSE;    /* force cursor update */
  1449. #endif
  1450.     int        force_scrollbar = FALSE;
  1451.     static win_T    *old_curwin = NULL;
  1452.  
  1453. /* #define DEBUG_GUI_WRITE */
  1454. #ifdef DEBUG_GUI_WRITE
  1455.     {
  1456.     int i;
  1457.     char_u *str;
  1458.  
  1459.     printf("gui_write(%d):\n    ", len);
  1460.     for (i = 0; i < len; i++)
  1461.         if (s[i] == ESC)
  1462.         {
  1463.         if (i != 0)
  1464.             printf("\n    ");
  1465.         printf("<ESC>");
  1466.         }
  1467.         else
  1468.         {
  1469.         str = transchar_byte(s[i]);
  1470.         if (str[0] && str[1])
  1471.             printf("<%s>", (char *)str);
  1472.         else
  1473.             printf("%s", (char *)str);
  1474.         }
  1475.     printf("\n");
  1476.     }
  1477. #endif
  1478.     while (len)
  1479.     {
  1480.     if (s[0] == ESC && s[1] == '|')
  1481.     {
  1482.         p = s + 2;
  1483.         if (isdigit(*p))
  1484.         {
  1485.         arg1 = getdigits(&p);
  1486.         if (p > s + len)
  1487.             break;
  1488.         if (*p == ';')
  1489.         {
  1490.             ++p;
  1491.             arg2 = getdigits(&p);
  1492.             if (p > s + len)
  1493.             break;
  1494.         }
  1495.         }
  1496.         switch (*p)
  1497.         {
  1498.         case 'C':    /* Clear screen */
  1499.             clip_scroll_selection(9999);
  1500.             gui_mch_clear_all();
  1501.             gui.cursor_is_valid = FALSE;
  1502.             force_scrollbar = TRUE;
  1503.             break;
  1504.         case 'M':    /* Move cursor */
  1505.             gui_set_cursor(arg1, arg2);
  1506.             break;
  1507.         case 's':    /* force cursor (shape) update */
  1508.             force_cursor = TRUE;
  1509.             break;
  1510.         case 'R':    /* Set scroll region */
  1511.             if (arg1 < arg2)
  1512.             {
  1513.             gui.scroll_region_top = arg1;
  1514.             gui.scroll_region_bot = arg2;
  1515.             }
  1516.             else
  1517.             {
  1518.             gui.scroll_region_top = arg2;
  1519.             gui.scroll_region_bot = arg1;
  1520.             }
  1521.             break;
  1522. #ifdef FEAT_VERTSPLIT
  1523.         case 'V':    /* Set vertical scroll region */
  1524.             if (arg1 < arg2)
  1525.             {
  1526.             gui.scroll_region_left = arg1;
  1527.             gui.scroll_region_right = arg2;
  1528.             }
  1529.             else
  1530.             {
  1531.             gui.scroll_region_left = arg2;
  1532.             gui.scroll_region_right = arg1;
  1533.             }
  1534.             break;
  1535. #endif
  1536.         case 'd':    /* Delete line */
  1537.             gui_delete_lines(gui.row, 1);
  1538.             break;
  1539.         case 'D':    /* Delete lines */
  1540.             gui_delete_lines(gui.row, arg1);
  1541.             break;
  1542.         case 'i':    /* Insert line */
  1543.             gui_insert_lines(gui.row, 1);
  1544.             break;
  1545.         case 'I':    /* Insert lines */
  1546.             gui_insert_lines(gui.row, arg1);
  1547.             break;
  1548.         case '$':    /* Clear to end-of-line */
  1549.             gui_clear_block(gui.row, gui.col, gui.row,
  1550.                                 (int)Columns - 1);
  1551.             break;
  1552.         case 'h':    /* Turn on highlighting */
  1553.             gui_start_highlight(arg1);
  1554.             break;
  1555.         case 'H':    /* Turn off highlighting */
  1556.             gui_stop_highlight(arg1);
  1557.             break;
  1558.         case 'f':    /* flash the window (visual bell) */
  1559.             gui_mch_flash(arg1 == 0 ? 20 : arg1);
  1560.             break;
  1561.         default:
  1562.             p = s + 1;    /* Skip the ESC */
  1563.             break;
  1564.         }
  1565.         len -= (int)(++p - s);
  1566.         s = p;
  1567.     }
  1568.     else if (
  1569. #ifdef EBCDIC
  1570.         CtrlChar(s[0]) != 0    /* Ctrl character */
  1571. #else
  1572.         s[0] < 0x20        /* Ctrl character */
  1573. #endif
  1574. #ifdef FEAT_SIGN_ICONS
  1575.         && s[0] != SIGN_BYTE
  1576. # ifdef FEAT_NETBEANS_INTG
  1577.         && s[0] != MULTISIGN_BYTE
  1578. # endif
  1579. #endif
  1580.         )
  1581.     {
  1582.         if (s[0] == '\n')        /* NL */
  1583.         {
  1584.         gui.col = 0;
  1585.         if (gui.row < gui.scroll_region_bot)
  1586.             gui.row++;
  1587.         else
  1588.             gui_delete_lines(gui.scroll_region_top, 1);
  1589.         }
  1590.         else if (s[0] == '\r')    /* CR */
  1591.         {
  1592.         gui.col = 0;
  1593.         }
  1594.         else if (s[0] == '\b')    /* Backspace */
  1595.         {
  1596.         if (gui.col)
  1597.             --gui.col;
  1598.         }
  1599.         else if (s[0] == Ctrl_L)    /* cursor-right */
  1600.         {
  1601.         ++gui.col;
  1602.         }
  1603.         else if (s[0] == Ctrl_G)    /* Beep */
  1604.         {
  1605.         gui_mch_beep();
  1606.         }
  1607.         /* Other Ctrl character: shouldn't happen! */
  1608.  
  1609.         --len;    /* Skip this char */
  1610.         ++s;
  1611.     }
  1612.     else
  1613.     {
  1614.         p = s;
  1615.         while (len > 0 && (
  1616. #ifdef EBCDIC
  1617.             CtrlChar(*p) == 0
  1618. #else
  1619.             *p >= 0x20
  1620. #endif
  1621. #ifdef FEAT_SIGN_ICONS
  1622.             || *p == SIGN_BYTE
  1623. # ifdef FEAT_NETBEANS_INTG
  1624.             || *p == MULTISIGN_BYTE
  1625. # endif
  1626. #endif
  1627.             ))
  1628.         {
  1629.         len--;
  1630.         p++;
  1631.         }
  1632.         gui_outstr(s, (int)(p - s));
  1633.         s = p;
  1634.     }
  1635.     }
  1636.  
  1637.     /* Don't update cursor when ScreenLines[] is invalid (busy scrolling). */
  1638.     if (can_update_cursor && force_cursor)
  1639.     gui_update_cursor(force_cursor, TRUE);
  1640.  
  1641.     /* When switching to another window the dragging must have stopped.
  1642.      * Required for GTK, dragged_sb isn't reset. */
  1643.     if (old_curwin != curwin)
  1644.     gui.dragged_sb = SBAR_NONE;
  1645.  
  1646.     /* Update the scrollbars after clearing the screen or when switched
  1647.      * to another window.
  1648.      * Update the horizontal scrollbar always, it's difficult to check all
  1649.      * situations where it might change. */
  1650.     if (force_scrollbar || old_curwin != curwin)
  1651.     gui_update_scrollbars(force_scrollbar);
  1652.     else
  1653.     gui_update_horiz_scrollbar(FALSE);
  1654.     old_curwin = curwin;
  1655.  
  1656.     /*
  1657.      * We need to make sure this is cleared since Athena doesn't tell us when
  1658.      * he is done dragging.  Do the same for GTK.
  1659.      */
  1660. #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK)
  1661.     gui.dragged_sb = SBAR_NONE;
  1662. #endif
  1663.  
  1664.     gui_mch_flush();            /* In case vim decides to take a nap */
  1665. }
  1666.  
  1667. /*
  1668.  * When ScreenLines[] is invalid, updating the cursor should not be done, it
  1669.  * produces wrong results.  Call gui_dont_update_cursor() before that code and
  1670.  * gui_can_update_cursor() afterwards.
  1671.  */
  1672.     void
  1673. gui_dont_update_cursor()
  1674. {
  1675.     can_update_cursor = FALSE;
  1676. }
  1677.  
  1678.     void
  1679. gui_can_update_cursor()
  1680. {
  1681.     can_update_cursor = TRUE;
  1682.     /* No need to update the cursor right now, there is always more output
  1683.      * after scrolling. */
  1684. }
  1685.  
  1686.     static void
  1687. gui_outstr(s, len)
  1688.     char_u  *s;
  1689.     int        len;
  1690. {
  1691.     int        this_len;
  1692. #ifdef FEAT_MBYTE
  1693.     int        cells;
  1694. #endif
  1695.  
  1696.     if (len == 0)
  1697.     return;
  1698.  
  1699.     if (len < 0)
  1700.     len = (int)STRLEN(s);
  1701.  
  1702.     while (len > 0)
  1703.     {
  1704. #ifdef FEAT_MBYTE
  1705.     if (has_mbyte)
  1706.     {
  1707.         /* Find out how many chars fit in the current line. */
  1708.         cells = 0;
  1709.         for (this_len = 0; this_len < len; )
  1710.         {
  1711.         cells += (*mb_ptr2cells)(s + this_len);
  1712.         if (gui.col + cells > Columns)
  1713.             break;
  1714.         this_len += (*mb_ptr2len_check)(s + this_len);
  1715.         }
  1716.         if (this_len > len)
  1717.         this_len = len;        /* don't include following composing char */
  1718.     }
  1719.     else
  1720. #endif
  1721.         if (gui.col + len > Columns)
  1722.         this_len = Columns - gui.col;
  1723.     else
  1724.         this_len = len;
  1725.  
  1726.     (void)gui_outstr_nowrap(s, this_len,
  1727.                       0, (guicolor_T)0, (guicolor_T)0, 0);
  1728.     s += this_len;
  1729.     len -= this_len;
  1730. #ifdef FEAT_MBYTE
  1731.     /* fill up for a double-width char that doesn't fit. */
  1732.     if (len > 0 && gui.col < Columns)
  1733.         (void)gui_outstr_nowrap((char_u *)" ", 1,
  1734.                       0, (guicolor_T)0, (guicolor_T)0, 0);
  1735. #endif
  1736.     /* The cursor may wrap to the next line. */
  1737.     if (gui.col >= Columns)
  1738.     {
  1739.         gui.col = 0;
  1740.         gui.row++;
  1741.     }
  1742.     }
  1743. }
  1744.  
  1745. /*
  1746.  * Output one character (may be one or two display cells).
  1747.  * Caller must check for valid "off".
  1748.  * Returns FAIL or OK, just like gui_outstr_nowrap().
  1749.  */
  1750.     static int
  1751. gui_screenchar(off, flags, fg, bg, back)
  1752.     int        off;        /* Offset from start of screen */
  1753.     int        flags;
  1754.     guicolor_T    fg, bg;        /* colors for cursor */
  1755.     int        back;        /* backup this many chars when using bold trick */
  1756. {
  1757. #ifdef FEAT_MBYTE
  1758.     char_u    buf[MB_MAXBYTES + 1];
  1759.  
  1760.     /* Don't draw right halve of a double-width UTF-8 char. "cannot happen" */
  1761.     if (enc_utf8 && ScreenLines[off] == 0)
  1762.     return OK;
  1763.  
  1764.     if (enc_utf8 && ScreenLinesUC[off] != 0)
  1765.     /* Draw UTF-8 multi-byte character. */
  1766.     return gui_outstr_nowrap(buf, utfc_char2bytes(off, buf),
  1767.                              flags, fg, bg, back);
  1768.  
  1769.     if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
  1770.     {
  1771.     buf[0] = ScreenLines[off];
  1772.     buf[1] = ScreenLines2[off];
  1773.     return gui_outstr_nowrap(buf, 2, flags, fg, bg, back);
  1774.     }
  1775.  
  1776.     /* Draw non-multi-byte character or DBCS character. */
  1777.     return gui_outstr_nowrap(ScreenLines + off,
  1778.         enc_dbcs ? (*mb_ptr2len_check)(ScreenLines + off) : 1,
  1779.                              flags, fg, bg, back);
  1780. #else
  1781.     return gui_outstr_nowrap(ScreenLines + off, 1, flags, fg, bg, back);
  1782. #endif
  1783. }
  1784.  
  1785. #ifdef HAVE_GTK2
  1786. /*
  1787.  * Output the string at the given screen position.  This is used in place
  1788.  * of gui_screenchar() where possible because Pango needs as much context
  1789.  * as possible to work nicely.  It's a lot faster as well.
  1790.  */
  1791.     static int
  1792. gui_screenstr(off, len, flags, fg, bg, back)
  1793.     int        off;        /* Offset from start of screen */
  1794.     int        len;        /* string length in screen cells */
  1795.     int        flags;
  1796.     guicolor_T    fg, bg;        /* colors for cursor */
  1797.     int        back;        /* backup this many chars when using bold trick */
  1798. {
  1799.     char_u  *buf;
  1800.     int        outlen = 0;
  1801.     int        i;
  1802.     int        retval;
  1803.  
  1804.     if (len <= 0) /* "cannot happen"? */
  1805.     return OK;
  1806.  
  1807.     if (enc_utf8)
  1808.     {
  1809.     buf = alloc((unsigned)(len * MB_MAXBYTES + 1));
  1810.     if (buf == NULL)
  1811.         return OK; /* not much we could do here... */
  1812.  
  1813.     for (i = off; i < off + len; ++i)
  1814.     {
  1815.         if (ScreenLines[i] == 0)
  1816.         continue; /* skip second half of double-width char */
  1817.  
  1818.         if (ScreenLinesUC[i] == 0)
  1819.         buf[outlen++] = ScreenLines[i];
  1820.         else
  1821.         outlen += utfc_char2bytes(i, buf + outlen);
  1822.     }
  1823.  
  1824.     buf[outlen] = NUL; /* only to aid debugging */
  1825.     retval = gui_outstr_nowrap(buf, outlen, flags, fg, bg, back);
  1826.     vim_free(buf);
  1827.  
  1828.     return retval;
  1829.     }
  1830.     else if (enc_dbcs == DBCS_JPNU)
  1831.     {
  1832.     buf = alloc((unsigned)(len * 2 + 1));
  1833.     if (buf == NULL)
  1834.         return OK; /* not much we could do here... */
  1835.  
  1836.     for (i = off; i < off + len; ++i)
  1837.     {
  1838.         buf[outlen++] = ScreenLines[i];
  1839.  
  1840.         /* handle double-byte single-width char */
  1841.         if (ScreenLines[i] == 0x8e)
  1842.         buf[outlen++] = ScreenLines2[i];
  1843.         else if (MB_BYTE2LEN(ScreenLines[i]) == 2)
  1844.         buf[outlen++] = ScreenLines[++i];
  1845.     }
  1846.  
  1847.     buf[outlen] = NUL; /* only to aid debugging */
  1848.     retval = gui_outstr_nowrap(buf, outlen, flags, fg, bg, back);
  1849.     vim_free(buf);
  1850.  
  1851.     return retval;
  1852.     }
  1853.     else
  1854.     {
  1855.     return gui_outstr_nowrap(&ScreenLines[off], len,
  1856.                  flags, fg, bg, back);
  1857.     }
  1858. }
  1859. #endif /* HAVE_GTK2 */
  1860.  
  1861. /*
  1862.  * Output the given string at the current cursor position.  If the string is
  1863.  * too long to fit on the line, then it is truncated.
  1864.  * "flags":
  1865.  * GUI_MON_IS_CURSOR should only be used when this function is being called to
  1866.  * actually draw (an inverted) cursor.
  1867.  * GUI_MON_TRS_CURSOR is used to draw the cursor text with a transparant
  1868.  * background.
  1869.  * GUI_MON_NOCLEAR is used to avoid clearing the selection when drawing over
  1870.  * it.
  1871.  * Returns OK, unless "back" is non-zero and using the bold trick, then return
  1872.  * FAIL (the caller should start drawing "back" chars back).
  1873.  */
  1874.     int
  1875. gui_outstr_nowrap(s, len, flags, fg, bg, back)
  1876.     char_u    *s;
  1877.     int        len;
  1878.     int        flags;
  1879.     guicolor_T    fg, bg;        /* colors for cursor */
  1880.     int        back;        /* backup this many chars when using bold trick */
  1881. {
  1882.     long_u    highlight_mask;
  1883.     long_u    hl_mask_todo;
  1884.     guicolor_T    fg_color;
  1885.     guicolor_T    bg_color;
  1886. #if !defined(MSWIN16_FASTTEXT) && !defined(HAVE_GTK2)
  1887.     GuiFont    font = NOFONT;
  1888. # ifdef FEAT_XFONTSET
  1889.     GuiFontset    fontset = NOFONTSET;
  1890. # endif
  1891. #endif
  1892.     attrentry_T    *aep = NULL;
  1893.     int        draw_flags;
  1894.     int        col = gui.col;
  1895. #ifdef FEAT_SIGN_ICONS
  1896.     int        draw_sign = FALSE;
  1897. # ifdef FEAT_NETBEANS_INTG
  1898.     int        multi_sign = FALSE;
  1899. # endif
  1900. #endif
  1901.  
  1902.     if (len < 0)
  1903.     len = (int)STRLEN(s);
  1904.     if (len == 0)
  1905.     return OK;
  1906.  
  1907. #ifdef FEAT_SIGN_ICONS
  1908.     if (*s == SIGN_BYTE
  1909. # ifdef FEAT_NETBEANS_INTG
  1910.       || *s == MULTISIGN_BYTE
  1911. # endif
  1912.     )
  1913.     {
  1914. # ifdef FEAT_NETBEANS_INTG
  1915.     if (*s == MULTISIGN_BYTE)
  1916.         multi_sign = TRUE;
  1917. # endif
  1918.     /* draw spaces instead */
  1919.     s = (char_u *)"  ";
  1920.     if (len == 1 && col > 0)
  1921.         --col;
  1922.     len = 2;
  1923.     draw_sign = TRUE;
  1924.     highlight_mask = 0;
  1925.     }
  1926.     else
  1927. #endif
  1928.     if (gui.highlight_mask > HL_ALL)
  1929.     {
  1930.     aep = syn_gui_attr2entry(gui.highlight_mask);
  1931.     if (aep == NULL)        /* highlighting not set */
  1932.         highlight_mask = 0;
  1933.     else
  1934.         highlight_mask = aep->ae_attr;
  1935.     }
  1936.     else
  1937.     highlight_mask = gui.highlight_mask;
  1938.     hl_mask_todo = highlight_mask;
  1939.  
  1940. #if !defined(MSWIN16_FASTTEXT) && !defined(HAVE_GTK2)
  1941.     /* Set the font */
  1942.     if (aep != NULL && aep->ae_u.gui.font != NOFONT)
  1943.     font = aep->ae_u.gui.font;
  1944. # ifdef FEAT_XFONTSET
  1945.     else if (aep != NULL && aep->ae_u.gui.fontset != NOFONTSET)
  1946.     fontset = aep->ae_u.gui.fontset;
  1947. # endif
  1948.     else
  1949.     {
  1950. # ifdef FEAT_XFONTSET
  1951.     if (gui.fontset != NOFONTSET)
  1952.         fontset = gui.fontset;
  1953.     else
  1954. # endif
  1955.         if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
  1956.     {
  1957.         if ((hl_mask_todo & HL_ITALIC) && gui.boldital_font != NOFONT)
  1958.         {
  1959.         font = gui.boldital_font;
  1960.         hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT | HL_ITALIC);
  1961.         }
  1962.         else if (gui.bold_font != NOFONT)
  1963.         {
  1964.         font = gui.bold_font;
  1965.         hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT);
  1966.         }
  1967.         else
  1968.         font = gui.norm_font;
  1969.     }
  1970.     else if ((hl_mask_todo & HL_ITALIC) && gui.ital_font != NOFONT)
  1971.     {
  1972.         font = gui.ital_font;
  1973.         hl_mask_todo &= ~HL_ITALIC;
  1974.     }
  1975.     else
  1976.         font = gui.norm_font;
  1977.     }
  1978. # ifdef FEAT_XFONTSET
  1979.     if (fontset != NOFONTSET)
  1980.     gui_mch_set_fontset(fontset);
  1981.     else
  1982. # endif
  1983.     gui_mch_set_font(font);
  1984. #endif
  1985.  
  1986.     draw_flags = 0;
  1987.  
  1988.     /* Set the color */
  1989.     bg_color = gui.back_pixel;
  1990.     if ((flags & GUI_MON_IS_CURSOR) && gui.in_focus)
  1991.     {
  1992.     draw_flags |= DRAW_CURSOR;
  1993.     fg_color = fg;
  1994.     bg_color = bg;
  1995.     }
  1996.     else if (aep != NULL)
  1997.     {
  1998.     fg_color = aep->ae_u.gui.fg_color;
  1999.     if (fg_color == INVALCOLOR)
  2000.         fg_color = gui.norm_pixel;
  2001.     bg_color = aep->ae_u.gui.bg_color;
  2002.     if (bg_color == INVALCOLOR)
  2003.         bg_color = gui.back_pixel;
  2004.     }
  2005.     else
  2006.     fg_color = gui.norm_pixel;
  2007.  
  2008.     if (highlight_mask & (HL_INVERSE | HL_STANDOUT))
  2009.     {
  2010. #if defined(AMIGA) || defined(RISCOS)
  2011.     gui_mch_set_colors(bg_color, fg_color);
  2012. #else
  2013.     gui_mch_set_fg_color(bg_color);
  2014.     gui_mch_set_bg_color(fg_color);
  2015. #endif
  2016.     }
  2017.     else
  2018.     {
  2019. #if defined(AMIGA) || defined(RISCOS)
  2020.     gui_mch_set_colors(fg_color, bg_color);
  2021. #else
  2022.     gui_mch_set_fg_color(fg_color);
  2023.     gui_mch_set_bg_color(bg_color);
  2024. #endif
  2025.     }
  2026.  
  2027.     /* Clear the selection if we are about to write over it */
  2028.     if (!(flags & GUI_MON_NOCLEAR))
  2029.     clip_may_clear_selection(gui.row, gui.row);
  2030.  
  2031.  
  2032. #ifndef MSWIN16_FASTTEXT
  2033.     /* If there's no bold font, then fake it */
  2034.     if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
  2035.     draw_flags |= DRAW_BOLD;
  2036. #endif
  2037.  
  2038.     /*
  2039.      * When drawing bold or italic characters the spill-over from the left
  2040.      * neighbor may be destroyed.  Let the caller backup to start redrawing
  2041.      * just after a blank.
  2042.      */
  2043.     if (back != 0 && ((draw_flags & DRAW_BOLD) || (highlight_mask & HL_ITALIC)))
  2044.     return FAIL;
  2045.  
  2046. #if defined(RISCOS) || defined(HAVE_GTK2)
  2047.     /* If there's no italic font, then fake it.
  2048.      * For GTK2, we don't need a different font for italic style. */
  2049.     if (hl_mask_todo & HL_ITALIC)
  2050.     draw_flags |= DRAW_ITALIC;
  2051.  
  2052.     /* Do we underline the text? */
  2053.     if (hl_mask_todo & HL_UNDERLINE)
  2054.     draw_flags |= DRAW_UNDERL;
  2055. #else
  2056.     /* Do we underline the text? */
  2057.     if ((hl_mask_todo & HL_UNDERLINE)
  2058. # ifndef MSWIN16_FASTTEXT
  2059.         || (hl_mask_todo & HL_ITALIC)
  2060. # endif
  2061.        )
  2062.     draw_flags |= DRAW_UNDERL;
  2063. #endif
  2064.  
  2065.     /* Do we draw transparantly? */
  2066.     if (flags & GUI_MON_TRS_CURSOR)
  2067.     draw_flags |= DRAW_TRANSP;
  2068.  
  2069.     /*
  2070.      * Draw the text.
  2071.      */
  2072. #ifdef HAVE_GTK2
  2073.     /* The value returned is the length in display cells */
  2074.     len = gui_gtk2_draw_string(gui.row, col, s, len, draw_flags);
  2075. #else
  2076. # ifdef FEAT_MBYTE
  2077.     if (enc_utf8)
  2078.     {
  2079.     int    start;        /* index of bytes to be drawn */
  2080.     int    cells;        /* cellwidth of bytes to be drawn */
  2081.     int    thislen;    /* length of bytes to be drawin */
  2082.     int    cn;        /* cellwidth of current char */
  2083.     int    i;        /* index of current char */
  2084.     int    c;        /* current char value */
  2085.     int    cl;        /* byte length of current char */
  2086.     int    comping;    /* current char is composing */
  2087.     int    scol = col;    /* screen column */
  2088.     int    dowide;        /* use 'guifontwide' */
  2089.  
  2090.     /* Break the string at a composing character, it has to be drawn on
  2091.      * top of the previous character. */
  2092.     start = 0;
  2093.     cells = 0;
  2094.     for (i = 0; i < len; i += cl)
  2095.     {
  2096.         c = utf_ptr2char(s + i);
  2097.         cn = utf_char2cells(c);
  2098.         if (cn > 1
  2099. #  ifdef FEAT_XFONTSET
  2100.             && fontset == NOFONTSET
  2101. #  endif
  2102.             && gui.wide_font != NOFONT)
  2103.         dowide = TRUE;
  2104.         else
  2105.         dowide = FALSE;
  2106.         comping = utf_iscomposing(c);
  2107.         if (!comping)    /* count cells from non-composing chars */
  2108.         cells += cn;
  2109.         cl = utf_ptr2len_check(s + i);
  2110.         if (cl == 0)    /* hit end of string */
  2111.         len = i + cl;    /* len must be wrong "cannot happen" */
  2112.  
  2113.         /* print the string so far if it's the last character or there is
  2114.          * a composing character. */
  2115.         if (i + cl >= len || (comping && i > start) || dowide
  2116. #  if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
  2117.             || (cn > 1
  2118. #   ifdef FEAT_XFONTSET
  2119.             /* No fontset: At least draw char after wide char at
  2120.              * right position. */
  2121.             && fontset == NOFONTSET
  2122. #   endif
  2123.                )
  2124. #  endif
  2125.            )
  2126.         {
  2127.         if (comping || dowide)
  2128.             thislen = i - start;
  2129.         else
  2130.             thislen = i - start + cl;
  2131.         if (thislen > 0)
  2132.         {
  2133.             gui_mch_draw_string(gui.row, scol, s + start, thislen,
  2134.                                   draw_flags);
  2135.             start += thislen;
  2136.         }
  2137.         scol += cells;
  2138.         cells = 0;
  2139.         if (dowide)
  2140.         {
  2141.             gui_mch_set_font(gui.wide_font);
  2142.             gui_mch_draw_string(gui.row, scol - cn,
  2143.                            s + start, cl, draw_flags);
  2144.             gui_mch_set_font(font);
  2145.             start += cl;
  2146.         }
  2147.  
  2148. #  if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
  2149.         /* No fontset: draw a space to fill the gap after a wide char */
  2150.         if (cn > 1 && (draw_flags & DRAW_TRANSP) == 0
  2151. #   ifdef FEAT_XFONTSET
  2152.             && fontset == NOFONTSET
  2153. #   endif
  2154.             && !dowide)
  2155.             gui_mch_draw_string(gui.row, scol - 1, (char_u *)" ",
  2156.                                    1, draw_flags);
  2157. #  endif
  2158.         }
  2159.         /* Draw a composing char on top of the previous char. */
  2160.         if (comping)
  2161.         {
  2162.         gui_mch_draw_string(gui.row, scol - cn, s + i, cl,
  2163.                             draw_flags | DRAW_TRANSP);
  2164.         start = i + cl;
  2165.         }
  2166.     }
  2167.     /* The stuff below assumes "len" is the length in screen columns. */
  2168.     len = scol - col;
  2169.     }
  2170.     else
  2171. # endif
  2172.     {
  2173.     gui_mch_draw_string(gui.row, col, s, len, draw_flags);
  2174. # ifdef FEAT_MBYTE
  2175.     if (enc_dbcs == DBCS_JPNU)
  2176.     {
  2177.         int        clen = 0;
  2178.         int        i;
  2179.  
  2180.         /* Get the length in display cells, this can be different from the
  2181.          * number of bytes for "euc-jp". */
  2182.         for (i = 0; i < len; i += (*mb_ptr2len_check)(s + i))
  2183.         clen += (*mb_ptr2cells)(s + i);
  2184.         len = clen;
  2185.     }
  2186. # endif
  2187.     }
  2188. #endif /* !HAVE_GTK2 */
  2189.  
  2190.     if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
  2191.     gui.col = col + len;
  2192.  
  2193.     /* May need to invert it when it's part of the selection. */
  2194.     if (flags & GUI_MON_NOCLEAR)
  2195.     clip_may_redraw_selection(gui.row, col, len);
  2196.  
  2197.     if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
  2198.     {
  2199.     /* Invalidate the old physical cursor position if we wrote over it */
  2200.     if (gui.cursor_row == gui.row
  2201.         && gui.cursor_col >= col
  2202.         && gui.cursor_col < col + len)
  2203.         gui.cursor_is_valid = FALSE;
  2204.     }
  2205.  
  2206. #ifdef FEAT_SIGN_ICONS
  2207.     if (draw_sign)
  2208.     /* Draw the sign on top of the spaces. */
  2209.     gui_mch_drawsign(gui.row, col, gui.highlight_mask);
  2210. # ifdef FEAT_NETBEANS_INTG
  2211.     if (multi_sign)
  2212.     netbeans_draw_multisign_indicator(gui.row);
  2213. # endif
  2214. #endif
  2215.  
  2216.     return OK;
  2217. }
  2218.  
  2219. /*
  2220.  * Un-draw the cursor.    Actually this just redraws the character at the given
  2221.  * position.  The character just before it too, for when it was in bold.
  2222.  */
  2223.     void
  2224. gui_undraw_cursor()
  2225. {
  2226.     if (gui.cursor_is_valid)
  2227.     {
  2228. #ifdef FEAT_HANGULIN
  2229.     if (composing_hangul
  2230.             && gui.col == gui.cursor_col && gui.row == gui.cursor_row)
  2231.         (void)gui_outstr_nowrap(composing_hangul_buffer, 2,
  2232.             GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR,
  2233.             gui.norm_pixel, gui.back_pixel, 0);
  2234.     else
  2235.     {
  2236. #endif
  2237.     if (gui_redraw_block(gui.cursor_row, gui.cursor_col,
  2238.                   gui.cursor_row, gui.cursor_col, GUI_MON_NOCLEAR)
  2239.         && gui.cursor_col > 0)
  2240.         (void)gui_redraw_block(gui.cursor_row, gui.cursor_col - 1,
  2241.              gui.cursor_row, gui.cursor_col - 1, GUI_MON_NOCLEAR);
  2242. #ifdef FEAT_HANGULIN
  2243.         if (composing_hangul)
  2244.         (void)gui_redraw_block(gui.cursor_row, gui.cursor_col + 1,
  2245.             gui.cursor_row, gui.cursor_col + 1, GUI_MON_NOCLEAR);
  2246.     }
  2247. #endif
  2248.     /* Cursor_is_valid is reset when the cursor is undrawn, also reset it
  2249.      * here in case it wasn't needed to undraw it. */
  2250.     gui.cursor_is_valid = FALSE;
  2251.     }
  2252. }
  2253.  
  2254.     void
  2255. gui_redraw(x, y, w, h)
  2256.     int        x;
  2257.     int        y;
  2258.     int        w;
  2259.     int        h;
  2260. {
  2261.     int        row1, col1, row2, col2;
  2262.  
  2263.     row1 = Y_2_ROW(y);
  2264.     col1 = X_2_COL(x);
  2265.     row2 = Y_2_ROW(y + h - 1);
  2266.     col2 = X_2_COL(x + w - 1);
  2267.  
  2268.     (void)gui_redraw_block(row1, col1, row2, col2, GUI_MON_NOCLEAR);
  2269.  
  2270.     /*
  2271.      * We may need to redraw the cursor, but don't take it upon us to change
  2272.      * its location after a scroll.
  2273.      * (maybe be more strict even and test col too?)
  2274.      * These things may be outside the update/clipping region and reality may
  2275.      * not reflect Vims internal ideas if these operations are clipped away.
  2276.      */
  2277.     if (gui.row == gui.cursor_row)
  2278.     gui_update_cursor(TRUE, TRUE);
  2279. }
  2280.  
  2281. /*
  2282.  * Draw a rectangular block of characters, from row1 to row2 (inclusive) and
  2283.  * from col1 to col2 (inclusive).
  2284.  * Return TRUE when the character before the first drawn character has
  2285.  * different attributes (may have to be redrawn too).
  2286.  */
  2287.     int
  2288. gui_redraw_block(row1, col1, row2, col2, flags)
  2289.     int        row1;
  2290.     int        col1;
  2291.     int        row2;
  2292.     int        col2;
  2293.     int        flags;    /* flags for gui_outstr_nowrap() */
  2294. {
  2295.     int        old_row, old_col;
  2296.     long_u    old_hl_mask;
  2297.     int        off;
  2298.     char_u    first_attr;
  2299.     int        idx, len;
  2300.     int        back, nback;
  2301.     int        retval = FALSE;
  2302. #ifdef FEAT_MBYTE
  2303.     int        orig_col1, orig_col2;
  2304. #endif
  2305.  
  2306.     /* Don't try to update when ScreenLines is not valid */
  2307.     if (!screen_cleared || ScreenLines == NULL)
  2308.     return retval;
  2309.  
  2310.     /* Don't try to draw outside the shell! */
  2311.     /* Check everything, strange values may be caused by a big border width */
  2312.     col1 = check_col(col1);
  2313.     col2 = check_col(col2);
  2314.     row1 = check_row(row1);
  2315.     row2 = check_row(row2);
  2316.  
  2317.     /* Remember where our cursor was */
  2318.     old_row = gui.row;
  2319.     old_col = gui.col;
  2320.     old_hl_mask = gui.highlight_mask;
  2321. #ifdef FEAT_MBYTE
  2322.     orig_col1 = col1;
  2323.     orig_col2 = col2;
  2324. #endif
  2325.  
  2326.     for (gui.row = row1; gui.row <= row2; gui.row++)
  2327.     {
  2328. #ifdef FEAT_MBYTE
  2329.     /* When only half of a double-wide character is in the block, include
  2330.      * the other half. */
  2331.     col1 = orig_col1;
  2332.     col2 = orig_col2;
  2333.     off = LineOffset[gui.row];
  2334.     if (enc_dbcs != 0)
  2335.     {
  2336.         if (col1 > 0)
  2337.         col1 -= dbcs_screen_head_off(ScreenLines + off,
  2338.                             ScreenLines + off + col1);
  2339.         col2 += dbcs_screen_tail_off(ScreenLines + off,
  2340.                             ScreenLines + off + col2);
  2341.     }
  2342.     else if (enc_utf8)
  2343.     {
  2344.         if (ScreenLines[off + col1] == 0)
  2345.         --col1;
  2346. # ifdef HAVE_GTK2
  2347.         if (col2 + 1 < Columns && ScreenLines[off + col2 + 1] == 0)
  2348.         ++col2;
  2349. # endif
  2350.     }
  2351. #endif
  2352.     gui.col = col1;
  2353.     off = LineOffset[gui.row] + gui.col;
  2354.     len = col2 - col1 + 1;
  2355.  
  2356.     /* Find how many chars back this highlighting starts, or where a space
  2357.      * is.  Needed for when the bold trick is used */
  2358.     for (back = 0; back < col1; ++back)
  2359.         if (ScreenAttrs[off - 1 - back] != ScreenAttrs[off]
  2360.             || ScreenLines[off - 1 - back] == ' ')
  2361.         break;
  2362.     retval = (col1 > 0 && ScreenAttrs[off - 1] != 0 && back == 0
  2363.                           && ScreenLines[off - 1] != ' ');
  2364.  
  2365.     /* Break it up in strings of characters with the same attributes. */
  2366.     /* Print UTF-8 characters individually. */
  2367.     while (len > 0)
  2368.     {
  2369.         first_attr = ScreenAttrs[off];
  2370.         gui.highlight_mask = first_attr;
  2371. #if defined(FEAT_MBYTE) && !defined(HAVE_GTK2)
  2372.         if (enc_utf8 && ScreenLinesUC[off] != 0)
  2373.         {
  2374.         /* output multi-byte character separately */
  2375.         nback = gui_screenchar(off, flags,
  2376.                       (guicolor_T)0, (guicolor_T)0, back);
  2377.         if (gui.col < Columns && ScreenLines[off + 1] == 0)
  2378.             idx = 2;
  2379.         else
  2380.             idx = 1;
  2381.         }
  2382.         else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
  2383.         {
  2384.         /* output double-byte, single-width character separately */
  2385.         nback = gui_screenchar(off, flags,
  2386.                       (guicolor_T)0, (guicolor_T)0, back);
  2387.         idx = 1;
  2388.         }
  2389.         else
  2390. #endif
  2391.         {
  2392. #ifdef HAVE_GTK2
  2393.         for (idx = 0; idx < len; ++idx)
  2394.         {
  2395.             if (enc_utf8 && ScreenLines[off + idx] == 0)
  2396.             continue; /* skip second half of double-width char */
  2397.             if (ScreenAttrs[off + idx] != first_attr)
  2398.             break;
  2399.         }
  2400.         /* gui_screenstr() takes care of multibyte chars */
  2401.         nback = gui_screenstr(off, idx, flags,
  2402.                       (guicolor_T)0, (guicolor_T)0, back);
  2403. #else
  2404.         for (idx = 0; idx < len && ScreenAttrs[off + idx] == first_attr;
  2405.                                     idx++)
  2406.         {
  2407. # ifdef FEAT_MBYTE
  2408.             /* Stop at a multi-byte Unicode character. */
  2409.             if (enc_utf8 && ScreenLinesUC[off + idx] != 0)
  2410.             break;
  2411.             if (enc_dbcs == DBCS_JPNU)
  2412.             {
  2413.             /* Stop at a double-byte single-width char. */
  2414.             if (ScreenLines[off + idx] == 0x8e)
  2415.                 break;
  2416.             if (len > 1 && (*mb_ptr2len_check)(ScreenLines
  2417.                                 + off + idx) == 2)
  2418.                 ++idx;  /* skip second byte of double-byte char */
  2419.             }
  2420. # endif
  2421.         }
  2422.         nback = gui_outstr_nowrap(ScreenLines + off, idx, flags,
  2423.                       (guicolor_T)0, (guicolor_T)0, back);
  2424. #endif
  2425.         }
  2426.         if (nback == FAIL)
  2427.         {
  2428.         /* Must back up to start drawing where a bold or italic word
  2429.          * starts. */
  2430.         off -= back;
  2431.         len += back;
  2432.         gui.col -= back;
  2433.         }
  2434.         else
  2435.         {
  2436.         off += idx;
  2437.         len -= idx;
  2438.         }
  2439.         back = 0;
  2440.     }
  2441.     }
  2442.  
  2443.     /* Put the cursor back where it was */
  2444.     gui.row = old_row;
  2445.     gui.col = old_col;
  2446.     gui.highlight_mask = old_hl_mask;
  2447.  
  2448.     return retval;
  2449. }
  2450.  
  2451.     static void
  2452. gui_delete_lines(row, count)
  2453.     int        row;
  2454.     int        count;
  2455. {
  2456.     if (count <= 0)
  2457.     return;
  2458.  
  2459.     if (row + count > gui.scroll_region_bot)
  2460.     /* Scrolled out of region, just blank the lines out */
  2461.     gui_clear_block(row, gui.scroll_region_left,
  2462.                   gui.scroll_region_bot, gui.scroll_region_right);
  2463.     else
  2464.     {
  2465.     gui_mch_delete_lines(row, count);
  2466.  
  2467.     /* If the cursor was in the deleted lines it's now gone.  If the
  2468.      * cursor was in the scrolled lines adjust its position. */
  2469.     if (gui.cursor_row >= row
  2470.         && gui.cursor_col >= gui.scroll_region_left
  2471.         && gui.cursor_col <= gui.scroll_region_right)
  2472.     {
  2473.         if (gui.cursor_row < row + count)
  2474.         gui.cursor_is_valid = FALSE;
  2475.         else if (gui.cursor_row <= gui.scroll_region_bot)
  2476.         gui.cursor_row -= count;
  2477.     }
  2478.     }
  2479. }
  2480.  
  2481.     static void
  2482. gui_insert_lines(row, count)
  2483.     int        row;
  2484.     int        count;
  2485. {
  2486.     if (count <= 0)
  2487.     return;
  2488.  
  2489.     if (row + count > gui.scroll_region_bot)
  2490.     /* Scrolled out of region, just blank the lines out */
  2491.     gui_clear_block(row, gui.scroll_region_left,
  2492.                   gui.scroll_region_bot, gui.scroll_region_right);
  2493.     else
  2494.     {
  2495.     gui_mch_insert_lines(row, count);
  2496.  
  2497.     if (gui.cursor_row >= gui.row
  2498.         && gui.cursor_col >= gui.scroll_region_left
  2499.         && gui.cursor_col <= gui.scroll_region_right)
  2500.     {
  2501.         if (gui.cursor_row <= gui.scroll_region_bot - count)
  2502.         gui.cursor_row += count;
  2503.         else if (gui.cursor_row <= gui.scroll_region_bot)
  2504.         gui.cursor_is_valid = FALSE;
  2505.     }
  2506.     }
  2507. }
  2508.  
  2509. /*
  2510.  * The main GUI input routine.    Waits for a character from the keyboard.
  2511.  * wtime == -1        Wait forever.
  2512.  * wtime == 0        Don't wait.
  2513.  * wtime > 0        Wait wtime milliseconds for a character.
  2514.  * Returns OK if a character was found to be available within the given time,
  2515.  * or FAIL otherwise.
  2516.  */
  2517.     int
  2518. gui_wait_for_chars(wtime)
  2519.     long    wtime;
  2520. {
  2521.     int        retval;
  2522. #ifdef FEAT_AUTOCMD
  2523.     static int once_already = 0;
  2524. #endif
  2525.  
  2526.     /*
  2527.      * If we're going to wait a bit, update the menus and mouse shape for the
  2528.      * current State.
  2529.      */
  2530.     if (wtime != 0)
  2531.     {
  2532. #ifdef FEAT_MENU
  2533.     gui_update_menus(0);
  2534. #endif
  2535.     }
  2536.  
  2537.     gui_mch_update();
  2538.     if (input_available())    /* Got char, return immediately */
  2539.     {
  2540. #ifdef FEAT_AUTOCMD
  2541.     once_already = 0;
  2542. #endif
  2543.     return OK;
  2544.     }
  2545.     if (wtime == 0)    /* Don't wait for char */
  2546.     {
  2547. #ifdef FEAT_AUTOCMD
  2548.     once_already = 0;
  2549. #endif
  2550.     return FAIL;
  2551.     }
  2552.  
  2553.     /* Before waiting, flush any output to the screen. */
  2554.     gui_mch_flush();
  2555.  
  2556.     if (wtime > 0)
  2557.     {
  2558.     /* Blink when waiting for a character.    Probably only does something
  2559.      * for showmatch() */
  2560.     gui_mch_start_blink();
  2561.     retval = gui_mch_wait_for_chars(wtime);
  2562.     gui_mch_stop_blink();
  2563. #ifdef FEAT_AUTOCMD
  2564.     once_already = 0;
  2565. #endif
  2566.     return retval;
  2567.     }
  2568.  
  2569.     /*
  2570.      * While we are waiting indefenitely for a character, blink the cursor.
  2571.      */
  2572.     gui_mch_start_blink();
  2573.  
  2574.  
  2575. #ifdef FEAT_AUTOCMD
  2576.     /* If there is no character available within 2 seconds (default),
  2577.      * write the autoscript file to disk */
  2578.     if (once_already == 2)
  2579.     {
  2580.     updatescript(0);
  2581.     retval = gui_mch_wait_for_chars(-1L);
  2582.     once_already = 0;
  2583.     }
  2584.     else if (once_already == 1)
  2585.     {
  2586.     setcursor();
  2587.     once_already = 2;
  2588.     retval = 0;
  2589.     }
  2590.     else
  2591. #endif
  2592.     if (gui_mch_wait_for_chars(p_ut) != OK)
  2593.     {
  2594. #ifdef FEAT_AUTOCMD
  2595.     if (has_cursorhold() && get_real_state() == NORMAL_BUSY)
  2596.     {
  2597.         apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, FALSE, curbuf);
  2598.         update_screen(VALID);
  2599.         showruler(FALSE);
  2600.         setcursor();
  2601.  
  2602.         once_already = 1;
  2603.         retval = 0;
  2604.     }
  2605.     else
  2606. #endif
  2607.     {
  2608.         updatescript(0);
  2609.         retval = gui_mch_wait_for_chars(-1L);
  2610. #ifdef FEAT_AUTOCMD
  2611.         once_already = 0;
  2612. #endif
  2613.     }
  2614.     }
  2615.     else
  2616.     retval = OK;
  2617.  
  2618.     gui_mch_stop_blink();
  2619.     return retval;
  2620. }
  2621.  
  2622. /*
  2623.  * Fill buffer with mouse coordinates encoded for check_termcode().
  2624.  */
  2625.     static void
  2626. fill_mouse_coord(p, col, row)
  2627.     char_u    *p;
  2628.     int        col;
  2629.     int        row;
  2630. {
  2631.     p[0] = (char_u)(col / 128 + ' ' + 1);
  2632.     p[1] = (char_u)(col % 128 + ' ' + 1);
  2633.     p[2] = (char_u)(row / 128 + ' ' + 1);
  2634.     p[3] = (char_u)(row % 128 + ' ' + 1);
  2635. }
  2636.  
  2637. /*
  2638.  * Generic mouse support function.  Add a mouse event to the input buffer with
  2639.  * the given properties.
  2640.  *  button        --- may be any of MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT,
  2641.  *            MOUSE_X1, MOUSE_X2
  2642.  *            MOUSE_DRAG, or MOUSE_RELEASE.
  2643.  *            MOUSE_4 and MOUSE_5 are used for a scroll wheel.
  2644.  *  x, y        --- Coordinates of mouse in pixels.
  2645.  *  repeated_click  --- TRUE if this click comes only a short time after a
  2646.  *            previous click.
  2647.  *  modifiers        --- Bit field which may be any of the following modifiers
  2648.  *            or'ed together: MOUSE_SHIFT | MOUSE_CTRL | MOUSE_ALT.
  2649.  * This function will ignore drag events where the mouse has not moved to a new
  2650.  * character.
  2651.  */
  2652.     void
  2653. gui_send_mouse_event(button, x, y, repeated_click, modifiers)
  2654.     int        button;
  2655.     int        x;
  2656.     int        y;
  2657.     int        repeated_click;
  2658.     int_u   modifiers;
  2659. {
  2660.     static int        prev_row = 0, prev_col = 0;
  2661.     static int        prev_button = -1;
  2662.     static int        num_clicks = 1;
  2663.     char_u        string[10];
  2664.     enum key_extra  button_char;
  2665.     int            row, col;
  2666. #ifdef FEAT_CLIPBOARD
  2667.     int            checkfor;
  2668.     int            did_clip = FALSE;
  2669. #endif
  2670.  
  2671.     /*
  2672.      * Scrolling may happen at any time, also while a selection is present.
  2673.      */
  2674.     switch (button)
  2675.     {
  2676.     case MOUSE_X1:
  2677.         button_char = KE_X1MOUSE;
  2678.         goto button_set;
  2679.     case MOUSE_X2:
  2680.         button_char = KE_X2MOUSE;
  2681.         goto button_set;
  2682.     case MOUSE_4:
  2683.         button_char = KE_MOUSEDOWN;
  2684.         goto button_set;
  2685.     case MOUSE_5:
  2686.         button_char = KE_MOUSEUP;
  2687. button_set:
  2688.         {
  2689.         /* Don't put events in the input queue now. */
  2690.         if (hold_gui_events)
  2691.             return;
  2692.  
  2693.         string[3] = CSI;
  2694.         string[4] = KS_EXTRA;
  2695.         string[5] = (int)button_char;
  2696.  
  2697.         /* Pass the pointer coordinates of the scroll event so that we
  2698.          * know which window to scroll. */
  2699.         row = gui_xy2colrow(x, y, &col);
  2700.         string[6] = (char_u)(col / 128 + ' ' + 1);
  2701.         string[7] = (char_u)(col % 128 + ' ' + 1);
  2702.         string[8] = (char_u)(row / 128 + ' ' + 1);
  2703.         string[9] = (char_u)(row % 128 + ' ' + 1);
  2704.  
  2705.         if (modifiers == 0)
  2706.             add_to_input_buf(string + 3, 7);
  2707.         else
  2708.         {
  2709.             string[0] = CSI;
  2710.             string[1] = KS_MODIFIER;
  2711.             string[2] = 0;
  2712.             if (modifiers & MOUSE_SHIFT)
  2713.             string[2] |= MOD_MASK_SHIFT;
  2714.             if (modifiers & MOUSE_CTRL)
  2715.             string[2] |= MOD_MASK_CTRL;
  2716.             if (modifiers & MOUSE_ALT)
  2717.             string[2] |= MOD_MASK_ALT;
  2718.             add_to_input_buf(string, 10);
  2719.         }
  2720.         return;
  2721.         }
  2722.     }
  2723.  
  2724. #ifdef FEAT_CLIPBOARD
  2725.     /* If a clipboard selection is in progress, handle it */
  2726.     if (clip_star.state == SELECT_IN_PROGRESS)
  2727.     {
  2728.     clip_process_selection(button, X_2_COL(x), Y_2_ROW(y), repeated_click);
  2729.     return;
  2730.     }
  2731.  
  2732.     /* Determine which mouse settings to look for based on the current mode */
  2733.     switch (get_real_state())
  2734.     {
  2735.     case NORMAL_BUSY:
  2736.     case OP_PENDING:
  2737.     case NORMAL:        checkfor = MOUSE_NORMAL;    break;
  2738.     case VISUAL:        checkfor = MOUSE_VISUAL;    break;
  2739.     case REPLACE:
  2740.     case REPLACE+LANGMAP:
  2741. #ifdef FEAT_VREPLACE
  2742.     case VREPLACE:
  2743.     case VREPLACE+LANGMAP:
  2744. #endif
  2745.     case INSERT:
  2746.     case INSERT+LANGMAP:    checkfor = MOUSE_INSERT;    break;
  2747.     case ASKMORE:
  2748.     case HITRETURN:        /* At the more- and hit-enter prompt pass the
  2749.                    mouse event for a click on the last line. */
  2750.                 if (Y_2_ROW(y) == Rows - 1)
  2751.                     checkfor = MOUSE_NORMAL;
  2752.                 else
  2753.                     checkfor = MOUSE_RETURN;
  2754.                 break;
  2755.  
  2756.         /*
  2757.          * On the command line, use the clipboard selection on all lines
  2758.          * but the command line.  But not when pasting.
  2759.          */
  2760.     case CMDLINE:
  2761.     case CMDLINE+LANGMAP:
  2762.         if (Y_2_ROW(y) < cmdline_row && button != MOUSE_MIDDLE)
  2763.         checkfor = MOUSE_NONE;
  2764.         else
  2765.         checkfor = MOUSE_COMMAND;
  2766.         break;
  2767.  
  2768.     default:
  2769.         checkfor = MOUSE_NONE;
  2770.         break;
  2771.     };
  2772.  
  2773.     /*
  2774.      * Allow clipboard selection of text on the command line in "normal"
  2775.      * modes.  Don't do this when dragging the status line, or extending a
  2776.      * Visual selection.
  2777.      */
  2778.     if ((State == NORMAL || State == NORMAL_BUSY || (State & INSERT))
  2779.         && Y_2_ROW(y) >= topframe->fr_height
  2780.         && button != MOUSE_DRAG
  2781. # ifdef FEAT_MOUSESHAPE
  2782.         && !drag_status_line
  2783. #  ifdef FEAT_VERTSPLIT
  2784.         && !drag_sep_line
  2785. #  endif
  2786. # endif
  2787.         )
  2788.     checkfor = MOUSE_NONE;
  2789.  
  2790.     /*
  2791.      * Use modeless selection when holding CTRL and SHIFT pressed.
  2792.      */
  2793.     if ((modifiers & MOUSE_CTRL) && (modifiers & MOUSE_SHIFT))
  2794.     checkfor = MOUSE_NONEF;
  2795.  
  2796.     /*
  2797.      * In Ex mode, always use modeless selection.
  2798.      */
  2799.     if (exmode_active)
  2800.     checkfor = MOUSE_NONE;
  2801.  
  2802.     /*
  2803.      * If the mouse settings say to not use the mouse, use the modeless
  2804.      * selection.  But if Visual is active, assume that only the Visual area
  2805.      * will be selected.
  2806.      * Exception: On the command line, both the selection is used and a mouse
  2807.      * key is send.
  2808.      */
  2809.     if (!mouse_has(checkfor) || checkfor == MOUSE_COMMAND)
  2810.     {
  2811. #ifdef FEAT_VISUAL
  2812.     /* Don't do modeless selection in Visual mode. */
  2813.     if (checkfor != MOUSE_NONEF && VIsual_active && (State & NORMAL))
  2814.         return;
  2815. #endif
  2816.  
  2817.     /*
  2818.      * When 'mousemodel' is "popup", shift-left is translated to right.
  2819.      * But not when also using Ctrl.
  2820.      */
  2821.     if (mouse_model_popup() && button == MOUSE_LEFT
  2822.         && (modifiers & MOUSE_SHIFT) && !(modifiers & MOUSE_CTRL))
  2823.     {
  2824.         button = MOUSE_RIGHT;
  2825.         modifiers &= ~ MOUSE_SHIFT;
  2826.     }
  2827.  
  2828.     /* If the selection is done, allow the right button to extend it.
  2829.      * If the selection is cleared, allow the right button to start it
  2830.      * from the cursor position. */
  2831.     if (button == MOUSE_RIGHT)
  2832.     {
  2833.         if (clip_star.state == SELECT_CLEARED)
  2834.         {
  2835.         if (State & CMDLINE)
  2836.         {
  2837.             col = msg_col;
  2838.             row = msg_row;
  2839.         }
  2840.         else
  2841.         {
  2842.             col = curwin->w_wcol;
  2843.             row = curwin->w_wrow + W_WINROW(curwin);
  2844.         }
  2845.         clip_start_selection(col, row, FALSE);
  2846.         }
  2847.         clip_process_selection(button, X_2_COL(x), Y_2_ROW(y),
  2848.                                   repeated_click);
  2849.         did_clip = TRUE;
  2850.     }
  2851.     /* Allow the left button to start the selection */
  2852.     else if (button ==
  2853. # ifdef RISCOS
  2854.         /* Only start a drag on a drag event. Otherwise
  2855.          * we don't get a release event.
  2856.          */
  2857.             MOUSE_DRAG
  2858. # else
  2859.             MOUSE_LEFT
  2860. # endif
  2861.                 )
  2862.     {
  2863.         clip_start_selection(X_2_COL(x), Y_2_ROW(y), repeated_click);
  2864.         did_clip = TRUE;
  2865.     }
  2866. # ifdef RISCOS
  2867.     else if (button == MOUSE_LEFT)
  2868.     {
  2869.         clip_clear_selection();
  2870.         did_clip = TRUE;
  2871.     }
  2872. # endif
  2873.  
  2874.     /* Always allow pasting */
  2875.     if (button != MOUSE_MIDDLE)
  2876.     {
  2877.         if (!mouse_has(checkfor) || button == MOUSE_RELEASE)
  2878.         return;
  2879.         if (checkfor != MOUSE_COMMAND)
  2880.         button = MOUSE_LEFT;
  2881.     }
  2882.     repeated_click = FALSE;
  2883.     }
  2884.  
  2885.     if (clip_star.state != SELECT_CLEARED && !did_clip)
  2886.     clip_clear_selection();
  2887. #endif
  2888.  
  2889.     /* Don't put events in the input queue now. */
  2890.     if (hold_gui_events)
  2891.     return;
  2892.  
  2893.     row = gui_xy2colrow(x, y, &col);
  2894.  
  2895.     /*
  2896.      * If we are dragging and the mouse hasn't moved far enough to be on a
  2897.      * different character, then don't send an event to vim.
  2898.      */
  2899.     if (button == MOUSE_DRAG)
  2900.     {
  2901.     if (row == prev_row && col == prev_col)
  2902.         return;
  2903.     /* Dragging above the window, set "row" to -1 to cause a scroll. */
  2904.     if (y < 0)
  2905.         row = -1;
  2906.     }
  2907.  
  2908.     /*
  2909.      * If topline has changed (window scrolled) since the last click, reset
  2910.      * repeated_click, because we don't want starting Visual mode when
  2911.      * clicking on a different character in the text.
  2912.      */
  2913.     if (curwin->w_topline != gui_prev_topline
  2914. #ifdef FEAT_DIFF
  2915.         || curwin->w_topfill != gui_prev_topfill
  2916. #endif
  2917.         )
  2918.     repeated_click = FALSE;
  2919.  
  2920.     string[0] = CSI;    /* this sequence is recognized by check_termcode() */
  2921.     string[1] = KS_MOUSE;
  2922.     string[2] = KE_FILLER;
  2923.     if (button != MOUSE_DRAG && button != MOUSE_RELEASE)
  2924.     {
  2925.     if (repeated_click)
  2926.     {
  2927.         /*
  2928.          * Handle multiple clicks.    They only count if the mouse is still
  2929.          * pointing at the same character.
  2930.          */
  2931.         if (button != prev_button || row != prev_row || col != prev_col)
  2932.         num_clicks = 1;
  2933.         else if (++num_clicks > 4)
  2934.         num_clicks = 1;
  2935.     }
  2936.     else
  2937.         num_clicks = 1;
  2938.     prev_button = button;
  2939.     gui_prev_topline = curwin->w_topline;
  2940. #ifdef FEAT_DIFF
  2941.     gui_prev_topfill = curwin->w_topfill;
  2942. #endif
  2943.  
  2944.     string[3] = (char_u)(button | 0x20);
  2945.     SET_NUM_MOUSE_CLICKS(string[3], num_clicks);
  2946.     }
  2947.     else
  2948.     string[3] = (char_u)button;
  2949.  
  2950.     string[3] |= modifiers;
  2951.     fill_mouse_coord(string + 4, col, row);
  2952.     add_to_input_buf(string, 8);
  2953.  
  2954.     if (row < 0)
  2955.     prev_row = 0;
  2956.     else
  2957.     prev_row = row;
  2958.     prev_col = col;
  2959.  
  2960.     /*
  2961.      * We need to make sure this is cleared since Athena doesn't tell us when
  2962.      * he is done dragging.  Neither does GTK+ 2 -- at least for now.
  2963.      */
  2964. #if defined(FEAT_GUI_ATHENA) || defined(HAVE_GTK2)
  2965.     gui.dragged_sb = SBAR_NONE;
  2966. #endif
  2967. }
  2968.  
  2969. /*
  2970.  * Convert x and y coordinate to column and row in text window.
  2971.  * Corrects for multi-byte character.
  2972.  * returns column in "*colp" and row as return value;
  2973.  */
  2974.     int
  2975. gui_xy2colrow(x, y, colp)
  2976.     int        x;
  2977.     int        y;
  2978.     int        *colp;
  2979. {
  2980.     int        col = check_col(X_2_COL(x));
  2981.     int        row = check_row(Y_2_ROW(y));
  2982.  
  2983. #ifdef FEAT_MBYTE
  2984.     *colp = mb_fix_col(col, row);
  2985. #else
  2986.     *colp = col;
  2987. #endif
  2988.     return row;
  2989. }
  2990.  
  2991. #if defined(FEAT_MENU) || defined(PROTO)
  2992. /*
  2993.  * Callback function for when a menu entry has been selected.
  2994.  */
  2995.     void
  2996. gui_menu_cb(menu)
  2997.     vimmenu_T *menu;
  2998. {
  2999.     char_u  bytes[3 + sizeof(long_u)];
  3000.  
  3001.     /* Don't put events in the input queue now. */
  3002.     if (hold_gui_events)
  3003.     return;
  3004.  
  3005.     bytes[0] = CSI;
  3006.     bytes[1] = KS_MENU;
  3007.     bytes[2] = KE_FILLER;
  3008.     add_long_to_buf((long_u)menu, bytes + 3);
  3009.     add_to_input_buf(bytes, 3 + sizeof(long_u));
  3010. }
  3011. #endif
  3012.  
  3013. /*
  3014.  * Set which components are present.
  3015.  * If "oldval" is not NULL, "oldval" is the previous value, the new * value is
  3016.  * in p_go.
  3017.  */
  3018. /*ARGSUSED*/
  3019.     void
  3020. gui_init_which_components(oldval)
  3021.     char_u    *oldval;
  3022. {
  3023.     static int    prev_which_scrollbars[3] = {-1, -1, -1};
  3024. #ifdef FEAT_MENU
  3025.     static int    prev_menu_is_active = -1;
  3026. #endif
  3027. #ifdef FEAT_TOOLBAR
  3028.     static int    prev_toolbar = -1;
  3029.     int        using_toolbar = FALSE;
  3030. #endif
  3031. #ifdef FEAT_FOOTER
  3032.     static int    prev_footer = -1;
  3033.     int        using_footer = FALSE;
  3034. #endif
  3035. #if defined(FEAT_MENU) && !defined(WIN16)
  3036.     static int    prev_tearoff = -1;
  3037.     int        using_tearoff = FALSE;
  3038. #endif
  3039.  
  3040.     char_u    *p;
  3041.     int        i;
  3042. #ifdef FEAT_MENU
  3043.     int        grey_old, grey_new;
  3044.     char_u    *temp;
  3045. #endif
  3046.     win_T    *wp;
  3047.     int        need_set_size;
  3048.  
  3049. #ifdef FEAT_MENU
  3050.     if (oldval != NULL && gui.in_use)
  3051.     {
  3052.     /*
  3053.      * Check if the menu's go from grey to non-grey or vise versa.
  3054.      */
  3055.     grey_old = (vim_strchr(oldval, GO_GREY) != NULL);
  3056.     grey_new = (vim_strchr(p_go, GO_GREY) != NULL);
  3057.     if (grey_old != grey_new)
  3058.     {
  3059.         temp = p_go;
  3060.         p_go = oldval;
  3061.         gui_update_menus(MENU_ALL_MODES);
  3062.         p_go = temp;
  3063.     }
  3064.     }
  3065.     gui.menu_is_active = FALSE;
  3066. #endif
  3067.  
  3068.     for (i = 0; i < 3; i++)
  3069.     gui.which_scrollbars[i] = FALSE;
  3070.     for (p = p_go; *p; p++)
  3071.     switch (*p)
  3072.     {
  3073.         case GO_LEFT:
  3074.         gui.which_scrollbars[SBAR_LEFT] = TRUE;
  3075.         break;
  3076.         case GO_RIGHT:
  3077.         gui.which_scrollbars[SBAR_RIGHT] = TRUE;
  3078.         break;
  3079. #ifdef FEAT_VERTSPLIT
  3080.         case GO_VLEFT:
  3081.         if (win_hasvertsplit())
  3082.             gui.which_scrollbars[SBAR_LEFT] = TRUE;
  3083.         break;
  3084.         case GO_VRIGHT:
  3085.         if (win_hasvertsplit())
  3086.             gui.which_scrollbars[SBAR_RIGHT] = TRUE;
  3087.         break;
  3088. #endif
  3089.         case GO_BOT:
  3090.         gui.which_scrollbars[SBAR_BOTTOM] = TRUE;
  3091.         break;
  3092. #ifdef FEAT_MENU
  3093.         case GO_MENUS:
  3094.         gui.menu_is_active = TRUE;
  3095.         break;
  3096. #endif
  3097.         case GO_GREY:
  3098.         /* make menu's have grey items, ignored here */
  3099.         break;
  3100. #ifdef FEAT_TOOLBAR
  3101.         case GO_TOOLBAR:
  3102.         using_toolbar = TRUE;
  3103.         break;
  3104. #endif
  3105. #ifdef FEAT_FOOTER
  3106.         case GO_FOOTER:
  3107.         using_footer = TRUE;
  3108.         break;
  3109. #endif
  3110.         case GO_TEAROFF:
  3111. #if defined(FEAT_MENU) && !defined(WIN16)
  3112.         using_tearoff = TRUE;
  3113. #endif
  3114.         break;
  3115.         default:
  3116.         /* Ignore options that are not supported */
  3117.         break;
  3118.     }
  3119.     if (gui.in_use)
  3120.     {
  3121.     need_set_size = FALSE;
  3122.     for (i = 0; i < 3; i++)
  3123.     {
  3124.         if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
  3125.         {
  3126.         if (i == SBAR_BOTTOM)
  3127.             gui_mch_enable_scrollbar(&gui.bottom_sbar,
  3128.                              gui.which_scrollbars[i]);
  3129.         else
  3130.         {
  3131.             FOR_ALL_WINDOWS(wp)
  3132.             {
  3133.             gui_do_scrollbar(wp, i, gui.which_scrollbars[i]);
  3134.             }
  3135.         }
  3136.         need_set_size = TRUE;
  3137.         }
  3138.         prev_which_scrollbars[i] = gui.which_scrollbars[i];
  3139.     }
  3140.  
  3141. #ifdef FEAT_MENU
  3142.     if (gui.menu_is_active != prev_menu_is_active)
  3143.     {
  3144.         gui_mch_enable_menu(gui.menu_is_active);
  3145.         prev_menu_is_active = gui.menu_is_active;
  3146.         need_set_size = TRUE;
  3147.     }
  3148. #endif
  3149.  
  3150. #ifdef FEAT_TOOLBAR
  3151.     if (using_toolbar != prev_toolbar)
  3152.     {
  3153.         gui_mch_show_toolbar(using_toolbar);
  3154.         prev_toolbar = using_toolbar;
  3155.         need_set_size = TRUE;
  3156.     }
  3157. #endif
  3158. #ifdef FEAT_FOOTER
  3159.     if (using_footer != prev_footer)
  3160.     {
  3161.         gui_mch_enable_footer(using_footer);
  3162.         prev_footer = using_footer;
  3163.         need_set_size = TRUE;
  3164.     }
  3165. #endif
  3166. #if defined(FEAT_MENU) && !defined(WIN16) && !(defined(WIN3264) && !defined(FEAT_TEAROFF))
  3167.     if (using_tearoff != prev_tearoff)
  3168.     {
  3169.         gui_mch_toggle_tearoffs(using_tearoff);
  3170.         prev_tearoff = using_tearoff;
  3171.     }
  3172. #endif
  3173.     if (need_set_size)
  3174.         gui_set_shellsize(FALSE, FALSE);
  3175.     }
  3176. }
  3177.  
  3178.  
  3179. /*
  3180.  * Scrollbar stuff:
  3181.  */
  3182.  
  3183.     void
  3184. gui_create_scrollbar(sb, type, wp)
  3185.     scrollbar_T    *sb;
  3186.     int        type;
  3187.     win_T    *wp;
  3188. {
  3189.     static int    sbar_ident = 0;
  3190.  
  3191.     sb->ident = sbar_ident++;    /* No check for too big, but would it happen? */
  3192.     sb->wp = wp;
  3193.     sb->type = type;
  3194.     sb->value = 0;
  3195. #ifdef FEAT_GUI_ATHENA
  3196.     sb->pixval = 0;
  3197. #endif
  3198.     sb->size = 1;
  3199.     sb->max = 1;
  3200.     sb->top = 0;
  3201.     sb->height = 0;
  3202. #ifdef FEAT_VERTSPLIT
  3203.     sb->width = 0;
  3204. #endif
  3205.     sb->status_height = 0;
  3206.     gui_mch_create_scrollbar(sb, (wp == NULL) ? SBAR_HORIZ : SBAR_VERT);
  3207. }
  3208.  
  3209. /*
  3210.  * Find the scrollbar with the given index.
  3211.  */
  3212.     scrollbar_T *
  3213. gui_find_scrollbar(ident)
  3214.     long    ident;
  3215. {
  3216.     win_T    *wp;
  3217.  
  3218.     if (gui.bottom_sbar.ident == ident)
  3219.     return &gui.bottom_sbar;
  3220.     FOR_ALL_WINDOWS(wp)
  3221.     {
  3222.     if (wp->w_scrollbars[SBAR_LEFT].ident == ident)
  3223.         return &wp->w_scrollbars[SBAR_LEFT];
  3224.     if (wp->w_scrollbars[SBAR_RIGHT].ident == ident)
  3225.         return &wp->w_scrollbars[SBAR_RIGHT];
  3226.     }
  3227.     return NULL;
  3228. }
  3229.  
  3230. /*
  3231.  * For most systems: Put a code in the input buffer for a dragged scrollbar.
  3232.  *
  3233.  * For Win32, Macintosh and GTK+ 2:
  3234.  * Scrollbars seem to grab focus and vim doesn't read the input queue until
  3235.  * you stop dragging the scrollbar.  We get here each time the scrollbar is
  3236.  * dragged another pixel, but as far as the rest of vim goes, it thinks
  3237.  * we're just hanging in the call to DispatchMessage() in
  3238.  * process_message().  The DispatchMessage() call that hangs was passed a
  3239.  * mouse button click event in the scrollbar window. -- webb.
  3240.  *
  3241.  * Solution: Do the scrolling right here.  But only when allowed.
  3242.  * Ignore the scrollbars while executing an external command or when there
  3243.  * are still characters to be processed.
  3244.  */
  3245.     void
  3246. gui_drag_scrollbar(sb, value, still_dragging)
  3247.     scrollbar_T    *sb;
  3248.     long    value;
  3249.     int        still_dragging;
  3250. {
  3251. #ifdef FEAT_WINDOWS
  3252.     win_T    *wp;
  3253. #endif
  3254.     int        sb_num;
  3255. #ifdef USE_ON_FLY_SCROLL
  3256.     colnr_T    old_leftcol = curwin->w_leftcol;
  3257. # ifdef FEAT_SCROLLBIND
  3258.     linenr_T    old_topline = curwin->w_topline;
  3259. # endif
  3260. # ifdef FEAT_DIFF
  3261.     int        old_topfill = curwin->w_topfill;
  3262. # endif
  3263. #else
  3264.     char_u    bytes[4 + sizeof(long_u)];
  3265.     int        byte_count;
  3266. #endif
  3267.  
  3268.     if (sb == NULL)
  3269.     return;
  3270.  
  3271.     /* Don't put events in the input queue now. */
  3272.     if (hold_gui_events)
  3273.     return;
  3274.  
  3275. #ifdef FEAT_CMDWIN
  3276.     if (cmdwin_type != 0 && sb->wp != curwin)
  3277.     return;
  3278. #endif
  3279.  
  3280.     if (still_dragging)
  3281.     {
  3282.     if (sb->wp == NULL)
  3283.         gui.dragged_sb = SBAR_BOTTOM;
  3284.     else if (sb == &sb->wp->w_scrollbars[SBAR_LEFT])
  3285.         gui.dragged_sb = SBAR_LEFT;
  3286.     else
  3287.         gui.dragged_sb = SBAR_RIGHT;
  3288.     gui.dragged_wp = sb->wp;
  3289.     }
  3290.     else
  3291.     gui.dragged_sb = SBAR_NONE;
  3292.  
  3293.     /* Vertical sbar info is kept in the first sbar (the left one) */
  3294.     if (sb->wp != NULL)
  3295.     sb = &sb->wp->w_scrollbars[0];
  3296.  
  3297.     /*
  3298.      * Check validity of value
  3299.      */
  3300.     if (value < 0)
  3301.     value = 0;
  3302. #ifdef SCROLL_PAST_END
  3303.     else if (value > sb->max)
  3304.     value = sb->max;
  3305. #else
  3306.     if (value > sb->max - sb->size + 1)
  3307.     value = sb->max - sb->size + 1;
  3308. #endif
  3309.  
  3310.     sb->value = value;
  3311.  
  3312. #ifdef USE_ON_FLY_SCROLL
  3313.     /* When not allowed to do the scrolling right now, return. */
  3314.     if (dont_scroll || input_available())
  3315.     return;
  3316. #endif
  3317.  
  3318. #ifdef FEAT_RIGHTLEFT
  3319.     if (sb->wp == NULL && curwin->w_p_rl)
  3320.     {
  3321.     value = sb->max + 1 - sb->size - value;
  3322.     if (value < 0)
  3323.         value = 0;
  3324.     }
  3325. #endif
  3326.  
  3327.     if (sb->wp != NULL)        /* vertical scrollbar */
  3328.     {
  3329.     sb_num = 0;
  3330. #ifdef FEAT_WINDOWS
  3331.     for (wp = firstwin; wp != sb->wp && wp != NULL; wp = wp->w_next)
  3332.         sb_num++;
  3333.     if (wp == NULL)
  3334.         return;
  3335. #else
  3336.     if (sb->wp != curwin)
  3337.         return;
  3338. #endif
  3339.  
  3340. #ifdef USE_ON_FLY_SCROLL
  3341.     current_scrollbar = sb_num;
  3342.     scrollbar_value = value;
  3343.     if (State & NORMAL)
  3344.     {
  3345.         gui_do_scroll();
  3346.         setcursor();
  3347.     }
  3348.     else if (State & INSERT)
  3349.     {
  3350.         ins_scroll();
  3351.         setcursor();
  3352.     }
  3353.     else if (State & CMDLINE)
  3354.     {
  3355.         if (msg_scrolled == 0)
  3356.         {
  3357.         gui_do_scroll();
  3358.         redrawcmdline();
  3359.         }
  3360.     }
  3361. # ifdef FEAT_FOLDING
  3362.     /* Value may have been changed for closed fold. */
  3363.     sb->value = sb->wp->w_topline - 1;
  3364. # endif
  3365. #else
  3366.     bytes[0] = CSI;
  3367.     bytes[1] = KS_VER_SCROLLBAR;
  3368.     bytes[2] = KE_FILLER;
  3369.     bytes[3] = (char_u)sb_num;
  3370.     byte_count = 4;
  3371. #endif
  3372.     }
  3373.     else
  3374.     {
  3375. #ifdef USE_ON_FLY_SCROLL
  3376.     scrollbar_value = value;
  3377.  
  3378.     if (State & NORMAL)
  3379.         gui_do_horiz_scroll();
  3380.     else if (State & INSERT)
  3381.         ins_horscroll();
  3382.     else if (State & CMDLINE)
  3383.     {
  3384.         if (!msg_scrolled)
  3385.         {
  3386.         gui_do_horiz_scroll();
  3387.         redrawcmdline();
  3388.         }
  3389.     }
  3390.     if (old_leftcol != curwin->w_leftcol)
  3391.     {
  3392.         updateWindow(curwin);   /* update window, status and cmdline */
  3393.         setcursor();
  3394.     }
  3395. #else
  3396.     bytes[0] = CSI;
  3397.     bytes[1] = KS_HOR_SCROLLBAR;
  3398.     bytes[2] = KE_FILLER;
  3399.     byte_count = 3;
  3400. #endif
  3401.     }
  3402.  
  3403. #ifdef USE_ON_FLY_SCROLL
  3404. # ifdef FEAT_SCROLLBIND
  3405.     /*
  3406.      * synchronize other windows, as necessary according to 'scrollbind'
  3407.      */
  3408.     if (curwin->w_p_scb
  3409.         && ((sb->wp == NULL && curwin->w_leftcol != old_leftcol)
  3410.         || (sb->wp == curwin && (curwin->w_topline != old_topline
  3411. #  ifdef FEAT_DIFF
  3412.                        || curwin->w_topfill != old_topfill
  3413. #  endif
  3414.             ))))
  3415.     {
  3416.     do_check_scrollbind(TRUE);
  3417.     /* need to update the window right here */
  3418.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3419.         if (wp->w_redr_type > 0)
  3420.         updateWindow(wp);
  3421.     setcursor();
  3422.     }
  3423. # endif
  3424.     out_flush();
  3425.     gui_update_cursor(FALSE, TRUE);
  3426. #else
  3427.     add_long_to_buf((long)value, bytes + byte_count);
  3428.     add_to_input_buf(bytes, byte_count + sizeof(long_u));
  3429. #endif
  3430. }
  3431.  
  3432. /*
  3433.  * Scrollbar stuff:
  3434.  */
  3435.  
  3436.     void
  3437. gui_update_scrollbars(force)
  3438.     int        force;        /* Force all scrollbars to get updated */
  3439. {
  3440.     win_T    *wp;
  3441.     scrollbar_T    *sb;
  3442.     long    val, size, max;        /* need 32 bits here */
  3443.     int        which_sb;
  3444.     int        h, y;
  3445. #ifdef FEAT_VERTSPLIT
  3446.     static win_T *prev_curwin = NULL;
  3447. #endif
  3448.  
  3449.     /* Update the horizontal scrollbar */
  3450.     gui_update_horiz_scrollbar(force);
  3451.  
  3452. #ifndef WIN3264
  3453.     /* Return straight away if there is neither a left nor right scrollbar.
  3454.      * On MS-Windows this is required anyway for scrollwheel messages. */
  3455.     if (!gui.which_scrollbars[SBAR_LEFT] && !gui.which_scrollbars[SBAR_RIGHT])
  3456.     return;
  3457. #endif
  3458.  
  3459.     /*
  3460.      * Don't want to update a scrollbar while we're dragging it.  But if we
  3461.      * have both a left and right scrollbar, and we drag one of them, we still
  3462.      * need to update the other one.
  3463.      */
  3464.     if (       (gui.dragged_sb == SBAR_LEFT
  3465.         || gui.dragged_sb == SBAR_RIGHT)
  3466.         && (!gui.which_scrollbars[SBAR_LEFT]
  3467.         || !gui.which_scrollbars[SBAR_RIGHT])
  3468.         && !force)
  3469.     return;
  3470.  
  3471.     if (!force && (gui.dragged_sb == SBAR_LEFT || gui.dragged_sb == SBAR_RIGHT))
  3472.     {
  3473.     /*
  3474.      * If we have two scrollbars and one of them is being dragged, just
  3475.      * copy the scrollbar position from the dragged one to the other one.
  3476.      */
  3477.     which_sb = SBAR_LEFT + SBAR_RIGHT - gui.dragged_sb;
  3478.     if (gui.dragged_wp != NULL)
  3479.         gui_mch_set_scrollbar_thumb(
  3480.             &gui.dragged_wp->w_scrollbars[which_sb],
  3481.             gui.dragged_wp->w_scrollbars[0].value,
  3482.             gui.dragged_wp->w_scrollbars[0].size,
  3483.             gui.dragged_wp->w_scrollbars[0].max);
  3484.     return;
  3485.     }
  3486.  
  3487.     /* avoid that moving components around generates events */
  3488.     ++hold_gui_events;
  3489.  
  3490.     for (wp = firstwin; wp != NULL; wp = W_NEXT(wp))
  3491.     {
  3492.     if (wp->w_buffer == NULL)    /* just in case */
  3493.         continue;
  3494. #ifdef SCROLL_PAST_END
  3495.     max = wp->w_buffer->b_ml.ml_line_count - 1;
  3496. #else
  3497.     max = wp->w_buffer->b_ml.ml_line_count + wp->w_height - 2;
  3498. #endif
  3499.     if (max < 0)            /* empty buffer */
  3500.         max = 0;
  3501.     val = wp->w_topline - 1;
  3502.     size = wp->w_height;
  3503. #ifdef SCROLL_PAST_END
  3504.     if (val > max)            /* just in case */
  3505.         val = max;
  3506. #else
  3507.     if (size > max + 1)        /* just in case */
  3508.         size = max + 1;
  3509.     if (val > max - size + 1)
  3510.         val = max - size + 1;
  3511. #endif
  3512.     if (val < 0)            /* minimal value is 0 */
  3513.         val = 0;
  3514.  
  3515.     /*
  3516.      * Scrollbar at index 0 (the left one) contains all the information.
  3517.      * It would be the same info for left and right so we just store it for
  3518.      * one of them.
  3519.      */
  3520.     sb = &wp->w_scrollbars[0];
  3521.  
  3522.     /*
  3523.      * Note: no check for valid w_botline.    If it's not valid the
  3524.      * scrollbars will be updated later anyway.
  3525.      */
  3526.     if (size < 1 || wp->w_botline - 2 > max)
  3527.     {
  3528.         /*
  3529.          * This can happen during changing files.  Just don't update the
  3530.          * scrollbar for now.
  3531.          */
  3532.         sb->height = 0;        /* Force update next time */
  3533.         if (gui.which_scrollbars[SBAR_LEFT])
  3534.         gui_do_scrollbar(wp, SBAR_LEFT, FALSE);
  3535.         if (gui.which_scrollbars[SBAR_RIGHT])
  3536.         gui_do_scrollbar(wp, SBAR_RIGHT, FALSE);
  3537.         continue;
  3538.     }
  3539.     if (force || sb->height != wp->w_height
  3540. #ifdef FEAT_WINDOWS
  3541.         || sb->top != wp->w_winrow
  3542.         || sb->status_height != wp->w_status_height
  3543. # ifdef FEAT_VERTSPLIT
  3544.         || sb->width != wp->w_width
  3545.         || prev_curwin != curwin
  3546. # endif
  3547. #endif
  3548.         )
  3549.     {
  3550.         /* Height, width or position of scrollbar has changed.  For
  3551.          * vertical split: curwin changed. */
  3552.         sb->height = wp->w_height;
  3553. #ifdef FEAT_WINDOWS
  3554.         sb->top = wp->w_winrow;
  3555.         sb->status_height = wp->w_status_height;
  3556. # ifdef FEAT_VERTSPLIT
  3557.         sb->width = wp->w_width;
  3558. # endif
  3559. #endif
  3560.  
  3561.         /* Calculate height and position in pixels */
  3562.         h = (sb->height + sb->status_height) * gui.char_height;
  3563.         y = sb->top * gui.char_height + gui.border_offset;
  3564. #if defined(FEAT_MENU) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF) && !defined(FEAT_GUI_PHOTON)
  3565.         if (gui.menu_is_active)
  3566.         y += gui.menu_height;
  3567. #endif
  3568.  
  3569. #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_ATHENA))
  3570.         if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  3571. # ifdef FEAT_GUI_ATHENA
  3572.         y += gui.toolbar_height;
  3573. # else
  3574. #  ifdef FEAT_GUI_MSWIN
  3575.         y += TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
  3576. #  endif
  3577. # endif
  3578. #endif
  3579.  
  3580. #ifdef FEAT_WINDOWS
  3581.         if (wp->w_winrow == 0)
  3582. #endif
  3583.         {
  3584.         /* Height of top scrollbar includes width of top border */
  3585.         h += gui.border_offset;
  3586.         y -= gui.border_offset;
  3587.         }
  3588.         if (gui.which_scrollbars[SBAR_LEFT])
  3589.         {
  3590.         gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_LEFT],
  3591.                       gui.left_sbar_x, y,
  3592.                       gui.scrollbar_width, h);
  3593.         gui_do_scrollbar(wp, SBAR_LEFT, TRUE);
  3594.         }
  3595.         if (gui.which_scrollbars[SBAR_RIGHT])
  3596.         {
  3597.         gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_RIGHT],
  3598.                       gui.right_sbar_x, y,
  3599.                       gui.scrollbar_width, h);
  3600.         gui_do_scrollbar(wp, SBAR_RIGHT, TRUE);
  3601.         }
  3602.     }
  3603.  
  3604.     /* Reduce the number of calls to gui_mch_set_scrollbar_thumb() by
  3605.      * checking if the thumb moved at least a pixel.  Only do this for
  3606.      * Athena, most other GUIs require the update anyway to make the
  3607.      * arrows work. */
  3608. #ifdef FEAT_GUI_ATHENA
  3609.     if (max == 0)
  3610.         y = 0;
  3611.     else
  3612.         y = (val * (sb->height + 2) * gui.char_height + max / 2) / max;
  3613.     if (force || sb->pixval != y || sb->size != size || sb->max != max)
  3614. #else
  3615.     if (force || sb->value != val || sb->size != size || sb->max != max)
  3616. #endif
  3617.     {
  3618.         /* Thumb of scrollbar has moved */
  3619.         sb->value = val;
  3620. #ifdef FEAT_GUI_ATHENA
  3621.         sb->pixval = y;
  3622. #endif
  3623.         sb->size = size;
  3624.         sb->max = max;
  3625.         if (gui.which_scrollbars[SBAR_LEFT] && gui.dragged_sb != SBAR_LEFT)
  3626.         gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_LEFT],
  3627.                         val, size, max);
  3628.         if (gui.which_scrollbars[SBAR_RIGHT]
  3629.                     && gui.dragged_sb != SBAR_RIGHT)
  3630.         gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_RIGHT],
  3631.                         val, size, max);
  3632.     }
  3633.     }
  3634. #ifdef FEAT_VERTSPLIT
  3635.     prev_curwin = curwin;
  3636. #endif
  3637.     --hold_gui_events;
  3638. }
  3639.  
  3640. /*
  3641.  * Enable or disable a scrollbar.
  3642.  * Check for scrollbars for vertically split windows which are not enabled
  3643.  * sometimes.
  3644.  */
  3645.     static void
  3646. gui_do_scrollbar(wp, which, enable)
  3647.     win_T    *wp;
  3648.     int        which;        /* SBAR_LEFT or SBAR_RIGHT */
  3649.     int        enable;        /* TRUE to enable scrollbar */
  3650. {
  3651. #ifdef FEAT_VERTSPLIT
  3652.     int        midcol = curwin->w_wincol + curwin->w_width / 2;
  3653.     int        has_midcol = (wp->w_wincol <= midcol
  3654.                      && wp->w_wincol + wp->w_width >= midcol);
  3655.  
  3656.     /* Only enable scrollbars that contain the middle column of the current
  3657.      * window. */
  3658.     if (gui.which_scrollbars[SBAR_RIGHT] != gui.which_scrollbars[SBAR_LEFT])
  3659.     {
  3660.     /* Scrollbars only on one side.  Don't enable scrollbars that don't
  3661.      * contain the middle column of the current window. */
  3662.     if (!has_midcol)
  3663.         enable = FALSE;
  3664.     }
  3665.     else
  3666.     {
  3667.     /* Scrollbars on both sides.  Don't enable scrollbars that neither
  3668.      * contain the middle column of the current window nor are on the far
  3669.      * side. */
  3670.     if (midcol > Columns / 2)
  3671.     {
  3672.         if (which == SBAR_LEFT ? wp->w_wincol != 0 : !has_midcol)
  3673.         enable = FALSE;
  3674.     }
  3675.     else
  3676.     {
  3677.         if (which == SBAR_RIGHT ? wp->w_wincol + wp->w_width != Columns
  3678.                                 : !has_midcol)
  3679.         enable = FALSE;
  3680.     }
  3681.     }
  3682. #endif
  3683.     gui_mch_enable_scrollbar(&wp->w_scrollbars[which], enable);
  3684. }
  3685.  
  3686. /*
  3687.  * Scroll a window according to the values set in the globals current_scrollbar
  3688.  * and scrollbar_value.  Return TRUE if the cursor in the current window moved
  3689.  * or FALSE otherwise.
  3690.  */
  3691.     int
  3692. gui_do_scroll()
  3693. {
  3694.     win_T    *wp, *save_wp;
  3695.     int        i;
  3696.     long    nlines;
  3697.     pos_T    old_cursor;
  3698.     linenr_T    old_topline;
  3699. #ifdef FEAT_DIFF
  3700.     int        old_topfill;
  3701. #endif
  3702.  
  3703.     for (wp = firstwin, i = 0; i < current_scrollbar; wp = W_NEXT(wp), i++)
  3704.     if (wp == NULL)
  3705.         break;
  3706.     if (wp == NULL)
  3707.     /* Couldn't find window */
  3708.     return FALSE;
  3709.  
  3710.     /*
  3711.      * Compute number of lines to scroll.  If zero, nothing to do.
  3712.      */
  3713.     nlines = (long)scrollbar_value + 1 - (long)wp->w_topline;
  3714.     if (nlines == 0)
  3715.     return FALSE;
  3716.  
  3717.     save_wp = curwin;
  3718.     old_topline = wp->w_topline;
  3719. #ifdef FEAT_DIFF
  3720.     old_topfill = wp->w_topfill;
  3721. #endif
  3722.     old_cursor = wp->w_cursor;
  3723.     curwin = wp;
  3724.     curbuf = wp->w_buffer;
  3725.     if (nlines < 0)
  3726.     scrolldown(-nlines, gui.dragged_wp == NULL);
  3727.     else
  3728.     scrollup(nlines, gui.dragged_wp == NULL);
  3729.     /* Reset dragged_wp after using it.  "dragged_sb" will have been reset for
  3730.      * the mouse-up event already, but we still want it to behave like when
  3731.      * dragging.  But not the next click in an arrow. */
  3732.     if (gui.dragged_sb == SBAR_NONE)
  3733.     gui.dragged_wp = NULL;
  3734.  
  3735.     if (old_topline != wp->w_topline
  3736. #ifdef FEAT_DIFF
  3737.         || old_topfill != wp->w_topfill
  3738. #endif
  3739.         )
  3740.     {
  3741.     if (p_so != 0)
  3742.     {
  3743.         cursor_correct();        /* fix window for 'so' */
  3744.         update_topline();        /* avoid up/down jump */
  3745.     }
  3746.     if (old_cursor.lnum != wp->w_cursor.lnum)
  3747.         coladvance(wp->w_curswant);
  3748. #ifdef FEAT_SCROLLBIND
  3749.     wp->w_scbind_pos = wp->w_topline;
  3750. #endif
  3751.     }
  3752.  
  3753.     curwin = save_wp;
  3754.     curbuf = save_wp->w_buffer;
  3755.  
  3756.     /*
  3757.      * Don't call updateWindow() when nothing has changed (it will overwrite
  3758.      * the status line!).
  3759.      */
  3760.     if (old_topline != wp->w_topline
  3761. #ifdef FEAT_DIFF
  3762.         || old_topfill != wp->w_topfill
  3763. #endif
  3764.         )
  3765.     {
  3766.     redraw_win_later(wp, VALID);
  3767.     updateWindow(wp);   /* update window, status line, and cmdline */
  3768.     }
  3769.  
  3770.     return (wp == curwin && !equal(curwin->w_cursor, old_cursor));
  3771. }
  3772.  
  3773.  
  3774. /*
  3775.  * Horizontal scrollbar stuff:
  3776.  */
  3777.  
  3778.     static void
  3779. gui_update_horiz_scrollbar(force)
  3780.     int        force;
  3781. {
  3782.     long    value, size, max;    /* need 32 bit ints here */
  3783.     char_u    *p;
  3784.  
  3785.     if (!gui.which_scrollbars[SBAR_BOTTOM])
  3786.     return;
  3787.  
  3788.     if (!force && gui.dragged_sb == SBAR_BOTTOM)
  3789.     return;
  3790.  
  3791.     if (!force && curwin->w_p_wrap && gui.prev_wrap)
  3792.     return;
  3793.  
  3794.     /*
  3795.      * It is possible for the cursor to be invalid if we're in the middle of
  3796.      * something (like changing files).  If so, don't do anything for now.
  3797.      */
  3798.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3799.     {
  3800.     gui.bottom_sbar.value = -1;
  3801.     return;
  3802.     }
  3803.  
  3804.     size = W_WIDTH(curwin);
  3805.     if (curwin->w_p_wrap)
  3806.     {
  3807.     value = 0;
  3808. #ifdef SCROLL_PAST_END
  3809.     max = 0;
  3810. #else
  3811.     max = W_WIDTH(curwin) - 1;
  3812. #endif
  3813.     }
  3814.     else
  3815.     {
  3816.     value = curwin->w_leftcol;
  3817.  
  3818.     /* Calculate max for horizontal scrollbar */
  3819.     p = ml_get_curline();
  3820.     max = 0;
  3821.     if (p != NULL && p[0] != NUL)
  3822.         for (;;)
  3823.         {
  3824.         int w = chartabsize(p, (colnr_T)max);
  3825. #ifdef FEAT_MBYTE
  3826.         if (has_mbyte)
  3827.             p += (*mb_ptr2len_check)(p);
  3828.         else
  3829. #endif
  3830.             ++p;
  3831.         if (*p == NUL)        /* Don't count last character */
  3832.             break;
  3833.         max += w;
  3834.         }
  3835. #ifndef SCROLL_PAST_END
  3836.     max += W_WIDTH(curwin) - 1;
  3837. #endif
  3838.     /* The line number isn't scrolled, thus there is less space when
  3839.      * 'number' is set (also for 'foldcolumn'). */
  3840.     size -= curwin_col_off();
  3841. #ifndef SCROLL_PAST_END
  3842.     max -= curwin_col_off();
  3843. #endif
  3844.     }
  3845.  
  3846. #ifndef SCROLL_PAST_END
  3847.     if (value > max - size + 1)
  3848.     value = max - size + 1;        /* limit the value to allowable range */
  3849. #endif
  3850.  
  3851. #ifdef FEAT_RIGHTLEFT
  3852.     if (curwin->w_p_rl)
  3853.     {
  3854.     value = max + 1 - size - value;
  3855.     if (value < 0)
  3856.     {
  3857.         size += value;
  3858.         value = 0;
  3859.     }
  3860.     }
  3861. #endif
  3862.     if (!force && value == gui.bottom_sbar.value && size == gui.bottom_sbar.size
  3863.                         && max == gui.bottom_sbar.max)
  3864.     return;
  3865.  
  3866.     gui.bottom_sbar.value = value;
  3867.     gui.bottom_sbar.size = size;
  3868.     gui.bottom_sbar.max = max;
  3869.     gui.prev_wrap = curwin->w_p_wrap;
  3870.  
  3871.     gui_mch_set_scrollbar_thumb(&gui.bottom_sbar, value, size, max);
  3872. }
  3873.  
  3874. /*
  3875.  * Do a horizontal scroll.  Return TRUE if the cursor moved, FALSE otherwise.
  3876.  */
  3877.     int
  3878. gui_do_horiz_scroll()
  3879. {
  3880.     /* no wrapping, no scrolling */
  3881.     if (curwin->w_p_wrap)
  3882.     return FALSE;
  3883.  
  3884.     if (curwin->w_leftcol == scrollbar_value)
  3885.     return FALSE;
  3886.  
  3887.     curwin->w_leftcol = scrollbar_value;
  3888.     return leftcol_changed();
  3889. }
  3890.  
  3891. /*
  3892.  * Check that none of the colors are the same as the background color
  3893.  */
  3894.     void
  3895. gui_check_colors()
  3896. {
  3897.     if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == INVALCOLOR)
  3898.     {
  3899.     gui_set_bg_color((char_u *)"White");
  3900.     if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == INVALCOLOR)
  3901.         gui_set_fg_color((char_u *)"Black");
  3902.     }
  3903. }
  3904.  
  3905.     void
  3906. gui_set_fg_color(name)
  3907.     char_u    *name;
  3908. {
  3909.     gui.norm_pixel = gui_get_color(name);
  3910.     hl_set_fg_color_name(vim_strsave(name));
  3911. }
  3912.  
  3913.     void
  3914. gui_set_bg_color(name)
  3915.     char_u    *name;
  3916. {
  3917.     gui.back_pixel = gui_get_color(name);
  3918.     hl_set_bg_color_name(vim_strsave(name));
  3919. }
  3920.  
  3921. /*
  3922.  * Allocate a color by name.
  3923.  * Returns INVALCOLOR and gives an error message when failed.
  3924.  */
  3925.     guicolor_T
  3926. gui_get_color(name)
  3927.     char_u    *name;
  3928. {
  3929.     guicolor_T    t;
  3930.  
  3931.     if (*name == NUL)
  3932.     return INVALCOLOR;
  3933.     t = gui_mch_get_color(name);
  3934.     if (t == INVALCOLOR
  3935. #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
  3936.         && gui.in_use
  3937. #endif
  3938.         )
  3939.     EMSG2(_("E254: Cannot allocate color %s"), name);
  3940.     return t;
  3941. }
  3942.  
  3943. /*
  3944.  * Return the grey value of a color (range 0-255).
  3945.  */
  3946.     int
  3947. gui_get_lightness(pixel)
  3948.     guicolor_T    pixel;
  3949. {
  3950.     long_u    rgb = gui_mch_get_rgb(pixel);
  3951.  
  3952.     return (  (((rgb >> 16) & 0xff) * 299)
  3953.         + (((rgb >> 8)  & 0xff) * 587)
  3954.         +  ((rgb        & 0xff) * 114)) / 1000;
  3955. }
  3956.  
  3957. #if defined(FEAT_GUI_X11) || defined(PROTO)
  3958.     void
  3959. gui_new_scrollbar_colors()
  3960. {
  3961.     win_T    *wp;
  3962.  
  3963.     /* Nothing to do if GUI hasn't started yet. */
  3964.     if (!gui.in_use)
  3965.     return;
  3966.  
  3967.     FOR_ALL_WINDOWS(wp)
  3968.     {
  3969.     gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_LEFT]));
  3970.     gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_RIGHT]));
  3971.     }
  3972.     gui_mch_set_scrollbar_colors(&gui.bottom_sbar);
  3973. }
  3974. #endif
  3975.  
  3976. /*
  3977.  * Call this when focus has changed.
  3978.  */
  3979.     void
  3980. gui_focus_change(in_focus)
  3981.     int        in_focus;
  3982. {
  3983.     gui.in_focus = in_focus;
  3984.     out_flush();        /* make sure output has been written */
  3985.     gui_update_cursor(TRUE, FALSE);
  3986.  
  3987. #ifdef FEAT_XIM
  3988.     xim_set_focus(in_focus);
  3989. #endif
  3990.  
  3991.     ui_focus_change(in_focus);
  3992. }
  3993.  
  3994. /*
  3995.  * Called when the mouse moved (but not when dragging).
  3996.  */
  3997.     void
  3998. gui_mouse_moved(x, y)
  3999.     int        x;
  4000.     int        y;
  4001. {
  4002.     win_T    *wp;
  4003.     char_u    st[6];
  4004.  
  4005. #ifdef FEAT_MOUSESHAPE
  4006.     /* Get window pointer, and update mouse shape as well. */
  4007.     wp = xy2win(x, y);
  4008. #endif
  4009.  
  4010.     /* Only handle this when 'mousefocus' set and ... */
  4011.     if (p_mousef
  4012.         && !hold_gui_events        /* not holding events */
  4013.         && (State & (NORMAL|INSERT))/* Normal/Visual/Insert mode */
  4014.         && State != HITRETURN    /* but not hit-return prompt */
  4015.         && msg_scrolled == 0    /* no scrolled message */
  4016.         && !need_mouse_correct    /* not moving the pointer */
  4017.         && gui.in_focus)        /* gvim in focus */
  4018.     {
  4019.     /* Don't move the mouse when it's left or right of the Vim window */
  4020.     if (x < 0 || x > Columns * gui.char_width)
  4021.         return;
  4022. #ifndef FEAT_MOUSESHAPE
  4023.     wp = xy2win(x, y);
  4024. #endif
  4025.     if (wp == curwin || wp == NULL)
  4026.         return;    /* still in the same old window, or none at all */
  4027.  
  4028.     /*
  4029.      * format a mouse click on status line input
  4030.      * ala gui_send_mouse_event(0, x, y, 0, 0);
  4031.      * Trick: Use a column of -1, so that check_termcode will generate a
  4032.      * K_LEFTMOUSE_NM key code.
  4033.      */
  4034.     if (finish_op)
  4035.     {
  4036.         /* abort the current operator first */
  4037.         st[0] = ESC;
  4038.         add_to_input_buf(st, 1);
  4039.     }
  4040.     st[0] = CSI;
  4041.     st[1] = KS_MOUSE;
  4042.     st[2] = KE_FILLER;
  4043.     st[3] = (char_u)MOUSE_LEFT;
  4044.     fill_mouse_coord(st + 4,
  4045. #ifdef FEAT_VERTSPLIT
  4046.         W_WINCOL(wp),
  4047. #else
  4048.         -1,
  4049. #endif
  4050.         wp->w_height + W_WINROW(wp));
  4051.  
  4052.     add_to_input_buf(st, 8);
  4053.     st[3] = (char_u)MOUSE_RELEASE;
  4054.     add_to_input_buf(st, 8);
  4055.  
  4056. #ifdef FEAT_GUI_GTK
  4057.     /* Need to wake up the main loop */
  4058.     if (gtk_main_level() > 0)
  4059.         gtk_main_quit();
  4060. #endif
  4061.     }
  4062. }
  4063.  
  4064. /*
  4065.  * Called when mouse should be moved to window with focus.
  4066.  */
  4067.     void
  4068. gui_mouse_correct()
  4069. {
  4070.     int        x, y;
  4071.     win_T    *wp = NULL;
  4072.  
  4073.     need_mouse_correct = FALSE;
  4074.     if (gui.in_use && p_mousef)
  4075.     {
  4076.     x = gui_mch_get_mouse_x();
  4077.     /* Don't move the mouse when it's left or right of the Vim window */
  4078.     if (x < 0 || x > Columns * gui.char_width)
  4079.         return;
  4080.     y = gui_mch_get_mouse_y();
  4081.     if (y >= 0)
  4082.         wp = xy2win(x, y);
  4083.     if (wp != curwin && wp != NULL)    /* If in other than current window */
  4084.     {
  4085.         validate_cline_row();
  4086.         gui_mch_setmouse((int)W_ENDCOL(curwin) * gui.char_width - 3,
  4087.              (W_WINROW(curwin) + curwin->w_wrow) * gui.char_height
  4088.                              + (gui.char_height) / 2);
  4089.     }
  4090.     }
  4091. }
  4092.  
  4093. /*
  4094.  * Find window where the mouse pointer "y" coordinate is in.
  4095.  */
  4096. /*ARGSUSED*/
  4097.     static win_T *
  4098. xy2win(x, y)
  4099.     int        x;
  4100.     int        y;
  4101. {
  4102. #ifdef FEAT_WINDOWS
  4103.     int        row;
  4104.     int        col;
  4105.     win_T    *wp;
  4106.  
  4107.     row = Y_2_ROW(y);
  4108.     col = X_2_COL(x);
  4109.     if (row < 0 || col < 0)        /* before first window */
  4110.     return NULL;
  4111.     wp = mouse_find_win(&row, &col);
  4112. # ifdef FEAT_MOUSESHAPE
  4113.     if (State == HITRETURN || State == ASKMORE)
  4114.     {
  4115.     if (Y_2_ROW(y) == Rows - 1)
  4116.         update_mouseshape(SHAPE_IDX_MOREL);
  4117.     else
  4118.         update_mouseshape(SHAPE_IDX_MORE);
  4119.     }
  4120.     else if (row > wp->w_height)    /* below status line */
  4121.     update_mouseshape(SHAPE_IDX_CLINE);
  4122. #  ifdef FEAT_VERTSPLIT
  4123.     else if (!(State & CMDLINE) && W_VSEP_WIDTH(wp) > 0 && col == wp->w_width
  4124.         && (row != wp->w_height || !stl_connected(wp)))
  4125.     update_mouseshape(SHAPE_IDX_VSEP);
  4126. #  endif
  4127.     else if (!(State & CMDLINE) && W_STATUS_HEIGHT(wp) > 0
  4128.                                && row == wp->w_height)
  4129.     update_mouseshape(SHAPE_IDX_STATUS);
  4130.     else
  4131.     update_mouseshape(-2);
  4132. # endif
  4133.     return wp;
  4134. #else
  4135.     return firstwin;
  4136. #endif
  4137. }
  4138.  
  4139. /*
  4140.  * ":gui" and ":gvim": Change from the terminal version to the GUI version.
  4141.  * File names may be given to redefine the args list.
  4142.  */
  4143.     void
  4144. ex_gui(eap)
  4145.     exarg_T    *eap;
  4146. {
  4147.     char_u    *arg = eap->arg;
  4148.  
  4149.     /*
  4150.      * Check for "-f" argument: foreground, don't fork.
  4151.      * Also don't fork when started with "gvim -f".
  4152.      * Do fork when using "gui -b".
  4153.      */
  4154.     if (arg[0] == '-'
  4155.         && (arg[1] == 'f' || arg[1] == 'b')
  4156.         && (arg[2] == NUL || vim_iswhite(arg[2])))
  4157.     {
  4158.     gui.dofork = (arg[1] == 'b');
  4159.     eap->arg = skipwhite(eap->arg + 2);
  4160.     }
  4161.     if (!gui.in_use)
  4162.     {
  4163.     /* Clear the command.  Needed for when forking+exiting, to avoid part
  4164.      * of the argument ending up after the shell prompt. */
  4165.     msg_clr_eos();
  4166.     gui_start();
  4167.     }
  4168.     if (!ends_excmd(*eap->arg))
  4169.     ex_next(eap);
  4170. }
  4171.  
  4172. #if ((defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32) \
  4173.     || defined(FEAT_GUI_PHOTON)) && defined(FEAT_TOOLBAR)) || defined(PROTO)
  4174. /*
  4175.  * This is shared between Athena, Motif and GTK.
  4176.  */
  4177. static char_u    *gfp_buffer;
  4178.  
  4179. static void gfp_setname __ARGS((char_u *fname));
  4180.  
  4181. /*
  4182.  * Callback function for do_in_runtimepath().
  4183.  */
  4184.     static void
  4185. gfp_setname(fname)
  4186.     char_u    *fname;
  4187. {
  4188.     if (STRLEN(fname) >= MAXPATHL)
  4189.     *gfp_buffer = NUL;
  4190.     else
  4191.     STRCPY(gfp_buffer, fname);
  4192. }
  4193.  
  4194. /*
  4195.  * Find the path of bitmap "name" with extension "ext" in 'runtimepath'.
  4196.  * Return FAIL for failure and OK if buffer[MAXPATHL] contains the result.
  4197.  */
  4198.     int
  4199. gui_find_bitmap(name, buffer, ext)
  4200.     char_u    *name;
  4201.     char_u    *buffer;
  4202.     char    *ext;
  4203. {
  4204.     if (STRLEN(name) > MAXPATHL - 14)
  4205.     return FAIL;
  4206.     sprintf((char *)buffer, "bitmaps/%s.%s", name, ext);
  4207.     gfp_buffer = buffer;
  4208.     if (do_in_runtimepath(buffer, FALSE, gfp_setname) == FAIL || *buffer == NUL)
  4209.     return FAIL;
  4210.     return OK;
  4211. }
  4212.  
  4213. # if !defined(HAVE_GTK2) || defined(PROTO)
  4214. /*
  4215.  * Given the name of the "icon=" argument, try finding the bitmap file for the
  4216.  * icon.  If it is an absolute path name, use it as it is.  Otherwise append
  4217.  * "ext" and search for it in 'runtimepath'.
  4218.  * The result is put in "buffer[MAXPATHL]".  If something fails "buffer"
  4219.  * contains "name".
  4220.  */
  4221.     void
  4222. gui_find_iconfile(name, buffer, ext)
  4223.     char_u    *name;
  4224.     char_u    *buffer;
  4225.     char    *ext;
  4226. {
  4227.     char_u    buf[MAXPATHL + 1];
  4228.  
  4229.     expand_env(name, buffer, MAXPATHL);
  4230.     if (!mch_isFullName(buffer) && gui_find_bitmap(buffer, buf, ext) == OK)
  4231.     STRCPY(buffer, buf);
  4232. }
  4233. # endif
  4234. #endif
  4235.  
  4236. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(PROTO)
  4237.     void
  4238. display_errors()
  4239. {
  4240.     char_u    *p;
  4241.  
  4242.     if (isatty(2))
  4243.     fflush(stderr);
  4244.     else if (error_ga.ga_data != NULL)
  4245.     {
  4246.     /* avoid putting up a message box with blanks only */
  4247.     for (p = (char_u *)error_ga.ga_data; *p != NUL; ++p)
  4248.         if (!isspace(*p))
  4249.         {
  4250.         /* Truncate a very long message, it will go off-screen. */
  4251.         if (STRLEN(p) > 2000)
  4252.             STRCPY(p + 2000 - 14, "...(truncated)");
  4253.         (void)do_dialog(VIM_ERROR, (char_u *)_("Error"),
  4254.                           p, (char_u *)_("&Ok"), 1, NULL);
  4255.         break;
  4256.         }
  4257.     ga_clear(&error_ga);
  4258.     }
  4259. }
  4260. #endif
  4261.  
  4262. #if defined(NO_CONSOLE_INPUT) || defined(PROTO)
  4263. /*
  4264.  * Return TRUE if still starting up and there is no place to enter text.
  4265.  * For GTK and X11 we check if stderr is not a tty, which means we were
  4266.  * (probably) started from the desktop.  Also check stdin, "vim >& file" does
  4267.  * allow typing on stdin.
  4268.  */
  4269.     int
  4270. no_console_input()
  4271. {
  4272.     return ((!gui.in_use || gui.starting)
  4273. # ifndef NO_CONSOLE
  4274.         && !isatty(0) && !isatty(2)
  4275. # endif
  4276.         );
  4277. }
  4278. #endif
  4279.  
  4280. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MOTIF) \
  4281.     || defined(MSWIN_FIND_REPLACE) || defined(FEAT_SUN_WORKSHOP) \
  4282.     || defined(PROTO)
  4283. /*
  4284.  * Update the current window and the screen.
  4285.  */
  4286.     void
  4287. gui_update_screen()
  4288. {
  4289.     update_topline();
  4290.     validate_cursor();
  4291.     update_screen(0);    /* may need to update the screen */
  4292.     setcursor();
  4293.     out_flush();        /* make sure output has been written */
  4294.     gui_update_cursor(TRUE, FALSE);
  4295.     gui_mch_flush();
  4296. }
  4297. #endif
  4298.  
  4299. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MOTIF) \
  4300.     || defined(MSWIN_FIND_REPLACE) || defined(PROTO)
  4301. static void concat_esc __ARGS((garray_T *gap, char_u *text, int what));
  4302.  
  4303. /*
  4304.  * Get the text to use in a find/replace dialog.  Uses the last search pattern
  4305.  * if the argument is empty.
  4306.  * Returns an allocated string.
  4307.  */
  4308.     char_u *
  4309. get_find_dialog_text(arg, wwordp, mcasep)
  4310.     char_u    *arg;
  4311.     int        *wwordp;    /* return: TRUE if \< \> found */
  4312.     int        *mcasep;    /* return: TRUE if \C found */
  4313. {
  4314.     char_u    *text;
  4315.  
  4316.     if (*arg == NUL)
  4317.     text = last_search_pat();
  4318.     else
  4319.     text = arg;
  4320.     if (text != NULL)
  4321.     {
  4322.     text = vim_strsave(text);
  4323.     if (text != NULL)
  4324.     {
  4325.         int len = STRLEN(text);
  4326.         int i;
  4327.  
  4328.         /* Remove "\V" */
  4329.         if (len >= 2 && STRNCMP(text, "\\V", 2) == 0)
  4330.         {
  4331.         mch_memmove(text, text + 2, (size_t)(len - 1));
  4332.         len -= 2;
  4333.         }
  4334.  
  4335.         /* Recognize "\c" and "\C" and remove. */
  4336.         if (len >= 2 && *text == '\\' && (text[1] == 'c' || text[1] == 'C'))
  4337.         {
  4338.         *mcasep = (text[1] == 'C');
  4339.         mch_memmove(text, text + 2, (size_t)(len - 1));
  4340.         len -= 2;
  4341.         }
  4342.  
  4343.         /* Recognize "\<text\>" and remove. */
  4344.         if (len >= 4
  4345.             && STRNCMP(text, "\\<", 2) == 0
  4346.             && STRNCMP(text + len - 2, "\\>", 2) == 0)
  4347.         {
  4348.         *wwordp = TRUE;
  4349.         mch_memmove(text, text + 2, (size_t)(len - 4));
  4350.         text[len - 4] = NUL;
  4351.         }
  4352.  
  4353.         /* Recognize "\/" or "\?" and remove. */
  4354.         for (i = 0; i + 1 < len; ++i)
  4355.         if (text[i] == '\\' && (text[i + 1] == '/'
  4356.                                || text[i + 1] == '?'))
  4357.         {
  4358.             mch_memmove(text + i, text + i + 1, (size_t)(len - i));
  4359.             --len;
  4360.         }
  4361.     }
  4362.     }
  4363.     return text;
  4364. }
  4365.  
  4366. /*
  4367.  * Concatenate "text" to grow array "gap", escaping "what" with a backslash.
  4368.  */
  4369.     static void
  4370. concat_esc(gap, text, what)
  4371.     garray_T    *gap;
  4372.     char_u    *text;
  4373.     int        what;
  4374. {
  4375.     while (*text != NUL)
  4376.     {
  4377. #ifdef FEAT_MBYTE
  4378.     int l = (*mb_ptr2len_check)(text);
  4379.     if (l > 1)
  4380.     {
  4381.         while (--l >= 0)
  4382.         ga_append(gap, *text++);
  4383.         continue;
  4384.     }
  4385. #endif
  4386.     if (*text == what)
  4387.         ga_append(gap, '\\');
  4388.     ga_append(gap, *text);
  4389.     ++text;
  4390.     }
  4391. }
  4392.  
  4393. /*
  4394.  * Handle the press of a button in the find-replace dialog.
  4395.  * Return TRUE when something was added to the input buffer.
  4396.  */
  4397.     int
  4398. gui_do_findrepl(flags, find_text, repl_text, down)
  4399.     int        flags;        /* one of FRD_REPLACE, FRD_FINDNEXT, etc. */
  4400.     char_u    *find_text;
  4401.     char_u    *repl_text;
  4402.     int        down;        /* Search downwards. */
  4403. {
  4404.     garray_T    ga;
  4405.     int        i;
  4406.     int        type = (flags & FRD_TYPE_MASK);
  4407.     char_u    *p;
  4408.  
  4409.     ga_init2(&ga, 1, 100);
  4410.  
  4411.     if (type == FRD_REPLACE)
  4412.     {
  4413.     /* Do the replacement when the text under the cursor matches. */
  4414.     i = STRLEN(find_text);
  4415.     p = ml_get_cursor();
  4416.     if (((flags & FRD_MATCH_CASE)
  4417.             ? STRNCMP(p, find_text, i) == 0
  4418.             : STRNICMP(p, find_text, i) == 0)
  4419.         && u_save_cursor() == OK)
  4420.     {
  4421.         /* A button was pressed thus undo should be synced. */
  4422.         if (no_u_sync == 0)
  4423.         u_sync();
  4424.  
  4425.         del_bytes((long)i, FALSE);
  4426.         ins_str(repl_text);
  4427.     }
  4428.     }
  4429.     else if (type == FRD_REPLACEALL)
  4430.     ga_concat(&ga, (char_u *)"%s/");
  4431.  
  4432.     ga_concat(&ga, (char_u *)"\\V");
  4433.     if (flags & FRD_MATCH_CASE)
  4434.     ga_concat(&ga, (char_u *)"\\C");
  4435.     else
  4436.     ga_concat(&ga, (char_u *)"\\c");
  4437.     if (flags & FRD_WHOLE_WORD)
  4438.     ga_concat(&ga, (char_u *)"\\<");
  4439.     if (type == FRD_REPLACEALL || down)
  4440.     concat_esc(&ga, find_text, '/');    /* escape slashes */
  4441.     else
  4442.     concat_esc(&ga, find_text, '?');    /* escape '?' */
  4443.     if (flags & FRD_WHOLE_WORD)
  4444.     ga_concat(&ga, (char_u *)"\\>");
  4445.  
  4446.     if (type == FRD_REPLACEALL)
  4447.     {
  4448.     /* A button was pressed, thus undo should be synced. */
  4449.     if (no_u_sync == 0)
  4450.         u_sync();
  4451.  
  4452.     ga_concat(&ga, (char_u *)"/");
  4453.     concat_esc(&ga, repl_text, '/');    /* escape slashes */
  4454.     ga_concat(&ga, (char_u *)"/g");
  4455.     do_cmdline_cmd(ga.ga_data);
  4456.     }
  4457.     else
  4458.     {
  4459.     /* Search for the next match. */
  4460.     i = msg_scroll;
  4461.     do_search(NULL, down ? '/' : '?', ga.ga_data, 1L,
  4462.                             SEARCH_MSG + SEARCH_MARK);
  4463.     msg_scroll = i;        /* don't let an error message set msg_scroll */
  4464.     }
  4465.  
  4466.     if (State & (NORMAL | INSERT))
  4467.     {
  4468.     gui_update_screen();        /* update the screen */
  4469.     msg_didout = 0;            /* overwrite any message */
  4470.     need_wait_return = FALSE;    /* don't wait for return */
  4471.     }
  4472.  
  4473.     vim_free(ga.ga_data);
  4474.     return (ga.ga_len > 0);
  4475. }
  4476.  
  4477. #endif
  4478.