[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.2

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