[BACK]Return to gui.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/gui.c, Revision 1.1.1.1

1.1       downsj      1: /* $OpenBSD$   */
                      2: /* vi:set ts=4 sw=4:
                      3:  *
                      4:  * VIM - Vi IMproved           by Bram Moolenaar
                      5:  *                             GUI/Motif support by Robert Webb
                      6:  *
                      7:  * Do ":help uganda"  in Vim to read copying and usage conditions.
                      8:  * Do ":help credits" in Vim to see a list of people who contributed.
                      9:  */
                     10:
                     11: #include "vim.h"
                     12: #include "globals.h"
                     13: #include "proto.h"
                     14: #include "option.h"
                     15:
                     16: /* Structure containing all the GUI information */
                     17: Gui gui;
                     18:
                     19: /* Set to TRUE after adding/removing menus to ensure they are updated */
                     20: int force_menu_update = FALSE;
                     21:
                     22:
                     23: static void gui_check_screen __ARGS((void));
                     24: static void gui_outstr __ARGS((char_u *, int));
                     25: static void gui_update_selection __ARGS((void));
                     26: static int gui_get_menu_cmd_modes __ARGS((char_u *, int, int *, int *));
                     27: static int gui_add_menu_path __ARGS((char_u *, int, void (*)(), char_u *, int));
                     28: static int gui_remove_menu __ARGS((GuiMenu **, char_u *, int));
                     29: static void gui_free_menu __ARGS((GuiMenu *));
                     30: static void gui_free_menu_string __ARGS((GuiMenu *, int));
                     31: static int gui_show_menus __ARGS((char_u *, int));
                     32: static void gui_show_menus_recursive __ARGS((GuiMenu *, int, int));
                     33: static char_u *gui_menu_name_skip __ARGS((char_u *name));
                     34: static void gui_create_initial_menus __ARGS((GuiMenu *, GuiMenu *));
                     35: static void gui_update_scrollbars __ARGS((void));
                     36: static void gui_update_horiz_scrollbar __ARGS((void));
                     37:
                     38: /*
                     39:  * The Athena scrollbars can move the thumb to after the end of the scrollbar,
                     40:  * this makes the thumb indicate the part of the text that is shown.  Motif
                     41:  * can't do this.
                     42:  */
                     43: #ifdef USE_GUI_ATHENA
                     44: # define SCROLL_PAST_END
                     45: #endif
                     46:
                     47: /*
                     48:  * gui_start -- Called when user wants to start the GUI.
                     49:  */
                     50:    void
                     51: gui_start()
                     52: {
                     53:    char_u  *old_term;
                     54:
                     55:    old_term = strsave(term_strings[KS_NAME]);
                     56:    mch_setmouse(FALSE);                    /* first switch mouse off */
                     57:
                     58:    /* set_termname() will call gui_init() to start the GUI */
                     59:    termcapinit((char_u *)"builtin_gui");
                     60:
                     61:    if (!gui.in_use)                        /* failed to start GUI */
                     62:        termcapinit(old_term);
                     63:
                     64:    vim_free(old_term);
                     65:
                     66:    /*
                     67:     * Quit the current process and continue in the child.
                     68:     * Makes "gvim file" disconnect from the shell it was started in.
                     69:     * Don't do this when Vim was started with "-f" or the 'f' flag is present
                     70:     * in 'guioptions'.
                     71:     */
                     72:    if (gui.in_use && gui.dofork &&
                     73:                      vim_strchr(p_guioptions, GO_FORG) == NULL && fork() > 0)
                     74:        exit(0);
                     75: }
                     76:
                     77: /*
                     78:  * Call this when vim starts up, whether or not the GUI is started
                     79:  */
                     80:    void
                     81: gui_prepare(argc, argv)
                     82:    int     *argc;
                     83:    char    **argv;
                     84: {
                     85:    /* Menu items may be added before the GUI is started, so set this now */
                     86:    gui.root_menu = NULL;
                     87:    gui.in_use = FALSE;             /* No GUI yet (maybe later) */
                     88:    gui.starting = FALSE;           /* No GUI yet (maybe later) */
                     89:    gui.dofork = TRUE;              /* default is to use fork() */
                     90:    gui_mch_prepare(argc, argv);
                     91: }
                     92:
                     93: static struct default_menu
                     94: {
                     95:    char    *name;          /* name of menu item */
                     96:    int     mode;           /* mode where menu is valid */
                     97:    char    *command;       /* resulting command */
                     98: } default_menus[] =
                     99: {
                    100:    /* Help menu.  Some reason Motif is happier if this is added first. */
                    101:    {"Help.Overview  <F1>", MENU_NORMAL_MODE,   ":help\r"},
                    102:    {"Help.Overview  <F1>", MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    103:                                                "\033:help\r"},
                    104:    {"Help.How to\\.\\.\\.",MENU_NORMAL_MODE,   ":help how_to\r"},
                    105:    {"Help.How to\\.\\.\\.",MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    106:                                                "\033:help how_to\r"},
                    107:    {"Help.GUI",            MENU_NORMAL_MODE,   ":help gui\r"},
                    108:    {"Help.GUI",            MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    109:                                                "\033:help gui\r"},
                    110:    {"Help.Version",        MENU_NORMAL_MODE,   ":version\r"},
                    111:    {"Help.Version",        MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    112:                                                "\033:version\r"},
                    113:    {"Help.Credits",        MENU_NORMAL_MODE,   ":help credits\r"},
                    114:    {"Help.Credits",        MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    115:                                                "\033:help credits\r"},
                    116:    {"Help.Copying",        MENU_NORMAL_MODE,   ":help uganda\r"},
                    117:    {"Help.Copying",        MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    118:                                                "\033:help uganda\r"},
                    119:
                    120:    /* File menu */
                    121:    {"File.Save       :w",  MENU_NORMAL_MODE,   ":w\r"},
                    122:    {"File.Save       :w",  MENU_INSERT_MODE,   "\017:w\r"},
                    123:
                    124:    {"File.Close      :q",  MENU_NORMAL_MODE,   ":q\r"},
                    125:    {"File.Close      :q",  MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    126:                                                "\033:q\r"},
                    127:
                    128:    {"File.Quit       :qa", MENU_NORMAL_MODE,   ":qa\r"},
                    129:    {"File.Quit       :qa", MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    130:                                                "\033:qa\r"},
                    131:
                    132:    {"File.Save-Quit  :wqa",MENU_NORMAL_MODE,   ":wqa\r"},
                    133:    {"File.Save-Quit  :wqa",MENU_VISUAL_MODE|MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    134:                                                "\033:wqa\r"},
                    135:
                    136:    /* Edit menu */
                    137:    {"Edit.Undo",           MENU_NORMAL_MODE,   "u"},
                    138:    {"Edit.Redo",           MENU_NORMAL_MODE,   "\022"},
                    139:
                    140:    {"Edit.Cut",            MENU_VISUAL_MODE,   "x"},
                    141:    {"Edit.Copy",           MENU_VISUAL_MODE,   "y"},
                    142:    {"Edit.Put Before",     MENU_NORMAL_MODE,   "[p"},
                    143:    {"Edit.Put Before",     MENU_INSERT_MODE,   "\017[p"},
                    144:    {"Edit.Put After",      MENU_NORMAL_MODE,   "]p"},
                    145:    {"Edit.Put After",      MENU_INSERT_MODE,   "\017]p"},
                    146:    {"Edit.Paste",          MENU_NORMAL_MODE,   "i\022*\033"},  /* CTRL-R * */
                    147:    {"Edit.Paste",          MENU_INSERT_MODE|MENU_CMDLINE_MODE,
                    148:                                                "\022*"},   /* CTRL-R * */
                    149:    {NULL,                  0,                  NULL}
                    150: };
                    151:
                    152: /*
                    153:  * This is the call which starts the GUI.
                    154:  */
                    155:    void
                    156: gui_init()
                    157: {
                    158:    char_u  *env_str;
                    159:    int     i;
                    160:
                    161:    gui.dying = FALSE;
                    162:    gui.in_focus = FALSE;
                    163:    gui.dragged_sb = SB_NONE;
                    164:    gui.dragged_wp = NULL;
                    165:    gui.col = gui.num_cols = 0;
                    166:    gui.row = gui.num_rows = 0;
                    167:
                    168:    /* Initialise gui.cursor_row: */
                    169:    INVALIDATE_CURSOR();
                    170:    gui.scroll_region_top = 0;
                    171:    gui.scroll_region_bot = Rows - 1;
                    172:    gui.highlight_mask = HL_NORMAL;
                    173:    gui.char_width = 0;
                    174:    gui.char_height = 0;
                    175:    gui.char_ascent = 0;
                    176:    gui.border_width = 0;
                    177:
                    178:    gui.selection.owned = FALSE;
                    179:    gui.selection.start.lnum = 0;
                    180:    gui.selection.start.col = 0;
                    181:    gui.selection.end.lnum = 0;
                    182:    gui.selection.end.col = 0;
                    183:    gui.selection.state = SELECT_CLEARED;
                    184:
                    185:    gui.root_menu = NULL;
                    186:    gui.menu_is_active = TRUE;      /* default: include menu */
                    187:
                    188:    gui.scrollbar_width = SB_DEFAULT_WIDTH;
                    189:    gui.menu_height = MENU_DEFAULT_HEIGHT;
                    190:    for (i = 0; i < 3; i++)
                    191:        gui.new_sb[i] = FALSE;
                    192:
                    193:    gui.prev_wrap = -1;
                    194:
                    195:    for (i = 0; default_menus[i].name != NULL; ++i)
                    196:        gui_add_menu_path((char_u *)default_menus[i].name,
                    197:                                    default_menus[i].mode, gui_menu_cb,
                    198:                          (char_u *)default_menus[i].command, TRUE);
                    199:
                    200:    /*
                    201:     * Switch on the mouse by default.
                    202:     * This can be changed in the .gvimrc.
                    203:     */
                    204:    set_string_option((char_u *)"mouse", -1, (char_u *)"a", TRUE);
                    205:
                    206:    /*
                    207:     * Get system wide defaults for gvim (Unix only)
                    208:     */
                    209: #ifdef HAVE_CONFIG_H
                    210:    do_source(sys_gvimrc_fname, FALSE);
                    211: #endif
                    212:
                    213:    /*
                    214:     * Try to read GUI initialization commands from the following places:
                    215:     * - environment variable GVIMINIT
                    216:     * - the user gvimrc file (~/.gvimrc for Unix)
                    217:     * The first that exists is used, the rest is ignored.
                    218:     */
                    219:    if ((env_str = vim_getenv((char_u *)"GVIMINIT")) != NULL && *env_str != NUL)
                    220:    {
                    221:        sourcing_name = (char_u *)"GVIMINIT";
                    222:        do_cmdline(env_str, TRUE, TRUE);
                    223:        sourcing_name = NULL;
                    224:    }
                    225:    else
                    226:        do_source((char_u *)USR_GVIMRC_FILE, FALSE);
                    227:
                    228:    /*
                    229:     * Read initialization commands from ".gvimrc" in current directory.  This
                    230:     * is only done if the 'exrc' option is set.  Because of security reasons
                    231:     * we disallow shell and write commands now, except for unix if the file is
                    232:     * owned by the user or 'secure' option has been reset in environment of
                    233:     * global ".gvimrc".  Only do this if GVIMRC_FILE is not the same as
                    234:     * USR_GVIMRC_FILE or sys_gvimrc_fname.
                    235:     */
                    236:    if (p_exrc)
                    237:    {
                    238: #ifdef UNIX
                    239:        {
                    240:            struct stat s;
                    241:
                    242:            /* if ".gvimrc" file is not owned by user, set 'secure' mode */
                    243:            if (stat(GVIMRC_FILE, &s) || s.st_uid != getuid())
                    244:                secure = p_secure;
                    245:        }
                    246: #else
                    247:        secure = p_secure;
                    248: #endif
                    249:
                    250:        i = FAIL;
                    251:        if (fullpathcmp((char_u *)USR_GVIMRC_FILE,
                    252:                                            (char_u *)GVIMRC_FILE) != FPC_SAME
                    253: #ifdef HAVE_CONFIG_H
                    254:                && fullpathcmp(sys_gvimrc_fname,
                    255:                                            (char_u *)GVIMRC_FILE) != FPC_SAME
                    256: #endif
                    257:                )
                    258:            i = do_source((char_u *)GVIMRC_FILE, FALSE);
                    259:    }
                    260:
                    261:    /*
                    262:     * Actually start the GUI itself.
                    263:     */
                    264:    gui.in_use = TRUE;      /* Must be set after menus have been set up */
                    265:    if (gui_mch_init() == FAIL)
                    266:    {
                    267:        gui.in_use = FALSE;
                    268:        return;
                    269:    }
                    270:
                    271:    maketitle();
                    272:
                    273:    gui_create_initial_menus(gui.root_menu, NULL);
                    274: }
                    275:
                    276:    void
                    277: gui_exit()
                    278: {
                    279:    gui.in_use = FALSE;
                    280:    gui_mch_exit();
                    281: }
                    282:
                    283: /*
                    284:  * Set the font. Uses the 'font' option. The first font name that works is
                    285:  * used. If none is found, use the default font.
                    286:  */
                    287:    int
                    288: gui_init_font()
                    289: {
                    290: #define FONTLEN 100
                    291:    char_u  *font_list;
                    292:    char_u  font_name[FONTLEN];
                    293:
                    294:    if (!gui.in_use)
                    295:        return FAIL;
                    296:
                    297:    for (font_list = p_guifont; *font_list != NUL; )
                    298:    {
                    299:        /* Isolate one font name */
                    300:        (void)copy_option_part(&font_list, font_name, FONTLEN, ",");
                    301:        if (gui_mch_init_font(font_name) == OK)
                    302:            return OK;
                    303:    }
                    304:
                    305:    /*
                    306:     * Couldn't load any font in 'font', tell gui_mch_init_font() to try and
                    307:     * find a font we can load.
                    308:     */
                    309:    return gui_mch_init_font(NULL);
                    310: }
                    311:
                    312:    void
                    313: gui_set_cursor(row, col)
                    314:    int     row;
                    315:    int     col;
                    316: {
                    317:    gui.row = row;
                    318:    gui.col = col;
                    319: }
                    320:
                    321: /*
                    322:  * gui_check_screen - check if the cursor is on the screen.
                    323:  */
                    324:    static void
                    325: gui_check_screen()
                    326: {
                    327:    if (gui.row >= Rows)
                    328:        gui.row = Rows - 1;
                    329:    if (gui.col >= Columns)
                    330:        gui.col = Columns - 1;
                    331:    if (gui.cursor_row >= Rows || gui.cursor_col >= Columns)
                    332:        INVALIDATE_CURSOR();
                    333: }
                    334:
                    335:    void
                    336: gui_update_cursor()
                    337: {
                    338:    gui_check_screen();
                    339:    if (gui.row != gui.cursor_row || gui.col != gui.cursor_col)
                    340:    {
                    341:        gui_undraw_cursor();
                    342:        gui.cursor_row = gui.row;
                    343:        gui.cursor_col = gui.col;
                    344:        gui_mch_draw_cursor();
                    345:    }
                    346: }
                    347:
                    348: /*
                    349:  * Should be called after the GUI window has been resized.  Its arguments are
                    350:  * the new width and height of the window in pixels.
                    351:  */
                    352:    void
                    353: gui_resize_window(pixel_width, pixel_height)
                    354:    int     pixel_width;
                    355:    int     pixel_height;
                    356: {
                    357:    gui.num_cols = (pixel_width - 2 * gui.border_offset) / gui.char_width;
                    358:    gui.num_rows = (pixel_height - 2 * gui.border_offset) / gui.char_height;
                    359:
                    360:    gui_reset_scroll_region();
                    361:    /*
                    362:     * At the "more" prompt there is no redraw, put the cursor at the last
                    363:     * line here (why does it have to be one row too low???).
                    364:     */
                    365:    if (State == ASKMORE)
                    366:        gui.row = gui.num_rows;
                    367:
                    368:    if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns)
                    369:        set_winsize(0, 0, FALSE);
                    370:    gui_update_cursor();
                    371: }
                    372:
                    373: /*
                    374:  * Make scroll region cover whole screen.
                    375:  */
                    376:    void
                    377: gui_reset_scroll_region()
                    378: {
                    379:    gui.scroll_region_top = 0;
                    380:    gui.scroll_region_bot = gui.num_rows - 1;
                    381: }
                    382:
                    383:    void
                    384: gui_start_highlight(mask)
                    385:    long_u  mask;
                    386: {
                    387:    gui.highlight_mask |= mask;
                    388: }
                    389:
                    390:    void
                    391: gui_stop_highlight(mask)
                    392:     long_u mask;
                    393: {
                    394:    gui.highlight_mask &= ~mask;
                    395: }
                    396:
                    397:    void
                    398: gui_write(s, len)
                    399:    char_u  *s;
                    400:    int     len;
                    401: {
                    402:    char_u  *p;
                    403:    int     arg1 = 0, arg2 = 0;
                    404:
                    405: /* #define DEBUG_GUI_WRITE */
                    406: #ifdef DEBUG_GUI_WRITE
                    407:    {
                    408:        int i;
                    409:        char_u *str;
                    410:
                    411:        printf("gui_write(%d):\n    ", len);
                    412:        for (i = 0; i < len; i++)
                    413:            if (s[i] == ESC)
                    414:            {
                    415:                if (i != 0)
                    416:                    printf("\n    ");
                    417:                printf("<ESC>");
                    418:            }
                    419:            else
                    420:            {
                    421:                str = transchar(s[i]);
                    422:                if (str[0] && str[1])
                    423:                    printf("<%s>", (char *)str);
                    424:                else
                    425:                    printf("%s", (char *)str);
                    426:            }
                    427:        printf("\n");
                    428:    }
                    429: #endif
                    430:    while (len)
                    431:    {
                    432:        if (s[0] == '\n')
                    433:        {
                    434:            len--;
                    435:            s++;
                    436:            gui.col = 0;
                    437:            if (gui.row < gui.scroll_region_bot)
                    438:                gui.row++;
                    439:            else
                    440:                gui_mch_delete_lines(gui.scroll_region_top, 1);
                    441:        }
                    442:        else if (s[0] == '\r')
                    443:        {
                    444:            len--;
                    445:            s++;
                    446:            gui.col = 0;
                    447:        }
                    448:        else if (s[0] == Ctrl('G'))     /* Beep */
                    449:        {
                    450:            gui_mch_beep();
                    451:            len--;
                    452:            s++;
                    453:        }
                    454:        else if (s[0] == ESC && s[1] == '|')
                    455:        {
                    456:            p = s + 2;
                    457:            if (isdigit(*p))
                    458:            {
                    459:                arg1 = getdigits(&p);
                    460:                if (p > s + len)
                    461:                    break;
                    462:                if (*p == ';')
                    463:                {
                    464:                    ++p;
                    465:                    arg2 = getdigits(&p);
                    466:                    if (p > s + len)
                    467:                        break;
                    468:                }
                    469:            }
                    470:            switch (*p)
                    471:            {
                    472:                case 'C':       /* Clear screen */
                    473:                    gui_mch_clear_block(0, 0, Rows - 1, Columns - 1);
                    474:                    break;
                    475:                case 'M':       /* Move cursor */
                    476:                    gui_set_cursor(arg1, arg2);
                    477:                    break;
                    478:                case 'R':       /* Set scroll region */
                    479:                    if (arg1 < arg2)
                    480:                    {
                    481:                        gui.scroll_region_top = arg1;
                    482:                        gui.scroll_region_bot = arg2;
                    483:                    }
                    484:                    else
                    485:                    {
                    486:                        gui.scroll_region_top = arg2;
                    487:                        gui.scroll_region_bot = arg1;
                    488:                    }
                    489:                    break;
                    490:                case 'd':       /* Delete line */
                    491:                    gui_mch_delete_lines(gui.row, 1);
                    492:                    break;
                    493:                case 'D':       /* Delete lines */
                    494:                    gui_mch_delete_lines(gui.row, arg1);
                    495:                    break;
                    496:                case 'i':       /* Insert line */
                    497:                    gui_mch_insert_lines(gui.row, 1);
                    498:                    break;
                    499:                case 'I':       /* Insert lines */
                    500:                    gui_mch_insert_lines(gui.row, arg1);
                    501:                    break;
                    502:                case '$':       /* Clear to end-of-line */
                    503:                    gui_mch_clear_block(gui.row, gui.col, gui.row, Columns - 1);
                    504:                    break;
                    505:                case 'h':       /* Turn on highlighting */
                    506:                    gui_start_highlight(arg1);
                    507:                    break;
                    508:                case 'H':       /* Turn off highlighting */
                    509:                    gui_stop_highlight(arg1);
                    510:                    break;
                    511:                case 'f':       /* flash the window (visual bell) */
                    512:                    gui_mch_flash();
                    513:                    break;
                    514:                default:
                    515:                    p = s + 1;  /* Skip the ESC */
                    516:                    break;
                    517:            }
                    518:            len -= ++p - s;
                    519:            s = p;
                    520:        }
                    521:        else if (s[0] < 0x20)           /* Ctrl character, shouldn't happen */
                    522:        {
                    523:            /*
                    524:             * For some reason vim sends me a ^M after hitting return on the
                    525:             * ':' line.  Make sure we ignore this here.
                    526:             */
                    527:            len--;      /* Skip this char */
                    528:            s++;
                    529:        }
                    530:        else
                    531:        {
                    532:            p = s;
                    533:            while (len && *p >= 0x20)
                    534:            {
                    535:                len--;
                    536:                p++;
                    537:            }
                    538:            gui_outstr(s, p - s);
                    539:            s = p;
                    540:        }
                    541:    }
                    542:    gui_update_cursor();
                    543:    gui_update_scrollbars();
                    544:    gui_update_horiz_scrollbar();
                    545:
                    546:    /*
                    547:     * We need to make sure this is cleared since Athena doesn't tell us when
                    548:     * he is done dragging.
                    549:     */
                    550:    gui.dragged_sb = SB_NONE;
                    551:
                    552:    if (vim_strchr(p_guioptions, GO_ASEL) != NULL)
                    553:        gui_update_selection();
                    554:    gui_mch_flush();                /* In case vim decides to take a nap */
                    555: }
                    556:
                    557:    static void
                    558: gui_outstr(s, len)
                    559:    char_u  *s;
                    560:    int     len;
                    561: {
                    562:    int     this_len;
                    563:
                    564:    if (len == 0)
                    565:        return;
                    566:
                    567:    if (len < 0)
                    568:        len = STRLEN(s);
                    569:
                    570:    while (gui.col + len > Columns)
                    571:    {
                    572:        this_len = Columns - gui.col;
                    573:        gui_mch_outstr_nowrap(s, this_len, TRUE, FALSE);
                    574:        s += this_len;
                    575:        len -= this_len;
                    576:    }
                    577:    gui_mch_outstr_nowrap(s, len, TRUE, FALSE);
                    578: }
                    579:
                    580: /*
                    581:  * Un-draw the cursor.  Actually this just redraws the character at the given
                    582:  * position.
                    583:  */
                    584:    void
                    585: gui_undraw_cursor()
                    586: {
                    587:    if (IS_CURSOR_VALID())
                    588:        gui_redraw_block(gui.cursor_row, gui.cursor_col, gui.cursor_row,
                    589:                                                            gui.cursor_col);
                    590: }
                    591:
                    592:    void
                    593: gui_redraw(x, y, w, h)
                    594:    int     x;
                    595:    int     y;
                    596:    int     w;
                    597:    int     h;
                    598: {
                    599:    int     row1, col1, row2, col2;
                    600:
                    601:    row1 = Y_2_ROW(y);
                    602:    col1 = X_2_COL(x);
                    603:    row2 = Y_2_ROW(y + h - 1);
                    604:    col2 = X_2_COL(x + w - 1);
                    605:
                    606:    gui_redraw_block(row1, col1, row2, col2);
                    607:
                    608:    /* We may need to redraw the cursor */
                    609:    gui_update_cursor();
                    610: }
                    611:
                    612:    void
                    613: gui_redraw_block(row1, col1, row2, col2)
                    614:    int     row1;
                    615:    int     col1;
                    616:    int     row2;
                    617:    int     col2;
                    618: {
                    619:    int     old_row, old_col;
                    620:    long_u  old_hl_mask;
                    621:    char_u  *screenp, *attrp, first_attr;
                    622:    int     idx, len;
                    623:
                    624:    /* Don't try to draw outside the window! */
                    625:    /* Check everything, strange values may be caused by big border width */
                    626:    col1 = check_col(col1);
                    627:    col2 = check_col(col2);
                    628:    row1 = check_row(row1);
                    629:    row2 = check_row(row2);
                    630:
                    631:    /* Don't try to update when NextScreen is not valid */
                    632:    if (!screen_cleared || NextScreen == NULL)
                    633:        return;
                    634:
                    635:    /* Remember where our cursor was */
                    636:    old_row = gui.row;
                    637:    old_col = gui.col;
                    638:    old_hl_mask = gui.highlight_mask;
                    639:
                    640:    for (gui.row = row1; gui.row <= row2; gui.row++)
                    641:    {
                    642:        gui.col = col1;
                    643:        screenp = LinePointers[gui.row] + gui.col;
                    644:        attrp = screenp + Columns;
                    645:        len = col2 - col1 + 1;
                    646:        while (len > 0)
                    647:        {
                    648:            switch (attrp[0])
                    649:            {
                    650:                case CHAR_INVERT:
                    651:                    gui.highlight_mask = HL_INVERSE;
                    652:                    break;
                    653:                case CHAR_UNDERL:
                    654:                    gui.highlight_mask = HL_UNDERLINE;
                    655:                    break;
                    656:                case CHAR_BOLD:
                    657:                    gui.highlight_mask = HL_BOLD;
                    658:                    break;
                    659:                case CHAR_STDOUT:
                    660:                    gui.highlight_mask = HL_STANDOUT;
                    661:                    break;
                    662:                case CHAR_ITALIC:
                    663:                    gui.highlight_mask = HL_ITAL;
                    664:                    break;
                    665:                case CHAR_NORMAL:
                    666:                default:
                    667:                    gui.highlight_mask = HL_NORMAL;
                    668:                    break;
                    669:            }
                    670:            first_attr = attrp[0];
                    671:            for (idx = 0; len > 0 && attrp[idx] == first_attr; idx++)
                    672:                --len;
                    673:            gui_mch_outstr_nowrap(screenp, idx, FALSE, FALSE);
                    674:            screenp += idx;
                    675:            attrp += idx;
                    676:        }
                    677:    }
                    678:
                    679:    /* Put the cursor back where it was */
                    680:    gui.row = old_row;
                    681:    gui.col = old_col;
                    682:    gui.highlight_mask = old_hl_mask;
                    683: }
                    684:
                    685: /*
                    686:  * Check bounds for column number
                    687:  */
                    688:    int
                    689: check_col(col)
                    690:    int     col;
                    691: {
                    692:    if (col < 0)
                    693:        return 0;
                    694:    if (col >= (int)Columns)
                    695:        return (int)Columns - 1;
                    696:    return col;
                    697: }
                    698:
                    699: /*
                    700:  * Check bounds for row number
                    701:  */
                    702:    int
                    703: check_row(row)
                    704:    int     row;
                    705: {
                    706:    if (row < 0)
                    707:        return 0;
                    708:    if (row >= (int)Rows)
                    709:        return (int)Rows - 1;
                    710:    return row;
                    711: }
                    712:
                    713: /*
                    714:  * Generic mouse support function.  Add a mouse event to the input buffer with
                    715:  * the given properties.
                    716:  * button          --- may be any of MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT,
                    717:  *                     MOUSE_DRAG, or MOUSE_RELEASE.
                    718:  * x, y            --- Coordinates of mouse in pixels.
                    719:  * repeated_click  --- TRUE if this click comes only a short time after a
                    720:  *                     previous click.
                    721:  * modifiers       --- Bit field which may be any of the following modifiers
                    722:  *                     or'ed together: MOUSE_SHIFT | MOUSE_CTRL | MOUSE_ALT.
                    723:  * This function will ignore drag events where the mouse has not moved to a new
                    724:  * character.
                    725:  */
                    726:    void
                    727: gui_send_mouse_event(button, x, y, repeated_click, modifiers)
                    728:    int     button;
                    729:    int     x;
                    730:    int     y;
                    731:    int     repeated_click;
                    732:    int_u   modifiers;
                    733: {
                    734:    static int      prev_row = 0, prev_col = 0;
                    735:    static int      prev_button = -1;
                    736:    static linenr_t prev_topline = 0;
                    737:    static int      num_clicks = 1;
                    738:    char_u          string[6];
                    739:    int             row, col;
                    740:
                    741:    row = Y_2_ROW(y);
                    742:    col = X_2_COL(x);
                    743:
                    744:    /*
                    745:     * If we are dragging and the mouse hasn't moved far enough to be on a
                    746:     * different character, then don't send an event to vim.
                    747:     */
                    748:    if (button == MOUSE_DRAG && row == prev_row && col == prev_col)
                    749:        return;
                    750:
                    751:    /*
                    752:     * If topline has changed (window scrolled) since the last click, reset
                    753:     * repeated_click, because we don't want starting Visual mode when
                    754:     * clicking on a different character in the text.
                    755:     */
                    756:    if (curwin->w_topline != prev_topline)
                    757:        repeated_click = FALSE;
                    758:
                    759:    string[0] = CSI;    /* this sequence is recognized by check_termcode() */
                    760:    string[1] = KS_MOUSE;
                    761:    string[2] = K_FILLER;
                    762:    if (button != MOUSE_DRAG && button != MOUSE_RELEASE)
                    763:    {
                    764:        if (repeated_click)
                    765:        {
                    766:            /*
                    767:             * Handle multiple clicks.  They only count if the mouse is still
                    768:             * pointing at the same character.
                    769:             */
                    770:            if (button != prev_button || row != prev_row || col != prev_col)
                    771:                num_clicks = 1;
                    772:            else if (++num_clicks > 4)
                    773:                num_clicks = 1;
                    774:        }
                    775:        else
                    776:            num_clicks = 1;
                    777:        prev_button = button;
                    778:        prev_topline = curwin->w_topline;
                    779:
                    780:        string[3] = (char_u)(button | 0x20);
                    781:        SET_NUM_MOUSE_CLICKS(string[3], num_clicks);
                    782:    }
                    783:    else
                    784:        string[3] = (char_u)button;
                    785:
                    786:    string[3] |= modifiers;
                    787:    string[4] = (char_u)(col + ' ' + 1);
                    788:    string[5] = (char_u)(row + ' ' + 1);
                    789:    add_to_input_buf(string, 6);
                    790:
                    791:    prev_row = row;
                    792:    prev_col = col;
                    793: }
                    794:
                    795: /*
                    796:  * Selection stuff, for cutting and pasting text to other windows.
                    797:  */
                    798:
                    799: /*
                    800:  * Check whether the VIsual area has changed, and if so try to become the owner
                    801:  * of the selection, and free any old converted selection we may still have
                    802:  * lying around.  If the VIsual mode has ended, make a copy of what was
                    803:  * selected so we can still give it to others.  Will probably have to make sure
                    804:  * this is called whenever VIsual mode is ended.
                    805:  */
                    806:    static void
                    807: gui_update_selection()
                    808: {
                    809:    /* If visual mode is only due to a redo command ("."), then ignore it */
                    810:    if (redo_VIsual_busy)
                    811:        return;
                    812:    if (!VIsual_active)
                    813:    {
                    814:        gui_mch_clear_selection();
                    815:        gui.selection.start = gui.selection.end = VIsual;
                    816:    }
                    817:    else if (lt(VIsual, curwin->w_cursor))
                    818:    {
                    819:        if (!equal(gui.selection.start, VIsual) ||
                    820:            !equal(gui.selection.end, curwin->w_cursor))
                    821:        {
                    822:            gui_mch_clear_selection();
                    823:            gui.selection.start = VIsual;
                    824:            gui.selection.end = curwin->w_cursor;
                    825:            gui_free_selection();
                    826:            gui_own_selection();
                    827:        }
                    828:    }
                    829:    else
                    830:    {
                    831:        if (!equal(gui.selection.start, curwin->w_cursor) ||
                    832:            !equal(gui.selection.end, VIsual))
                    833:        {
                    834:            gui_mch_clear_selection();
                    835:            gui.selection.start = curwin->w_cursor;
                    836:            gui.selection.end = VIsual;
                    837:            gui_free_selection();
                    838:            gui_own_selection();
                    839:        }
                    840:    }
                    841: }
                    842:
                    843:    void
                    844: gui_own_selection()
                    845: {
                    846:    /*
                    847:     * Also want to check somehow that we are reading from the keyboard rather
                    848:     * than a mapping etc.
                    849:     */
                    850:    if (!gui.selection.owned && gui_mch_own_selection())
                    851:    {
                    852:        gui_free_selection();
                    853:        gui.selection.owned = TRUE;
                    854:    }
                    855: }
                    856:
                    857:    void
                    858: gui_lose_selection()
                    859: {
                    860:    gui_free_selection();
                    861:    gui.selection.owned = FALSE;
                    862:    gui_mch_lose_selection();
                    863: }
                    864:
                    865:    void
                    866: gui_copy_selection()
                    867: {
                    868:    if (VIsual_active)
                    869:    {
                    870:        if (vim_strchr(p_guioptions, GO_ASEL) == NULL)
                    871:            gui_update_selection();
                    872:        gui_own_selection();
                    873:        if (gui.selection.owned)
                    874:            gui_get_selection();
                    875:    }
                    876: }
                    877:
                    878:    void
                    879: gui_auto_select()
                    880: {
                    881:    if (vim_strchr(p_guioptions, GO_ASEL) != NULL)
                    882:        gui_copy_selection();
                    883: }
                    884:
                    885: /*
                    886:  * Menu stuff.
                    887:  */
                    888:
                    889:    void
                    890: gui_menu_cb(menu)
                    891:    GuiMenu *menu;
                    892: {
                    893:    char_u  bytes[3 + sizeof(long_u)];
                    894:
                    895:    bytes[0] = CSI;
                    896:    bytes[1] = KS_MENU;
                    897:    bytes[2] = K_FILLER;
                    898:    add_long_to_buf((long_u)menu, bytes + 3);
                    899:    add_to_input_buf(bytes, 3 + sizeof(long_u));
                    900: }
                    901:
                    902: /*
                    903:  * Return the index into the menu->strings or menu->noremap arrays for the
                    904:  * current state.  Returns MENU_INDEX_INVALID if there is no mapping for the
                    905:  * given menu in the current mode.
                    906:  */
                    907:    int
                    908: gui_get_menu_index(menu, state)
                    909:    GuiMenu *menu;
                    910:    int     state;
                    911: {
                    912:    int     idx;
                    913:
                    914:    if (VIsual_active)
                    915:        idx = MENU_INDEX_VISUAL;
                    916:    else if ((state & NORMAL))
                    917:        idx = MENU_INDEX_NORMAL;
                    918:    else if ((state & INSERT))
                    919:        idx = MENU_INDEX_INSERT;
                    920:    else if ((state & CMDLINE))
                    921:        idx = MENU_INDEX_CMDLINE;
                    922:    else
                    923:        idx = MENU_INDEX_INVALID;
                    924:
                    925:    if (idx != MENU_INDEX_INVALID && menu->strings[idx] == NULL)
                    926:        idx = MENU_INDEX_INVALID;
                    927:    return idx;
                    928: }
                    929:
                    930: /*
                    931:  * Return the modes specified by the given menu command (eg :menu! returns
                    932:  * MENU_CMDLINE_MODE | MENU_INSERT_MODE).  If noremap is not NULL, then the
                    933:  * flag it points to is set according to whether the command is a "nore"
                    934:  * command.  If unmenu is not NULL, then the flag it points to is set
                    935:  * according to whether the command is an "unmenu" command.
                    936:  */
                    937:    static int
                    938: gui_get_menu_cmd_modes(cmd, force, noremap, unmenu)
                    939:    char_u  *cmd;
                    940:    int     force;      /* Was there a "!" after the command? */
                    941:    int     *noremap;
                    942:    int     *unmenu;
                    943: {
                    944:    int     modes = 0x0;
                    945:
                    946:    if (*cmd == 'n' && cmd[1] != 'o')   /* nmenu, nnoremenu */
                    947:    {
                    948:        modes |= MENU_NORMAL_MODE;
                    949:        cmd++;
                    950:    }
                    951:    else if (*cmd == 'v')               /* vmenu, vnoremenu */
                    952:    {
                    953:        modes |= MENU_VISUAL_MODE;
                    954:        cmd++;
                    955:    }
                    956:    else if (*cmd == 'i')               /* imenu, inoremenu */
                    957:    {
                    958:        modes |= MENU_INSERT_MODE;
                    959:        cmd++;
                    960:    }
                    961:    else if (*cmd == 'c')               /* cmenu, cnoremenu */
                    962:    {
                    963:        modes |= MENU_CMDLINE_MODE;
                    964:        cmd++;
                    965:    }
                    966:    else if (force)                 /* menu!, noremenu! */
                    967:        modes |= MENU_INSERT_MODE | MENU_CMDLINE_MODE;
                    968:    else                            /* menu, noremenu */
                    969:        modes |= MENU_NORMAL_MODE | MENU_VISUAL_MODE;
                    970:
                    971:    if (noremap != NULL)
                    972:        *noremap = (*cmd == 'n');
                    973:    if (unmenu != NULL)
                    974:        *unmenu = (*cmd == 'u');
                    975:    return modes;
                    976: }
                    977:
                    978: /*
                    979:  * Do the :menu commands.
                    980:  */
                    981:    void
                    982: gui_do_menu(cmd, arg, force)
                    983:    char_u  *cmd;
                    984:    char_u  *arg;
                    985:    int     force;
                    986: {
                    987:    char_u  *menu_path;
                    988:    int     modes;
                    989:    char_u  *map_to;
                    990:    int     noremap;
                    991:    int     unmenu;
                    992:    char_u  *map_buf;
                    993:
                    994:    modes = gui_get_menu_cmd_modes(cmd, force, &noremap, &unmenu);
                    995:    menu_path = arg;
                    996:    if (*menu_path == NUL)
                    997:    {
                    998:        gui_show_menus(menu_path, modes);
                    999:        return;
                   1000:    }
                   1001:    while (*arg && !vim_iswhite(*arg))
                   1002:    {
                   1003:        if ((*arg == '\\' || *arg == Ctrl('V')) && arg[1] != NUL)
                   1004:            arg++;
                   1005:        arg++;
                   1006:    }
                   1007:    if (*arg != NUL)
                   1008:        *arg++ = NUL;
                   1009:    arg = skipwhite(arg);
                   1010:    map_to = arg;
                   1011:    if (*map_to == NUL && !unmenu)
                   1012:    {
                   1013:        gui_show_menus(menu_path, modes);
                   1014:        return;
                   1015:    }
                   1016:    else if (*map_to != NUL && unmenu)
                   1017:    {
                   1018:        EMSG("Trailing characters");
                   1019:        return;
                   1020:    }
                   1021:    if (unmenu)
                   1022:    {
                   1023:        if (STRCMP(menu_path, "*") == 0)        /* meaning: remove all menus */
                   1024:            menu_path = (char_u *)"";
                   1025:        gui_remove_menu(&gui.root_menu, menu_path, modes);
                   1026:    }
                   1027:    else
                   1028:    {
                   1029:        /* Replace special key codes */
                   1030:        map_to = replace_termcodes(map_to, &map_buf, FALSE);
                   1031:        gui_add_menu_path(menu_path, modes, gui_menu_cb, map_to, noremap);
                   1032:        vim_free(map_buf);
                   1033:    }
                   1034: }
                   1035:
                   1036: /*
                   1037:  * Add the menu with the given name to the menu hierarchy
                   1038:  */
                   1039:    static int
                   1040: gui_add_menu_path(path_name, modes, call_back, call_data, noremap)
                   1041:    char_u  *path_name;
                   1042:    int     modes;
                   1043:    void    (*call_back)();
                   1044:    char_u  *call_data;
                   1045:    int     noremap;
                   1046: {
                   1047:    GuiMenu **menup;
                   1048:    GuiMenu *menu = NULL;
                   1049:    GuiMenu *parent;
                   1050:    char_u  *p;
                   1051:    char_u  *name;
                   1052:    int     i;
                   1053:
                   1054:    /* Make a copy so we can stuff around with it, since it could be const */
                   1055:    path_name = strsave(path_name);
                   1056:    if (path_name == NULL)
                   1057:        return FAIL;
                   1058:    menup = &gui.root_menu;
                   1059:    parent = NULL;
                   1060:    name = path_name;
                   1061:    while (*name)
                   1062:    {
                   1063:        /* Get name of this element in the menu hierarchy */
                   1064:        p = gui_menu_name_skip(name);
                   1065:
                   1066:        /* See if it's already there */
                   1067:        menu = *menup;
                   1068:        while (menu != NULL)
                   1069:        {
                   1070:            if (STRCMP(name, menu->name) == 0)
                   1071:            {
                   1072:                if (*p == NUL && menu->children != NULL)
                   1073:                {
                   1074:                    EMSG("Menu path must not lead to a sub-menu");
                   1075:                    vim_free(path_name);
                   1076:                    return FAIL;
                   1077:                }
                   1078:                else if (*p != NUL && menu->children == NULL)
                   1079:                {
                   1080:                    EMSG("Part of menu-item path is not sub-menu");
                   1081:                    vim_free(path_name);
                   1082:                    return FAIL;
                   1083:                }
                   1084:                break;
                   1085:            }
                   1086:            menup = &menu->next;
                   1087:            menu = menu->next;
                   1088:        }
                   1089:        if (menu == NULL)
                   1090:        {
                   1091:            if (*p == NUL && parent == NULL)
                   1092:            {
                   1093:                EMSG("Must not add menu items directly to menu bar");
                   1094:                vim_free(path_name);
                   1095:                return FAIL;
                   1096:            }
                   1097:
                   1098:            /* Not already there, so lets add it */
                   1099:            menu = (GuiMenu *)alloc(sizeof(GuiMenu));
                   1100:            if (menu == NULL)
                   1101:            {
                   1102:                vim_free(path_name);
                   1103:                return FAIL;
                   1104:            }
                   1105:            menu->modes = modes;
                   1106:            menu->name = strsave(name);
                   1107:            menu->cb = NULL;
                   1108:            for (i = 0; i < 4; i++)
                   1109:            {
                   1110:                menu->strings[i] = NULL;
                   1111:                menu->noremap[i] = FALSE;
                   1112:            }
                   1113:            menu->children = NULL;
                   1114:            menu->next = NULL;
                   1115:            if (gui.in_use)  /* Otherwise it will be added when GUI starts */
                   1116:            {
                   1117:                if (*p == NUL)
                   1118:                {
                   1119:                    /* Real menu item, not sub-menu */
                   1120:                    gui_mch_add_menu_item(menu, parent);
                   1121:
                   1122:                    /* Want to update menus now even if mode not changed */
                   1123:                    force_menu_update = TRUE;
                   1124:                }
                   1125:                else
                   1126:                {
                   1127:                    /* Sub-menu (not at end of path yet) */
                   1128:                    gui_mch_add_menu(menu, parent);
                   1129:                }
                   1130:            }
                   1131:            *menup = menu;
                   1132:        }
                   1133:        else
                   1134:        {
                   1135:            /*
                   1136:             * If this menu option was previously only available in other
                   1137:             * modes, then make sure it's available for this one now
                   1138:             */
                   1139:            menu->modes |= modes;
                   1140:        }
                   1141:
                   1142:        menup = &menu->children;
                   1143:        parent = menu;
                   1144:        name = p;
                   1145:    }
                   1146:    vim_free(path_name);
                   1147:
                   1148:    if (menu != NULL)
                   1149:    {
                   1150:        menu->cb = call_back;
                   1151:        p = (call_data == NULL) ? NULL : strsave(call_data);
                   1152:
                   1153:        /* May match more than one of these */
                   1154:        if (modes & MENU_NORMAL_MODE)
                   1155:        {
                   1156:            gui_free_menu_string(menu, MENU_INDEX_NORMAL);
                   1157:            menu->strings[MENU_INDEX_NORMAL] = p;
                   1158:            menu->noremap[MENU_INDEX_NORMAL] = noremap;
                   1159:        }
                   1160:        if (modes & MENU_VISUAL_MODE)
                   1161:        {
                   1162:            gui_free_menu_string(menu, MENU_INDEX_VISUAL);
                   1163:            menu->strings[MENU_INDEX_VISUAL] = p;
                   1164:            menu->noremap[MENU_INDEX_VISUAL] = noremap;
                   1165:        }
                   1166:        if (modes & MENU_INSERT_MODE)
                   1167:        {
                   1168:            gui_free_menu_string(menu, MENU_INDEX_INSERT);
                   1169:            menu->strings[MENU_INDEX_INSERT] = p;
                   1170:            menu->noremap[MENU_INDEX_INSERT] = noremap;
                   1171:        }
                   1172:        if (modes & MENU_CMDLINE_MODE)
                   1173:        {
                   1174:            gui_free_menu_string(menu, MENU_INDEX_CMDLINE);
                   1175:            menu->strings[MENU_INDEX_CMDLINE] = p;
                   1176:            menu->noremap[MENU_INDEX_CMDLINE] = noremap;
                   1177:        }
                   1178:    }
                   1179:    return OK;
                   1180: }
                   1181:
                   1182: /*
                   1183:  * Remove the (sub)menu with the given name from the menu hierarchy
                   1184:  * Called recursively.
                   1185:  */
                   1186:    static int
                   1187: gui_remove_menu(menup, name, modes)
                   1188:    GuiMenu **menup;
                   1189:    char_u  *name;
                   1190:    int     modes;
                   1191: {
                   1192:    GuiMenu *menu;
                   1193:    GuiMenu *child;
                   1194:    char_u  *p;
                   1195:
                   1196:    if (*menup == NULL)
                   1197:        return OK;          /* Got to bottom of hierarchy */
                   1198:
                   1199:    /* Get name of this element in the menu hierarchy */
                   1200:    p = gui_menu_name_skip(name);
                   1201:
                   1202:    /* Find the menu */
                   1203:    menu = *menup;
                   1204:    while (menu != NULL)
                   1205:    {
                   1206:        if (*name == NUL || STRCMP(name, menu->name) == 0)
                   1207:        {
                   1208:            if (*p != NUL && menu->children == NULL)
                   1209:            {
                   1210:                EMSG("Part of menu-item path is not sub-menu");
                   1211:                return FAIL;
                   1212:            }
                   1213:            if ((menu->modes & modes) != 0x0)
                   1214:            {
                   1215:                if (gui_remove_menu(&menu->children, p, modes) == FAIL)
                   1216:                    return FAIL;
                   1217:            }
                   1218:            else if (*name != NUL)
                   1219:            {
                   1220:                EMSG("Menu only exists in another mode");
                   1221:                return FAIL;
                   1222:            }
                   1223:
                   1224:            /*
                   1225:             * When name is empty, we are removing all menu items for the given
                   1226:             * modes, so keep looping, otherwise we are just removing the named
                   1227:             * menu item (which has been found) so break here.
                   1228:             */
                   1229:            if (*name != NUL)
                   1230:                break;
                   1231:
                   1232:            /* Remove the menu item for the given mode[s] */
                   1233:            menu->modes &= ~modes;
                   1234:
                   1235:            if (menu->modes == 0x0)
                   1236:            {
                   1237:                /* The menu item is no longer valid in ANY mode, so delete it */
                   1238:                *menup = menu->next;
                   1239:                gui_free_menu(menu);
                   1240:            }
                   1241:            else
                   1242:                menup = &menu->next;
                   1243:        }
                   1244:        else
                   1245:            menup = &menu->next;
                   1246:        menu = *menup;
                   1247:    }
                   1248:    if (*name != NUL)
                   1249:    {
                   1250:        if (menu == NULL)
                   1251:        {
                   1252:            EMSG("No menu of that name");
                   1253:            return FAIL;
                   1254:        }
                   1255:
                   1256:        /* Recalculate modes for menu based on the new updated children */
                   1257:        menu->modes = 0x0;
                   1258:        for (child = menu->children; child != NULL; child = child->next)
                   1259:            menu->modes |= child->modes;
                   1260:        if (menu->modes == 0x0)
                   1261:        {
                   1262:            /* The menu item is no longer valid in ANY mode, so delete it */
                   1263:            *menup = menu->next;
                   1264:            gui_free_menu(menu);
                   1265:        }
                   1266:    }
                   1267:
                   1268:    return OK;
                   1269: }
                   1270:
                   1271: /*
                   1272:  * Free the given menu structure
                   1273:  */
                   1274:    static void
                   1275: gui_free_menu(menu)
                   1276:    GuiMenu *menu;
                   1277: {
                   1278:    int     i;
                   1279:
                   1280:    gui_mch_destroy_menu(menu);     /* Free machine specific menu structures */
                   1281:    vim_free(menu->name);
                   1282:    for (i = 0; i < 4; i++)
                   1283:        gui_free_menu_string(menu, i);
                   1284:    vim_free(menu);
                   1285:
                   1286:    /* Want to update menus now even if mode not changed */
                   1287:    force_menu_update = TRUE;
                   1288: }
                   1289:
                   1290: /*
                   1291:  * Free the menu->string with the given index.
                   1292:  */
                   1293:    static void
                   1294: gui_free_menu_string(menu, idx)
                   1295:    GuiMenu *menu;
                   1296:    int     idx;
                   1297: {
                   1298:    int     count = 0;
                   1299:    int     i;
                   1300:
                   1301:    for (i = 0; i < 4; i++)
                   1302:        if (menu->strings[i] == menu->strings[idx])
                   1303:            count++;
                   1304:    if (count == 1)
                   1305:        vim_free(menu->strings[idx]);
                   1306:    menu->strings[idx] = NULL;
                   1307: }
                   1308:
                   1309: /*
                   1310:  * Show the mapping associated with a menu item or hierarchy in a sub-menu.
                   1311:  */
                   1312:    static int
                   1313: gui_show_menus(path_name, modes)
                   1314:    char_u  *path_name;
                   1315:    int     modes;
                   1316: {
                   1317:    char_u  *p;
                   1318:    char_u  *name;
                   1319:    GuiMenu *menu;
                   1320:    GuiMenu *parent = NULL;
                   1321:
                   1322:    menu = gui.root_menu;
                   1323:    name = path_name = strsave(path_name);
                   1324:    if (path_name == NULL)
                   1325:        return FAIL;
                   1326:
                   1327:    /* First, find the (sub)menu with the given name */
                   1328:    while (*name)
                   1329:    {
                   1330:        p = gui_menu_name_skip(name);
                   1331:        while (menu != NULL)
                   1332:        {
                   1333:            if (STRCMP(name, menu->name) == 0)
                   1334:            {
                   1335:                /* Found menu */
                   1336:                if (*p != NUL && menu->children == NULL)
                   1337:                {
                   1338:                    EMSG("Part of menu-item path is not sub-menu");
                   1339:                    vim_free(path_name);
                   1340:                    return FAIL;
                   1341:                }
                   1342:                else if ((menu->modes & modes) == 0x0)
                   1343:                {
                   1344:                    EMSG("Menu only exists in another mode");
                   1345:                    vim_free(path_name);
                   1346:                    return FAIL;
                   1347:                }
                   1348:                break;
                   1349:            }
                   1350:            menu = menu->next;
                   1351:        }
                   1352:        if (menu == NULL)
                   1353:        {
                   1354:            EMSG("No menu of that name");
                   1355:            vim_free(path_name);
                   1356:            return FAIL;
                   1357:        }
                   1358:        name = p;
                   1359:        parent = menu;
                   1360:        menu = menu->children;
                   1361:    }
                   1362:
                   1363:    /* Now we have found the matching menu, and we list the mappings */
                   1364:    set_highlight('t');     /* Highlight title */
                   1365:    start_highlight();
                   1366:    MSG_OUTSTR("\n--- Menus ---");
                   1367:    stop_highlight();
                   1368:
                   1369:    gui_show_menus_recursive(parent, modes, 0);
                   1370:    return OK;
                   1371: }
                   1372:
                   1373: /*
                   1374:  * Recursively show the mappings associated with the menus under the given one
                   1375:  */
                   1376:    static void
                   1377: gui_show_menus_recursive(menu, modes, depth)
                   1378:    GuiMenu *menu;
                   1379:    int     modes;
                   1380:    int     depth;
                   1381: {
                   1382:    int     i;
                   1383:    int     bit;
                   1384:
                   1385:    if (menu != NULL && (menu->modes & modes) == 0x0)
                   1386:        return;
                   1387:
                   1388:    if (menu != NULL)
                   1389:    {
                   1390:        msg_outchar('\n');
                   1391:        if (got_int)            /* "q" hit for "--more--" */
                   1392:            return;
                   1393:        for (i = 0; i < depth; i++)
                   1394:            MSG_OUTSTR("  ");
                   1395:        set_highlight('d');         /* Same as for directories!? */
                   1396:        start_highlight();
                   1397:        msg_outstr(menu->name);
                   1398:        stop_highlight();
                   1399:    }
                   1400:
                   1401:    if (menu != NULL && menu->children == NULL)
                   1402:    {
                   1403:        for (bit = 0; bit < 4; bit++)
                   1404:            if ((menu->modes & modes & (1 << bit)) != 0)
                   1405:            {
                   1406:                msg_outchar('\n');
                   1407:                if (got_int)            /* "q" hit for "--more--" */
                   1408:                    return;
                   1409:                for (i = 0; i < depth + 2; i++)
                   1410:                    MSG_OUTSTR("  ");
                   1411:                msg_outchar("nvic"[bit]);
                   1412:                if (menu->noremap[bit])
                   1413:                    msg_outchar('*');
                   1414:                else
                   1415:                    msg_outchar(' ');
                   1416:                MSG_OUTSTR("  ");
                   1417:                msg_outtrans_special(menu->strings[bit], TRUE);
                   1418:            }
                   1419:    }
                   1420:    else
                   1421:    {
                   1422:        if (menu == NULL)
                   1423:        {
                   1424:            menu = gui.root_menu;
                   1425:            depth--;
                   1426:        }
                   1427:        else
                   1428:            menu = menu->children;
                   1429:        for (; menu != NULL; menu = menu->next)
                   1430:            gui_show_menus_recursive(menu, modes, depth + 1);
                   1431:    }
                   1432: }
                   1433:
                   1434: /*
                   1435:  * Used when expanding menu names.
                   1436:  */
                   1437: static GuiMenu *expand_menu = NULL;
                   1438: static int     expand_modes = 0x0;
                   1439:
                   1440: /*
                   1441:  * Work out what to complete when doing command line completion of menu names.
                   1442:  */
                   1443:    char_u *
                   1444: gui_set_context_in_menu_cmd(cmd, arg, force)
                   1445:    char_u  *cmd;
                   1446:    char_u  *arg;
                   1447:    int     force;
                   1448: {
                   1449:    char_u  *after_dot;
                   1450:    char_u  *p;
                   1451:    char_u  *path_name = NULL;
                   1452:    char_u  *name;
                   1453:    int     unmenu;
                   1454:    GuiMenu *menu;
                   1455:
                   1456:    expand_context = EXPAND_UNSUCCESSFUL;
                   1457:
                   1458:    after_dot = arg;
                   1459:    for (p = arg; *p && !vim_iswhite(*p); ++p)
                   1460:    {
                   1461:        if ((*p == '\\' || *p == Ctrl('V')) && p[1] != NUL)
                   1462:            p++;
                   1463:        else if (*p == '.')
                   1464:            after_dot = p + 1;
                   1465:    }
                   1466:    if (*p == NUL)              /* Complete the menu name */
                   1467:    {
                   1468:        /*
                   1469:         * With :unmenu, you only want to match menus for the appropriate mode.
                   1470:         * With :menu though you might want to add a menu with the same name as
                   1471:         * one in another mode, so match menus fom other modes too.
                   1472:         */
                   1473:        expand_modes = gui_get_menu_cmd_modes(cmd, force, NULL, &unmenu);
                   1474:        if (!unmenu)
                   1475:            expand_modes = MENU_ALL_MODES;
                   1476:
                   1477:        menu = gui.root_menu;
                   1478:        if (after_dot != arg)
                   1479:        {
                   1480:            path_name = alloc(after_dot - arg);
                   1481:            if (path_name == NULL)
                   1482:                return NULL;
                   1483:            STRNCPY(path_name, arg, after_dot - arg - 1);
                   1484:            path_name[after_dot - arg - 1] = NUL;
                   1485:        }
                   1486:        name = path_name;
                   1487:        while (name != NULL && *name)
                   1488:        {
                   1489:            p = gui_menu_name_skip(name);
                   1490:            while (menu != NULL)
                   1491:            {
                   1492:                if (STRCMP(name, menu->name) == 0)
                   1493:                {
                   1494:                    /* Found menu */
                   1495:                    if ((*p != NUL && menu->children == NULL)
                   1496:                        || ((menu->modes & expand_modes) == 0x0))
                   1497:                    {
                   1498:                        /*
                   1499:                         * Menu path continues, but we have reached a leaf.
                   1500:                         * Or menu exists only in another mode.
                   1501:                         */
                   1502:                        vim_free(path_name);
                   1503:                        return NULL;
                   1504:                    }
                   1505:                    break;
                   1506:                }
                   1507:                menu = menu->next;
                   1508:            }
                   1509:            if (menu == NULL)
                   1510:            {
                   1511:                /* No menu found with the name we were looking for */
                   1512:                vim_free(path_name);
                   1513:                return NULL;
                   1514:            }
                   1515:            name = p;
                   1516:            menu = menu->children;
                   1517:        }
                   1518:
                   1519:        expand_context = EXPAND_MENUS;
                   1520:        expand_pattern = after_dot;
                   1521:        expand_menu = menu;
                   1522:    }
                   1523:    else                        /* We're in the mapping part */
                   1524:        expand_context = EXPAND_NOTHING;
                   1525:    return NULL;
                   1526: }
                   1527:
                   1528: /*
                   1529:  * Expand the menu names.
                   1530:  */
                   1531:    int
                   1532: gui_ExpandMenuNames(prog, num_file, file)
                   1533:    regexp  *prog;
                   1534:    int     *num_file;
                   1535:    char_u  ***file;
                   1536: {
                   1537:    GuiMenu *menu;
                   1538:    int     round;
                   1539:    int     count;
                   1540:
                   1541:    /*
                   1542:     * round == 1: Count the matches.
                   1543:     * round == 2: Save the matches into the array.
                   1544:     */
                   1545:    for (round = 1; round <= 2; ++round)
                   1546:    {
                   1547:        count = 0;
                   1548:        for (menu = expand_menu; menu != NULL; menu = menu->next)
                   1549:            if ((menu->modes & expand_modes) != 0x0
                   1550:                && vim_regexec(prog, menu->name, TRUE))
                   1551:            {
                   1552:                if (round == 1)
                   1553:                    count++;
                   1554:                else
                   1555:                    (*file)[count++] = strsave_escaped(menu->name,
                   1556:                                                       (char_u *)" \t\\.");
                   1557:            }
                   1558:        if (round == 1)
                   1559:        {
                   1560:            *num_file = count;
                   1561:            if (count == 0 || (*file = (char_u **)
                   1562:                         alloc((unsigned)(count * sizeof(char_u *)))) == NULL)
                   1563:                return FAIL;
                   1564:        }
                   1565:    }
                   1566:    return OK;
                   1567: }
                   1568:
                   1569: /*
                   1570:  * Skip over this element of the menu path and return the start of the next
                   1571:  * element.  Any \ and ^Vs are removed from the current element.
                   1572:  */
                   1573:    static char_u *
                   1574: gui_menu_name_skip(name)
                   1575:    char_u  *name;
                   1576: {
                   1577:    char_u  *p;
                   1578:
                   1579:    for (p = name; *p && *p != '.'; p++)
                   1580:        if (*p == '\\' || *p == Ctrl('V'))
                   1581:        {
                   1582:            STRCPY(p, p + 1);
                   1583:            if (*p == NUL)
                   1584:                break;
                   1585:        }
                   1586:    if (*p)
                   1587:        *p++ = NUL;
                   1588:    return p;
                   1589: }
                   1590:
                   1591: /*
                   1592:  * After we have started the GUI, then we can create any menus that have been
                   1593:  * defined.  This is done once here.  gui_add_menu_path() may have already been
                   1594:  * called to define these menus, and may be called again.  This function calls
                   1595:  * itself recursively. Should be called at the top level with:
                   1596:  * gui_create_initial_menus(gui.root_menu, NULL);
                   1597:  */
                   1598:    static void
                   1599: gui_create_initial_menus(menu, parent)
                   1600:    GuiMenu *menu;
                   1601:    GuiMenu *parent;
                   1602: {
                   1603:    while (menu)
                   1604:    {
                   1605:        if (menu->children != NULL)
                   1606:        {
                   1607:            gui_mch_add_menu(menu, parent);
                   1608:            gui_create_initial_menus(menu->children, menu);
                   1609:        }
                   1610:        else
                   1611:            gui_mch_add_menu_item(menu, parent);
                   1612:        menu = menu->next;
                   1613:    }
                   1614: }
                   1615:
                   1616:
                   1617: /*
                   1618:  * Set which components are present.
                   1619:  * If "oldval" is not NULL, "oldval" is the previous value, the new * value is
                   1620:  * in p_guioptions.
                   1621:  */
                   1622:    void
                   1623: gui_init_which_components(oldval)
                   1624:    char_u  *oldval;
                   1625: {
                   1626:    char_u  *p;
                   1627:    int     i;
                   1628:    int     grey_old, grey_new;
                   1629:    char_u  *temp;
                   1630:
                   1631:    if (oldval != NULL)
                   1632:    {
                   1633:        /*
                   1634:         * Check if the menu's go from grey to non-grey or vise versa.
                   1635:         */
                   1636:        grey_old = (vim_strchr(oldval, GO_GREY) != NULL);
                   1637:        grey_new = (vim_strchr(p_guioptions, GO_GREY) != NULL);
                   1638:        if (grey_old != grey_new)
                   1639:        {
                   1640:            temp = p_guioptions;
                   1641:            p_guioptions = oldval;
                   1642:            gui_x11_update_menus(MENU_ALL_MODES);
                   1643:            p_guioptions = temp;
                   1644:        }
                   1645:    }
                   1646:
                   1647:    gui.menu_is_active = FALSE;
                   1648:    for (i = 0; i < 3; i++)
                   1649:        gui.which_scrollbars[i] = FALSE;
                   1650:    for (p = p_guioptions; *p; p++)
                   1651:        switch (*p)
                   1652:        {
                   1653:            case GO_LEFT:
                   1654:                gui.which_scrollbars[SB_LEFT] = TRUE;
                   1655:                break;
                   1656:            case GO_RIGHT:
                   1657:                gui.which_scrollbars[SB_RIGHT] = TRUE;
                   1658:                break;
                   1659:            case GO_BOT:
                   1660:                gui.which_scrollbars[SB_BOTTOM] = TRUE;
                   1661:                break;
                   1662:            case GO_MENUS:
                   1663:                gui.menu_is_active = TRUE;
                   1664:                break;
                   1665:            case GO_GREY:
                   1666:                /* make menu's have grey items, ignored here */
                   1667:                break;
                   1668:            default:
                   1669:                /* Should give error message for internal error */
                   1670:                break;
                   1671:        }
                   1672:    if (gui.in_use)
                   1673:        gui_mch_create_which_components();
                   1674: }
                   1675:
                   1676:
                   1677: /*
                   1678:  * Vertical scrollbar stuff:
                   1679:  */
                   1680:
                   1681:    static void
                   1682: gui_update_scrollbars()
                   1683: {
                   1684:    WIN     *wp;
                   1685:    int     worst_update = SB_UPDATE_NOTHING;
                   1686:    int     val, size, max;
                   1687:    int     which_sb;
                   1688:    int     cmdline_height;
                   1689:
                   1690:    /*
                   1691:     * Don't want to update a scrollbar while we're dragging it.  But if we
                   1692:     * have both a left and right scrollbar, and we drag one of them, we still
                   1693:     * need to update the other one.
                   1694:     */
                   1695:    if ((gui.dragged_sb == SB_LEFT || gui.dragged_sb == SB_RIGHT) &&
                   1696:            (!gui.which_scrollbars[SB_LEFT] || !gui.which_scrollbars[SB_RIGHT]))
                   1697:        return;
                   1698:
                   1699:    if (gui.dragged_sb == SB_LEFT || gui.dragged_sb == SB_RIGHT)
                   1700:    {
                   1701:        /*
                   1702:         * If we have two scrollbars and one of them is being dragged, just
                   1703:         * copy the scrollbar position from the dragged one to the other one.
                   1704:         */
                   1705:        which_sb = SB_LEFT + SB_RIGHT - gui.dragged_sb;
                   1706:        if (gui.dragged_wp != NULL)
                   1707:            gui.dragged_wp->w_scrollbar.update[which_sb] = SB_UPDATE_VALUE;
                   1708:        else
                   1709:            gui.cmdline_sb.update[which_sb] = SB_UPDATE_VALUE;
                   1710:
                   1711:        gui_mch_update_scrollbars(SB_UPDATE_VALUE, which_sb);
                   1712:        return;
                   1713:    }
                   1714:
                   1715:    /* Return straight away if there is neither a left nor right scrollbar */
                   1716:    if (!gui.which_scrollbars[SB_LEFT] && !gui.which_scrollbars[SB_RIGHT])
                   1717:        return;
                   1718:
                   1719:    cmdline_height = Rows;
                   1720:    for (wp = firstwin; wp; wp = wp->w_next)
                   1721:    {
                   1722:        cmdline_height -= wp->w_height + wp->w_status_height;
                   1723:        if (wp->w_buffer == NULL)       /* just in case */
                   1724:            continue;
                   1725: #ifdef SCROLL_PAST_END
                   1726:        max = wp->w_buffer->b_ml.ml_line_count;
                   1727: #else
                   1728:        max = wp->w_buffer->b_ml.ml_line_count + wp->w_height - 1;
                   1729: #endif
                   1730:        if (max < 1)                    /* empty buffer */
                   1731:            max = 1;
                   1732:        val = wp->w_topline;
                   1733:        size = wp->w_height;
                   1734: #ifdef SCROLL_PAST_END
                   1735:        if (val > max)                  /* just in case */
                   1736:            val = max;
                   1737: #else
                   1738:        if (size > max)                 /* just in case */
                   1739:            size = max;
                   1740:        if (val > max - size + 1)
                   1741:        {
                   1742:            val = max - size + 1;
                   1743:            if (val < 1)                /* minimal value is 1 */
                   1744:                val = 1;
                   1745:        }
                   1746: #endif
                   1747:        if (size < 1 || wp->w_botline - 1 > max)
                   1748:        {
                   1749:            /*
                   1750:             * This can happen during changing files.  Just don't update the
                   1751:             * scrollbar for now.
                   1752:             */
                   1753:        }
                   1754:        else if (wp->w_scrollbar.height == 0)
                   1755:        {
                   1756:            /* Must be a new window */
                   1757:            wp->w_scrollbar.update[SB_LEFT] = SB_UPDATE_CREATE;
                   1758:            wp->w_scrollbar.update[SB_RIGHT] = SB_UPDATE_CREATE;
                   1759:            wp->w_scrollbar.value = val;
                   1760:            wp->w_scrollbar.size = size;
                   1761:            wp->w_scrollbar.max = max;
                   1762:            wp->w_scrollbar.top = wp->w_winpos;
                   1763:            wp->w_scrollbar.height = wp->w_height;
                   1764:            wp->w_scrollbar.status_height = wp->w_status_height;
                   1765:            gui.num_scrollbars++;
                   1766:            worst_update = SB_UPDATE_CREATE;
                   1767:        }
                   1768:        else if (wp->w_scrollbar.top != wp->w_winpos
                   1769:            || wp->w_scrollbar.height != wp->w_height
                   1770:            || wp->w_scrollbar.status_height != wp->w_status_height)
                   1771:        {
                   1772:            /* Height of scrollbar has changed */
                   1773:            wp->w_scrollbar.update[SB_LEFT] = SB_UPDATE_HEIGHT;
                   1774:            wp->w_scrollbar.update[SB_RIGHT] = SB_UPDATE_HEIGHT;
                   1775:            wp->w_scrollbar.value = val;
                   1776:            wp->w_scrollbar.size = size;
                   1777:            wp->w_scrollbar.max = max;
                   1778:            wp->w_scrollbar.top = wp->w_winpos;
                   1779:            wp->w_scrollbar.height = wp->w_height;
                   1780:            wp->w_scrollbar.status_height = wp->w_status_height;
                   1781:            if (worst_update < SB_UPDATE_HEIGHT)
                   1782:                worst_update = SB_UPDATE_HEIGHT;
                   1783:        }
                   1784:        else if (wp->w_scrollbar.value != val
                   1785:            || wp->w_scrollbar.size != size
                   1786:            || wp->w_scrollbar.max != max)
                   1787:        {
                   1788:            /* Thumb of scrollbar has moved */
                   1789:            wp->w_scrollbar.update[SB_LEFT] = SB_UPDATE_VALUE;
                   1790:            wp->w_scrollbar.update[SB_RIGHT] = SB_UPDATE_VALUE;
                   1791:            wp->w_scrollbar.value = val;
                   1792:            wp->w_scrollbar.size = size;
                   1793:            wp->w_scrollbar.max = max;
                   1794:            if (worst_update < SB_UPDATE_VALUE)
                   1795:                worst_update = SB_UPDATE_VALUE;
                   1796:        }
                   1797:
                   1798:        /*
                   1799:         * We may have just created the left scrollbar say, when we already had
                   1800:         * the right one.
                   1801:         */
                   1802:        if (gui.new_sb[SB_LEFT])
                   1803:            wp->w_scrollbar.update[SB_LEFT] = SB_UPDATE_CREATE;
                   1804:        if (gui.new_sb[SB_RIGHT])
                   1805:            wp->w_scrollbar.update[SB_RIGHT] = SB_UPDATE_CREATE;
                   1806:    }
                   1807:    if (cmdline_height < 1)
                   1808:        cmdline_height = 1;             /* Shouldn't happen, but just in case */
                   1809:
                   1810:    /* Check the command line scrollbar */
                   1811:    if (gui.cmdline_sb.height != cmdline_height
                   1812:        || gui.cmdline_sb.status_height != lastwin->w_status_height)
                   1813:    {
                   1814:        /* Height of scrollbar has changed */
                   1815:        gui.cmdline_sb.update[SB_LEFT] = SB_UPDATE_HEIGHT;
                   1816:        gui.cmdline_sb.update[SB_RIGHT] = SB_UPDATE_HEIGHT;
                   1817:        gui.cmdline_sb.value = 0;
                   1818:        gui.cmdline_sb.size = 1;            /* No thumb */
                   1819:        gui.cmdline_sb.max = 0;
                   1820:        gui.cmdline_sb.top = Rows - cmdline_height;
                   1821:        gui.cmdline_sb.height = cmdline_height;
                   1822:        gui.cmdline_sb.status_height = lastwin->w_status_height;
                   1823:        if (worst_update < SB_UPDATE_HEIGHT)
                   1824:            worst_update = SB_UPDATE_HEIGHT;
                   1825:    }
                   1826:
                   1827:    /*
                   1828:     * If we have just created the left or right scrollbar-box, then we need to
                   1829:     * update the height of the command line scrollbar (it will already be
                   1830:     * created).
                   1831:     */
                   1832:    if (gui.new_sb[SB_LEFT])
                   1833:    {
                   1834:        gui.cmdline_sb.update[SB_LEFT] = SB_UPDATE_HEIGHT;
                   1835:        worst_update = SB_UPDATE_CREATE;
                   1836:        gui.new_sb[SB_LEFT] = FALSE;
                   1837:    }
                   1838:    if (gui.new_sb[SB_RIGHT])
                   1839:    {
                   1840:        gui.cmdline_sb.update[SB_RIGHT] = SB_UPDATE_HEIGHT;
                   1841:        worst_update = SB_UPDATE_CREATE;
                   1842:        gui.new_sb[SB_RIGHT] = FALSE;
                   1843:    }
                   1844:
                   1845:    if (worst_update != SB_UPDATE_NOTHING)
                   1846:    {
                   1847:        if (gui.which_scrollbars[SB_LEFT] && gui.dragged_sb != SB_LEFT)
                   1848:            gui_mch_update_scrollbars(worst_update, SB_LEFT);
                   1849:        if (gui.which_scrollbars[SB_RIGHT] && gui.dragged_sb != SB_RIGHT)
                   1850:            gui_mch_update_scrollbars(worst_update, SB_RIGHT);
                   1851:    }
                   1852: }
                   1853:
                   1854: /*
                   1855:  * Scroll a window according to the values set in the globals current_scrollbar
                   1856:  * and scrollbar_value.  Return TRUE if the cursor in the current window moved
                   1857:  * or FALSE otherwise.
                   1858:  */
                   1859:    int
                   1860: gui_do_scroll()
                   1861: {
                   1862:    WIN     *wp, *old_wp;
                   1863:    int     i;
                   1864:    FPOS    old_cursor;
                   1865:
                   1866:    for (wp = firstwin, i = 0; i < current_scrollbar; i++)
                   1867:    {
                   1868:        if (wp == NULL)
                   1869:            break;
                   1870:        wp = wp->w_next;
                   1871:    }
                   1872:    if (wp != NULL)
                   1873:    {
                   1874:        old_cursor = curwin->w_cursor;
                   1875:        old_wp = curwin;
                   1876:        curwin = wp;
                   1877:        curbuf = wp->w_buffer;
                   1878:        i = (long)scrollbar_value - (long)wp->w_topline;
                   1879:        if (i < 0)
                   1880:            scrolldown(-i);
                   1881:        else if (i > 0)
                   1882:            scrollup(i);
                   1883:        if (p_so)
                   1884:            cursor_correct();
                   1885:        coladvance(curwin->w_curswant);
                   1886:
                   1887:        curwin = old_wp;
                   1888:        curbuf = old_wp->w_buffer;
                   1889:
                   1890:        if (wp == curwin)
                   1891:            cursupdate();           /* fix window for 'so' */
                   1892:        wp->w_redr_type = VALID;
                   1893:        updateWindow(wp);       /* update window, status line, and cmdline */
                   1894:
                   1895:        return !equal(curwin->w_cursor, old_cursor);
                   1896:    }
                   1897:    else
                   1898:    {
                   1899:        /* Command-line scrollbar, unimplemented */
                   1900:        return FALSE;
                   1901:    }
                   1902: }
                   1903:
                   1904:
                   1905: /*
                   1906:  * Horizontal scrollbar stuff:
                   1907:  */
                   1908:
                   1909:    static void
                   1910: gui_update_horiz_scrollbar()
                   1911: {
                   1912:    int     value, size, max;
                   1913:
                   1914:    if (!gui.which_scrollbars[SB_BOTTOM])
                   1915:        return;
                   1916:
                   1917:    if (gui.dragged_sb == SB_BOTTOM)
                   1918:        return;
                   1919:
                   1920:    if (curwin->w_p_wrap && gui.prev_wrap)
                   1921:        return;
                   1922:
                   1923:    /*
                   1924:     * It is possible for the cursor to be invalid if we're in the middle of
                   1925:     * something (like changing files).  If so, don't do anything for now.
                   1926:     */
                   1927:    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
                   1928:        return;
                   1929:
                   1930:    if (curwin->w_p_wrap)
                   1931:    {
                   1932:        value = 0;
                   1933:        size = Columns;
                   1934: #ifdef SCROLL_PAST_END
                   1935:        max = 0;
                   1936: #else
                   1937:        max = Columns - 1;
                   1938: #endif
                   1939:    }
                   1940:    else
                   1941:    {
                   1942:        value = curwin->w_leftcol;
                   1943:        size = Columns;
                   1944: #ifdef SCROLL_PAST_END
                   1945:        max = gui_get_max_horiz_scroll();
                   1946: #else
                   1947:        max = gui_get_max_horiz_scroll() + Columns - 1;
                   1948: #endif
                   1949:    }
                   1950:    gui_mch_update_horiz_scrollbar(value, size, max + 1);
                   1951:    gui.prev_wrap = curwin->w_p_wrap;
                   1952: }
                   1953:
                   1954: /*
                   1955:  * Determine the maximum value for scrolling right.
                   1956:  */
                   1957:    int
                   1958: gui_get_max_horiz_scroll()
                   1959: {
                   1960:    int     max = 0;
                   1961:    char_u  *p;
                   1962:
                   1963:    p = ml_get_curline();
                   1964:    if (p[0] != NUL)
                   1965:        while (p[1] != NUL)             /* Don't count last character */
                   1966:            max += chartabsize(*p++, (colnr_t)max);
                   1967:    return max;
                   1968: }
                   1969:
                   1970: /*
                   1971:  * Do a horizontal scroll.  Return TRUE if the cursor moved, or FALSE otherwise
                   1972:  */
                   1973:    int
                   1974: gui_do_horiz_scroll()
                   1975: {
                   1976:    char_u  *p;
                   1977:    int     i;
                   1978:    int     vcol;
                   1979:    int     ret_val = FALSE;
                   1980:
                   1981:    /* no wrapping, no scrolling */
                   1982:    if (curwin->w_p_wrap)
                   1983:        return FALSE;
                   1984:
                   1985:    curwin->w_leftcol = scrollbar_value;
                   1986:
                   1987:    i = 0;
                   1988:    vcol = 0;
                   1989:    p = ml_get_curline();
                   1990:    while (p[i] && i < curwin->w_cursor.col && vcol < curwin->w_leftcol)
                   1991:        vcol += chartabsize(p[i++], (colnr_t)vcol);
                   1992:    if (vcol < curwin->w_leftcol)
                   1993:    {
                   1994:        /*
                   1995:         * Cursor is on a character that is at least partly off the left hand
                   1996:         * side of the screen.
                   1997:         */
                   1998:        while (p[i] && vcol < curwin->w_leftcol)
                   1999:            vcol += chartabsize(p[i++], (colnr_t)vcol);
                   2000:        curwin->w_cursor.col = i;
                   2001:        curwin->w_set_curswant = TRUE;
                   2002:        ret_val = TRUE;
                   2003:    }
                   2004:
                   2005:    while (p[i] && i <= curwin->w_cursor.col
                   2006:                                    && vcol <= curwin->w_leftcol + Columns)
                   2007:        vcol += chartabsize(p[i++], (colnr_t)vcol);
                   2008:    if (vcol > curwin->w_leftcol + Columns)
                   2009:    {
                   2010:        /*
                   2011:         * Cursor is on a character that is at least partly off the right hand
                   2012:         * side of the screen.
                   2013:         */
                   2014:        if (i < 2)
                   2015:            i = 0;
                   2016:        else
                   2017:            i -= 2;
                   2018:        curwin->w_cursor.col = i;
                   2019:        curwin->w_set_curswant = TRUE;
                   2020:        ret_val = TRUE;
                   2021:    }
                   2022:    updateScreen(NOT_VALID);
                   2023:    return ret_val;
                   2024: }