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

1.2     ! downsj      1: /* $OpenBSD: gui_athena.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:  *                             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:
1.2     ! downsj     31: static char_u puller_bits[] =
1.1       downsj     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:
1.2     ! downsj    103:            value = *((float *)call_data) * (float)(sb->max - 1) + 0.5;
1.1       downsj    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:
1.2     ! downsj    565:        pullright_name = strnsave(menu->name,
        !           566:                                   STRLEN(menu->name) + strlen("-pullright"));
        !           567:        strcat((char *)pullright_name, "-pullright");
1.1       downsj    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:
1.2     ! downsj   1019:    pullright_name = strnsave((char_u *)XtName(menuw),
        !          1020:                                strlen(XtName(menuw)) + strlen("-pullright"));
        !          1021:    strcat((char *)pullright_name, "-pullright");
1.1       downsj   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: }