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

Annotation of src/usr.bin/vim/gui_athena.c, Revision 1.1

1.1     ! downsj      1: /* $OpenBSD$   */
        !             2: /* vi:set ts=4 sw=4:
        !             3:  *
        !             4:  * VIM - Vi IMproved           by Bram Moolenaar
        !             5:  *                             GUI/Motif support by Robert Webb
        !             6:  *                             Athena port by Bill Foster
        !             7:  *
        !             8:  * Do ":help uganda"  in Vim to read copying and usage conditions.
        !             9:  * Do ":help credits" in Vim to see a list of people who contributed.
        !            10:  */
        !            11:
        !            12: #include <X11/StringDefs.h>
        !            13: #include <X11/Intrinsic.h>
        !            14: #include <X11/Xaw/Paned.h>
        !            15: #include <X11/Xaw/Form.h>
        !            16: #include <X11/Xaw/SimpleMenu.h>
        !            17: #include <X11/Xaw/MenuButton.h>
        !            18: #include <X11/Xaw/SmeBSB.h>
        !            19: #include <X11/Xaw/Box.h>
        !            20:
        !            21: #include "vim.h"
        !            22: #include "globals.h"
        !            23: #include "proto.h"
        !            24: #include "option.h"
        !            25: #include "ops.h"
        !            26: #include "gui_at_sb.h"
        !            27:
        !            28: #define puller_width   19
        !            29: #define puller_height  19
        !            30:
        !            31: static char puller_bits[] =
        !            32: {
        !            33:    0x00,0x00,0xf8,0x00,0x00,0xf8,0xf8,0x7f,0xf8,0x04,0x80,0xf8,0x04,0x80,0xf9,
        !            34:    0x84,0x81,0xf9,0x84,0x83,0xf9,0x84,0x87,0xf9,0x84,0x8f,0xf9,0x84,0x8f,0xf9,
        !            35:    0x84,0x87,0xf9,0x84,0x83,0xf9,0x84,0x81,0xf9,0x04,0x80,0xf9,0x04,0x80,0xf9,
        !            36:    0xf8,0xff,0xf9,0xf0,0x7f,0xf8,0x00,0x00,0xf8,0x00,0x00,0xf8
        !            37: };
        !            38:
        !            39: extern Widget vimShell;
        !            40:
        !            41: static Widget vimPanes;
        !            42: static Widget vimForm = (Widget)NULL;
        !            43: static Widget textArea;
        !            44: static Widget scrollbarBox[3];     /* Left, right & bottom scrollbar boxes */
        !            45: static Widget bottomScrollbar;         /* Bottom scrollbar */
        !            46: static Widget leftBottomScrollFiller;  /* Left filler for bottom scrollbar */
        !            47: static Widget rightBottomScrollFiller; /* Right filler for bottom scrollbar */
        !            48: static Widget leftScrollbarFiller;     /* Filler for left scrollbar */
        !            49: static Widget rightScrollbarFiller;        /* Filler for right scrollbar */
        !            50: static Widget menuBar;
        !            51:
        !            52: static void gui_athena_scroll_cb_jump   __ARGS((Widget, XtPointer, XtPointer));
        !            53: static void gui_athena_scroll_cb_scroll __ARGS((Widget, XtPointer, XtPointer));
        !            54: static void gui_athena_reorder_menus    __ARGS((void));
        !            55: static void    gui_athena_pullright_action __ARGS((Widget, XEvent *, String *,
        !            56:                                                Cardinal *));
        !            57:
        !            58: static XtActionsRec        pullAction = { "menu-pullright",
        !            59:                                (XtActionProc)gui_athena_pullright_action };
        !            60: static XtTranslations  parentTrans, menuTrans;
        !            61: static Pixmap          pullerBitmap;
        !            62:
        !            63: /*
        !            64:  * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
        !            65:  * left or middle mouse button.
        !            66:  */
        !            67:    static void
        !            68: gui_athena_scroll_cb_jump(w, client_data, call_data)
        !            69:    Widget      w;
        !            70:    XtPointer   client_data, call_data;
        !            71: {
        !            72:    char_u      bytes[4 + sizeof(long_u)];
        !            73:    WIN         *wp;
        !            74:    GuiScrollbar *sb;
        !            75:    int         sb_num;
        !            76:    int         i;
        !            77:    int         byte_count;
        !            78:    long_u      value;
        !            79:
        !            80:    gui.dragged_sb = SB_NONE;
        !            81:    for (i = 0; i <= SB_BOTTOM; i++)
        !            82:        if (XtParent(w) == scrollbarBox[i])
        !            83:        {
        !            84:            gui.dragged_sb = i;
        !            85:            break;
        !            86:        }
        !            87:
        !            88:    switch (gui.dragged_sb)
        !            89:    {
        !            90:        case SB_LEFT:
        !            91:        case SB_RIGHT:
        !            92:            gui.dragged_wp = (WIN *)client_data;
        !            93:            sb_num = 0;
        !            94:            wp = firstwin;
        !            95:            for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
        !            96:                sb_num++;
        !            97:
        !            98:            if (gui.dragged_wp == NULL)
        !            99:                return;
        !           100:
        !           101:            sb = &wp->w_scrollbar;
        !           102:
        !           103:            value = *((float *)call_data) * (float)sb->max + 0.5;
        !           104:            ++value;                        /* range is 1 to line_count */
        !           105:            sb->value = value;
        !           106:
        !           107:            bytes[0] = CSI;
        !           108:            bytes[1] = KS_SCROLLBAR;
        !           109:            bytes[2] = K_FILLER;
        !           110:            bytes[3] = (char_u)sb_num;
        !           111:            byte_count = 4;
        !           112:            break;
        !           113:
        !           114:        case SB_BOTTOM:
        !           115:                                            /* why not use sb->max? */
        !           116:            value = *((float *)call_data) *
        !           117:                                    (float)(gui_get_max_horiz_scroll()) + 0.5;
        !           118:            bytes[0] = CSI;
        !           119:            bytes[1] = KS_HORIZ_SCROLLBAR;
        !           120:            bytes[2] = K_FILLER;
        !           121:            byte_count = 3;
        !           122:            break;
        !           123:
        !           124:        case SB_NONE:
        !           125:        default:
        !           126:            return;
        !           127:    }
        !           128:
        !           129:    add_long_to_buf(value, bytes + byte_count);
        !           130:    add_to_input_buf(bytes, byte_count + sizeof(long_u));
        !           131: }
        !           132:
        !           133: /*
        !           134:  * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
        !           135:  * right mouse buttons.
        !           136:  */
        !           137:    static void
        !           138: gui_athena_scroll_cb_scroll(w, client_data, call_data)
        !           139:    Widget      w;
        !           140:    XtPointer   client_data, call_data;
        !           141: {
        !           142:    char_u      bytes[4 + sizeof(long_u)];
        !           143:    WIN         *wp;
        !           144:    GuiScrollbar *sb;
        !           145:    int         sb_num;
        !           146:    int         i;
        !           147:    int         byte_count;
        !           148:    long        value;
        !           149:    int         data = (int)call_data;
        !           150:
        !           151:    for (i = 0; i <= SB_BOTTOM; i++)
        !           152:        if (XtParent(w) == scrollbarBox[i])
        !           153:        {
        !           154:            gui.dragged_sb = i;
        !           155:            break;
        !           156:        }
        !           157:
        !           158:    switch (gui.dragged_sb)
        !           159:    {
        !           160:        case SB_LEFT:
        !           161:        case SB_RIGHT:
        !           162:            gui.dragged_wp = (WIN *)client_data;
        !           163:            sb_num = 0;
        !           164:            wp = firstwin;
        !           165:            for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
        !           166:                sb_num++;
        !           167:
        !           168:            if (gui.dragged_wp == NULL)
        !           169:                return;
        !           170:
        !           171:            sb = &wp->w_scrollbar;
        !           172:
        !           173:            if (sb->size > 5)
        !           174:                i = sb->size - 2;       /* use two lines of context */
        !           175:            else
        !           176:                i = sb->size;
        !           177:            switch (data)
        !           178:            {
        !           179:                case  ONE_LINE_DATA: data = 1; break;
        !           180:                case -ONE_LINE_DATA: data = -1; break;
        !           181:                case  ONE_PAGE_DATA: data = i; break;
        !           182:                case -ONE_PAGE_DATA: data = -i; break;
        !           183:                case  END_PAGE_DATA: data = sb->max; break;
        !           184:                case -END_PAGE_DATA: data = -sb->max; break;
        !           185:                            default: data = 0; break;
        !           186:            }
        !           187:            value = sb->value + data;
        !           188:            if (value > sb->max)
        !           189:                value = sb->max;
        !           190:            else if (value < 1)         /* range is 1 to line_count */
        !           191:                value = 1;
        !           192:
        !           193:            bytes[0] = CSI;
        !           194:            bytes[1] = KS_SCROLLBAR;
        !           195:            bytes[2] = K_FILLER;
        !           196:            bytes[3] = (char_u)sb_num;
        !           197:            byte_count = 4;
        !           198:            break;
        !           199:
        !           200:        case SB_BOTTOM:
        !           201:            if (data < -1)
        !           202:                data = -(Columns - 5);
        !           203:            else if (data > 1)
        !           204:                data = (Columns - 5);
        !           205:            value = curwin->w_leftcol + data;
        !           206:            if (value < 0)              /* range is 0 to max_col */
        !           207:                value = 0;
        !           208:            else
        !           209:            {
        !           210:                int max;
        !           211:                                        /* why not use sb->max here? */
        !           212:                max = gui_get_max_horiz_scroll();
        !           213:                if (value >= max)
        !           214:                    value = max;
        !           215:            }
        !           216:
        !           217:            bytes[0] = CSI;
        !           218:            bytes[1] = KS_HORIZ_SCROLLBAR;
        !           219:            bytes[2] = K_FILLER;
        !           220:            byte_count = 3;
        !           221:            break;
        !           222:
        !           223:        case SB_NONE:
        !           224:        default:
        !           225:            return;
        !           226:    }
        !           227:
        !           228:    /*
        !           229:     * This type of scrolling doesn't move the thumb automatically so we need
        !           230:     * make sure the scrollbar still gets updated.
        !           231:     */
        !           232:    gui.dragged_sb = SB_NONE;
        !           233:
        !           234:    add_long_to_buf((long_u)value, bytes + byte_count);
        !           235:    add_to_input_buf(bytes, byte_count + sizeof(long_u));
        !           236: }
        !           237:
        !           238: /*
        !           239:  * Create all the Athena widgets necessary.
        !           240:  */
        !           241:    void
        !           242: gui_mch_create_widgets()
        !           243: {
        !           244:    Dimension   base_width, base_height;
        !           245:
        !           246:    /*
        !           247:     * We don't have any borders handled internally by the textArea to worry
        !           248:     * about so only skip over the configured border width.
        !           249:     */
        !           250:    gui.border_offset = gui.border_width;
        !           251:
        !           252:    base_width  = 2 * gui.border_offset;
        !           253:    base_height = 2 * gui.border_offset;
        !           254:
        !           255:    XtInitializeWidgetClass(panedWidgetClass);
        !           256:    XtInitializeWidgetClass(simpleMenuWidgetClass);
        !           257:    XtInitializeWidgetClass(vim_scrollbarWidgetClass);
        !           258:    XtInitializeWidgetClass(labelWidgetClass);
        !           259:
        !           260:    /* Panes for menu bar, middle stuff, and bottom scrollbar box */
        !           261:    vimPanes = XtVaCreateManagedWidget("vimPanes",
        !           262:        panedWidgetClass,   vimShell,
        !           263:        XtNorientation,     XtorientVertical,
        !           264:        NULL);
        !           265:
        !           266:    /* The top menu bar */
        !           267:    menuBar = XtVaCreateManagedWidget("menuBar",
        !           268:        boxWidgetClass,         vimPanes,
        !           269:        XtNmin,                 gui.menu_height,
        !           270:        XtNborderWidth,         1,
        !           271:        XtNallowResize,         True,
        !           272:        XtNresizeToPreferred,   True,
        !           273:        XtNskipAdjust,          True,
        !           274:        XtNshowGrip,            False,
        !           275:        XtNforeground,          gui.menu_fg_pixel,
        !           276:        XtNbackground,          gui.menu_bg_pixel,
        !           277:        XtNborderColor,         gui.menu_fg_pixel,
        !           278:        NULL);
        !           279:
        !           280:    /*
        !           281:     * Panes for the middle stuff (left scrollbar box, text area, and right
        !           282:     * scrollbar box.
        !           283:     */
        !           284:    vimForm = XtVaCreateManagedWidget("vimForm",
        !           285:        panedWidgetClass,       vimPanes,
        !           286:        XtNallowResize,         True,
        !           287:        XtNorientation,         XtorientHorizontal,
        !           288:        XtNborderWidth,         0,
        !           289:        XtNdefaultDistance,     0,
        !           290:        XtNshowGrip,            False,
        !           291:        NULL);
        !           292:
        !           293:    /* Panes for the left window scrollbars. */
        !           294:    scrollbarBox[SB_LEFT] = XtVaCreateWidget("scrollBarBox",
        !           295:        panedWidgetClass,       vimForm,
        !           296:        XtNpreferredPaneSize,   gui.scrollbar_width,
        !           297:        XtNallowResize,         True,
        !           298:        XtNskipAdjust,          True,
        !           299:        XtNborderWidth,         1,
        !           300:        XtNshowGrip,            False,
        !           301:        XtNforeground,          gui.scroll_fg_pixel,
        !           302:        XtNbackground,          gui.scroll_fg_pixel,
        !           303:        XtNborderColor,         gui.scroll_fg_pixel,
        !           304:        NULL);
        !           305:
        !           306:    /* The text area. */
        !           307:    textArea = XtVaCreateManagedWidget("textArea",
        !           308:        coreWidgetClass,        vimForm,
        !           309:        XtNallowResize,         True,
        !           310:        XtNshowGrip,            False,
        !           311:        XtNbackground,          gui.back_pixel,
        !           312:        XtNborderWidth,         0,
        !           313:        XtNheight,              Rows * gui.char_height + base_height,
        !           314:        XtNwidth,               Columns * gui.char_width + base_width,
        !           315:        NULL);
        !           316:
        !           317:    /* Panes for the right window scrollbars. */
        !           318:    scrollbarBox[SB_RIGHT] = XtVaCreateWidget("scrollBarBox",
        !           319:        panedWidgetClass,       vimForm,
        !           320:        XtNpreferredPaneSize,   gui.scrollbar_width,
        !           321:        XtNallowResize,         True,
        !           322:        XtNskipAdjust,          True,
        !           323:        XtNborderWidth,         1,
        !           324:        XtNresizeToPreferred,   True,
        !           325:        XtNshowGrip,            False,
        !           326:        XtNforeground,          gui.scroll_fg_pixel,
        !           327:        XtNbackground,          gui.scroll_fg_pixel,
        !           328:        XtNborderColor,         gui.scroll_fg_pixel,
        !           329:        NULL);
        !           330:
        !           331:    /* Panes for the bottom scrollbar and fillers on each side. */
        !           332:    scrollbarBox[SB_BOTTOM] = XtVaCreateWidget("scrollBarBox",
        !           333:        panedWidgetClass,       vimPanes,
        !           334:        XtNpreferredPaneSize,   gui.scrollbar_width,
        !           335:        XtNallowResize,         True,
        !           336:        XtNskipAdjust,          True,
        !           337:        XtNborderWidth,         1,
        !           338:        XtNresizeToPreferred,   True,
        !           339:        XtNshowGrip,            False,
        !           340:        XtNforeground,          gui.scroll_fg_pixel,
        !           341:        XtNbackground,          gui.scroll_fg_pixel,
        !           342:        XtNborderColor,         gui.scroll_fg_pixel,
        !           343:        XtNorientation,         XtorientHorizontal,
        !           344:        NULL);
        !           345:
        !           346:    /* A filler for the gap on the left side of the bottom scrollbar. */
        !           347:    leftBottomScrollFiller = XtVaCreateManagedWidget("",
        !           348:        labelWidgetClass,   scrollbarBox[SB_BOTTOM],
        !           349:        XtNshowGrip,        False,
        !           350:        XtNresize,          False,
        !           351:        XtNborderWidth,     4,
        !           352:        XtNmin,             gui.scrollbar_width + 1,
        !           353:        XtNmax,             gui.scrollbar_width + 1,
        !           354:        XtNforeground,      gui.scroll_fg_pixel,
        !           355:        XtNbackground,      gui.scroll_fg_pixel,
        !           356:        XtNborderColor,     gui.scroll_fg_pixel,
        !           357:        NULL);
        !           358:
        !           359:    /* The bottom scrollbar. */
        !           360:    bottomScrollbar = XtVaCreateManagedWidget("bottomScrollBar",
        !           361:        vim_scrollbarWidgetClass,   scrollbarBox[SB_BOTTOM],
        !           362:        XtNresizeToPreferred,   True,
        !           363:        XtNallowResize,         True,
        !           364:        XtNskipAdjust,          True,
        !           365:        XtNshowGrip,            False,
        !           366:        XtNorientation,         XtorientHorizontal,
        !           367:        XtNforeground,          gui.scroll_fg_pixel,
        !           368:        XtNbackground,          gui.scroll_bg_pixel,
        !           369:        NULL);
        !           370:
        !           371:    XtAddCallback(bottomScrollbar, XtNjumpProc,
        !           372:            gui_athena_scroll_cb_jump, (XtPointer)NULL);
        !           373:    XtAddCallback(bottomScrollbar, XtNscrollProc,
        !           374:            gui_athena_scroll_cb_scroll, (XtPointer)NULL);
        !           375:
        !           376:    vim_XawScrollbarSetThumb(bottomScrollbar, 0., 1., 0.);
        !           377:
        !           378:    /* A filler for the gap on the right side of the bottom scrollbar. */
        !           379:    rightBottomScrollFiller = XtVaCreateManagedWidget("",
        !           380:        labelWidgetClass,   scrollbarBox[SB_BOTTOM],
        !           381:        XtNshowGrip,        False,
        !           382:        XtNresize,          False,
        !           383:        XtNborderWidth,     4,
        !           384:        XtNmin,             gui.scrollbar_width + 1,
        !           385:        XtNmax,             gui.scrollbar_width + 1,
        !           386:        XtNforeground,      gui.scroll_fg_pixel,
        !           387:        XtNbackground,      gui.scroll_fg_pixel,
        !           388:        NULL);
        !           389:
        !           390:    /* A filler for the gap on the bottom of the left scrollbar. */
        !           391:    leftScrollbarFiller = XtVaCreateManagedWidget("",
        !           392:        labelWidgetClass,   scrollbarBox[SB_LEFT],
        !           393:        XtNshowGrip,        False,
        !           394:        XtNresize,          False,
        !           395:        XtNborderWidth,     4,
        !           396:        XtNmin,             gui.scrollbar_width + 1,
        !           397:        XtNmax,             gui.scrollbar_width + 1,
        !           398:        XtNforeground,      gui.scroll_fg_pixel,
        !           399:        XtNbackground,      gui.scroll_fg_pixel,
        !           400:        NULL);
        !           401:
        !           402:    /* A filler for the gap on the bottom of the right scrollbar. */
        !           403:    rightScrollbarFiller = XtVaCreateManagedWidget("",
        !           404:        labelWidgetClass,   scrollbarBox[SB_RIGHT],
        !           405:        XtNshowGrip,        False,
        !           406:        XtNresize,          False,
        !           407:        XtNborderWidth,     4,
        !           408:        XtNmin,             gui.scrollbar_width + 1,
        !           409:        XtNmax,             gui.scrollbar_width + 1,
        !           410:        XtNforeground,      gui.scroll_fg_pixel,
        !           411:        XtNbackground,      gui.scroll_fg_pixel,
        !           412:        NULL);
        !           413:
        !           414:    gui.num_scrollbars = 0;
        !           415:
        !           416:    /*
        !           417:     * Text area callbacks
        !           418:     */
        !           419:    XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
        !           420:        gui_x11_visibility_cb, (XtPointer)0);
        !           421:
        !           422:    XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
        !           423:        (XtPointer)0);
        !           424:
        !           425:    XtAddEventHandler(textArea, StructureNotifyMask, FALSE,
        !           426:        gui_x11_resize_window_cb, (XtPointer)0);
        !           427:
        !           428:    XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
        !           429:        (XtPointer)0);
        !           430:
        !           431:    XtAddEventHandler(vimPanes, KeyPressMask, FALSE, gui_x11_key_hit_cb,
        !           432:        (XtPointer)0);
        !           433:
        !           434:    XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
        !           435:        ButtonMotionMask, FALSE, gui_x11_mouse_cb, (XtPointer)0);
        !           436:
        !           437:    parentTrans = XtParseTranslationTable("<BtnMotion>: highlight() menu-pullright()");
        !           438:    menuTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight() MenuPopdown()\n<BtnUp>: notify() unhighlight() MenuPopdown()\n<BtnMotion>: highlight()");
        !           439:
        !           440:    XtAppAddActions(XtWidgetToApplicationContext(vimForm), &pullAction, 1);
        !           441:
        !           442:    pullerBitmap = XCreateBitmapFromData(gui.dpy, DefaultRootWindow(gui.dpy),
        !           443:                            (char *)puller_bits, puller_width, puller_height);
        !           444: }
        !           445:
        !           446:    int
        !           447: gui_mch_get_winsize()
        !           448: {
        !           449:    Dimension   base_width, base_height;
        !           450:    Dimension   total_width, total_height;
        !           451:    Dimension   left_width = 0, right_width = 0;
        !           452:    Dimension   bottom_height = 0, menu_height = 0;
        !           453:
        !           454:    base_height = 2 * gui.border_offset;
        !           455:    base_width  = 2 * gui.border_offset;
        !           456:
        !           457:    if (gui.which_scrollbars[SB_LEFT])
        !           458:        XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);
        !           459:
        !           460:    if (gui.which_scrollbars[SB_RIGHT])
        !           461:        XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);
        !           462:
        !           463:    if (gui.which_scrollbars[SB_BOTTOM])
        !           464:        XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);
        !           465:
        !           466:    if (XtIsManaged(menuBar))
        !           467:        XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);
        !           468:
        !           469:    base_width  += left_width + right_width;
        !           470:    base_height += menu_height + bottom_height;
        !           471:
        !           472:    XtVaGetValues(vimShell,
        !           473:        XtNheight, &total_height,
        !           474:        XtNwidth,  &total_width,
        !           475:        NULL);
        !           476:
        !           477:    gui.num_rows = (total_height - base_height) / gui.char_height;
        !           478:    gui.num_cols = (total_width  - base_width)  / gui.char_width;
        !           479:
        !           480:    Rows    = gui.num_rows;
        !           481:    Columns = gui.num_cols;
        !           482:    gui_reset_scroll_region();
        !           483:
        !           484:    return OK;
        !           485: }
        !           486:
        !           487:    void
        !           488: gui_mch_set_winsize()
        !           489: {
        !           490:    Dimension   left_width = 0, right_width = 0;
        !           491:    Dimension   bottom_height = 0, menu_height = 0;
        !           492:    Dimension   base_width, base_height;
        !           493:
        !           494:    base_width  = 2 * gui.border_offset;
        !           495:    base_height = 2 * gui.border_offset;
        !           496:
        !           497:    if (gui.which_scrollbars[SB_LEFT])
        !           498:        XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);
        !           499:
        !           500:    if (gui.which_scrollbars[SB_RIGHT])
        !           501:        XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);
        !           502:
        !           503:    if (gui.which_scrollbars[SB_BOTTOM])
        !           504:        XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);
        !           505:
        !           506:    if (XtIsManaged(menuBar))
        !           507:        XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);
        !           508:
        !           509:    base_width  += left_width + right_width;
        !           510:    base_height += menu_height + bottom_height;
        !           511:
        !           512:    XtVaSetValues(vimShell,
        !           513:        XtNwidthInc,   gui.char_width,
        !           514:        XtNheightInc,  gui.char_height,
        !           515:        XtNbaseWidth,  base_width,
        !           516:        XtNbaseHeight, base_height,
        !           517:        XtNminWidth,   base_width  + MIN_COLUMNS * gui.char_width,
        !           518:        XtNminHeight,  base_height + MIN_ROWS    * gui.char_height,
        !           519:        XtNwidth,      base_width  + Columns     * gui.char_width,
        !           520:        XtNheight,     base_height + Rows        * gui.char_height,
        !           521:        NULL);
        !           522: }
        !           523:
        !           524: /*
        !           525:  * Menu stuff.
        !           526:  */
        !           527:
        !           528:    void
        !           529: gui_mch_add_menu(menu, parent)
        !           530:    GuiMenu *menu;
        !           531:    GuiMenu *parent;
        !           532: {
        !           533:    char_u  *pullright_name;
        !           534:
        !           535:    if (parent == NULL)
        !           536:    {
        !           537:        menu->id = XtVaCreateManagedWidget(menu->name,
        !           538:            menuButtonWidgetClass, menuBar,
        !           539:            XtNmenuName, menu->name,
        !           540:            XtNforeground, gui.menu_fg_pixel,
        !           541:            XtNbackground, gui.menu_bg_pixel,
        !           542:            NULL);
        !           543:
        !           544:        menu->submenu_id = XtVaCreatePopupShell(menu->name,
        !           545:            simpleMenuWidgetClass, menu->id,
        !           546:            XtNforeground, gui.menu_fg_pixel,
        !           547:            XtNbackground, gui.menu_bg_pixel,
        !           548:            NULL);
        !           549:
        !           550:        gui_athena_reorder_menus();
        !           551:    }
        !           552:    else
        !           553:    {
        !           554:        menu->id = XtVaCreateManagedWidget(menu->name,
        !           555:            smeBSBObjectClass, parent->submenu_id,
        !           556:            XtNforeground, gui.menu_fg_pixel,
        !           557:            XtNbackground, gui.menu_bg_pixel,
        !           558:            XtNrightMargin, puller_width,
        !           559:            XtNrightBitmap, pullerBitmap,
        !           560:
        !           561:            NULL);
        !           562:        XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
        !           563:            (XtPointer)menu);
        !           564:
        !           565:        pullright_name = strnsave(menu->name, strlen(menu->name) +
        !           566:                                                        strlen("-pullright"));
        !           567:        strcat(pullright_name, "-pullright");
        !           568:        menu->submenu_id = XtVaCreatePopupShell(pullright_name,
        !           569:            simpleMenuWidgetClass, parent->submenu_id,
        !           570:            XtNforeground, gui.menu_fg_pixel,
        !           571:            XtNbackground, gui.menu_bg_pixel,
        !           572:            XtNtranslations, menuTrans,
        !           573:            NULL);
        !           574:        vim_free(pullright_name);
        !           575:
        !           576:        XtOverrideTranslations(parent->submenu_id, parentTrans);
        !           577:    }
        !           578: }
        !           579:
        !           580:    void
        !           581: gui_mch_add_menu_item(menu, parent)
        !           582:    GuiMenu *menu;
        !           583:    GuiMenu *parent;
        !           584: {
        !           585:    menu->submenu_id = (Widget)0;
        !           586:    menu->id = XtVaCreateManagedWidget(menu->name,
        !           587:        smeBSBObjectClass, parent->submenu_id,
        !           588:        XtNforeground, gui.menu_fg_pixel,
        !           589:        XtNbackground, gui.menu_bg_pixel,
        !           590:        NULL);
        !           591:    XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
        !           592:        (XtPointer)menu);
        !           593: }
        !           594:
        !           595: /*
        !           596:  * Destroy the machine specific menu widget.
        !           597:  */
        !           598:    void
        !           599: gui_mch_destroy_menu(menu)
        !           600:    GuiMenu *menu;
        !           601: {
        !           602:    if (menu->id != (Widget)NULL)
        !           603:    {
        !           604:        /*
        !           605:         * This is a hack for the Athena simpleMenuWidget to keep it from
        !           606:         * getting a BadValue error when it's last child is destroyed. We
        !           607:         * check to see if this is the last child and if so, go ahead and
        !           608:         * delete the parent ahead of time. The parent will delete it's
        !           609:         * children like all good widgets do.
        !           610:         */
        !           611:        if (XtParent(menu->id) != menuBar)
        !           612:        {
        !           613:            int num_children;
        !           614:
        !           615:            XtVaGetValues(XtParent(menu->id),
        !           616:                    XtNnumChildren, &num_children, NULL);
        !           617:            if (num_children <= 1)
        !           618:                XtDestroyWidget(XtParent(menu->id));
        !           619:            else
        !           620:                XtDestroyWidget(menu->id);
        !           621:        }
        !           622:        else
        !           623:            XtDestroyWidget(menu->id);
        !           624:        menu->id = (Widget)NULL;
        !           625:    }
        !           626: }
        !           627:
        !           628: /*
        !           629:  * Reorder the menus so "Help" is the rightmost item on the menu.
        !           630:  */
        !           631:    static void
        !           632: gui_athena_reorder_menus()
        !           633: {
        !           634:    Widget  *children;
        !           635:    Widget  help_widget = (Widget)NULL;
        !           636:    int     num_children;
        !           637:    int     i;
        !           638:
        !           639:    XtVaGetValues(menuBar,
        !           640:            XtNchildren,    &children,
        !           641:            XtNnumChildren, &num_children,
        !           642:            NULL);
        !           643:
        !           644:    XtUnmanageChildren(children, num_children);
        !           645:
        !           646:    for (i = 0; i < num_children - 1; i++)
        !           647:        if (help_widget == (Widget)NULL)
        !           648:        {
        !           649:            if (strcmp((char *)XtName(children[i]), "Help") == 0)
        !           650:            {
        !           651:                help_widget = children[i];
        !           652:                children[i] = children[i + 1];
        !           653:            }
        !           654:        }
        !           655:        else
        !           656:            children[i] = children[i + 1];
        !           657:
        !           658:    if (help_widget != (Widget)NULL)
        !           659:        children[num_children - 1] = help_widget;
        !           660:
        !           661:    XtManageChildren(children, num_children);
        !           662: }
        !           663:
        !           664:
        !           665: /*
        !           666:  * Scrollbar stuff:
        !           667:  */
        !           668:
        !           669:    void
        !           670: gui_mch_create_which_components()
        !           671: {
        !           672:    static int prev_which_scrollbars[3] = {-1, -1, -1};
        !           673:    static int prev_menu_is_active = -1;
        !           674:
        !           675:    int       i;
        !           676:    WIN       *wp;
        !           677:
        !           678:    /*
        !           679:     * When removing the left/right scrollbar and creating the right/left
        !           680:     * scrollbar, we have to force a redraw (the size of the text area doesn't
        !           681:     * change).
        !           682:     */
        !           683:    if (prev_which_scrollbars[SB_LEFT] != gui.which_scrollbars[SB_LEFT] &&
        !           684:            prev_which_scrollbars[SB_RIGHT] != gui.which_scrollbars[SB_RIGHT])
        !           685:        must_redraw = CLEAR;
        !           686:
        !           687:    gui_x11_use_resize_callback(textArea, FALSE);
        !           688:
        !           689:    for (i = 0; i < 3; i++)
        !           690:    {
        !           691:        if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
        !           692:        {
        !           693:            if (gui.which_scrollbars[i])
        !           694:            {
        !           695:                switch (i)
        !           696:                {
        !           697:                    /* When adding the left one, we need to reorder them all */
        !           698:                    case SB_LEFT:
        !           699:                        XtUnmanageChild(textArea);
        !           700:                        if (gui.which_scrollbars[SB_RIGHT])
        !           701:                            XtUnmanageChild(scrollbarBox[SB_RIGHT]);
        !           702:                        XtManageChild(scrollbarBox[SB_LEFT]);
        !           703:                        XtManageChild(textArea);
        !           704:                        if (gui.which_scrollbars[SB_RIGHT])
        !           705:                            XtManageChild(scrollbarBox[SB_RIGHT]);
        !           706:
        !           707:                        /*
        !           708:                         * When adding at the left and we have a bottom
        !           709:                         * scrollbar, we need to reorder these too.
        !           710:                         */
        !           711:                        if (gui.which_scrollbars[SB_BOTTOM])
        !           712:                        {
        !           713:                            XtUnmanageChild(bottomScrollbar);
        !           714:                            if (gui.which_scrollbars[SB_RIGHT])
        !           715:                                XtUnmanageChild(rightBottomScrollFiller);
        !           716:
        !           717:                            XtManageChild(leftBottomScrollFiller);
        !           718:                            XtManageChild(bottomScrollbar);
        !           719:                            if (gui.which_scrollbars[SB_RIGHT])
        !           720:                                XtManageChild(rightBottomScrollFiller);
        !           721:                        }
        !           722:                        break;
        !           723:
        !           724:                    case SB_RIGHT:
        !           725:                        XtManageChild(rightBottomScrollFiller);
        !           726:                        XtManageChild(scrollbarBox[i]);
        !           727:                        break;
        !           728:
        !           729:                    case SB_BOTTOM:
        !           730:                        /* Unmanage the bottom scrollbar and fillers */
        !           731:                        XtUnmanageChild(leftBottomScrollFiller);
        !           732:                        XtUnmanageChild(bottomScrollbar);
        !           733:                        XtUnmanageChild(rightBottomScrollFiller);
        !           734:
        !           735:                        /*
        !           736:                         * Now manage the bottom scrollbar and fillers that
        !           737:                         * are supposed to be there.
        !           738:                         */
        !           739:                        if (gui.which_scrollbars[SB_LEFT])
        !           740:                            XtManageChild(leftBottomScrollFiller);
        !           741:                        XtManageChild(bottomScrollbar);
        !           742:                        if (gui.which_scrollbars[SB_RIGHT])
        !           743:                            XtManageChild(rightBottomScrollFiller);
        !           744:
        !           745:                        XtManageChild(scrollbarBox[i]);
        !           746:                        break;
        !           747:                }
        !           748:            }
        !           749:            else
        !           750:            {
        !           751:                switch (i)
        !           752:                {
        !           753:                    case SB_LEFT:
        !           754:                        XtUnmanageChild(leftBottomScrollFiller);
        !           755:                        break;
        !           756:
        !           757:                    case SB_RIGHT:
        !           758:                        XtUnmanageChild(rightBottomScrollFiller);
        !           759:                        break;
        !           760:                }
        !           761:                XtUnmanageChild(scrollbarBox[i]);
        !           762:            }
        !           763:        }
        !           764:        if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
        !           765:        {
        !           766:            if (i == SB_LEFT || i == SB_RIGHT)
        !           767:            {
        !           768:                if (gui.which_scrollbars[i])
        !           769:                {
        !           770:                    /* Scrollbar box has just appeared */
        !           771:                    gui.new_sb[i] = TRUE;
        !           772:                }
        !           773:                else if (prev_which_scrollbars[i] == TRUE)
        !           774:                {
        !           775:                    /* Scrollbar box has just been deleted */
        !           776:                    for (wp = firstwin; wp != NULL; wp = wp->w_next)
        !           777:                        XtDestroyWidget(wp->w_scrollbar.id[i]);
        !           778:                }
        !           779:            }
        !           780:        }
        !           781:        prev_which_scrollbars[i] = gui.which_scrollbars[i];
        !           782:    }
        !           783:
        !           784:    if (gui.menu_is_active != prev_menu_is_active)
        !           785:    {
        !           786:        if (gui.menu_is_active)
        !           787:        {
        !           788:            XtUnmanageChild(menuBar);
        !           789:            XtUnmanageChild(vimForm);
        !           790:            if (gui.which_scrollbars[SB_BOTTOM])
        !           791:                XtUnmanageChild(scrollbarBox[SB_BOTTOM]);
        !           792:
        !           793:            XtManageChild(menuBar);
        !           794:            XtManageChild(vimForm);
        !           795:            if (gui.which_scrollbars[SB_BOTTOM])
        !           796:                XtManageChild(scrollbarBox[SB_BOTTOM]);
        !           797:        }
        !           798:        else
        !           799:            XtUnmanageChild(menuBar);
        !           800:        prev_menu_is_active = gui.menu_is_active;
        !           801:    }
        !           802:
        !           803:    gui_x11_use_resize_callback(textArea, TRUE);
        !           804:    if (vimForm != (Widget)NULL && XtIsRealized(vimForm))
        !           805:        gui_mch_set_winsize();
        !           806: }
        !           807:
        !           808:
        !           809: /*
        !           810:  * Vertical scrollbar stuff:
        !           811:  */
        !           812:    void
        !           813: gui_mch_update_scrollbars(worst_update, which_sb)
        !           814:    int     worst_update;
        !           815:    int     which_sb;       /* SB_LEFT or SB_RIGHT */
        !           816: {
        !           817:    WIN             *wp;
        !           818:    GuiScrollbar    *sb;
        !           819:    int             idx;
        !           820:    Dimension       h;      /* Height of scrollbar (in pixels) */
        !           821:    Dimension       y;      /* Coord of top of scrollbar (in pixels) */
        !           822:    int             tmp;
        !           823:    float           val = 0., size = 0.;
        !           824:
        !           825:    if (worst_update >= SB_UPDATE_HEIGHT)
        !           826:    {
        !           827:        XawPanedSetRefigureMode(scrollbarBox[which_sb], False);
        !           828:        gui_x11_use_resize_callback(textArea, FALSE);
        !           829:    }
        !           830:
        !           831:    /*
        !           832:     * This has to get cleared manually since Athena doesn't tell us when the
        !           833:     * draggin' stops.
        !           834:     */
        !           835:    gui.dragged_sb = SB_NONE;
        !           836:
        !           837:    for (wp = firstwin, idx = 0; wp; wp = wp->w_next, idx++)
        !           838:    {
        !           839:        sb = &wp->w_scrollbar;
        !           840:        if (sb->update[which_sb] >= SB_UPDATE_VALUE)
        !           841:        {
        !           842:            val = (float)(sb->value - 1) / (float)sb->max;
        !           843:            size = (float)sb->size / (float)sb->max;
        !           844:        }
        !           845:        if (sb->update[which_sb] == SB_UPDATE_CREATE)
        !           846:        {
        !           847:            sb->id[which_sb] = XtVaCreateManagedWidget("scrollBar",
        !           848:                    vim_scrollbarWidgetClass, scrollbarBox[which_sb],
        !           849:                    XtNborderWidth, 1,
        !           850:                    XtNdefaultDistance, 0,
        !           851:                    XtNallowResize, True,
        !           852:                    XtNpreferredPaneSize, True,
        !           853:                    XtNresizeToPreferred, True,
        !           854:                    XtNskipAdjust, True,
        !           855:                    XtNorientation, XtorientVertical,
        !           856:                    XtNshowGrip, False,
        !           857:                    XtNforeground, gui.scroll_fg_pixel,
        !           858:                    XtNbackground, gui.scroll_bg_pixel,
        !           859:                    NULL);
        !           860:            XtAddCallback(sb->id[which_sb], XtNjumpProc,
        !           861:                gui_athena_scroll_cb_jump, (XtPointer)wp);
        !           862:            XtAddCallback(sb->id[which_sb], XtNscrollProc,
        !           863:                gui_athena_scroll_cb_scroll, (XtPointer)wp);
        !           864:        }
        !           865:        if (sb->update[which_sb] >= SB_UPDATE_HEIGHT)
        !           866:        {
        !           867:            h = sb->height * gui.char_height
        !           868:                    + sb->status_height * gui.char_height / 2;
        !           869:            y = wp->w_winpos * gui.char_height + gui.border_offset;
        !           870:
        !           871:            if (wp == firstwin)
        !           872:            {
        !           873:                /* Height of top scrollbar includes width of top border */
        !           874:                h += gui.border_offset;
        !           875:            }
        !           876:            else
        !           877:            {
        !           878:                /*
        !           879:                 * Height of other scrollbars includes half of status bar above
        !           880:                 */
        !           881:                tmp = wp->w_prev->w_status_height * (gui.char_height + 1) / 2;
        !           882:                h += tmp;
        !           883:                y -= tmp;
        !           884:            }
        !           885:
        !           886:            XtVaSetValues(sb->id[which_sb],
        !           887:                XtNheight, h,
        !           888:                XtNmin, h,
        !           889:                XtNmax, h,
        !           890:                XtNy, y,
        !           891:                NULL);
        !           892:            vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
        !           893:        }
        !           894:        else if (sb->update[which_sb] == SB_UPDATE_VALUE)
        !           895:        {
        !           896:            vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
        !           897:        }
        !           898:        sb->update[which_sb] = SB_UPDATE_NOTHING;
        !           899:    }
        !           900:
        !           901:    if (worst_update >= SB_UPDATE_HEIGHT)
        !           902:    {
        !           903:        if (worst_update >= SB_UPDATE_CREATE)
        !           904:            gui_mch_reorder_scrollbars(which_sb);
        !           905:        XawPanedSetRefigureMode(scrollbarBox[which_sb], True);
        !           906:        gui_x11_use_resize_callback(textArea, TRUE);
        !           907:    }
        !           908: }
        !           909:
        !           910:    void
        !           911: gui_mch_reorder_scrollbars(which_sb)
        !           912:    int     which_sb;
        !           913: {
        !           914:    WIN     *wp;
        !           915:
        !           916:    if (which_sb == SB_LEFT)
        !           917:        XtUnmanageChild(leftScrollbarFiller);
        !           918:    else
        !           919:        XtUnmanageChild(rightScrollbarFiller);
        !           920:
        !           921:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
        !           922:        if (wp->w_scrollbar.id[which_sb] != NULL)
        !           923:            XtUnmanageChild(wp->w_scrollbar.id[which_sb]);
        !           924:
        !           925:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
        !           926:        if (wp->w_scrollbar.id[which_sb] != NULL)
        !           927:            XtManageChild(wp->w_scrollbar.id[which_sb]);
        !           928:
        !           929:    if (which_sb == SB_LEFT)
        !           930:        XtManageChild(leftScrollbarFiller);
        !           931:    else
        !           932:        XtManageChild(rightScrollbarFiller);
        !           933:
        !           934: }
        !           935:
        !           936:    void
        !           937: gui_mch_destroy_scrollbar(wp)
        !           938:    WIN     *wp;
        !           939: {
        !           940:    if (gui.which_scrollbars[SB_LEFT])
        !           941:        XtDestroyWidget(wp->w_scrollbar.id[SB_LEFT]);
        !           942:    if (gui.which_scrollbars[SB_RIGHT])
        !           943:        XtDestroyWidget(wp->w_scrollbar.id[SB_RIGHT]);
        !           944:    gui.num_scrollbars--;
        !           945: }
        !           946:
        !           947:
        !           948: /*
        !           949:  * Horizontal scrollbar stuff:
        !           950:  */
        !           951:    void
        !           952: gui_mch_update_horiz_scrollbar(value, size, max)
        !           953:    int     value;
        !           954:    int     size;
        !           955:    int     max;
        !           956: {
        !           957:    static int prev_value = -1, prev_size = -1, prev_max = -1;
        !           958:    float val, shown, maxval;
        !           959:
        !           960:    if (value == prev_value && size == prev_size && max == prev_max)
        !           961:        return;
        !           962:
        !           963:    prev_value = value;
        !           964:    prev_size = size;
        !           965:    prev_max = max;
        !           966:
        !           967:    if (max == 1)           /* maximum is one more than maximal value */
        !           968:    {
        !           969:        val   = 0.0;
        !           970:        shown = 1.0;
        !           971:        maxval = 0.0;
        !           972:    }
        !           973:    else
        !           974:    {
        !           975:        val   = (float)value / (float)max;
        !           976:        shown = (float)size  / (float)max;
        !           977:        maxval = 1.0;
        !           978:    }
        !           979:    vim_XawScrollbarSetThumb(bottomScrollbar, val, shown, maxval);
        !           980: }
        !           981:
        !           982:    Window
        !           983: gui_mch_get_wid()
        !           984: {
        !           985:    return( XtWindow(textArea) );
        !           986: }
        !           987:
        !           988:    static void
        !           989: gui_athena_pullright_action(w, event, args, nargs)
        !           990:    Widget      w;
        !           991:    XEvent      *event;
        !           992:    String      *args;
        !           993:    Cardinal    *nargs;
        !           994: {
        !           995:    Widget      menuw;
        !           996:    Dimension   width, height;
        !           997:    char_u      *pullright_name;
        !           998:    Widget      popup;
        !           999:
        !          1000:    if (event->type != MotionNotify)
        !          1001:        return;
        !          1002:
        !          1003:    /* Get the active entry for the current menu */
        !          1004:    if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)NULL)
        !          1005:        return;
        !          1006:
        !          1007:    XtVaGetValues(w,
        !          1008:        XtNwidth,   &width,
        !          1009:        XtNheight,  &height,
        !          1010:        NULL);
        !          1011:
        !          1012:    if (event->xmotion.x >= width || event->xmotion.y >= height)
        !          1013:        return;
        !          1014:
        !          1015:    /* We do the pull-off when the pointer is in the rightmost 1/4th */
        !          1016:    if (event->xmotion.x < (width * 3) / 4)
        !          1017:        return;
        !          1018:
        !          1019:    pullright_name = strnsave(XtName(menuw), strlen(XtName(menuw)) +
        !          1020:                                                    strlen("-pullright"));
        !          1021:    strcat(pullright_name, "-pullright");
        !          1022:    popup = XtNameToWidget(w, pullright_name);
        !          1023:    vim_free(pullright_name);
        !          1024:
        !          1025:    if (popup == (Widget)NULL)
        !          1026:        return;
        !          1027:
        !          1028:    XtVaSetValues(popup,
        !          1029:        XtNx, event->xmotion.x_root,
        !          1030:        XtNy, event->xmotion.y_root - 7,
        !          1031:        NULL);
        !          1032:
        !          1033:    XtPopup(popup, XtGrabExclusive);
        !          1034: }