gui.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:91k
源码类别:

编辑器/阅读器

开发平台:

DOS

  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.  */
  9. #include "vim.h"
  10. /* Structure containing all the GUI information */
  11. Gui gui;
  12. /* Set to TRUE after adding/removing menus to ensure they are updated */
  13. int force_menu_update = FALSE;
  14. static void gui_check_screen __ARGS((void));
  15. static void gui_position_components __ARGS((int, int));
  16. static void gui_outstr __ARGS((char_u *, int));
  17. static void gui_delete_lines __ARGS((int row, int count));
  18. static void gui_insert_lines __ARGS((int row, int count));
  19. static int gui_get_menu_cmd_modes __ARGS((char_u *, int, int *, int *));
  20. static char_u *popup_mode_name __ARGS((char_u *name, int idx));
  21. static void  gui_update_menus_recurse __ARGS((GuiMenu *, int));
  22. #ifdef USE_GUI_WIN32
  23. static int gui_add_menu_path __ARGS((char_u *, int, int *, void (*)(), char_u *, int, int));
  24. #else
  25. static int gui_add_menu_path __ARGS((char_u *, int, int *, void (*)(), char_u *, int));
  26. #endif
  27. static int gui_remove_menu __ARGS((GuiMenu **, char_u *, int, int silent));
  28. static void gui_free_menu __ARGS((GuiMenu *));
  29. static void gui_free_menu_string __ARGS((GuiMenu *, int));
  30. static int gui_show_menus __ARGS((char_u *, int));
  31. static void gui_show_menus_recursive __ARGS((GuiMenu *, int, int));
  32. static int menu_name_equal __ARGS((char_u *name, GuiMenu *menu));
  33. static int menu_namecmp __ARGS((char_u *name, char_u *mname));
  34. static void gui_create_initial_menus __ARGS((GuiMenu *, GuiMenu *));
  35. static void gui_update_scrollbars __ARGS((int));
  36. static void gui_update_horiz_scrollbar __ARGS((int));
  37. static WIN *y2win __ARGS((int y));
  38. static int get_menu_mode __ARGS((void));
  39. #ifdef USE_GUI_WIN32
  40. static void gui_create_tearoffs_recurse __ARGS((GuiMenu *menu, const char_u *pname, int *pri_tab, int pri_idx));
  41. static void gui_add_tearoff __ARGS((char_u *tearpath, int *pri_tab, int pri_idx));
  42. static void gui_destroy_tearoffs_recurse __ARGS((GuiMenu *menu));
  43. static int s_tearoffs = FALSE;
  44. #endif
  45. /*
  46.  * The Athena scrollbars can move the thumb to after the end of the scrollbar,
  47.  * this makes the thumb indicate the part of the text that is shown.  Motif
  48.  * can't do this.
  49.  */
  50. #if defined(USE_GUI_ATHENA) || defined(macintosh)
  51. # define SCROLL_PAST_END
  52. #endif
  53. /*
  54.  * While defining the system menu, gui_sys_menu is TRUE.  This avoids
  55.  * overruling of menus that the user already defined.
  56.  */
  57. static int gui_sys_menu = FALSE;
  58. /*
  59.  * gui_start -- Called when user wants to start the GUI.
  60.  */
  61.     void
  62. gui_start()
  63. {
  64.     char_u  *old_term;
  65. #if defined(UNIX) && !defined(__BEOS__)
  66.     pid_t   pid;
  67. #endif
  68.     old_term = vim_strsave(T_NAME);
  69.     mch_setmouse(FALSE); /* first switch mouse off */
  70.     /*
  71.      * Set_termname() will call gui_init() to start the GUI.
  72.      * Set the "starting" flag, to indicate that the GUI will start.
  73.      *
  74.      * We don't want to open the GUI window until after we've read .gvimrc,
  75.      * otherwise we don't know what font we will use, and hence we don't know
  76.      * what size the window should be. So if there are errors in the .gvimrc
  77.      * file, they will have to go to the terminal: Set full_screen to FALSE.
  78.      * full_screen will be set to TRUE again by a successful termcapinit().
  79.      */
  80.     settmode(TMODE_COOK); /* stop RAW mode */
  81.     if (full_screen)
  82. cursor_on(); /* needed for ":gui" in .vimrc */
  83.     gui.starting = TRUE;
  84.     full_screen = FALSE;
  85.     termcapinit((char_u *)"builtin_gui");
  86.     gui.starting = FALSE;
  87.     if (!gui.in_use) /* failed to start GUI */
  88.     {
  89. termcapinit(old_term); /* back to old term settings */
  90. settmode(TMODE_RAW); /* restart RAW mode */
  91. set_title_defaults(); /* set 'title' and 'icon' again */
  92.     }
  93.     vim_free(old_term);
  94. #if defined(UNIX) && !defined(__BEOS__)
  95.     /*
  96.      * Quit the current process and continue in the child.
  97.      * Makes "gvim file" disconnect from the shell it was started in.
  98.      * Don't do this when Vim was started with "-f" or the 'f' flag is present
  99.      * in 'guioptions'.
  100.      */
  101.     if (gui.in_use && gui.dofork && vim_strchr(p_guioptions, GO_FORG) == NULL)
  102.     {
  103. pid = fork();
  104. if (pid > 0)     /* Parent */
  105.     exit(0);
  106. #if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
  107. /*
  108.  * Change our process group.  On some systems/shells a CTRL-C in the
  109.  * shell where Vim was started would otherwise kill gvim!
  110.  */
  111. if (pid == 0)     /* child */
  112. # if defined(HAVE_SETSID)
  113.     (void)setsid();
  114. # else
  115.     (void)setpgid(0, 0);
  116. # endif
  117. #endif
  118.     }
  119. #endif
  120. }
  121. /*
  122.  * Call this when vim starts up, whether or not the GUI is started
  123.  */
  124.     void
  125. gui_prepare(argc, argv)
  126.     int     *argc;
  127.     char    **argv;
  128. {
  129.     /* Menu items may be added before the GUI is started, so set this now */
  130.     gui.root_menu = NULL;
  131.     gui.in_use = FALSE;     /* No GUI yet (maybe later) */
  132.     gui.starting = FALSE;     /* No GUI yet (maybe later) */
  133.     gui.dofork = TRUE;     /* default is to use fork() */
  134.     gui_mch_prepare(argc, argv);
  135. }
  136. /*
  137.  * This is the call which starts the GUI.
  138.  */
  139.     void
  140. gui_init()
  141. {
  142.     WIN *wp;
  143.     static int recursive = 0;
  144.     /*
  145.      * It's possible to use ":gui" in a .gvimrc file.  The first halve of this
  146.      * function will then be executed at the first call, the rest by the
  147.      * recursive call.  This allow the window to be opened halfway reading a
  148.      * gvimrc file.
  149.      */
  150.     if (!recursive)
  151.     {
  152. ++recursive;
  153. gui.window_created = FALSE;
  154. gui.dying = FALSE;
  155. gui.in_focus = TRUE; /* so the guicursor setting works */
  156. gui.dragged_sb = SBAR_NONE;
  157. gui.dragged_wp = NULL;
  158. gui.pointer_hidden = FALSE;
  159. gui.col = gui.num_cols = 0;
  160. gui.row = gui.num_rows = 0;
  161. gui.cursor_is_valid = FALSE;
  162. gui.scroll_region_top = 0;
  163. gui.scroll_region_bot = Rows - 1;
  164. gui.highlight_mask = HL_NORMAL;
  165. gui.char_width = 1;
  166. gui.char_height = 1;
  167. gui.char_ascent = 0;
  168. gui.border_width = 0;
  169. gui.norm_font = (GuiFont)NULL;
  170. gui.bold_font = (GuiFont)NULL;
  171. gui.ital_font = (GuiFont)NULL;
  172. gui.boldital_font = (GuiFont)NULL;
  173. clip_init(TRUE);
  174. gui.menu_is_active = TRUE;     /* default: include menu */
  175. gui.scrollbar_width = gui.scrollbar_height = SB_DEFAULT_WIDTH;
  176. gui.menu_height = MENU_DEFAULT_HEIGHT;
  177. gui.menu_width = 0;
  178. gui.prev_wrap = -1;
  179. /*
  180.  * Set up system-wide default menus.
  181.  */
  182. #ifdef SYS_MENU_FILE
  183. gui_sys_menu = TRUE;
  184. do_source((char_u *)SYS_MENU_FILE, FALSE, FALSE);
  185. gui_sys_menu = FALSE;
  186. #endif
  187. /*
  188.  * Switch on the mouse by default, unless the user changed it already.
  189.  * This can then be changed in the .gvimrc.
  190.  */
  191. if (!option_was_set((char_u *)"mouse"))
  192.     set_string_option_direct((char_u *)"mouse", -1,
  193.  (char_u *)"a", TRUE);
  194. /*
  195.  * If -U option given, use only the initializations from that file and
  196.  * nothing else.  Skip all initializations for "-U NONE".
  197.  */
  198. if (use_gvimrc != NULL)
  199. {
  200.     if (STRCMP(use_gvimrc, "NONE") != 0
  201.     && do_source(use_gvimrc, FALSE, FALSE) != OK)
  202. EMSG2("Cannot read from "%s"", use_gvimrc);
  203. }
  204. else
  205. {
  206.     /*
  207.      * Get system wide defaults for gvim, only when file name defined.
  208.      */
  209. #ifdef SYS_GVIMRC_FILE
  210.     do_source((char_u *)SYS_GVIMRC_FILE, FALSE, FALSE);
  211. #endif
  212.     /*
  213.      * Try to read GUI initialization commands from the following
  214.      * places:
  215.      * - environment variable GVIMINIT
  216.      * - the user gvimrc file (~/.gvimrc)
  217.      * - the second user gvimrc file ($VIM/.gvimrc for Dos)
  218.      * The first that exists is used, the rest is ignored.
  219.      */
  220.     if (process_env((char_u *)"GVIMINIT") == FAIL
  221.  && do_source((char_u *)USR_GVIMRC_FILE, TRUE, FALSE) == FAIL)
  222. {
  223. #ifdef USR_GVIMRC_FILE2
  224.     (void)do_source((char_u *)USR_GVIMRC_FILE2, TRUE, FALSE);
  225. #endif
  226. }
  227.     /*
  228.      * Read initialization commands from ".gvimrc" in current
  229.      * directory.  This is only done if the 'exrc' option is set.
  230.      * Because of security reasons we disallow shell and write
  231.      * commands now, except for unix if the file is owned by the user
  232.      * or 'secure' option has been reset in environment of global
  233.      * ".gvimrc".
  234.      * Only do this if GVIMRC_FILE is not the same as USR_GVIMRC_FILE,
  235.      * USR_GVIMRC_FILE2 or SYS_GVIMRC_FILE.
  236.      */
  237.     if (p_exrc)
  238.     {
  239. #ifdef UNIX
  240. {
  241.     struct stat s;
  242.     /* if ".gvimrc" file is not owned by user, set 'secure'
  243.      * mode */
  244.     if (stat(GVIMRC_FILE, &s) || s.st_uid != getuid())
  245. secure = p_secure;
  246. }
  247. #else
  248. secure = p_secure;
  249. #endif
  250. if (       fullpathcmp((char_u *)USR_GVIMRC_FILE,
  251.      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  252. #ifdef SYS_GVIMRC_FILE
  253. && fullpathcmp((char_u *)SYS_GVIMRC_FILE,
  254.      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  255. #endif
  256. #ifdef USR_GVIMRC_FILE2
  257. && fullpathcmp((char_u *)USR_GVIMRC_FILE2,
  258.      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  259. #endif
  260. )
  261.     do_source((char_u *)GVIMRC_FILE, FALSE, FALSE);
  262. if (secure == 2)
  263.     need_wait_return = TRUE;
  264. secure = 0;
  265.     }
  266. }
  267. if (need_wait_return || msg_didany)
  268.     wait_return(TRUE);
  269. --recursive;
  270.     }
  271.     /* If recursive call opened the window, return here from the first call */
  272.     if (gui.in_use)
  273. return;
  274.     /*
  275.      * Create the GUI windows ready for opening.
  276.      */
  277.     gui.in_use = TRUE; /* Must be set after menus have been set up */
  278.     if (gui_mch_init() == FAIL)
  279. goto error;
  280.     /*
  281.      * Check validity of any generic resources that may have been loaded.
  282.      */
  283.     if (gui.border_width < 0)
  284. gui.border_width = 0;
  285.     /*
  286.      * Set up the fonts.
  287.      */
  288.     if (font_opt)
  289. set_option_value((char_u *)"gfn", 0L, (char_u *)font_opt);
  290.     if (gui_init_font(p_guifont) == FAIL)
  291. goto error;
  292.     gui.num_cols = Columns;
  293.     gui.num_rows = Rows;
  294.     gui_reset_scroll_region();
  295.     /* Create initial scrollbars */
  296.     for (wp = firstwin; wp; wp = wp->w_next)
  297.     {
  298. gui_create_scrollbar(&wp->w_scrollbars[SBAR_LEFT], wp);
  299. gui_create_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], wp);
  300.     }
  301.     gui_create_scrollbar(&gui.bottom_sbar, NULL);
  302.     gui_create_initial_menus(gui.root_menu, NULL);
  303.     /* Configure the desired menu and scrollbars */
  304.     gui_init_which_components(NULL);
  305.     /* All components of the window have been created now */
  306.     gui.window_created = TRUE;
  307.     gui_set_winsize(TRUE);
  308.     /*
  309.      * Actually open the GUI window.
  310.      */
  311.     if (gui_mch_open() != FAIL)
  312.     {
  313. maketitle();
  314. init_gui_options();
  315. return;
  316.     }
  317. error:
  318.     gui.in_use = FALSE;
  319.     clip_init(FALSE);
  320. }
  321.     void
  322. gui_exit(rc)
  323.     int rc;
  324. {
  325.     free_highlight_fonts();
  326.     gui.in_use = FALSE;
  327.     gui_mch_exit(rc);
  328. }
  329. /*
  330.  * Set the font. Uses the 'font' option. The first font name that works is
  331.  * used. If none is found, use the default font.
  332.  * Return OK when able to set the font.
  333.  */
  334.     int
  335. gui_init_font(font_list)
  336.     char_u  *font_list;
  337. {
  338. #define FONTLEN 100
  339.     char_u  font_name[FONTLEN];
  340.     int     font_list_empty = FALSE;
  341.     int     ret = FAIL;
  342.     if (!gui.in_use)
  343. return FAIL;
  344.     font_name[0] = NUL;
  345.     if (*font_list == NUL)
  346. font_list_empty = TRUE;
  347.     else
  348. while (*font_list != NUL)
  349. {
  350.     /* Isolate one font name */
  351.     (void)copy_option_part(&font_list, font_name, FONTLEN, ",");
  352.     if (gui_mch_init_font(font_name) == OK)
  353.     {
  354. ret = OK;
  355. break;
  356.     }
  357. }
  358.     if (ret != OK && STRCMP(font_name, "*") != 0
  359.     && (font_list_empty || gui.norm_font == (GuiFont)0))
  360.     {
  361. /*
  362.  * Couldn't load any font in 'font_list', keep the current font if
  363.  * there is one.  If 'font_list' is empty, or if there is no current
  364.  * font, tell gui_mch_init_font() to try to find a font we can load.
  365.  */
  366. ret = gui_mch_init_font(NULL);
  367.     }
  368.     if (ret == OK)
  369.     {
  370. /* Set normal font as current font */
  371. gui_mch_set_font(gui.norm_font);
  372. gui_set_winsize(
  373. #ifdef WIN32
  374. TRUE
  375. #else
  376. FALSE
  377. #endif
  378. );
  379.     }
  380.     return ret;
  381. }
  382.     void
  383. gui_set_cursor(row, col)
  384.     int     row;
  385.     int     col;
  386. {
  387.     gui.row = row;
  388.     gui.col = col;
  389. }
  390. /*
  391.  * gui_check_screen - check if the cursor is on the screen.
  392.  */
  393.     static void
  394. gui_check_screen()
  395. {
  396.     if (gui.row >= Rows)
  397. gui.row = Rows - 1;
  398.     if (gui.col >= Columns)
  399. gui.col = Columns - 1;
  400.     if (gui.cursor_row >= Rows || gui.cursor_col >= Columns)
  401. gui.cursor_is_valid = FALSE;
  402. }
  403. /*
  404.  * Redraw the cursor if necessary or when forced.
  405.  * Careful: The contents of LinePointers[] must match what is on the screen,
  406.  * otherwise this goes wrong.  May need to call out_flush() first.
  407.  */
  408.     void
  409. gui_update_cursor(force, clear_selection)
  410.     int force; /* when TRUE, update even when not moved */
  411.     int clear_selection;/* clear selection under cursor */
  412. {
  413.     int cur_width = 0;
  414.     int cur_height = 0;
  415.     long_u old_hl_mask;
  416.     int idx;
  417.     int id;
  418.     GuiColor cfg, cbg, cc; /* cursor fore-/background color */
  419.     int cattr; /* cursor attributes */
  420.     int attr;
  421.     struct attr_entry *aep = NULL;
  422.     gui_check_screen();
  423.     if (!gui.cursor_is_valid || force
  424.     || gui.row != gui.cursor_row || gui.col != gui.cursor_col)
  425.     {
  426. gui_undraw_cursor();
  427. if (gui.row <0)
  428.     return;
  429. gui.cursor_row = gui.row;
  430. gui.cursor_col = gui.col;
  431. gui.cursor_is_valid = TRUE;
  432. /* Only write to the screen after LinePointers[] has been initialized */
  433. if (!screen_cleared || NextScreen == NULL)
  434.     return;
  435. /* Clear the selection if we are about to write over it */
  436. if (clear_selection)
  437.     clip_may_clear_selection(gui.row, gui.row);
  438. /* Check that the cursor is inside the window (resizing may have made
  439.  * it invalid) */
  440. if (gui.row >= screen_Rows || gui.col >= screen_Columns)
  441.     return;
  442. /*
  443.  * How the cursor is drawn depends on the current mode.
  444.  */
  445. idx = get_cursor_idx();
  446. id = cursor_table[idx].id;
  447. /* get the colors and attributes for the cursor.  Default is inverted */
  448. cfg = (GuiColor)-1;
  449. cbg = (GuiColor)-1;
  450. cattr = HL_INVERSE;
  451. gui_mch_set_blinking(cursor_table[idx].blinkwait,
  452.      cursor_table[idx].blinkon,
  453.      cursor_table[idx].blinkoff);
  454. if (id > 0)
  455. {
  456.     cattr = syn_id2colors(id, &cfg, &cbg);
  457.     --cbg;
  458.     --cfg;
  459. }
  460. /*
  461.  * Get the attributes for the character under the cursor.
  462.  * When no cursor color was given, use the character color.
  463.  */
  464. attr = *(LinePointers[gui.row] + gui.col + screen_Columns);
  465. if (attr > HL_ALL)
  466.     aep = syn_gui_attr2entry(attr);
  467. if (aep != NULL)
  468. {
  469.     attr = aep->ae_attr;
  470.     if (cfg < 0)
  471. cfg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.bg_color
  472.     : aep->ae_u.gui.fg_color) - 1;
  473.     if (cbg < 0)
  474. cbg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.fg_color
  475.     : aep->ae_u.gui.bg_color) - 1;
  476. }
  477. if (cfg < 0)
  478.     cfg = (attr & HL_INVERSE) ? gui.back_pixel : gui.norm_pixel;
  479. if (cbg < 0)
  480.     cbg = (attr & HL_INVERSE) ? gui.norm_pixel : gui.back_pixel;
  481. attr &= ~HL_INVERSE;
  482. if (cattr & HL_INVERSE)
  483. {
  484.     cc = cbg;
  485.     cbg = cfg;
  486.     cfg = cc;
  487. }
  488. cattr &= ~HL_INVERSE;
  489. /*
  490.  * When we don't have window focus, draw a hollow cursor.
  491.  */
  492. if (!gui.in_focus)
  493. {
  494.     gui_mch_draw_hollow_cursor(cbg);
  495.     return;
  496. }
  497. old_hl_mask = gui.highlight_mask;
  498. if (cursor_table[idx].shape == SHAPE_BLOCK)
  499. {
  500.     /*
  501.      * Draw the text character with the cursor colors. Use the
  502.      * character attributes plus the cursor attributes.
  503.      */
  504.     gui.highlight_mask = (cattr | attr);
  505.     gui_outstr_nowrap(LinePointers[gui.row] + gui.col, 1,
  506.     GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR, cfg, cbg, 0);
  507. }
  508. else
  509. {
  510.     /*
  511.      * First draw the partial cursor, then overwrite with the text
  512.      * character, using a transparant background.
  513.      */
  514.     if (cursor_table[idx].shape == SHAPE_VER)
  515.     {
  516. cur_height = gui.char_height;
  517. cur_width = (gui.char_width * cursor_table[idx].percentage
  518.   + 99) / 100;
  519.     }
  520.     else
  521.     {
  522. cur_height = (gui.char_height * cursor_table[idx].percentage
  523.   + 99) / 100;
  524. cur_width = gui.char_width;
  525.     }
  526.     gui_mch_draw_part_cursor(cur_width, cur_height, cbg);
  527. #ifndef USE_GUI_WIN32     /* doesn't seem to work for Win32 */
  528.     gui.highlight_mask = *(LinePointers[gui.row] + gui.col
  529.     + screen_Columns);
  530.     gui_outstr_nowrap(LinePointers[gui.row] + gui.col, 1,
  531.     GUI_MON_TRS_CURSOR | GUI_MON_NOCLEAR,
  532.     (GuiColor)0, (GuiColor)0, 0);
  533. #endif
  534. }
  535. gui.highlight_mask = old_hl_mask;
  536.     }
  537. }
  538.     void
  539. gui_position_menu()
  540. {
  541.     if (gui.menu_is_active && gui.in_use)
  542. gui_mch_set_menu_pos(0, 0, gui.menu_width, gui.menu_height);
  543. }
  544. /*
  545.  * Position the various GUI components (text area, menu).  The vertical
  546.  * scrollbars are NOT handled here.  See gui_update_scrollbars().
  547.  */
  548. /* ARGSUSED */
  549.     static void
  550. gui_position_components(total_width, total_height)
  551.     int     total_width;
  552.     int     total_height;
  553. {
  554.     int     text_area_x;
  555.     int     text_area_y;
  556.     int     text_area_width;
  557.     int     text_area_height;
  558.     gui.menu_width = total_width;
  559.     text_area_x = 0;
  560.     if (gui.which_scrollbars[SBAR_LEFT])
  561. text_area_x += gui.scrollbar_width;
  562. #ifdef USE_GUI_WIN32
  563.     if (vim_strchr(p_guioptions, GO_TOOLBAR) != NULL)
  564. text_area_y = TOOLBAR_BUTTON_HEIGHT + 12;
  565.     else
  566. #endif
  567. text_area_y = 0;
  568.     if (gui.menu_is_active)
  569. text_area_y += gui.menu_height;
  570.     text_area_width = gui.num_cols * gui.char_width + gui.border_offset * 2;
  571.     text_area_height = gui.num_rows * gui.char_height + gui.border_offset * 2;
  572.     gui_mch_set_text_area_pos(text_area_x,
  573.       text_area_y,
  574.       text_area_width,
  575.       text_area_height);
  576.     gui_position_menu();
  577.     if (gui.which_scrollbars[SBAR_BOTTOM])
  578. gui_mch_set_scrollbar_pos(&gui.bottom_sbar,
  579.   text_area_x,
  580.   text_area_y + text_area_height,
  581.   text_area_width,
  582.   gui.scrollbar_height);
  583.     gui.left_sbar_x = 0;
  584.     gui.right_sbar_x = text_area_x + text_area_width;
  585. }
  586.     int
  587. gui_get_base_width()
  588. {
  589.     int     base_width;
  590.     base_width = 2 * gui.border_offset;
  591.     if (gui.which_scrollbars[SBAR_LEFT])
  592. base_width += gui.scrollbar_width;
  593.     if (gui.which_scrollbars[SBAR_RIGHT])
  594. base_width += gui.scrollbar_width;
  595.     return base_width;
  596. }
  597.     int
  598. gui_get_base_height()
  599. {
  600.     int     base_height;
  601.     base_height = 2 * gui.border_offset;
  602.     if (gui.which_scrollbars[SBAR_BOTTOM])
  603. base_height += gui.scrollbar_height;
  604.     if (gui.menu_is_active)
  605. base_height += gui.menu_height;
  606. #ifdef USE_GUI_WIN32
  607.     if (vim_strchr(p_guioptions, GO_TOOLBAR) != NULL)
  608. base_height += (TOOLBAR_BUTTON_HEIGHT+12);
  609. #endif
  610.     return base_height;
  611. }
  612. /*
  613.  * Should be called after the GUI window has been resized.  Its arguments are
  614.  * the new width and height of the window in pixels.
  615.  */
  616.     void
  617. gui_resize_window(pixel_width, pixel_height)
  618.     int     pixel_width;
  619.     int     pixel_height;
  620. {
  621.     if (!gui.window_created)
  622. return;
  623. #ifdef USE_GUI_BEOS
  624.     vim_lock_screen();
  625. #endif
  626.     /* Flush pending output before redrawing */
  627.     out_flush();
  628.     gui.num_cols = (pixel_width - gui_get_base_width()) / gui.char_width;
  629.     gui.num_rows = (pixel_height - gui_get_base_height()) / gui.char_height;
  630.     gui_position_components(pixel_width, pixel_height);
  631.     gui_reset_scroll_region();
  632.     /*
  633.      * At the "more" and ":confirm" prompt there is no redraw, put the cursor
  634.      * at the last line here (why does it have to be one row too low?).
  635.      */
  636.     if (State == ASKMORE || State == CONFIRM)
  637. gui.row = gui.num_rows;
  638.     if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns)
  639. set_winsize(0, 0, FALSE);
  640. #ifdef USE_GUI_BEOS
  641.     vim_unlock_screen();
  642. #endif
  643.     gui_update_scrollbars(TRUE);
  644.     gui_update_cursor(FALSE, TRUE);
  645. }
  646.     int
  647. gui_get_winsize()
  648. {
  649.     Rows = gui.num_rows;
  650.     Columns = gui.num_cols;
  651.     return OK;
  652. }
  653. /*
  654.  * Set the size of the window according to Rows and Columns.
  655.  */
  656.     void
  657. gui_set_winsize(fit_to_display)
  658.     int     fit_to_display;
  659. {
  660.     int     base_width;
  661.     int     base_height;
  662.     int     width;
  663.     int     height;
  664.     int     min_width;
  665.     int     min_height;
  666.     int     screen_w;
  667.     int     screen_h;
  668.     if (!gui.window_created)
  669. return;
  670.     base_width = gui_get_base_width();
  671.     base_height = gui_get_base_height();
  672.     width = Columns * gui.char_width + base_width;
  673.     height = Rows * gui.char_height + base_height;
  674.     if (fit_to_display)
  675.     {
  676. gui_mch_get_screen_dimensions(&screen_w, &screen_h);
  677. if (width > screen_w)
  678. {
  679.     Columns = (screen_w - base_width) / gui.char_width;
  680.     if (Columns < MIN_COLUMNS)
  681. Columns = MIN_COLUMNS;
  682.     gui.num_cols = Columns;
  683.     gui_reset_scroll_region();
  684.     width = Columns * gui.char_width + base_width;
  685. }
  686. if (height > screen_h)
  687. {
  688.     Rows = (screen_h - base_height) / gui.char_height;
  689.     if (Rows < MIN_LINES)
  690. Rows = MIN_LINES;
  691.     gui.num_rows = Rows;
  692.     gui_reset_scroll_region();
  693.     height = Rows * gui.char_height + base_height;
  694. }
  695.     }
  696.     min_width = base_width + MIN_COLUMNS * gui.char_width;
  697.     min_height = base_height + MIN_LINES * gui.char_height;
  698.     gui_mch_set_winsize(width, height, min_width, min_height,
  699. base_width, base_height);
  700.     gui_position_components(width, height);
  701.     gui_update_scrollbars(TRUE);
  702. }
  703. /*
  704.  * Make scroll region cover whole screen.
  705.  */
  706.     void
  707. gui_reset_scroll_region()
  708. {
  709.     gui.scroll_region_top = 0;
  710.     gui.scroll_region_bot = gui.num_rows - 1;
  711. }
  712.     void
  713. gui_start_highlight(mask)
  714.     int     mask;
  715. {
  716.     if (mask > HL_ALL)     /* highlight code */
  717. gui.highlight_mask = mask;
  718.     else     /* mask */
  719. gui.highlight_mask |= mask;
  720. }
  721.     void
  722. gui_stop_highlight(mask)
  723.     int     mask;
  724. {
  725.     if (mask > HL_ALL)     /* highlight code */
  726. gui.highlight_mask = HL_NORMAL;
  727.     else     /* mask */
  728. gui.highlight_mask &= ~mask;
  729. }
  730. /*
  731.  * Clear a rectangular region of the screen from text pos (row1, col1) to
  732.  * (row2, col2) inclusive.
  733.  */
  734.     void
  735. gui_clear_block(row1, col1, row2, col2)
  736.     int     row1;
  737.     int     col1;
  738.     int     row2;
  739.     int     col2;
  740. {
  741.     /* Clear the selection if we are about to write over it */
  742.     clip_may_clear_selection(row1, row2);
  743.     gui_mch_clear_block(row1, col1, row2, col2);
  744.     /* Invalidate cursor if it was in this block */
  745.     if (       gui.cursor_row >= row1 && gui.cursor_row <= row2
  746.     && gui.cursor_col >= col1 && gui.cursor_col <= col2)
  747. gui.cursor_is_valid = FALSE;
  748. }
  749. /*
  750.  * Write code to update cursor shape later.
  751.  */
  752.     void
  753. gui_upd_cursor_shape()
  754. {
  755.     OUT_STR("33|s");
  756. }
  757.     void
  758. gui_write(s, len)
  759.     char_u  *s;
  760.     int     len;
  761. {
  762.     char_u  *p;
  763.     int     arg1 = 0, arg2 = 0;
  764. #ifdef RISCOS
  765.     int     force = TRUE;  /* JK230798, stop Vim being smart or our redraw speed will suffer */
  766. #else
  767.     int     force = FALSE; /* force cursor update */
  768. #endif
  769. /* #define DEBUG_GUI_WRITE */
  770. #ifdef DEBUG_GUI_WRITE
  771.     {
  772. int i;
  773. char_u *str;
  774. printf("gui_write(%d):n    ", len);
  775. for (i = 0; i < len; i++)
  776.     if (s[i] == ESC)
  777.     {
  778. if (i != 0)
  779.     printf("n    ");
  780. printf("<ESC>");
  781.     }
  782.     else
  783.     {
  784. str = transchar(s[i]);
  785. if (str[0] && str[1])
  786.     printf("<%s>", (char *)str);
  787. else
  788.     printf("%s", (char *)str);
  789.     }
  790. printf("n");
  791.     }
  792. #endif
  793.     while (len)
  794.     {
  795. if (s[0] == ESC && s[1] == '|')
  796. {
  797.     p = s + 2;
  798.     if (isdigit(*p))
  799.     {
  800. arg1 = getdigits(&p);
  801. if (p > s + len)
  802.     break;
  803. if (*p == ';')
  804. {
  805.     ++p;
  806.     arg2 = getdigits(&p);
  807.     if (p > s + len)
  808. break;
  809. }
  810.     }
  811.     switch (*p)
  812.     {
  813. case 'C': /* Clear screen */
  814.     clip_scroll_selection(9999);
  815.     gui_mch_clear_all();
  816.     gui.cursor_is_valid = FALSE;
  817.     break;
  818. case 'M': /* Move cursor */
  819.     gui_set_cursor(arg1, arg2);
  820.     break;
  821. case 's': /* force cursor (shape) update */
  822.     force = TRUE;
  823.     break;
  824. case 'R': /* Set scroll region */
  825.     if (arg1 < arg2)
  826.     {
  827. gui.scroll_region_top = arg1;
  828. gui.scroll_region_bot = arg2;
  829.     }
  830.     else
  831.     {
  832. gui.scroll_region_top = arg2;
  833. gui.scroll_region_bot = arg1;
  834.     }
  835.     break;
  836. case 'd': /* Delete line */
  837.     gui_delete_lines(gui.row, 1);
  838.     break;
  839. case 'D': /* Delete lines */
  840.     gui_delete_lines(gui.row, arg1);
  841.     break;
  842. case 'i': /* Insert line */
  843.     gui_insert_lines(gui.row, 1);
  844.     break;
  845. case 'I': /* Insert lines */
  846.     gui_insert_lines(gui.row, arg1);
  847.     break;
  848. case '$': /* Clear to end-of-line */
  849.     gui_clear_block(gui.row, gui.col, gui.row,
  850.     (int)Columns - 1);
  851.     break;
  852. case 'h': /* Turn on highlighting */
  853.     gui_start_highlight(arg1);
  854.     break;
  855. case 'H': /* Turn off highlighting */
  856.     gui_stop_highlight(arg1);
  857.     break;
  858. case 'f': /* flash the window (visual bell) */
  859.     gui_mch_flash();
  860.     break;
  861. default:
  862.     p = s + 1; /* Skip the ESC */
  863.     break;
  864.     }
  865.     len -= ++p - s;
  866.     s = p;
  867. }
  868. else if (s[0] < 0x20) /* Ctrl character */
  869. {
  870.     if (s[0] == 'n') /* NL */
  871.     {
  872. gui.col = 0;
  873. if (gui.row < gui.scroll_region_bot)
  874.     gui.row++;
  875. else
  876.     gui_delete_lines(gui.scroll_region_top, 1);
  877.     }
  878.     else if (s[0] == 'r') /* CR */
  879.     {
  880. gui.col = 0;
  881.     }
  882.     else if (s[0] == 'b') /* Backspace */
  883.     {
  884. if (gui.col)
  885.     --gui.col;
  886.     }
  887.     else if (s[0] == Ctrl('L')) /* cursor-right */
  888.     {
  889. ++gui.col;
  890.     }
  891.     else if (s[0] == Ctrl('G')) /* Beep */
  892.     {
  893. gui_mch_beep();
  894.     }
  895.     /* Other Ctrl character: shouldn't happen! */
  896.     --len; /* Skip this char */
  897.     ++s;
  898. }
  899. else
  900. {
  901.     p = s;
  902.     while (len && *p >= 0x20)
  903.     {
  904. len--;
  905. p++;
  906.     }
  907.     gui_outstr(s, p - s);
  908.     s = p;
  909. }
  910.     }
  911.     gui_update_cursor(force, TRUE);
  912.     gui_update_scrollbars(FALSE);
  913.     /*
  914.      * We need to make sure this is cleared since Athena doesn't tell us when
  915.      * he is done dragging.
  916.      */
  917. #ifdef USE_GUI_ATHENA
  918.     gui.dragged_sb = SBAR_NONE;
  919. #endif
  920.     if (vim_strchr(p_guioptions, GO_ASEL) != NULL)
  921. clip_update_selection();
  922.     gui_mch_flush();     /* In case vim decides to take a nap */
  923. }
  924.     static void
  925. gui_outstr(s, len)
  926.     char_u  *s;
  927.     int     len;
  928. {
  929.     int     this_len;
  930.     if (len == 0)
  931. return;
  932.     if (len < 0)
  933. len = STRLEN(s);
  934.     while (gui.col + len > Columns)
  935.     {
  936. this_len = Columns - gui.col;
  937. gui_outstr_nowrap(s, this_len, GUI_MON_WRAP_CURSOR, (GuiColor)0,
  938.       (GuiColor)0, 0);
  939. s += this_len;
  940. len -= this_len;
  941.     }
  942.     gui_outstr_nowrap(s, len, GUI_MON_WRAP_CURSOR, (GuiColor)0, (GuiColor)0, 0);
  943. }
  944. /*
  945.  * Output the given string at the current cursor position.  If the string is
  946.  * too long to fit on the line, then it is truncated.
  947.  * "flags":
  948.  * GUI_MON_WRAP_CURSOR may be used if the cursor position should be wrapped
  949.  * when the end of the line is reached, however the string will still be
  950.  * truncated and not continue on the next line.
  951.  * GUI_MON_IS_CURSOR should only be used when this function is being called to
  952.  * actually draw (an inverted) cursor.
  953.  * GUI_MON_TRS_CURSOR is used to draw the cursor text with a transparant
  954.  * background.
  955.  */
  956.     void
  957. gui_outstr_nowrap(s, len, flags, fg, bg, back)
  958.     char_u *s;
  959.     int len;
  960.     int flags;
  961.     GuiColor fg, bg;     /* colors for cursor */
  962.     int back;     /* backup this many chars when using bold trick */
  963. {
  964.     long_u     highlight_mask;
  965.     GuiColor     fg_color;
  966.     GuiColor     bg_color;
  967.     GuiFont     font;
  968.     struct attr_entry *aep = NULL;
  969.     int     draw_flags;
  970.     int     col = gui.col;
  971.     if (len == 0)
  972. return;
  973.     if (len < 0)
  974. len = STRLEN(s);
  975.     if (gui.highlight_mask > HL_ALL)
  976.     {
  977. aep = syn_gui_attr2entry(gui.highlight_mask);
  978. if (aep == NULL)     /* highlighting not set */
  979.     highlight_mask = 0;
  980. else
  981.     highlight_mask = aep->ae_attr;
  982.     }
  983.     else
  984. highlight_mask = gui.highlight_mask;
  985.     /* Set the font */
  986.     if (aep != NULL && aep->ae_u.gui.font != 0)
  987. font = aep->ae_u.gui.font;
  988.     else
  989.     {
  990. if ((highlight_mask & (HL_BOLD | HL_STANDOUT)) && gui.bold_font != 0)
  991. {
  992.     if ((highlight_mask & HL_ITALIC) && gui.boldital_font != 0)
  993. font = gui.boldital_font;
  994.     else
  995. font = gui.bold_font;
  996. }
  997. else if ((highlight_mask & HL_ITALIC) && gui.ital_font != 0)
  998.     font = gui.ital_font;
  999. else
  1000.     font = gui.norm_font;
  1001.     }
  1002.     gui_mch_set_font(font);
  1003.     /* Set the color */
  1004.     bg_color = gui.back_pixel;
  1005.     if ((flags & GUI_MON_IS_CURSOR) && gui.in_focus)
  1006.     {
  1007. fg_color = fg;
  1008. bg_color = bg;
  1009.     }
  1010.     else if (aep != NULL)
  1011.     {
  1012. fg_color = aep->ae_u.gui.fg_color;
  1013. if (fg_color == 0)
  1014.     fg_color = gui.norm_pixel;
  1015. else
  1016.     --fg_color;
  1017. bg_color = aep->ae_u.gui.bg_color;
  1018. if (bg_color == 0)
  1019.     bg_color = gui.back_pixel;
  1020. else
  1021.     --bg_color;
  1022.     }
  1023.     else
  1024. fg_color = gui.norm_pixel;
  1025.     if (highlight_mask & (HL_INVERSE | HL_STANDOUT))
  1026.     {
  1027. #if defined(AMIGA) || defined(RISCOS)
  1028. gui_mch_set_colors(bg_color, fg_color);
  1029. #else
  1030. gui_mch_set_fg_color(bg_color);
  1031. gui_mch_set_bg_color(fg_color);
  1032. #endif
  1033.     }
  1034.     else
  1035.     {
  1036. #if defined(AMIGA) || defined(RISCOS)
  1037. gui_mch_set_colors(fg_color, bg_color);
  1038. #else
  1039. gui_mch_set_fg_color(fg_color);
  1040. gui_mch_set_bg_color(bg_color);
  1041. #endif
  1042.     }
  1043.     /* Clear the selection if we are about to write over it */
  1044.     if (!(flags & GUI_MON_NOCLEAR))
  1045. clip_may_clear_selection(gui.row, gui.row);
  1046.     draw_flags = 0;
  1047.     /* If there's no bold font, then fake it */
  1048.     if ((highlight_mask & (HL_BOLD | HL_STANDOUT)) &&
  1049.     (gui.bold_font == 0 || (aep != NULL && aep->ae_u.gui.font != 0)))
  1050.     {
  1051. draw_flags |= DRAW_BOLD;
  1052. s -= back;
  1053. len += back;
  1054. col -= back;
  1055.     }
  1056. #ifdef RISCOS
  1057.     /* If there's no italic font, then fake it */
  1058.     if ((highlight_mask & HL_ITALIC) && gui.ital_font == 0)
  1059. draw_flags |= DRAW_ITALIC;
  1060.     /* Do we underline the text? */
  1061.     if (highlight_mask & HL_UNDERLINE)
  1062. draw_flags |= DRAW_UNDERL;
  1063. #else
  1064.     /* Do we underline the text? */
  1065.     if ((highlight_mask & HL_UNDERLINE) ||
  1066.     ((highlight_mask & HL_ITALIC) && gui.ital_font == 0))
  1067. draw_flags |= DRAW_UNDERL;
  1068. #endif
  1069.     /* Do we draw transparantly? */
  1070.     if ((flags & GUI_MON_TRS_CURSOR))
  1071. draw_flags |= DRAW_TRANSP;
  1072.     /* Draw the text */
  1073.     gui_mch_draw_string(gui.row, col, s, len, draw_flags);
  1074.     /* May need to invert it when it's part of the selection (assumes len==1) */
  1075.     if (flags & GUI_MON_NOCLEAR)
  1076. clip_may_redraw_selection(gui.row, col);
  1077.     if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
  1078.     {
  1079. /* Invalidate the old physical cursor position if we wrote over it */
  1080. if (gui.cursor_row == gui.row && gui.cursor_col >= col
  1081. && gui.cursor_col < col + len)
  1082.     gui.cursor_is_valid = FALSE;
  1083. /* Update the cursor position */
  1084. gui.col = col + len;
  1085. if ((flags & GUI_MON_WRAP_CURSOR) && gui.col >= Columns)
  1086. {
  1087.     gui.col = 0;
  1088.     gui.row++;
  1089. }
  1090.     }
  1091. }
  1092. /*
  1093.  * Un-draw the cursor. Actually this just redraws the character at the given
  1094.  * position.  The character just before it too, for when it was in bold.
  1095.  */
  1096.     void
  1097. gui_undraw_cursor()
  1098. {
  1099.     if (gui.cursor_is_valid)
  1100.     {
  1101. if (gui_redraw_block(gui.cursor_row, gui.cursor_col,
  1102.       gui.cursor_row, gui.cursor_col, GUI_MON_NOCLEAR)
  1103. && gui.cursor_col > 0)
  1104.     (void)gui_redraw_block(gui.cursor_row, gui.cursor_col - 1,
  1105.  gui.cursor_row, gui.cursor_col - 1, GUI_MON_NOCLEAR);
  1106.     }
  1107. }
  1108.     void
  1109. gui_redraw(x, y, w, h)
  1110.     int     x;
  1111.     int     y;
  1112.     int     w;
  1113.     int     h;
  1114. {
  1115.     int     row1, col1, row2, col2;
  1116.     row1 = Y_2_ROW(y);
  1117.     col1 = X_2_COL(x);
  1118.     row2 = Y_2_ROW(y + h - 1);
  1119.     col2 = X_2_COL(x + w - 1);
  1120.     (void)gui_redraw_block(row1, col1, row2, col2, 0);
  1121.     /*
  1122.      * We may need to redraw the cursor, but don't take it upon us to change
  1123.      * its location after a scroll.
  1124.      * (maybe be more strict even and test col too?)
  1125.      * These things may be outside the update/clipping region and reality may
  1126.      * not reflect Vims internal ideas if these operations are clipped away.
  1127.      */
  1128.     if (gui.row == gui.cursor_row)
  1129. gui_update_cursor(FALSE, TRUE);
  1130.     if (clipboard.state != SELECT_CLEARED)
  1131. clip_redraw_selection(x, y, w, h);
  1132. }
  1133. /*
  1134.  * Draw a rectangular block of characters, from row1 to row2 (inclusive) and
  1135.  * from col1 to col2 (inclusive).
  1136.  * Return TRUE when the character before the first drawn character has
  1137.  * different attributes (may have to be redrawn too).
  1138.  */
  1139.     int
  1140. gui_redraw_block(row1, col1, row2, col2, flags)
  1141.     int     row1;
  1142.     int     col1;
  1143.     int     row2;
  1144.     int     col2;
  1145.     int     flags; /* flags for gui_outstr_nowrap() */
  1146. {
  1147.     int     old_row, old_col;
  1148.     long_u  old_hl_mask;
  1149.     char_u  *screenp, *attrp, first_attr;
  1150.     int     idx, len;
  1151.     int     back;
  1152.     int     retval = FALSE;
  1153.     /* Don't try to update when NextScreen is not valid */
  1154.     if (!screen_cleared || NextScreen == NULL)
  1155. return retval;
  1156.     /* Don't try to draw outside the window! */
  1157.     /* Check everything, strange values may be caused by big border width */
  1158.     col1 = check_col(col1);
  1159.     col2 = check_col(col2);
  1160.     row1 = check_row(row1);
  1161.     row2 = check_row(row2);
  1162.     /* Remember where our cursor was */
  1163.     old_row = gui.row;
  1164.     old_col = gui.col;
  1165.     old_hl_mask = gui.highlight_mask;
  1166.     for (gui.row = row1; gui.row <= row2; gui.row++)
  1167.     {
  1168. gui.col = col1;
  1169. screenp = LinePointers[gui.row] + gui.col;
  1170. attrp = screenp + screen_Columns;
  1171. len = col2 - col1 + 1;
  1172. /* Find how many chars back this highlighting starts, or where a space
  1173.  * is.  Needed for when the bold trick is used */
  1174. for (back = 0; back < col1; ++back)
  1175.     if (attrp[-1 - back] != attrp[0] || screenp[-1 - back] == ' ')
  1176. break;
  1177. retval = (col1 && attrp[-1] && back == 0);
  1178. /* break it up in strings of characters with the same attributes */
  1179. while (len > 0)
  1180. {
  1181.     first_attr = attrp[0];
  1182.     for (idx = 0; len > 0 && attrp[idx] == first_attr; idx++)
  1183. --len;
  1184.     gui.highlight_mask = first_attr;
  1185.     gui_outstr_nowrap(screenp, idx, flags,
  1186.       (GuiColor)0, (GuiColor)0, back);
  1187.     screenp += idx;
  1188.     attrp += idx;
  1189.     back = 0;
  1190. }
  1191.     }
  1192.     /* Put the cursor back where it was */
  1193.     gui.row = old_row;
  1194.     gui.col = old_col;
  1195.     gui.highlight_mask = old_hl_mask;
  1196.     return retval;
  1197. }
  1198.     static void
  1199. gui_delete_lines(row, count)
  1200.     int     row;
  1201.     int     count;
  1202. {
  1203.     if (row == 0)
  1204. clip_scroll_selection(count);
  1205.     gui_mch_delete_lines(row, count);
  1206. }
  1207.     static void
  1208. gui_insert_lines(row, count)
  1209.     int     row;
  1210.     int     count;
  1211. {
  1212.     if (row == 0)
  1213. clip_scroll_selection(-count);
  1214.     gui_mch_insert_lines(row, count);
  1215. }
  1216. /*
  1217.  * Check bounds for column number
  1218.  */
  1219.     int
  1220. check_col(col)
  1221.     int     col;
  1222. {
  1223.     if (col < 0)
  1224. return 0;
  1225.     if (col >= (int)screen_Columns)
  1226. return (int)screen_Columns - 1;
  1227.     return col;
  1228. }
  1229. /*
  1230.  * Check bounds for row number
  1231.  */
  1232.     int
  1233. check_row(row)
  1234.     int     row;
  1235. {
  1236.     if (row < 0)
  1237. return 0;
  1238.     if (row >= (int)screen_Rows)
  1239. return (int)screen_Rows - 1;
  1240.     return row;
  1241. }
  1242. /*
  1243.  * The main GUI input routine. Waits for a character from the keyboard.
  1244.  * wtime == -1     Wait forever.
  1245.  * wtime == 0     Don't wait.
  1246.  * wtime > 0     Wait wtime milliseconds for a character.
  1247.  * Returns OK if a character was found to be available within the given time,
  1248.  * or FAIL otherwise.
  1249.  */
  1250.     int
  1251. gui_wait_for_chars(wtime)
  1252.     long    wtime;
  1253. {
  1254.     int     retval;
  1255.     /*
  1256.      * If we're going to wait a bit, update the menus for the current
  1257.      * State.
  1258.      */
  1259.     if (wtime != 0)
  1260. gui_update_menus(0);
  1261.     gui_mch_update();
  1262.     if (!vim_is_input_buf_empty()) /* Got char, return immediately */
  1263. return OK;
  1264.     if (wtime == 0) /* Don't wait for char */
  1265. return FAIL;
  1266.     if (wtime > 0)
  1267.     {
  1268. /* Blink when waiting for a character. Probably only does something
  1269.  * for showmatch() */
  1270. gui_mch_start_blink();
  1271. retval = gui_mch_wait_for_chars(wtime);
  1272. gui_mch_stop_blink();
  1273. return retval;
  1274.     }
  1275.     /*
  1276.      * While we are waiting indefenitely for a character, blink the cursor.
  1277.      */
  1278.     gui_mch_start_blink();
  1279.     if (gui_mch_wait_for_chars(p_ut) == OK)
  1280. retval = OK;
  1281.     else
  1282.     {
  1283. /*
  1284.  * If no characters arrive within 'updatetime' milli-seconds, flush
  1285.  * all the swap files to disk.
  1286.  */
  1287. updatescript(0);
  1288. retval = gui_mch_wait_for_chars(-1L);
  1289.     }
  1290.     gui_mch_stop_blink();
  1291.     return retval;
  1292. }
  1293. /*
  1294.  * Generic mouse support function.  Add a mouse event to the input buffer with
  1295.  * the given properties.
  1296.  *  button     --- may be any of MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT,
  1297.  * MOUSE_DRAG, or MOUSE_RELEASE.
  1298.  *  x, y     --- Coordinates of mouse in pixels.
  1299.  *  repeated_click  --- TRUE if this click comes only a short time after a
  1300.  * previous click.
  1301.  *  modifiers     --- Bit field which may be any of the following modifiers
  1302.  * or'ed together: MOUSE_SHIFT | MOUSE_CTRL | MOUSE_ALT.
  1303.  * This function will ignore drag events where the mouse has not moved to a new
  1304.  * character.
  1305.  */
  1306.     void
  1307. gui_send_mouse_event(button, x, y, repeated_click, modifiers)
  1308.     int     button;
  1309.     int     x;
  1310.     int     y;
  1311.     int     repeated_click;
  1312.     int_u   modifiers;
  1313. {
  1314.     static int     prev_row = 0, prev_col = 0;
  1315.     static int     prev_button = -1;
  1316.     static int     num_clicks = 1;
  1317.     char_u     string[6];
  1318.     int     row, col;
  1319. #ifdef USE_CLIPBOARD
  1320.     int     checkfor;
  1321.     int     did_clip = FALSE;
  1322.     /* If a clipboard selection is in progress, handle it */
  1323.     if (clipboard.state == SELECT_IN_PROGRESS)
  1324.     {
  1325. clip_process_selection(button, x, y, repeated_click, modifiers);
  1326. return;
  1327.     }
  1328.     /* Determine which mouse settings to look for based on the current mode */
  1329.     switch (get_real_state())
  1330.     {
  1331. case NORMAL_BUSY:
  1332. case OP_PENDING:
  1333. case NORMAL:     checkfor = MOUSE_NORMAL; break;
  1334. case VISUAL:     checkfor = MOUSE_VISUAL; break;
  1335. case REPLACE:
  1336. case INSERT:     checkfor = MOUSE_INSERT; break;
  1337. case HITRETURN:     checkfor = MOUSE_RETURN; break;
  1338.     /*
  1339.      * On the command line, use the clipboard selection on all lines
  1340.      * but the command line.  But not when pasting.
  1341.      */
  1342. case CMDLINE:
  1343.     if (Y_2_ROW(y) < cmdline_row && button != MOUSE_MIDDLE)
  1344. checkfor = ' ';
  1345.     else
  1346. checkfor = MOUSE_COMMAND;
  1347.     break;
  1348. default:
  1349.     checkfor = ' ';
  1350.     break;
  1351.     };
  1352.     /*
  1353.      * Allow clipboard selection of text on the command line in "normal"
  1354.      * modes.  Don't do this when dragging the status line, or extending a
  1355.      * Visual selection.
  1356.      */
  1357.     if ((State == NORMAL || State == NORMAL_BUSY
  1358.        || State == INSERT || State == REPLACE)
  1359.     && Y_2_ROW(y) >= gui.num_rows - p_ch
  1360.     && button != MOUSE_DRAG)
  1361. checkfor = ' ';
  1362.     /*
  1363.      * If the mouse settings say to not use the mouse, use the non-Visual mode
  1364.      * selection.  But if Visual is active, assume that only the Visual area
  1365.      * will be selected.
  1366.      * Exception: On the command line, both the selection is used and a mouse
  1367.      * key is send.
  1368.      */
  1369.     if (!mouse_has(checkfor) || checkfor == MOUSE_COMMAND)
  1370.     {
  1371. /* Don't do non-visual selection in Visual mode. */
  1372. if (VIsual_active)
  1373.     return;
  1374. /*
  1375.  * When 'mousemodel' is "popup", shift-left is translated to right.
  1376.  */
  1377. if (mouse_model_popup())
  1378. {
  1379.     if (button == MOUSE_LEFT && (modifiers & MOUSE_SHIFT))
  1380.     {
  1381. button = MOUSE_RIGHT;
  1382. modifiers &= ~ MOUSE_SHIFT;
  1383.     }
  1384. }
  1385. /* If the selection is done, allow the right button to extend it.
  1386.  * If the selection is cleared, allow the right button to start it
  1387.  * from the cursor position. */
  1388. if (button == MOUSE_RIGHT)
  1389. {
  1390.     if (clipboard.state == SELECT_CLEARED)
  1391.     {
  1392. if (State == CMDLINE)
  1393. {
  1394.     col = msg_col;
  1395.     row = msg_row;
  1396. }
  1397. else
  1398. {
  1399.     col = curwin->w_wcol;
  1400.     row = curwin->w_wrow + curwin->w_winpos;
  1401. }
  1402. clip_start_selection(MOUSE_LEFT, FILL_X(col), FILL_Y(row),
  1403.     FALSE, 0);
  1404.     }
  1405.     clip_process_selection(button, x, y, repeated_click, modifiers);
  1406.     did_clip = TRUE;
  1407. }
  1408. /* Allow the left button to start the selection */
  1409. else if (button ==
  1410. # ifdef RISCOS
  1411. /* Only start a drag on a drag event. Otherwise
  1412.  * we don't get a release event.
  1413.  */
  1414.     MOUSE_DRAG
  1415. # else
  1416.     MOUSE_LEFT
  1417. # endif
  1418. )
  1419. {
  1420.     clip_start_selection(button, x, y, repeated_click, modifiers);
  1421.     did_clip = TRUE;
  1422. }
  1423. # ifdef RISCOS
  1424. else if (button == MOUSE_LEFT)
  1425. {
  1426.     clip_clear_selection();
  1427.     did_clip = TRUE;
  1428. }
  1429. # endif
  1430. /* Always allow pasting */
  1431. if (button != MOUSE_MIDDLE)
  1432. {
  1433.     if (!mouse_has(checkfor) || button == MOUSE_RELEASE)
  1434. return;
  1435.     button = MOUSE_LEFT;
  1436. }
  1437. repeated_click = FALSE;
  1438.     }
  1439.     if (clipboard.state != SELECT_CLEARED && !did_clip)
  1440. clip_clear_selection();
  1441. #endif
  1442.     /*
  1443.      * Don't put mouse events in the input queue while executing an external
  1444.      * command.
  1445.      */
  1446.     if (!termcap_active)
  1447. return;
  1448.     row = check_row(Y_2_ROW(y));
  1449.     col = check_col(X_2_COL(x));
  1450.     /*
  1451.      * If we are dragging and the mouse hasn't moved far enough to be on a
  1452.      * different character, then don't send an event to vim.
  1453.      */
  1454.     if (button == MOUSE_DRAG && row == prev_row && col == prev_col)
  1455. return;
  1456.     /*
  1457.      * If topline has changed (window scrolled) since the last click, reset
  1458.      * repeated_click, because we don't want starting Visual mode when
  1459.      * clicking on a different character in the text.
  1460.      */
  1461.     if (curwin->w_topline != gui_prev_topline)
  1462. repeated_click = FALSE;
  1463.     string[0] = CSI; /* this sequence is recognized by check_termcode() */
  1464.     string[1] = KS_MOUSE;
  1465.     string[2] = K_FILLER;
  1466.     if (button != MOUSE_DRAG && button != MOUSE_RELEASE)
  1467.     {
  1468. if (repeated_click)
  1469. {
  1470.     /*
  1471.      * Handle multiple clicks. They only count if the mouse is still
  1472.      * pointing at the same character.
  1473.      */
  1474.     if (button != prev_button || row != prev_row || col != prev_col)
  1475. num_clicks = 1;
  1476.     else if (++num_clicks > 4)
  1477. num_clicks = 1;
  1478. }
  1479. else
  1480.     num_clicks = 1;
  1481. prev_button = button;
  1482. gui_prev_topline = curwin->w_topline;
  1483. string[3] = (char_u)(button | 0x20);
  1484. SET_NUM_MOUSE_CLICKS(string[3], num_clicks);
  1485.     }
  1486.     else
  1487. string[3] = (char_u)button;
  1488.     string[3] |= modifiers;
  1489.     string[4] = (char_u)(col + ' ' + 1);
  1490.     string[5] = (char_u)(row + ' ' + 1);
  1491.     add_to_input_buf(string, 6);
  1492.     prev_row = row;
  1493.     prev_col = col;
  1494. }
  1495. /*
  1496.  * Menu stuff.
  1497.  */
  1498.     void
  1499. gui_menu_cb(menu)
  1500.     GuiMenu *menu;
  1501. {
  1502.     char_u  bytes[3 + sizeof(long_u)];
  1503.     bytes[0] = CSI;
  1504.     bytes[1] = KS_MENU;
  1505.     bytes[2] = K_FILLER;
  1506.     add_long_to_buf((long_u)menu, bytes + 3);
  1507.     add_to_input_buf(bytes, 3 + sizeof(long_u));
  1508. }
  1509. /*
  1510.  * Return the index into the menu->strings or menu->noremap arrays for the
  1511.  * current state.  Returns MENU_INDEX_INVALID if there is no mapping for the
  1512.  * given menu in the current mode.
  1513.  */
  1514.     int
  1515. gui_get_menu_index(menu, state)
  1516.     GuiMenu *menu;
  1517.     int     state;
  1518. {
  1519.     int     idx;
  1520.     if (VIsual_active)
  1521. idx = MENU_INDEX_VISUAL;
  1522.     else if ((state & INSERT))
  1523. idx = MENU_INDEX_INSERT;
  1524.     else if ((state & CMDLINE))
  1525. idx = MENU_INDEX_CMDLINE;
  1526.     else if (finish_op)
  1527. idx = MENU_INDEX_OP_PENDING;
  1528.     else if ((state & NORMAL))
  1529. idx = MENU_INDEX_NORMAL;
  1530.     else
  1531. idx = MENU_INDEX_INVALID;
  1532.     if (idx != MENU_INDEX_INVALID && menu->strings[idx] == NULL)
  1533. idx = MENU_INDEX_INVALID;
  1534.     return idx;
  1535. }
  1536. /*
  1537.  * Return the modes specified by the given menu command (eg :menu! returns
  1538.  * MENU_CMDLINE_MODE | MENU_INSERT_MODE).  If noremap is not NULL, then the
  1539.  * flag it points to is set according to whether the command is a "nore"
  1540.  * command.  If unmenu is not NULL, then the flag it points to is set
  1541.  * according to whether the command is an "unmenu" command.
  1542.  */
  1543.     static int
  1544. gui_get_menu_cmd_modes(cmd, forceit, noremap, unmenu)
  1545.     char_u  *cmd;
  1546.     int     forceit;     /* Was there a "!" after the command? */
  1547.     int     *noremap;
  1548.     int     *unmenu;
  1549. {
  1550.     int     modes;
  1551.     switch (*cmd++)
  1552.     {
  1553. case 'v': /* vmenu, vunmenu, vnoremenu */
  1554.     modes = MENU_VISUAL_MODE;
  1555.     break;
  1556. case 'o': /* omenu */
  1557.     modes = MENU_OP_PENDING_MODE;
  1558.     break;
  1559. case 'i': /* imenu */
  1560.     modes = MENU_INSERT_MODE;
  1561.     break;
  1562. case 't':
  1563.     modes = MENU_TIP_MODE; /* tmenu */
  1564.     break;
  1565. case 'c': /* cmenu */
  1566.     modes = MENU_CMDLINE_MODE;
  1567.     break;
  1568. case 'a': /* amenu */
  1569.     modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE | MENU_NORMAL_MODE
  1570.     | MENU_VISUAL_MODE | MENU_OP_PENDING_MODE;
  1571.     break;
  1572. case 'n':
  1573.     if (cmd[1] != 'o') /* nmenu */
  1574.     {
  1575. modes = MENU_NORMAL_MODE;
  1576. break;
  1577.     }
  1578.     /* FALLTHROUGH */
  1579. default:
  1580.     --cmd;
  1581.     if (forceit) /* menu!! */
  1582. modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE;
  1583.     else /* menu */
  1584. modes = MENU_NORMAL_MODE | MENU_VISUAL_MODE
  1585.        | MENU_OP_PENDING_MODE;
  1586.     }
  1587.     if (noremap != NULL)
  1588. *noremap = (*cmd == 'n');
  1589.     if (unmenu != NULL)
  1590. *unmenu = (*cmd == 'u');
  1591.     return modes;
  1592. }
  1593. #define MENUDEPTH   10 /* maximum depth of menus */
  1594. /*
  1595.  * Do the :menu commands.
  1596.  */
  1597.     void
  1598. do_menu(eap)
  1599.     EXARG *eap;     /* Ex command arguments */
  1600. {
  1601.     char_u *menu_path;
  1602.     int modes;
  1603.     char_u *map_to;
  1604.     int noremap;
  1605.     int unmenu;
  1606.     char_u *map_buf;
  1607.     char_u *arg;
  1608.     char_u *p;
  1609.     int i;
  1610.     int old_menu_height;
  1611.     int pri_tab[MENUDEPTH + 1];
  1612.     modes = gui_get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);
  1613.     arg = eap->arg;
  1614.     /* fill in the priority table */
  1615.     for (p = arg; *p; ++p)
  1616. if (!isdigit(*p) && *p != '.')
  1617.     break;
  1618.     if (vim_iswhite(*p))
  1619.     {
  1620. for (i = 0; i < MENUDEPTH && !vim_iswhite(*arg); ++i)
  1621. {
  1622.     pri_tab[i] = getdigits(&arg);
  1623.     if (pri_tab[i] == 0)
  1624. pri_tab[i] = 500;
  1625.     if (*arg == '.')
  1626. ++arg;
  1627. }
  1628. arg = skipwhite(arg);
  1629.     }
  1630.     else if (eap->addr_count)
  1631.     {
  1632. pri_tab[0] = eap->line2;
  1633. i = 1;
  1634.     }
  1635.     else
  1636. i = 0;
  1637.     while (i < MENUDEPTH)
  1638. pri_tab[i++] = 500;
  1639.     pri_tab[MENUDEPTH] = -1; /* mark end of the table */
  1640.     menu_path = arg;
  1641.     if (*menu_path == NUL)
  1642.     {
  1643. gui_show_menus(menu_path, modes);
  1644. return;
  1645.     }
  1646.     /* skip the menu name, and translate <Tab> into a real TAB */
  1647.     while (*arg && !vim_iswhite(*arg))
  1648.     {
  1649. if ((*arg == '\' || *arg == Ctrl('V')) && arg[1] != NUL)
  1650.     arg++;
  1651. else if (STRNICMP(arg, "<TAB>", 5) == 0)
  1652. {
  1653.     *arg = TAB;
  1654.     mch_memmove(arg + 1, arg + 5, STRLEN(arg + 4));
  1655. }
  1656. arg++;
  1657.     }
  1658.     if (*arg != NUL)
  1659. *arg++ = NUL;
  1660.     arg = skipwhite(arg);
  1661.     map_to = arg;
  1662.     if (*map_to == NUL && !unmenu)
  1663.     {
  1664. gui_show_menus(menu_path, modes);
  1665. return;
  1666.     }
  1667.     else if (*map_to != NUL && unmenu)
  1668.     {
  1669. EMSG("Trailing characters");
  1670. return;
  1671.     }
  1672.     old_menu_height = gui.menu_height;
  1673.     if (unmenu)
  1674.     {
  1675. if (STRCMP(menu_path, "*") == 0) /* meaning: remove all menus */
  1676.     menu_path = (char_u *)"";
  1677. gui_remove_menu(&gui.root_menu, menu_path, modes, FALSE);
  1678. /*
  1679.  * For the PopUp menu, remove a menu for each mode separately.
  1680.  */
  1681. if (STRNCMP(menu_path, "PopUp", 5) == 0)
  1682. {
  1683.     for (i = 0; i < MENU_INDEX_TIP; ++i)
  1684. if (modes & (1 << i))
  1685. {
  1686.     p = popup_mode_name(menu_path, i);
  1687.     if (p != NULL)
  1688.     {
  1689. gui_remove_menu(&gui.root_menu, p, 1 << i, TRUE);
  1690. vim_free(p);
  1691.     }
  1692. }
  1693. }
  1694.     }
  1695.     else
  1696.     {
  1697. /* Replace special key codes */
  1698. map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE);
  1699. gui_add_menu_path(menu_path, modes,
  1700. pri_tab, gui_menu_cb, map_to, noremap
  1701. #ifdef USE_GUI_WIN32
  1702. , TRUE
  1703. #endif
  1704. );
  1705. /*
  1706.  * For the PopUp menu, add a menu for each mode separately.
  1707.  */
  1708. if (STRNCMP(menu_path, "PopUp", 5) == 0)
  1709. {
  1710.     for (i = 0; i < MENU_INDEX_TIP; ++i)
  1711. if (modes & (1 << i))
  1712. {
  1713.     p = popup_mode_name(menu_path, i);
  1714.     if (p != NULL)
  1715.     {
  1716. /* Include all modes, to make ":amenu" work */
  1717. gui_add_menu_path(p, modes,
  1718. pri_tab, gui_menu_cb, map_to, noremap
  1719. #ifdef USE_GUI_WIN32
  1720. , TRUE
  1721. #endif
  1722.  );
  1723. vim_free(p);
  1724.     }
  1725. }
  1726. }
  1727. vim_free(map_buf);
  1728.     }
  1729.     /* If the menubar height changed, resize the window */
  1730.     if (gui.menu_height != old_menu_height)
  1731. gui_set_winsize(FALSE);
  1732. }
  1733. /*
  1734.  * Modify a menu name starting with "PopUp" to include the mode character.
  1735.  * Returns the name in allocated memory (NULL for failure).
  1736.  */
  1737.     static char_u *
  1738. popup_mode_name(name, idx)
  1739.     char_u *name;
  1740.     int idx;
  1741. {
  1742.     char_u *p;
  1743.     int len = STRLEN(name);
  1744.     p = vim_strnsave(name, len + 1);
  1745.     if (p != NULL)
  1746.     {
  1747. mch_memmove(p + 6, p + 5, len - 4);
  1748. p[5] = MENU_MODE_CHARS[idx];
  1749.     }
  1750.     return p;
  1751. }
  1752. /*
  1753.  * Used recursively by gui_update_menus (see below)
  1754.  */
  1755.     static void
  1756. gui_update_menus_recurse(menu, mode)
  1757.     GuiMenu *menu;
  1758.     int     mode;
  1759. {
  1760.     int     i;
  1761.     while (menu)
  1762.     {
  1763. if (menu->modes & mode)
  1764.     i = FALSE;
  1765. else
  1766.     i = TRUE;
  1767. if (vim_strchr(p_guioptions, GO_GREY) != NULL)
  1768.     gui_mch_menu_grey(menu, i);
  1769. else
  1770.     gui_mch_menu_hidden(menu, i);
  1771. gui_update_menus_recurse(menu->children, mode);
  1772. menu = menu->next;
  1773.     }
  1774. }
  1775. /*
  1776.  * Make sure only the valid menu items appear for this mode.  If
  1777.  * force_menu_update is not TRUE, then we only do this if the mode has changed
  1778.  * since last time.  If "modes" is not 0, then we use these modes instead.
  1779.  */
  1780.     void
  1781. gui_update_menus(modes)
  1782.     int     modes;
  1783. {
  1784.     static int     prev_mode = -1;
  1785.     int     mode = 0;
  1786.     if (modes != 0x0)
  1787. mode = modes;
  1788.     else
  1789.     {
  1790. mode = get_menu_mode();
  1791. if (mode == MENU_INDEX_INVALID)
  1792.     mode = 0;
  1793. else
  1794.     mode = (1 << mode);
  1795.     }
  1796.     if (force_menu_update || mode != prev_mode)
  1797.     {
  1798. gui_update_menus_recurse(gui.root_menu, mode);
  1799. gui_mch_draw_menubar();
  1800. prev_mode = mode;
  1801. force_menu_update = FALSE;
  1802.     }
  1803. }
  1804.     static int
  1805. get_menu_mode()
  1806. {
  1807.     if (VIsual_active)
  1808. return MENU_INDEX_VISUAL;
  1809.     if (State & INSERT)
  1810. return MENU_INDEX_INSERT;
  1811.     if (State & CMDLINE)
  1812. return MENU_INDEX_CMDLINE;
  1813.     if (finish_op)
  1814. return MENU_INDEX_OP_PENDING;
  1815.     if (State & NORMAL)
  1816. return MENU_INDEX_NORMAL;
  1817.     return MENU_INDEX_INVALID;
  1818. }
  1819. /*
  1820.  * Check if a key is used as a mnemonic for a toplevel menu.
  1821.  * Case of the key is ignored.
  1822.  */
  1823.     int
  1824. gui_is_menu_shortcut(key)
  1825.     int key;
  1826. {
  1827.     GuiMenu *menu;
  1828.     key = TO_LOWER(key);
  1829.     for (menu = gui.root_menu; menu != NULL; menu = menu->next)
  1830. if (TO_LOWER(menu->mnemonic) == key)
  1831.     return TRUE;
  1832.     return FALSE;
  1833. }
  1834. #if defined(USE_GUI_WIN32) || defined(PROTO)
  1835. /*
  1836.  * Deal with tearoff items that are added like a menu item.
  1837.  * Currently only for Win32 GUI.  Others may follow later.
  1838.  */
  1839.     void
  1840. gui_mch_toggle_tearoffs(int enable)
  1841. {
  1842.     int pri_tab[MENUDEPTH + 1];
  1843.     int i;
  1844.     if (enable)
  1845.     {
  1846. for (i = 0; i < MENUDEPTH; ++i)
  1847.     pri_tab[i] = 500;
  1848. pri_tab[MENUDEPTH] = -1;
  1849. gui_create_tearoffs_recurse(gui.root_menu, (char_u *)"", pri_tab, 0);
  1850.     }
  1851.     else
  1852. gui_destroy_tearoffs_recurse(gui.root_menu);
  1853.     s_tearoffs = enable;
  1854. }
  1855. /*
  1856.  * Recursively add tearoff items
  1857.  */
  1858.     static void
  1859. gui_create_tearoffs_recurse(menu, pname, pri_tab, pri_idx)
  1860.     GuiMenu *menu;
  1861.     const char_u *pname;
  1862.     int *pri_tab;
  1863.     int pri_idx;
  1864. {
  1865.     char_u *newpname = NULL;
  1866.     int len;
  1867.     char_u *s;
  1868.     char_u *d;
  1869.     if (pri_tab[pri_idx + 1] != -1)
  1870. ++pri_idx;
  1871.     while (menu != NULL)
  1872.     {
  1873. if (menu->children != NULL && gui_menubar_menu(menu->name))
  1874. {
  1875.     /* Add the menu name to the menu path.  Insert a backslash before
  1876.      * dots (it's used to separate menu names). */
  1877.     len = STRLEN(pname) + STRLEN(menu->name);
  1878.     for (s = menu->name; *s; ++s)
  1879. if (*s == '.' || *s == '\')
  1880.     ++len;
  1881.     newpname = alloc(len + TEAR_LEN + 2);
  1882.     if (newpname != NULL)
  1883.     {
  1884. STRCPY(newpname, pname);
  1885. d = newpname + STRLEN(newpname);
  1886. for (s = menu->name; *s; ++s)
  1887. {
  1888.     if (*s == '.' || *s == '\')
  1889. *d++ = '\';
  1890.     *d++ = *s;
  1891. }
  1892. *d = NUL;
  1893. /* check if tearoff already exists */
  1894. if (STRCMP(menu->children->name, TEAR_STRING) != 0)
  1895. {
  1896.     gui_add_tearoff(newpname, pri_tab, pri_idx - 1);
  1897.     *d = NUL; /* remove TEAR_STRING */
  1898. }
  1899. STRCAT(newpname, ".");
  1900. gui_create_tearoffs_recurse(menu->children, newpname,
  1901.     pri_tab, pri_idx);
  1902. vim_free(newpname);
  1903.     }
  1904. }
  1905. menu = menu->next;
  1906.     }
  1907. }
  1908. /*
  1909.  * Add tear-off menu item for a submenu.
  1910.  * "tearpath" is the menu path, and must have room to add TEAR_STRING.
  1911.  */
  1912.     static void
  1913. gui_add_tearoff(tearpath, pri_tab, pri_idx)
  1914.     char_u *tearpath;
  1915.     int *pri_tab;
  1916.     int pri_idx;
  1917. {
  1918.     char_u *tbuf;
  1919.     int t;
  1920.     tbuf = alloc(5 + STRLEN(tearpath));
  1921.     if (tbuf != NULL)
  1922.     {
  1923. tbuf[0] = K_SPECIAL;
  1924. tbuf[1] = K_SECOND(K_TEAROFF);
  1925. tbuf[2] = K_THIRD(K_TEAROFF);
  1926. STRCPY(tbuf + 3, tearpath);
  1927. STRCAT(tbuf + 3, "r");
  1928. STRCAT(tearpath, ".");
  1929. STRCAT(tearpath, TEAR_STRING);
  1930. /* Priority of tear-off is always 1 */
  1931. t = pri_tab[pri_idx + 1];
  1932. pri_tab[pri_idx + 1] = 1;
  1933. gui_add_menu_path(tearpath, MENU_ALL_MODES, pri_tab,
  1934. gui_menu_cb, tbuf, TRUE, FALSE);
  1935. gui_add_menu_path(tearpath, MENU_TIP_MODE, pri_tab,
  1936. gui_menu_cb, (char_u *)"Tear off this menu", TRUE, FALSE);
  1937. pri_tab[pri_idx + 1] = t;
  1938. vim_free(tbuf);
  1939.     }
  1940. }
  1941. /*
  1942.  * Recursively destroy tearoff items
  1943.  */
  1944.     static void
  1945. gui_destroy_tearoffs_recurse(menu)
  1946.     GuiMenu *menu;
  1947. {
  1948.     GuiMenu *oldmenu;
  1949.     while (menu)
  1950.     {
  1951. if (menu->children)
  1952. {
  1953.     /* check if tearoff exists */
  1954.     if ( STRCMP(menu->children->name, TEAR_STRING) == 0)
  1955.     {
  1956. /* Disconnect the item */
  1957. oldmenu = menu->children;
  1958. menu->children = oldmenu->next;
  1959. /* Free the memory */
  1960. gui_free_menu(oldmenu);
  1961.     }
  1962.     if (menu->children != NULL) /* might have been last one */
  1963. gui_destroy_tearoffs_recurse(menu->children);
  1964. }
  1965. menu = menu->next;
  1966.     }
  1967. }
  1968. #endif /*USE_GUI_WIN32*/
  1969. /*
  1970.  * Add the menu with the given name to the menu hierarchy
  1971.  */
  1972.     static int
  1973. gui_add_menu_path(menu_path, modes, pri_tab, call_back, call_data, noremap
  1974. #ifdef USE_GUI_WIN32
  1975. , addtearoff
  1976. #endif
  1977. )
  1978.     char_u *menu_path;
  1979.     int modes;
  1980.     int *pri_tab;
  1981.     void (*call_back)();
  1982.     char_u *call_data;
  1983.     int noremap;
  1984. #ifdef USE_GUI_WIN32
  1985.     int addtearoff; /* may add tearoff item */
  1986. #endif
  1987. {
  1988.     char_u *path_name;
  1989.     GuiMenu **menup;
  1990.     GuiMenu *menu = NULL;
  1991.     GuiMenu *parent;
  1992.     GuiMenu **lower_pri;
  1993.     char_u *p;
  1994.     char_u *name;
  1995.     char_u *dname;
  1996.     char_u *next_name;
  1997.     int i;
  1998.     int c;
  1999.     int idx, new_idx;
  2000.     int pri_idx = 0;
  2001.     int old_modes = 0;
  2002.     int amenu;
  2003.     /* Make a copy so we can stuff around with it, since it could be const */
  2004.     path_name = vim_strsave(menu_path);
  2005.     if (path_name == NULL)
  2006. return FAIL;
  2007.     menup = &gui.root_menu;
  2008.     parent = NULL;
  2009.     name = path_name;
  2010.     while (*name)
  2011.     {
  2012. /* Get name of this element in the menu hierarchy, and the simplified
  2013.  * name (without mnemonic and accelerator text). */
  2014. next_name = gui_menu_name_skip(name);
  2015. dname = gui_menu_text(name, NULL, NULL);
  2016. /* See if it's already there */
  2017. lower_pri = menup;
  2018. idx = 0;
  2019. new_idx = 0;
  2020. menu = *menup;
  2021. while (menu != NULL)
  2022. {
  2023.     if (menu_name_equal(name, menu) || menu_name_equal(dname, menu))
  2024.     {
  2025. if (*next_name == NUL && menu->children != NULL)
  2026. {
  2027.     if (!gui_sys_menu)
  2028. EMSG("Menu path must not lead to a sub-menu");
  2029.     vim_free(path_name);
  2030.     vim_free(dname);
  2031.     return FAIL;
  2032. }
  2033. if (*next_name != NUL && menu->children == NULL
  2034. #ifdef USE_GUI_WIN32
  2035. && addtearoff
  2036. #endif
  2037. )
  2038. {
  2039.     if (!gui_sys_menu)
  2040. EMSG("Part of menu-item path is not sub-menu");
  2041.     vim_free(path_name);
  2042.     vim_free(dname);
  2043.     return FAIL;
  2044. }
  2045. break;
  2046.     }
  2047.     menup = &menu->next;
  2048.     /* Count menus, to find where this one needs to be inserted.
  2049.      * Ignore menus that are not in the menubar (PopUp and Toolbar) */
  2050.     if (parent != NULL || gui_menubar_menu(menu->name))
  2051.     {
  2052. ++idx;
  2053. if (menu->priority <= pri_tab[pri_idx])
  2054. {
  2055.     lower_pri = menup;
  2056.     new_idx = idx;
  2057. }
  2058.     }
  2059.     menu = menu->next;
  2060. }
  2061. if (menu == NULL)
  2062. {
  2063.     if (*next_name == NUL && parent == NULL)
  2064.     {
  2065. EMSG("Must not add menu items directly to menu bar");
  2066. vim_free(path_name);
  2067. vim_free(dname);
  2068. return FAIL;
  2069.     }
  2070.     /* Not already there, so lets add it */
  2071.     menu = (GuiMenu *)alloc_clear(sizeof(GuiMenu));
  2072.     if (menu == NULL)
  2073.     {
  2074. vim_free(path_name);
  2075. vim_free(dname);
  2076. return FAIL;
  2077.     }
  2078.     menu->modes = modes;
  2079.     menu->name = vim_strsave(name);
  2080.     /* separate mnemonic and accelerator text from actual menu name */
  2081.     menu->dname = gui_menu_text(name, &menu->mnemonic, &menu->actext);
  2082.     menu->priority = pri_tab[pri_idx];
  2083.     /*
  2084.      * Add after menu that has lower priority.
  2085.      */
  2086.     menu->next = *lower_pri;
  2087.     *lower_pri = menu;
  2088.     if (gui.in_use)  /* Otherwise it will be added when GUI starts */
  2089.     {
  2090. if (*next_name == NUL)
  2091. {
  2092.     /* Real menu item, not sub-menu */
  2093.     gui_mch_add_menu_item(menu, parent, new_idx);
  2094.     /* Want to update menus now even if mode not changed */
  2095.     force_menu_update = TRUE;
  2096. }
  2097. else
  2098. {
  2099.     /* Sub-menu (not at end of path yet) */
  2100.     gui_mch_add_menu(menu, parent, new_idx);
  2101. }
  2102.     }
  2103. #ifdef USE_GUI_WIN32
  2104.     /* When adding a new submenu, may add a tearoff item */
  2105.     if ( addtearoff
  2106.     && *next_name
  2107.     && vim_strchr(p_guioptions, GO_TEAROFF) != NULL
  2108.     && gui_menubar_menu(name))
  2109.     {
  2110. char_u *tearpath;
  2111. /*
  2112.  * The pointers next_name & path_name refer to a string with
  2113.  * 's and ^V's stripped out. But menu_path is a "raw"
  2114.  * string, so we must correct for special characters.
  2115.  */
  2116. tearpath = alloc(STRLEN(menu_path) + TEAR_LEN + 2);
  2117. if (tearpath != NULL)
  2118. {
  2119.     char_u  *s;
  2120.     int     idx;
  2121.     STRCPY(tearpath, menu_path);
  2122.     idx = next_name - path_name - 1;
  2123.     for (s = tearpath; *s && s < tearpath + idx; ++s)
  2124. if ((*s == '\' || *s == Ctrl('V')) && s[1])
  2125. {
  2126.     ++idx;
  2127.     ++s;
  2128. }
  2129.     tearpath[idx] = NUL;
  2130.     gui_add_tearoff(tearpath, pri_tab, pri_idx);
  2131.     vim_free(tearpath);
  2132. }
  2133.     }
  2134. #endif
  2135.     old_modes = 0;
  2136. }
  2137. else
  2138. {
  2139.     old_modes = menu->modes;
  2140.     /*
  2141.      * If this menu option was previously only available in other
  2142.      * modes, then make sure it's available for this one now
  2143.      */
  2144. #ifdef USE_GUI_WIN32
  2145.     /* If adding a tearbar (addtearoff == FALSE) don't update modes */
  2146.     if (addtearoff)
  2147. #endif
  2148. menu->modes |= modes;
  2149. }
  2150. menup = &menu->children;
  2151. parent = menu;
  2152. name = next_name;
  2153. vim_free(dname);
  2154. if (pri_tab[pri_idx + 1] != -1)
  2155.     ++pri_idx;
  2156.     }
  2157.     vim_free(path_name);
  2158.     /*
  2159.      * Only add system menu items which have not been defined yet.
  2160.      * First check if this was an ":amenu".
  2161.      */
  2162.     amenu = ((modes & (MENU_NORMAL_MODE | MENU_INSERT_MODE)) ==
  2163.        (MENU_NORMAL_MODE | MENU_INSERT_MODE));
  2164.     if (gui_sys_menu)
  2165. modes &= ~old_modes;
  2166.     if (menu != NULL && modes)
  2167.     {
  2168. menu->cb = call_back;
  2169. p = (call_data == NULL) ? NULL : vim_strsave(call_data);
  2170. /* loop over all modes, may add more than one */
  2171. for (i = 0; i < MENU_MODES; ++i)
  2172. {
  2173.     if (modes & (1 << i))
  2174.     {
  2175. /* free any old menu */
  2176. gui_free_menu_string(menu, i);
  2177. /* For "amenu", may insert an extra character */
  2178. /* Don't do this if adding a tearbar (addtearoff == FALSE) */
  2179. c = 0;
  2180. if (amenu
  2181. #ifdef USE_GUI_WIN32
  2182.        && addtearoff
  2183. #endif
  2184.        )
  2185. {
  2186.     switch (1 << i)
  2187.     {
  2188. case MENU_VISUAL_MODE:
  2189. case MENU_OP_PENDING_MODE:
  2190. case MENU_CMDLINE_MODE:
  2191.     c = Ctrl('C');
  2192.     break;
  2193. case MENU_INSERT_MODE:
  2194.     c = Ctrl('O');
  2195.     break;
  2196.     }
  2197. }
  2198. if (c)
  2199. {
  2200.     menu->strings[i] = alloc((unsigned)(STRLEN(call_data) + 2));
  2201.     if (menu->strings[i] != NULL)
  2202.     {
  2203. menu->strings[i][0] = c;
  2204. STRCPY(menu->strings[i] + 1, call_data);
  2205.     }
  2206. }
  2207. else
  2208.     menu->strings[i] = p;
  2209. menu->noremap[i] = noremap;
  2210.     }
  2211. }
  2212.     }
  2213.     return OK;
  2214. }
  2215. /*
  2216.  * Remove the (sub)menu with the given name from the menu hierarchy
  2217.  * Called recursively.
  2218.  */
  2219.     static int
  2220. gui_remove_menu(menup, name, modes, silent)
  2221.     GuiMenu **menup;
  2222.     char_u *name;
  2223.     int modes;
  2224.     int silent; /* don't give error messages */
  2225. {
  2226.     GuiMenu *menu;
  2227.     GuiMenu *child;
  2228.     char_u *p;
  2229.     if (*menup == NULL)
  2230. return OK; /* Got to bottom of hierarchy */
  2231.     /* Get name of this element in the menu hierarchy */
  2232.     p = gui_menu_name_skip(name);
  2233.     /* Find the menu */
  2234.     menu = *menup;
  2235.     while (menu != NULL)
  2236.     {
  2237. if (*name == NUL || menu_name_equal(name, menu))
  2238. {
  2239.     if (*p != NUL && menu->children == NULL)
  2240.     {
  2241. if (!silent)
  2242.     EMSG("Part of menu-item path is not sub-menu");
  2243. return FAIL;
  2244.     }
  2245.     if ((menu->modes & modes) != 0x0)
  2246.     {
  2247. if (gui_remove_menu(&menu->children, p, modes, silent) == FAIL)
  2248.     return FAIL;
  2249.     }
  2250.     else if (*name != NUL)
  2251.     {
  2252. if (!silent)
  2253.     EMSG("Menu only exists in another mode");
  2254. return FAIL;
  2255.     }
  2256.     /*
  2257.      * When name is empty, we are removing all menu items for the given
  2258.      * modes, so keep looping, otherwise we are just removing the named
  2259.      * menu item (which has been found) so break here.
  2260.      */
  2261.     if (*name != NUL)
  2262. break;
  2263.     /* Remove the menu item for the given mode[s] */
  2264.     menu->modes &= ~modes;
  2265.     if (modes & MENU_TIP_MODE)
  2266. gui_free_menu_string(menu, MENU_INDEX_TIP);
  2267.     if ((menu->modes & MENU_ALL_MODES) == 0)
  2268.     {
  2269. /* The menu item is no longer valid in ANY mode, so delete it */
  2270. *menup = menu->next;
  2271. gui_free_menu(menu);
  2272.     }
  2273.     else
  2274. menup = &menu->next;
  2275. }
  2276. else
  2277.     menup = &menu->next;
  2278. menu = *menup;
  2279.     }
  2280.     if (*name != NUL)
  2281.     {
  2282. if (menu == NULL)
  2283. {
  2284.     if (!silent)
  2285. EMSG("No menu of that name");
  2286.     return FAIL;
  2287. }
  2288. /* Recalculate modes for menu based on the new updated children */
  2289. menu->modes &= ~modes;
  2290. #ifdef USE_GUI_WIN32
  2291. if ((s_tearoffs) && (menu->children != NULL)) /* there's a tear bar.. */
  2292.     child = menu->children->next; /* don't count tearoff bar */
  2293. else
  2294. #endif
  2295.     child = menu->children;
  2296. for ( ; child != NULL; child = child->next)
  2297.     menu->modes |= child->modes;
  2298. if (modes & MENU_TIP_MODE)
  2299.     gui_free_menu_string(menu, MENU_INDEX_TIP);
  2300. if ((menu->modes & MENU_ALL_MODES) == 0)
  2301. {
  2302.     /* The menu item is no longer valid in ANY mode, so delete it */
  2303. #ifdef USE_GUI_WIN32
  2304.     if ((s_tearoffs) && (menu->children != NULL)) /* there's a tear bar.. */
  2305. gui_free_menu(menu->children);
  2306. #endif
  2307.     *menup = menu->next;
  2308.     gui_free_menu(menu);
  2309. }
  2310.     }
  2311.     return OK;
  2312. }
  2313. /*
  2314.  * Free the given menu structure
  2315.  */
  2316.     static void
  2317. gui_free_menu(menu)
  2318.     GuiMenu *menu;
  2319. {
  2320.     int     i;
  2321.     /* Free machine specific menu structures (only when already created) */
  2322.     if (gui.in_use)
  2323. gui_mch_destroy_menu(menu);
  2324.     vim_free(menu->name);
  2325.     vim_free(menu->dname);
  2326.     vim_free(menu->actext);
  2327.     for (i = 0; i < MENU_MODES; i++)
  2328. gui_free_menu_string(menu, i);
  2329.     vim_free(menu);
  2330.     /* Want to update menus now even if mode not changed */
  2331.     force_menu_update = TRUE;
  2332. }
  2333. /*
  2334.  * Free the menu->string with the given index.
  2335.  */
  2336.     static void
  2337. gui_free_menu_string(menu, idx)
  2338.     GuiMenu *menu;
  2339.     int     idx;
  2340. {
  2341.     int     count = 0;
  2342.     int     i;
  2343.     for (i = 0; i < MENU_MODES; i++)
  2344. if (menu->strings[i] == menu->strings[idx])
  2345.     count++;
  2346.     if (count == 1)
  2347. vim_free(menu->strings[idx]);
  2348.     menu->strings[idx] = NULL;
  2349. }
  2350. /*
  2351.  * Show the mapping associated with a menu item or hierarchy in a sub-menu.
  2352.  */
  2353.     static int
  2354. gui_show_menus(path_name, modes)
  2355.     char_u  *path_name;
  2356.     int     modes;
  2357. {
  2358.     char_u  *p;
  2359.     char_u  *name;
  2360.     GuiMenu *menu;
  2361.     GuiMenu *parent = NULL;
  2362.     menu = gui.root_menu;
  2363.     name = path_name = vim_strsave(path_name);
  2364.     if (path_name == NULL)
  2365. return FAIL;
  2366.     /* First, find the (sub)menu with the given name */
  2367.     while (*name)
  2368.     {
  2369. p = gui_menu_name_skip(name);
  2370. while (menu != NULL)
  2371. {
  2372.     if (menu_name_equal(name, menu))
  2373.     {
  2374. /* Found menu */
  2375. if (*p != NUL && menu->children == NULL)
  2376. {
  2377.     EMSG("Part of menu-item path is not sub-menu");
  2378.     vim_free(path_name);
  2379.     return FAIL;
  2380. }
  2381. else if ((menu->modes & modes) == 0x0)
  2382. {
  2383.     EMSG("Menu only exists in another mode");
  2384.     vim_free(path_name);
  2385.     return FAIL;
  2386. }
  2387. break;
  2388.     }
  2389.     menu = menu->next;
  2390. }
  2391. if (menu == NULL)
  2392. {
  2393.     EMSG("No menu of that name");
  2394.     vim_free(path_name);
  2395.     return FAIL;
  2396. }
  2397. name = p;
  2398. parent = menu;
  2399. menu = menu->children;
  2400.     }
  2401.     /* Now we have found the matching menu, and we list the mappings */
  2402.     /* Highlight title */
  2403.     MSG_PUTS_TITLE("n--- Menus ---");
  2404.     gui_show_menus_recursive(parent, modes, 0);
  2405.     return OK;
  2406. }
  2407. /*
  2408.  * Recursively show the mappings associated with the menus under the given one
  2409.  */
  2410.     static void
  2411. gui_show_menus_recursive(menu, modes, depth)
  2412.     GuiMenu *menu;
  2413.     int     modes;
  2414.     int     depth;
  2415. {
  2416.     int     i;
  2417.     int     bit;
  2418.     if (menu != NULL && (menu->modes & modes) == 0x0)
  2419. return;
  2420.     if (menu != NULL)
  2421.     {
  2422. msg_putchar('n');
  2423. if (got_int) /* "q" hit for "--more--" */
  2424.     return;
  2425. for (i = 0; i < depth; i++)
  2426.     MSG_PUTS("  ");
  2427. if (menu->priority)
  2428. {
  2429.     msg_outnum((long)menu->priority);
  2430.     MSG_PUTS(" ");
  2431. }
  2432. /* Same highlighting as for directories!? */
  2433. msg_puts_attr(menu->name, hl_attr(HLF_D));
  2434.     }
  2435.     if (menu != NULL && menu->children == NULL)
  2436.     {
  2437. for (bit = 0; bit < MENU_MODES; bit++)
  2438.     if ((menu->modes & modes & (1 << bit)) != 0)
  2439.     {
  2440. msg_putchar('n');
  2441. if (got_int) /* "q" hit for "--more--" */
  2442.     return;
  2443. for (i = 0; i < depth + 2; i++)
  2444.     MSG_PUTS("  ");
  2445. msg_putchar(MENU_MODE_CHARS[bit]);
  2446. if (menu->noremap[bit])
  2447.     msg_putchar('*');
  2448. else
  2449.     msg_putchar(' ');
  2450. MSG_PUTS("  ");
  2451. msg_outtrans_special(menu->strings[bit], TRUE);
  2452.     }
  2453.     }
  2454.     else
  2455.     {
  2456. if (menu == NULL)
  2457. {
  2458.     menu = gui.root_menu;
  2459.     depth--;
  2460. }
  2461. else
  2462.     menu = menu->children;
  2463. /* recursively show all children.  Skip PopUp[nvoci]. */
  2464. for (; menu != NULL && !got_int; menu = menu->next)
  2465.     if (!gui_popup_menu(menu->dname) || menu->dname[5] == NUL)
  2466. gui_show_menus_recursive(menu, modes, depth + 1);
  2467.     }
  2468. }
  2469. /*
  2470.  * Used when expanding menu names.
  2471.  */
  2472. static GuiMenu *expand_menu = NULL;
  2473. static int expand_modes = 0x0;
  2474. /*
  2475.  * Work out what to complete when doing command line completion of menu names.
  2476.  */
  2477.     char_u *
  2478. gui_set_context_in_menu_cmd(cmd, arg, forceit)
  2479.     char_u  *cmd;
  2480.     char_u  *arg;
  2481.     int     forceit;
  2482. {
  2483.     char_u  *after_dot;
  2484.     char_u  *p;
  2485.     char_u  *path_name = NULL;
  2486.     char_u  *name;
  2487.     int     unmenu;
  2488.     GuiMenu *menu;
  2489.     expand_context = EXPAND_UNSUCCESSFUL;
  2490.     after_dot = arg;
  2491.     for (p = arg; *p && !vim_iswhite(*p); ++p)
  2492.     {
  2493. if ((*p == '\' || *p == Ctrl('V')) && p[1] != NUL)
  2494.     p++;
  2495. else if (*p == '.')
  2496.     after_dot = p + 1;
  2497.     }
  2498.     if (*p == NUL) /* Complete the menu name */
  2499.     {
  2500. /*
  2501.  * With :unmenu, you only want to match menus for the appropriate mode.
  2502.  * With :menu though you might want to add a menu with the same name as
  2503.  * one in another mode, so match menus fom other modes too.
  2504.  */
  2505. expand_modes = gui_get_menu_cmd_modes(cmd, forceit, NULL, &unmenu);
  2506. if (!unmenu)
  2507.     expand_modes = MENU_ALL_MODES;
  2508. menu = gui.root_menu;
  2509. if (after_dot != arg)
  2510. {
  2511.     path_name = alloc(after_dot - arg);
  2512.     if (path_name == NULL)
  2513. return NULL;
  2514.     STRNCPY(path_name, arg, after_dot - arg - 1);
  2515.     path_name[after_dot - arg - 1] = NUL;
  2516. }
  2517. name = path_name;
  2518. while (name != NULL && *name)
  2519. {
  2520.     p = gui_menu_name_skip(name);
  2521.     while (menu != NULL)
  2522.     {
  2523. if (menu_name_equal(name, menu))
  2524. {
  2525.     /* Found menu */
  2526.     if ((*p != NUL && menu->children == NULL)
  2527. || ((menu->modes & expand_modes) == 0x0))
  2528.     {
  2529. /*
  2530.  * Menu path continues, but we have reached a leaf.
  2531.  * Or menu exists only in another mode.
  2532.  */
  2533. vim_free(path_name);
  2534. return NULL;
  2535.     }
  2536.     break;
  2537. }
  2538. menu = menu->next;
  2539.     }
  2540.     if (menu == NULL)
  2541.     {
  2542. /* No menu found with the name we were looking for */
  2543. vim_free(path_name);
  2544. return NULL;
  2545.     }
  2546.     name = p;
  2547.     menu = menu->children;
  2548. }
  2549. expand_context = EXPAND_MENUS;
  2550. expand_pattern = after_dot;
  2551. expand_menu = menu;
  2552.     }
  2553.     else /* We're in the mapping part */
  2554. expand_context = EXPAND_NOTHING;
  2555.     return NULL;
  2556. }
  2557. /*
  2558.  * Function given to ExpandGeneric() to obtain the list of group names.
  2559.  */
  2560.     char_u *
  2561. get_menu_name(idx)
  2562.     int     idx;
  2563. {
  2564.     static GuiMenu  *menu = NULL;
  2565.     static int     get_dname = FALSE; /* return menu->dname next time */
  2566.     char_u     *str;
  2567.     if (idx == 0)     /* first call: start at first item */
  2568.     {
  2569. menu = expand_menu;
  2570. get_dname = FALSE;
  2571.     }
  2572.     /* Skip PopUp[nvoci]. */
  2573.     while (menu != NULL && gui_popup_menu(menu->dname) && menu->dname[5])
  2574. menu = menu->next;
  2575.     if (menu == NULL)     /* at end of linked list */
  2576. return NULL;
  2577.     if (menu->modes & expand_modes)
  2578.     {
  2579. if (get_dname)
  2580. {
  2581.     str = menu->dname;
  2582.     get_dname = FALSE;
  2583. }
  2584. else
  2585. {
  2586.     str = menu->name;
  2587.     if (STRCMP(menu->name, menu->dname))
  2588. get_dname = TRUE;
  2589. }
  2590.     }
  2591.     else
  2592.     {
  2593. str = (char_u *)"";
  2594. get_dname = FALSE;
  2595.     }
  2596.     /* Advance to next menu entry. */
  2597.     if (!get_dname)
  2598. menu = menu->next;
  2599.     return str;
  2600. }
  2601. /*
  2602.  * Skip over this element of the menu path and return the start of the next
  2603.  * element.  Any  and ^Vs are removed from the current element.
  2604.  */
  2605.     char_u *
  2606. gui_menu_name_skip(name)
  2607.     char_u  *name;
  2608. {
  2609.     char_u  *p;
  2610.     for (p = name; *p && *p != '.'; p++)
  2611. if (*p == '\' || *p == Ctrl('V'))
  2612. {
  2613.     mch_memmove(p, p + 1, STRLEN(p));
  2614.     if (*p == NUL)
  2615. break;
  2616. }
  2617.     if (*p)
  2618. *p++ = NUL;
  2619.     return p;
  2620. }
  2621. /*
  2622.  * Return TRUE when "name" matches with menu "menu".  The name is compared in
  2623.  * two ways: raw menu name and menu name without '&'.  ignore part after a TAB.
  2624.  */
  2625.     static int
  2626. menu_name_equal(name, menu)
  2627.     char_u *name;
  2628.     GuiMenu *menu;
  2629. {
  2630.     return (menu_namecmp(name, menu->name) || menu_namecmp(name, menu->dname));
  2631. }
  2632.     static int
  2633. menu_namecmp(name, mname)
  2634.     char_u *name;
  2635.     char_u *mname;
  2636. {
  2637.     int i;
  2638.     for (i = 0; name[i] != NUL && name[i] != TAB; ++i)
  2639. if (name[i] != mname[i])
  2640.     break;
  2641.     return ((name[i] == NUL || name[i] == TAB)
  2642.     && (mname[i] == NUL || mname[i] == TAB));
  2643. }
  2644. /*
  2645.  * After we have started the GUI, then we can create any menus that have been
  2646.  * defined.  This is done once here.  gui_add_menu_path() may have already been
  2647.  * called to define these menus, and may be called again.  This function calls
  2648.  * itself recursively. Should be called at the top level with:
  2649.  * gui_create_initial_menus(gui.root_menu, NULL);
  2650.  */
  2651.     static void
  2652. gui_create_initial_menus(menu, parent)
  2653.     GuiMenu *menu;
  2654.     GuiMenu *parent;
  2655. {
  2656.     int idx = 0;
  2657.     while (menu)
  2658.     {
  2659. if (menu->children != NULL)
  2660. {
  2661.     gui_mch_add_menu(menu, parent, idx);
  2662.     gui_create_initial_menus(menu->children, menu);
  2663. }
  2664. else
  2665.     gui_mch_add_menu_item(menu, parent, idx);
  2666. menu = menu->next;
  2667. ++idx;
  2668.     }
  2669. }
  2670. /*
  2671.  * Set which components are present.
  2672.  * If "oldval" is not NULL, "oldval" is the previous value, the new * value is
  2673.  * in p_guioptions.
  2674.  */
  2675.     void
  2676. gui_init_which_components(oldval)
  2677.     char_u  *oldval;
  2678. {
  2679.     static int prev_which_scrollbars[3] = {-1, -1, -1};
  2680.     static int prev_menu_is_active = -1;
  2681. #ifdef USE_GUI_WIN32_TOOLBAR
  2682.     static int prev_toolbar = -1;
  2683.     int using_toolbar = FALSE;
  2684. #endif
  2685.     static int prev_tearoff = -1;
  2686.     int using_tearoff = FALSE;
  2687.     char_u  *p;
  2688.     int     i;
  2689.     int     grey_old, grey_new;
  2690.     char_u  *temp;
  2691.     WIN     *wp;
  2692.     int     need_winsize;
  2693.     if (oldval != NULL && gui.in_use)
  2694.     {
  2695. /*
  2696.  * Check if the menu's go from grey to non-grey or vise versa.
  2697.  */
  2698. grey_old = (vim_strchr(oldval, GO_GREY) != NULL);
  2699. grey_new = (vim_strchr(p_guioptions, GO_GREY) != NULL);
  2700. if (grey_old != grey_new)
  2701. {
  2702.     temp = p_guioptions;
  2703.     p_guioptions = oldval;
  2704.     gui_update_menus(MENU_ALL_MODES);
  2705.     p_guioptions = temp;
  2706. }
  2707.     }
  2708.     gui.menu_is_active = FALSE;
  2709.     for (i = 0; i < 3; i++)
  2710. gui.which_scrollbars[i] = FALSE;
  2711.     for (p = p_guioptions; *p; p++)
  2712. switch (*p)
  2713. {
  2714.     case GO_LEFT:
  2715. gui.which_scrollbars[SBAR_LEFT] = TRUE;
  2716. break;
  2717.     case GO_RIGHT:
  2718. gui.which_scrollbars[SBAR_RIGHT] = TRUE;
  2719. break;
  2720.     case GO_BOT:
  2721. gui.which_scrollbars[SBAR_BOTTOM] = TRUE;
  2722. break;
  2723.     case GO_MENUS:
  2724. gui.menu_is_active = TRUE;
  2725. break;
  2726.     case GO_GREY:
  2727. /* make menu's have grey items, ignored here */
  2728. break;
  2729. #ifdef USE_GUI_WIN32_TOOLBAR
  2730.     case GO_TOOLBAR:
  2731. using_toolbar = TRUE;
  2732. break;
  2733. #endif
  2734.     case GO_TEAROFF:
  2735. using_tearoff = TRUE;
  2736. break;
  2737.     default:
  2738. /* Should give error message for internal error */
  2739. break;
  2740. }
  2741.     if (gui.in_use)
  2742.     {
  2743. need_winsize = FALSE;
  2744. for (i = 0; i < 3; i++)
  2745. {
  2746.     if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
  2747.     {
  2748. if (i == SBAR_BOTTOM)
  2749. {
  2750.     gui_mch_enable_scrollbar(&gui.bottom_sbar,
  2751.      gui.which_scrollbars[i]);
  2752. }
  2753. else
  2754. {
  2755.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  2756. gui_mch_enable_scrollbar(&wp->w_scrollbars[i],
  2757.  gui.which_scrollbars[i]);
  2758. }
  2759. need_winsize = TRUE;
  2760.     }
  2761.     prev_which_scrollbars[i] = gui.which_scrollbars[i];
  2762. }
  2763. if (gui.menu_is_active != prev_menu_is_active)
  2764. {
  2765.     gui_mch_enable_menu(gui.menu_is_active);
  2766.     prev_menu_is_active = gui.menu_is_active;
  2767.     need_winsize = TRUE;
  2768. }
  2769. #ifdef USE_GUI_WIN32_TOOLBAR
  2770. if (using_toolbar != prev_toolbar)
  2771. {
  2772.     gui_mch_show_toolbar(using_toolbar);
  2773.     prev_toolbar = using_toolbar;
  2774.     need_winsize = TRUE;
  2775. }
  2776. #endif
  2777. if (using_tearoff != prev_tearoff)
  2778. {
  2779.     gui_mch_toggle_tearoffs(using_tearoff);
  2780.     prev_tearoff = using_tearoff;
  2781. }
  2782. if (need_winsize)
  2783.     gui_set_winsize(FALSE);
  2784.     }
  2785. }
  2786. /*
  2787.  * Scrollbar stuff:
  2788.  */
  2789.     void
  2790. gui_create_scrollbar(sb, wp)
  2791.     GuiScrollbar    *sb;
  2792.     WIN     *wp;
  2793. {
  2794.     static int sbar_ident = 0;
  2795.     int     which;
  2796.     sb->ident = sbar_ident++; /* No check for too big, but would it happen? */
  2797.     sb->wp = wp;
  2798.     sb->value = -1;
  2799.     sb->pixval = -1;
  2800.     sb->size = -1;
  2801.     sb->max = -1;
  2802.     sb->top = -1;
  2803.     sb->height = -1;
  2804.     sb->status_height = -1;
  2805.     gui_mch_create_scrollbar(sb, (wp == NULL) ? SBAR_HORIZ : SBAR_VERT);
  2806.     if (wp != NULL)
  2807.     {
  2808. which = (sb == &wp->w_scrollbars[SBAR_LEFT]) ? SBAR_LEFT : SBAR_RIGHT;
  2809. gui_mch_enable_scrollbar(sb, gui.which_scrollbars[which]);
  2810.     }
  2811. }
  2812. /*
  2813.  * Find the scrollbar with the given index.
  2814.  */
  2815.     GuiScrollbar *
  2816. gui_find_scrollbar(ident)
  2817.     long ident;
  2818. {
  2819.     WIN     *wp;
  2820.     if (gui.bottom_sbar.ident == ident)
  2821. return &gui.bottom_sbar;
  2822.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  2823.     {
  2824. if (wp->w_scrollbars[SBAR_LEFT].ident == ident)
  2825.     return &wp->w_scrollbars[SBAR_LEFT];
  2826. if (wp->w_scrollbars[SBAR_RIGHT].ident == ident)
  2827.     return &wp->w_scrollbars[SBAR_RIGHT];
  2828.     }
  2829.     return NULL;
  2830. }
  2831.     void
  2832. gui_drag_scrollbar(sb, value, still_dragging)
  2833.     GuiScrollbar    *sb;
  2834.     long     value;
  2835.     int     still_dragging;
  2836. {
  2837.     char_u bytes[4 + sizeof(long_u)];
  2838.     WIN *wp;
  2839.     int sb_num;
  2840.     int byte_count;
  2841.     if (sb == NULL)
  2842. return;
  2843.     /*
  2844.      * Ignore the scrollbars while executing an external command.
  2845.      */
  2846.     if (!termcap_active)
  2847. return;
  2848.     if (still_dragging)
  2849.     {
  2850. if (sb->wp == NULL)
  2851.     gui.dragged_sb = SBAR_BOTTOM;
  2852. else if (sb == &sb->wp->w_scrollbars[SBAR_LEFT])
  2853.     gui.dragged_sb = SBAR_LEFT;
  2854. else
  2855.     gui.dragged_sb = SBAR_RIGHT;
  2856. gui.dragged_wp = sb->wp;
  2857.     }
  2858.     else
  2859. gui.dragged_sb = SBAR_NONE;
  2860.     if (sb->wp != NULL)
  2861.     {
  2862. /* Vertical sbar info is kept in the first sbar (the left one) */
  2863. sb = &sb->wp->w_scrollbars[0];
  2864.     }
  2865.     /*
  2866.      * Check validity of value
  2867.      */
  2868.     if (value < 0)
  2869. value = 0;
  2870. #ifdef SCROLL_PAST_END
  2871.     else if (value > sb->max)
  2872. value = sb->max;
  2873. #else
  2874.     if (value > sb->max - sb->size + 1)
  2875. value = sb->max - sb->size + 1;
  2876. #endif
  2877.     sb->value = value;
  2878. #ifdef RIGHTLEFT
  2879.     if (sb->wp == NULL && curwin->w_p_rl)
  2880.     {
  2881. value = sb->max + 1 - sb->size - value;
  2882. if (value < 0)
  2883.     value = 0;
  2884.     }
  2885. #endif
  2886.     if (sb->wp != NULL)
  2887.     {
  2888. sb_num = 0;
  2889. for (wp = firstwin; wp != sb->wp && wp != NULL; wp = wp->w_next)
  2890.     sb_num++;
  2891. if (wp == NULL)
  2892.     return;
  2893. bytes[0] = CSI;
  2894. bytes[1] = KS_SCROLLBAR;
  2895. bytes[2] = K_FILLER;
  2896. bytes[3] = (char_u)sb_num;
  2897. byte_count = 4;
  2898.     }
  2899.     else
  2900.     {
  2901. bytes[0] = CSI;
  2902. bytes[1] = KS_HORIZ_SCROLLBAR;
  2903. bytes[2] = K_FILLER;
  2904. byte_count = 3;
  2905.     }
  2906.     add_long_to_buf((long)value, bytes + byte_count);
  2907.     add_to_input_buf(bytes, byte_count + sizeof(long_u));
  2908. }
  2909. /*
  2910.  * Scrollbar stuff:
  2911.  */
  2912.     static void
  2913. gui_update_scrollbars(force)
  2914.     int     force;     /* Force all scrollbars to get updated */
  2915. {
  2916.     WIN     *wp;
  2917.     GuiScrollbar    *sb;
  2918.     int     val, size, max;
  2919.     int     which_sb;
  2920.     int     h, y;
  2921.     /* Update the horizontal scrollbar */
  2922.     gui_update_horiz_scrollbar(force);
  2923.     /* Return straight away if there is neither a left nor right scrollbar */
  2924.     if (!gui.which_scrollbars[SBAR_LEFT] && !gui.which_scrollbars[SBAR_RIGHT])
  2925. return;
  2926.     /*
  2927.      * Don't want to update a scrollbar while we're dragging it.  But if we
  2928.      * have both a left and right scrollbar, and we drag one of them, we still
  2929.      * need to update the other one.
  2930.      */
  2931.     if (       (gui.dragged_sb == SBAR_LEFT
  2932. || gui.dragged_sb == SBAR_RIGHT)
  2933.     && (!gui.which_scrollbars[SBAR_LEFT]
  2934. || !gui.which_scrollbars[SBAR_RIGHT])
  2935.     && !force)
  2936. return;
  2937.     if (!force && (gui.dragged_sb == SBAR_LEFT || gui.dragged_sb == SBAR_RIGHT))
  2938.     {
  2939. /*
  2940.  * If we have two scrollbars and one of them is being dragged, just
  2941.  * copy the scrollbar position from the dragged one to the other one.
  2942.  */
  2943. which_sb = SBAR_LEFT + SBAR_RIGHT - gui.dragged_sb;
  2944. if (gui.dragged_wp != NULL)
  2945.     gui_mch_set_scrollbar_thumb(
  2946.     &gui.dragged_wp->w_scrollbars[which_sb],
  2947.     gui.dragged_wp->w_scrollbars[0].value,
  2948.     gui.dragged_wp->w_scrollbars[0].size,
  2949.     gui.dragged_wp->w_scrollbars[0].max);
  2950. return;
  2951.     }
  2952.     for (wp = firstwin; wp; wp = wp->w_next)
  2953.     {
  2954. if (wp->w_buffer == NULL) /* just in case */
  2955.     continue;
  2956. #ifdef SCROLL_PAST_END
  2957. max = wp->w_buffer->b_ml.ml_line_count - 1;
  2958. #else
  2959. max = wp->w_buffer->b_ml.ml_line_count + wp->w_height - 2;
  2960. #endif
  2961. if (max < 0) /* empty buffer */
  2962.     max = 0;
  2963. val = wp->w_topline - 1;
  2964. size = wp->w_height;
  2965. #ifdef SCROLL_PAST_END
  2966. if (val > max) /* just in case */
  2967.     val = max;
  2968. #else
  2969. if (size > max + 1) /* just in case */
  2970.     size = max + 1;
  2971. if (val > max - size + 1)
  2972.     val = max - size + 1;
  2973. #endif
  2974. if (val < 0) /* minimal value is 0 */
  2975.     val = 0;
  2976. /*
  2977.  * Scrollbar at index 0 (the left one) contains all the information.
  2978.  * It would be the same info for left and right so we just store it for
  2979.  * one of them.
  2980.  */
  2981. sb = &wp->w_scrollbars[0];
  2982. /*
  2983.  * Note: no check for valid w_botline. If it's not valid the
  2984.  * scrollbars will be updated later anyway.
  2985.  */
  2986. if (size < 1 || wp->w_botline - 2 > max)
  2987. {
  2988.     /*
  2989.      * This can happen during changing files.  Just don't update the
  2990.      * scrollbar for now.
  2991.      */
  2992.     sb->height = 0;     /* Force update next time */
  2993.     if (gui.which_scrollbars[SBAR_LEFT])
  2994. gui_mch_enable_scrollbar(&wp->w_scrollbars[SBAR_LEFT], FALSE);
  2995.     if (gui.which_scrollbars[SBAR_RIGHT])
  2996. gui_mch_enable_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], FALSE);
  2997.     continue;
  2998. }
  2999. if (force || sb->height != wp->w_height
  3000.     || sb->top != wp->w_winpos
  3001.     || sb->status_height != wp->w_status_height)
  3002. {
  3003.     /* Height or position of scrollbar has changed */
  3004.     sb->top = wp->w_winpos;
  3005.     sb->height = wp->w_height;
  3006.     sb->status_height = wp->w_status_height;
  3007.     /* Calculate height and position in pixels */
  3008.     h = (sb->height + sb->status_height) * gui.char_height;
  3009.     y = sb->top * gui.char_height + gui.border_offset;
  3010.     if (gui.menu_is_active)
  3011. y += gui.menu_height;
  3012. #ifdef USE_GUI_WIN32
  3013.     if (vim_strchr(p_guioptions, GO_TOOLBAR) != NULL)
  3014. y += (TOOLBAR_BUTTON_HEIGHT+12);
  3015. #endif
  3016.     if (wp == firstwin)
  3017.     {
  3018. /* Height of top scrollbar includes width of top border */
  3019. h += gui.border_offset;
  3020. y -= gui.border_offset;
  3021.     }
  3022.     if (gui.which_scrollbars[SBAR_LEFT])
  3023.     {
  3024. gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_LEFT],
  3025.   gui.left_sbar_x, y,
  3026.   gui.scrollbar_width, h);
  3027. gui_mch_enable_scrollbar(&wp->w_scrollbars[SBAR_LEFT], TRUE);
  3028.     }
  3029.     if (gui.which_scrollbars[SBAR_RIGHT])
  3030.     {
  3031. gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_RIGHT],
  3032.   gui.right_sbar_x, y,
  3033.   gui.scrollbar_width, h);
  3034. gui_mch_enable_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], TRUE);
  3035.     }
  3036. }
  3037. /* reduce the number of calls to gui_mch_set_scrollbar_thumb() by
  3038.  * checking if the thumb moved at least a pixel */
  3039. if (max == 0)
  3040.     y = 0;
  3041. else
  3042.     y = (val * (sb->height + 2) * gui.char_height + max / 2) / max;
  3043. if (force
  3044. #ifdef RISCOS
  3045. /* RISCOS does scrollbars differently - use the old check */
  3046. || sb->pixval != val
  3047. #else
  3048. || sb->pixval != y
  3049. #endif
  3050. || sb->size != size || sb->max != max)
  3051. {
  3052.     /* Thumb of scrollbar has moved */
  3053.     sb->value = val;
  3054.     sb->pixval = y;
  3055.     sb->size = size;
  3056.     sb->max = max;
  3057.     if (gui.which_scrollbars[SBAR_LEFT] && gui.dragged_sb != SBAR_LEFT)
  3058. gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_LEFT],
  3059.     val, size, max);
  3060.     if (gui.which_scrollbars[SBAR_RIGHT]
  3061. && gui.dragged_sb != SBAR_RIGHT)
  3062. gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_RIGHT],
  3063.     val, size, max);
  3064. }
  3065.     }
  3066. }
  3067. /*
  3068.  * Scroll a window according to the values set in the globals current_scrollbar
  3069.  * and scrollbar_value.  Return TRUE if the cursor in the current window moved
  3070.  * or FALSE otherwise.
  3071.  */
  3072.     int
  3073. gui_do_scroll()
  3074. {
  3075.     WIN *wp, *old_wp;
  3076.     int i;
  3077.     long nlines;
  3078.     FPOS old_cursor;
  3079.     linenr_t old_topline;
  3080.     for (wp = firstwin, i = 0; i < current_scrollbar; i++)
  3081.     {
  3082. if (wp == NULL)
  3083.     break;
  3084. wp = wp->w_next;
  3085.     }
  3086.     if (wp == NULL)
  3087.     {
  3088. /* Couldn't find window */
  3089. return FALSE;
  3090.     }
  3091.     /*
  3092.      * Compute number of lines to scroll.  If zero, nothing to do.
  3093.      */
  3094.     nlines = (long)scrollbar_value + 1 - (long)wp->w_topline;
  3095.     if (nlines == 0)
  3096. return FALSE;
  3097.     old_cursor = curwin->w_cursor;
  3098.     old_wp = curwin;
  3099.     old_topline = wp->w_topline;
  3100.     curwin = wp;
  3101.     curbuf = wp->w_buffer;
  3102.     if (nlines < 0)
  3103. scrolldown(-nlines);
  3104.     else
  3105. scrollup(nlines);
  3106.     if (old_topline != wp->w_topline)
  3107.     {
  3108. if (p_so)
  3109. {
  3110.     cursor_correct(); /* fix window for 'so' */
  3111.     update_topline(); /* avoid up/down jump */
  3112. }
  3113. coladvance(curwin->w_curswant);
  3114.     }
  3115.     curwin = old_wp;
  3116.     curbuf = old_wp->w_buffer;
  3117.     /*
  3118.      * Don't call updateWindow() when nothing has changed (it will overwrite
  3119.      * the status line!).
  3120.      */
  3121.     if (old_topline != wp->w_topline)
  3122.     {
  3123. wp->w_redr_type = VALID;
  3124. updateWindow(wp);   /* update window, status line, and cmdline */
  3125.     }
  3126.     return !equal(curwin->w_cursor, old_cursor);
  3127. }
  3128. /*
  3129.  * Horizontal scrollbar stuff:
  3130.  */
  3131.     static void
  3132. gui_update_horiz_scrollbar(force)
  3133.     int     force;
  3134. {
  3135.     int     value, size, max;
  3136.     char_u  *p;
  3137.     if (!gui.which_scrollbars[SBAR_BOTTOM])
  3138. return;
  3139.     if (!force && gui.dragged_sb == SBAR_BOTTOM)
  3140. return;
  3141.     if (!force && curwin->w_p_wrap && gui.prev_wrap)
  3142. return;
  3143.     /*
  3144.      * It is possible for the cursor to be invalid if we're in the middle of
  3145.      * something (like changing files).  If so, don't do anything for now.
  3146.      */
  3147.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3148.     {
  3149. gui.bottom_sbar.value = -1;
  3150. return;
  3151.     }
  3152.     size = Columns;
  3153.     if (curwin->w_p_wrap)
  3154.     {
  3155. value = 0;
  3156. #ifdef SCROLL_PAST_END
  3157. max = 0;
  3158. #else
  3159. max = Columns - 1;
  3160. #endif
  3161.     }
  3162.     else
  3163.     {
  3164. value = curwin->w_leftcol;
  3165. /* Calculate max for horizontal scrollbar */
  3166. p = ml_get_curline();
  3167. max = 0;
  3168. if (p != NULL && p[0] != NUL)
  3169.     while (p[1] != NUL)     /* Don't count last character */
  3170. max += chartabsize(*p++, (colnr_t)max);
  3171. #ifndef SCROLL_PAST_END
  3172. max += Columns - 1;
  3173. #endif
  3174.     }
  3175. #ifndef SCROLL_PAST_END
  3176.     if (value > max - size + 1)
  3177. value = max - size + 1;     /* limit the value to allowable range */
  3178. #endif
  3179. #ifdef RIGHTLEFT
  3180.     if (curwin->w_p_rl)
  3181.     {
  3182. value = max + 1 - size - value;
  3183. if (value < 0)
  3184. {
  3185.     size += value;
  3186.     value = 0;
  3187. }
  3188.     }
  3189. #endif
  3190.     if (!force && value == gui.bottom_sbar.value && size == gui.bottom_sbar.size
  3191. && max == gui.bottom_sbar.max)
  3192. return;
  3193.     gui.bottom_sbar.value = value;
  3194.     gui.bottom_sbar.size = size;
  3195.     gui.bottom_sbar.max = max;
  3196.     gui.prev_wrap = curwin->w_p_wrap;
  3197.     gui_mch_set_scrollbar_thumb(&gui.bottom_sbar, value, size, max);
  3198. }
  3199. /*
  3200.  * Do a horizontal scroll.  Return TRUE if the cursor moved, FALSE otherwise.
  3201.  */
  3202.     int
  3203. gui_do_horiz_scroll()
  3204. {
  3205.     /* no wrapping, no scrolling */
  3206.     if (curwin->w_p_wrap)
  3207. return FALSE;
  3208.     if (curwin->w_leftcol == scrollbar_value)
  3209. return FALSE;
  3210.     curwin->w_leftcol = scrollbar_value;
  3211.     return leftcol_changed();
  3212. }
  3213. /*
  3214.  * Check that none of the colors are the same as the background color
  3215.  */
  3216.     void
  3217. gui_check_colors()
  3218. {
  3219.     if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == (GuiColor)-1)
  3220.     {
  3221. gui_set_bg_color((char_u *)"White");
  3222. if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == (GuiColor)-1)
  3223.     gui_set_fg_color((char_u *)"Black");
  3224.     }
  3225. }
  3226.     void
  3227. gui_set_fg_color(name)
  3228.     char_u *name;
  3229. {
  3230.     gui.norm_pixel = gui_mch_get_color(name);
  3231.     hl_set_fg_color_name(vim_strsave(name));
  3232. }
  3233.     void
  3234. gui_set_bg_color(name)
  3235.     char_u *name;
  3236. {
  3237.     gui.back_pixel = gui_mch_get_color(name);
  3238.     hl_set_bg_color_name(vim_strsave(name));
  3239. }
  3240. #ifdef USE_GUI_X11
  3241.     void
  3242. gui_new_scrollbar_colors()
  3243. {
  3244.     WIN     *wp;
  3245.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3246.     {
  3247. gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_LEFT]));
  3248. gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_RIGHT]));
  3249.     }
  3250.     gui_mch_set_scrollbar_colors(&gui.bottom_sbar);
  3251. }
  3252. #endif
  3253. /*
  3254.  * Call this when focus has changed.
  3255.  */
  3256.     void
  3257. gui_focus_change(in_focus)
  3258.     int     in_focus;
  3259. {
  3260.     gui.in_focus = in_focus;
  3261.     out_flush(); /* make sure output has been written */
  3262.     gui_update_cursor(TRUE, FALSE);
  3263. }
  3264. /*
  3265.  * Duplicate the menu item text and then process to see if a mnemonic key
  3266.  * and/or accelerator text has been identified.
  3267.  * Returns a pointer to allocated memory, or NULL for failure.
  3268.  * If mnemonic != NULL, *mnemonic is set to the character after the first '&'.
  3269.  * If actext != NULL, *actext is set to the text after the first TAB.
  3270.  */
  3271.     char_u *
  3272. gui_menu_text(text, mnemonic, actext)
  3273.     char_u *text;
  3274.     int *mnemonic;
  3275.     char_u **actext;
  3276. {
  3277.     char_u *p;
  3278.     char_u *menu_text;
  3279.     /* Locate accelerator text, after the first TAB */
  3280.     p = vim_strchr(text, TAB);
  3281.     if (p != NULL)
  3282.     {
  3283. if (actext != NULL)
  3284.     *actext = vim_strsave(p + 1);
  3285. menu_text = vim_strnsave(text, (int)(p - text));
  3286.     }
  3287.     else
  3288. menu_text = vim_strsave(text);
  3289.     if (menu_text != NULL)
  3290.     {
  3291. p = vim_strchr(menu_text, '&');
  3292. if (p != NULL)
  3293. {
  3294.     if (mnemonic != NULL)
  3295. *mnemonic = p[1];
  3296.     mch_memmove(p, p + 1, STRLEN(p));
  3297. }
  3298.     }
  3299.     return menu_text;
  3300. }
  3301. /*
  3302.  * Return TRUE if "name" can be a menu in the MenuBar.
  3303.  */
  3304.     int
  3305. gui_menubar_menu(name)
  3306.     char_u *name;
  3307. {
  3308.     return (!gui_popup_menu(name)
  3309.     && !gui_toolbar_menu(name)
  3310.     && *name != MNU_HIDDEN_CHAR);
  3311. }
  3312.     int
  3313. gui_popup_menu(name)
  3314.     char_u *name;
  3315. {
  3316.     return (STRNCMP(name, "PopUp", 5) == 0);
  3317. }
  3318.     int
  3319. gui_toolbar_menu(name)
  3320.     char_u *name;
  3321. {
  3322.     return (STRNCMP(name, "ToolBar", 7) == 0);
  3323. }
  3324. /*
  3325.  * Called when the mouse moved (but not when dragging).
  3326.  * Ignore this while in command-line mode, or while changing the window layout
  3327.  * (causes a mouse-move event in Win32 GUI).
  3328.  */
  3329.     void
  3330. gui_mouse_moved(y)
  3331.     int y;
  3332. {
  3333.     WIN *wp;
  3334.     char_u st[6];
  3335.     int x;
  3336.     if (p_mousef && State != CMDLINE && !need_mouse_correct && gui.in_focus)
  3337.     {
  3338. x = gui_mch_get_mouse_x();
  3339. /* Don't move the mouse when it's left or right of the Vim window */
  3340. if (x < 0 || x > Columns * gui.char_width)
  3341.     return;
  3342. wp = y2win(y);
  3343. if (wp == curwin || wp == NULL)
  3344.     return; /* still in the same old window, or none at all */
  3345. /*
  3346.  * format a mouse click on status line input
  3347.  * ala gui_send_mouse_event(0, x, y, 0, 0);
  3348.  */
  3349. st[0] = CSI;
  3350. st[1] = KS_MOUSE;
  3351. st[2] = K_FILLER;
  3352. st[3] = (char_u)MOUSE_LEFT;
  3353. st[4] = (char_u)(2 + ' ');
  3354. st[5] = (char_u)(wp->w_height + wp->w_winpos + ' ' + 1);
  3355. add_to_input_buf(st, 6);
  3356.     }
  3357. }
  3358. /*
  3359.  * Called when mouse should be moved to window with focus.
  3360.  */
  3361.     void
  3362. gui_mouse_correct()
  3363. {
  3364.     int x, y;
  3365.     WIN *wp = NULL;
  3366.     need_mouse_correct = FALSE;
  3367.     if (gui.in_use && p_mousef)
  3368.     {
  3369. x = gui_mch_get_mouse_x();
  3370. /* Don't move the mouse when it's left or right of the Vim window */
  3371. if (x < 0 || x > Columns * gui.char_width)
  3372.     return;
  3373. y = gui_mch_get_mouse_y();
  3374. if (y >= 0)
  3375.     wp = y2win(y);
  3376. if (wp != curwin && wp != NULL) /* If in other than current window */
  3377. {
  3378.     validate_cline_row();
  3379.     gui_mch_setmouse((int)Columns * gui.char_width - 3,
  3380.  (curwin->w_winpos + curwin->w_wrow) * gui.char_height
  3381.      + (gui.char_height) / 2);
  3382. }
  3383.     }
  3384. }
  3385. /*
  3386.  * Find window where the mouse pointer "y" coordinate is in.
  3387.  */
  3388.     static WIN *
  3389. y2win(y)
  3390.     int y;
  3391. {
  3392.     int row;
  3393.     WIN *wp;
  3394.     row = Y_2_ROW(y);
  3395.     if (row < firstwin->w_winpos)    /* before first window (Toolbar) */
  3396. return NULL;
  3397.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3398. if (row < wp->w_winpos + wp->w_height + wp->w_status_height)
  3399.     break;
  3400.     return wp;
  3401. }
  3402. /*
  3403.  * Display the Special "PopUp" menu as a pop-up at the current mouse
  3404.  * position.  The "PopUpn" menu is for Normal mode, "PopUpi" for Insert mode,
  3405.  * etc.
  3406.  */
  3407.     void
  3408. gui_show_popupmenu()
  3409. {
  3410.     GuiMenu *menu;
  3411.     int mode;
  3412.     mode = get_menu_mode();
  3413.     if (mode == MENU_INDEX_INVALID)
  3414. return;
  3415.     mode = MENU_MODE_CHARS[mode];
  3416.     for (menu = gui.root_menu; menu != NULL; menu = menu->next)
  3417. if (STRNCMP("PopUp", menu->name, 5) == 0 && menu->name[5] == mode)
  3418.     break;
  3419.     /* Only show a popup when it is defined and has entries */
  3420.     if (menu != NULL && menu->children != NULL)
  3421. gui_mch_show_popupmenu(menu);
  3422. }